/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
package org.alfresco.repo.version;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ApplicationModel;
import org.alfresco.model.ContentModel;
import org.alfresco.model.WebDAVModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.version.common.VersionUtil;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.cmr.version.VersionServiceException;
import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
/**
* versionService test class.
*
* @author Roy Wetherall, janv
*/
public class VersionServiceImplTest extends BaseVersionStoreTest
{
private static Log logger = LogFactory.getLog(VersionServiceImplTest.class);
private static final String UPDATED_VALUE_1 = "updatedValue1";
private static final String UPDATED_VALUE_2 = "updatedValue2";
private static final String UPDATED_VALUE_3 = "updatedValue3";
private static final String UPDATED_CONTENT_1 = "updatedContent1";
private static final String UPDATED_CONTENT_2 = "updatedContent2";
private static final String PWD_A = "passA";
private static final String USER_NAME_A = "userA";
private VersionableAspect versionableAspect;
private List excludedOnUpdateProps;
@Override
protected void onSetUpInTransaction() throws Exception
{
super.onSetUpInTransaction();
versionableAspect = (VersionableAspect) applicationContext.getBean("versionableAspect");
excludedOnUpdateProps = versionableAspect.getExcludedOnUpdateProps();
}
@Override
protected void onTearDownAfterTransaction() throws Exception
{
super.onTearDownAfterTransaction();
versionableAspect.setExcludedOnUpdateProps(excludedOnUpdateProps);
versionableAspect.afterDictionaryInit();
}
public void testSetup()
{
// NOOP
}
/**
* Tests the creation of the initial version of a versionable node
*/
public void testCreateIntialVersion()
{
NodeRef versionableNode = createNewVersionableNode();
createVersion(versionableNode);
}
/**
* Test creating a version history with many versions from the same workspace
*/
public void testCreateManyVersionsSameWorkspace()
{
NodeRef versionableNode = createNewVersionableNode();
createVersion(versionableNode);
// TODO mess with some of the properties and stuff as you version
createVersion(versionableNode);
// TODO mess with some of the properties and stuff as you version
createVersion(versionableNode);
VersionHistory vh = this.versionService.getVersionHistory(versionableNode);
assertNotNull(vh);
assertEquals(3, vh.getAllVersions().size());
// TODO check list of versions ... !
}
/**
* Tests the creation of multiple versions of a versionable node with null version properties
*/
public void testCreateManyVersionsWithNullVersionProperties()
{
this.versionProperties = null;
NodeRef versionableNode = createNewVersionableNode();
createVersion(versionableNode);
createVersion(versionableNode);
createVersion(versionableNode);
VersionHistory vh = this.versionService.getVersionHistory(versionableNode);
assertNotNull(vh);
assertEquals(3, vh.getAllVersions().size());
}
/**
* Test versioning a non versionable node ie: no version apsect
*/
public void testCreateInitialVersionWhenNotVersionable()
{
NodeRef node = createNewNode(); // not marked as versionable
createVersion(node);
}
// TODO test versioning numberious times with branchs implies by different workspaces
/**
* Test versioning the children of a verionable node
*/
public void testVersioningChildren()
{
NodeRef versionableNode = createNewVersionableNode();
// Snap shot data
String expectedVersionLabel = peekNextVersionLabel(versionableNode, versionProperties);
// Snap-shot the node created date-time
long beforeVersionTime = ((Date)nodeService.getProperty(versionableNode, ContentModel.PROP_CREATED)).getTime();
// Version the node and its children
Collection versions = this.versionService.createVersion(
versionableNode,
this.versionProperties,
true);
// Check the returned versions are correct
CheckVersionCollection(expectedVersionLabel, beforeVersionTime, versions);
// TODO check the version history is correct
}
/**
* Test versioning many nodes in one go
*/
public void testVersioningManyNodes()
{
NodeRef versionableNode = createNewVersionableNode();
// Snap shot data
String expectedVersionLabel = peekNextVersionLabel(versionableNode, versionProperties);
// Snap-shot the node created date-time
long beforeVersionTime = ((Date)nodeService.getProperty(versionableNode, ContentModel.PROP_CREATED)).getTime();
// Version the list of nodes created
Collection versions = this.versionService.createVersion(
this.versionableNodes.values(),
this.versionProperties);
// Check the returned versions are correct
CheckVersionCollection(expectedVersionLabel, beforeVersionTime, versions);
// TODO check the version histories
}
/**
* Helper method to check the validity of the list of newly created versions.
*
* @param beforeVersionTime the time before the versions where created
* @param versions the collection of version objects
*/
private void CheckVersionCollection(String expectedVersionLabel, long beforeVersionTime, Collection versions)
{
for (Version version : versions)
{
// Get the frozen id from the version
String frozenNodeId = null;
// Switch VersionStore depending on configured impl
if (versionService.getVersionStoreReference().getIdentifier().equals(Version2Model.STORE_ID))
{
// V2 version store (eg. workspace://version2Store)
frozenNodeId = ((NodeRef)version.getVersionProperty(Version2Model.PROP_FROZEN_NODE_REF)).getId();
}
else if (versionService.getVersionStoreReference().getIdentifier().equals(VersionModel.STORE_ID))
{
// Deprecated V1 version store (eg. workspace://lightWeightVersionStore)
frozenNodeId = (String)version.getVersionProperty(VersionModel.PROP_FROZEN_NODE_ID);
}
assertNotNull("Unable to retrieve the frozen node id from the created version.", frozenNodeId);
// Get the origional node ref (based on the forzen node)
NodeRef originalNodeRef = this.versionableNodes.get(frozenNodeId);
assertNotNull("The versionable node ref that relates to the frozen node id can not be found.", originalNodeRef);
// Check the new version
checkNewVersion(beforeVersionTime, expectedVersionLabel, version, originalNodeRef);
}
}
private void CheckVersionHistory(VersionHistory vh, List expectedVersions)
{
if (vh == null)
{
assertNull(expectedVersions);
}
else
{
Iterator itr = expectedVersions.iterator();
for (Version version : vh.getAllVersions())
{
Version expectedVersion = itr.next();
assertEquals(version.getVersionLabel(), expectedVersion.getVersionLabel());
assertEquals(version.getFrozenStateNodeRef(), expectedVersion.getFrozenStateNodeRef());
}
assertFalse(itr.hasNext());
}
}
/**
* Tests the version history
*/
public void testNoVersionHistory()
{
NodeRef nodeRef = createNewVersionableNode();
VersionHistory vh = this.versionService.getVersionHistory(nodeRef);
assertNull(vh);
}
/**
* Tests getVersionHistory when all the entries in the version history
* are from the same workspace.
*/
public void testGetVersionHistorySameWorkspace()
{
NodeRef versionableNode = createNewVersionableNode();
Version version1 = addToVersionHistory(versionableNode, null);
Version version2 = addToVersionHistory(versionableNode, version1);
Version version3 = addToVersionHistory(versionableNode, version2);
Version version4 = addToVersionHistory(versionableNode, version3);
addToVersionHistory(versionableNode, version4);
}
/**
* Adds another version to the version history then checks that getVersionHistory is returning
* the correct data.
*
* @param versionableNode the versionable node reference
* @param parentVersion the parent version
*/
private Version addToVersionHistory(NodeRef versionableNode, Version parentVersion)
{
Version createdVersion = createVersion(versionableNode);
VersionHistory vh = this.versionService.getVersionHistory(versionableNode);
assertNotNull("The version history should not be null since we know we have versioned this node.", vh);
if (parentVersion == null)
{
// Check the root is the newly created version
Version root = vh.getRootVersion();
assertNotNull(
"The root version should never be null, since every version history ust have a root version.",
root);
assertEquals(createdVersion.getVersionLabel(), root.getVersionLabel());
}
// Get the version from the version history
Version version = vh.getVersion(createdVersion.getVersionLabel());
assertNotNull(version);
assertEquals(createdVersion.getVersionLabel(), version.getVersionLabel());
// Check that the version is a leaf node of the version history (since it is newly created)
Collection suc = vh.getSuccessors(version);
assertNotNull(suc);
assertEquals(0, suc.size());
// Check that the predessor is the passed parent version (if root version should be null)
Version pre = vh.getPredecessor(version);
if (parentVersion == null)
{
assertNull(pre);
}
else
{
assertNotNull(pre);
assertEquals(parentVersion.getVersionLabel(), pre.getVersionLabel());
}
if (parentVersion != null)
{
// Check that the successors of the parent are the created version
Collection parentSuc = vh.getSuccessors(parentVersion);
assertNotNull(parentSuc);
assertEquals(1, parentSuc.size());
Version tempVersion = (Version)parentSuc.toArray()[0];
assertEquals(version.getVersionLabel(), tempVersion.getVersionLabel());
}
return createdVersion;
}
/**
* Test revert
*/
@SuppressWarnings("unused")
public void testRevert()
{
// Create a versionable node
NodeRef versionableNode = createNewVersionableNode();
// Store the node details for later
Set origAspects = this.dbNodeService.getAspects(versionableNode);
// Create the initial version
Version version1 = createVersion(versionableNode);
// Change the property and content values
this.dbNodeService.setProperty(versionableNode, PROP_1, UPDATED_VALUE_1);
this.dbNodeService.setProperty(versionableNode, PROP_2, null);
ContentWriter contentWriter = this.contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, true);
assertNotNull(contentWriter);
contentWriter.putContent(UPDATED_CONTENT_1);
// Change the aspects on the node
this.dbNodeService.addAspect(versionableNode, ApplicationModel.ASPECT_SIMPLE_WORKFLOW, null);
// Store the node details for later
Set origAspects2 = this.dbNodeService.getAspects(versionableNode);
// Create a new version
Version version2 = createVersion(versionableNode);
// Change the property and content values
this.dbNodeService.setProperty(versionableNode, PROP_1, UPDATED_VALUE_2);
this.dbNodeService.setProperty(versionableNode, PROP_2, UPDATED_VALUE_3);
this.dbNodeService.setProperty(versionableNode, PROP_3, null);
ContentWriter contentWriter2 = this.contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, true);
assertNotNull(contentWriter2);
contentWriter2.putContent(UPDATED_CONTENT_2);
String versionLabel = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
// Revert to the previous version
this.versionService.revert(versionableNode);
// Check that the version label is unchanged
assertEquals(versionLabel, this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL));
// Check that the properties have been reverted
assertEquals(UPDATED_VALUE_1, this.dbNodeService.getProperty(versionableNode, PROP_1));
assertNull(this.dbNodeService.getProperty(versionableNode, PROP_2));
assertEquals(VALUE_3, this.dbNodeService.getProperty(versionableNode, PROP_3));
// Check that the content has been reverted
ContentReader contentReader1 = this.contentService.getReader(versionableNode, ContentModel.PROP_CONTENT);
assertNotNull(contentReader1);
assertEquals(UPDATED_CONTENT_1, contentReader1.getContentString());
// Check that the aspects have been reverted correctly
Set aspects1 = this.dbNodeService.getAspects(versionableNode);
assertEquals(aspects1.size(), origAspects2.size());
// Revert to the first version
this.versionService.revert(versionableNode, version1);
// Check that the version label is correct
assertEquals(versionLabel, this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL));
// Check that the properties are correct
assertEquals(VALUE_1, this.dbNodeService.getProperty(versionableNode, PROP_1));
assertEquals(VALUE_2, this.dbNodeService.getProperty(versionableNode, PROP_2));
assertEquals(VALUE_3, this.dbNodeService.getProperty(versionableNode, PROP_3));
// Check that the content is correct
ContentReader contentReader2 = this.contentService.getReader(versionableNode, ContentModel.PROP_CONTENT);
assertNotNull(contentReader2);
assertEquals(TEST_CONTENT, contentReader2.getContentString());
// Check that the aspects have been reverted correctly
Set aspects2 = this.dbNodeService.getAspects(versionableNode);
assertEquals(aspects2.size(), origAspects.size());
// Check that the version label is still the same
assertEquals(versionLabel, this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL));
}
/**
* Test restore
*/
public void testRestore()
{
// Try and restore a node without any version history
try
{
this.versionService.restore(
new NodeRef(this.testStoreRef, "123"),
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{test}MyVersionableNode"));
fail("An exception should have been raised since this node has no version history.");
}
catch (VersionServiceException exception)
{
// We where expecting this exception
}
// Create a versionable node
NodeRef versionableNode = createNewVersionableNode();
// Store the node details for later
Set origAspects = this.dbNodeService.getAspects(versionableNode);
// Try and restore the node (fail since exist!!)
try
{
this.versionService.restore(
versionableNode,
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{test}MyVersionableNode"));
fail("An exception should have been raised since this node exists and you can't restore a node that exists.");
}
catch (VersionServiceException exception)
{
// We where expecting this exception
}
// Version it
this.versionService.createVersion(versionableNode, null);
// Delete it
this.dbNodeService.deleteNode(versionableNode);
assertFalse(this.dbNodeService.exists(versionableNode));
// Try and resotre it
NodeRef restoredNode = this.versionService.restore(
versionableNode,
this.rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{test}MyVersionableNode"));
assertNotNull(restoredNode);
assertTrue(this.dbNodeService.exists(restoredNode));
// Check that the properties are correct
assertEquals(VALUE_1, this.dbNodeService.getProperty(restoredNode, PROP_1));
assertEquals(VALUE_2, this.dbNodeService.getProperty(restoredNode, PROP_2));
assertEquals(VALUE_3, this.dbNodeService.getProperty(restoredNode, PROP_3));
// Check that the content is correct
ContentReader contentReader2 = this.contentService.getReader(restoredNode, ContentModel.PROP_CONTENT);
assertNotNull(contentReader2);
assertEquals(TEST_CONTENT, contentReader2.getContentString());
// Check that the aspects have been reverted correctly
Set aspects2 = this.dbNodeService.getAspects(restoredNode);
assertEquals(aspects2.size(), origAspects.size());
}
/**
* Test deleteVersionHistory
*/
public void testDeleteVersionHistory()
{
// Create a versionable node
NodeRef versionableNode = createNewVersionableNode();
// Check that there is no version history
VersionHistory versionHistory1 = this.versionService.getVersionHistory(versionableNode);
assertNull(versionHistory1);
// Create a couple of versions
createVersion(versionableNode);
Version version1 = createVersion(versionableNode);
// Check that the version label is correct on the versionable node
String versionLabel1 = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
assertNotNull(versionLabel1);
assertEquals(version1.getVersionLabel(), versionLabel1);
// Check that the version history has been created correctly
VersionHistory versionHistory2 = this.versionService.getVersionHistory(versionableNode);
assertNotNull(versionHistory2);
assertEquals(2, versionHistory2.getAllVersions().size());
// Delete the version history
this.versionService.deleteVersionHistory(versionableNode);
// Check that there is no version history available for the node
VersionHistory versionHistory3 = this.versionService.getVersionHistory(versionableNode);
assertNull(versionHistory3);
// Check that the current version property on the versionable node is no longer set
String versionLabel2 = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
assertNull(versionLabel2);
// Create a couple of versions
createVersion(versionableNode);
Version version2 = createVersion(versionableNode);
// Check that the version history is correct
VersionHistory versionHistory4 = this.versionService.getVersionHistory(versionableNode);
assertNotNull(versionHistory4);
assertEquals(2, versionHistory4.getAllVersions().size());
// Check that the version label is correct on the versionable node
String versionLabel3 = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
assertNotNull(versionLabel3);
assertEquals(version2.getVersionLabel(), versionLabel3);
}
/**
* Test deleteVersion
*/
public void testDeleteVersion()
{
// Create a versionable node
NodeRef versionableNode = createNewVersionableNode();
// Check that there is no version history
VersionHistory versionHistory = this.versionService.getVersionHistory(versionableNode);
CheckVersionHistory(versionHistory, null);
// Check that the current version property on the versionable node is not set
String versionLabel = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
assertNull(versionLabel);
// Check that there is no current version
Version version = this.versionService.getCurrentVersion(versionableNode);
assertNull(version);
// Create a couple of versions
Version version0 = createVersion(versionableNode);
Version version1 = createVersion(versionableNode);
// Check that the version label is correct on the versionable node
String versionLabel1 = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
assertEquals("first version label", "0.2", versionLabel1);
assertEquals(version1.getVersionLabel(), versionLabel1);
// Check the version history
List expectedVersions = new ArrayList(2);
expectedVersions.add(version1); // 0.1
expectedVersions.add(version0); // 0.2
versionHistory = this.versionService.getVersionHistory(versionableNode);
assertEquals(2, versionHistory.getAllVersions().size());
CheckVersionHistory(versionHistory, expectedVersions);
// Check current version
Version currentVersion = this.versionService.getCurrentVersion(versionableNode);
assertEquals(currentVersion.getVersionLabel(), version1.getVersionLabel());
assertEquals(currentVersion.getFrozenStateNodeRef(), version1.getFrozenStateNodeRef());
// Create a couple more versions
Version version2 = createVersion(versionableNode); // 0.3
Version version3 = createVersion(versionableNode); //0.4
// Check that the version label is correct on the versionable node
String versionLabel3 = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
assertEquals("0.4", versionLabel3);
assertEquals(version3.getVersionLabel(), versionLabel3);
// Check the version history
expectedVersions = new ArrayList(4);
expectedVersions.add(version3);
expectedVersions.add(version2);
expectedVersions.add(version1);
expectedVersions.add(version0);
versionHistory = this.versionService.getVersionHistory(versionableNode);
assertEquals(4, versionHistory.getAllVersions().size());
CheckVersionHistory(versionHistory, expectedVersions);
// Check current version
currentVersion = this.versionService.getCurrentVersion(versionableNode);
assertEquals(currentVersion.getVersionLabel(), version3.getVersionLabel());
assertEquals(currentVersion.getFrozenStateNodeRef(), version3.getFrozenStateNodeRef());
// Delete version 2
this.versionService.deleteVersion(versionableNode, version2);
// Delete version 0
this.versionService.deleteVersion(versionableNode, version0);
// Check the version history
expectedVersions = new ArrayList(2);
expectedVersions.add(version3);
expectedVersions.add(version1);
versionHistory = this.versionService.getVersionHistory(versionableNode);
assertEquals(2, versionHistory.getAllVersions().size());
CheckVersionHistory(versionHistory, expectedVersions);
// Check current version is unchanged
currentVersion = this.versionService.getCurrentVersion(versionableNode);
assertEquals(currentVersion.getVersionLabel(), version3.getVersionLabel());
assertEquals(currentVersion.getFrozenStateNodeRef(), version3.getFrozenStateNodeRef());
// Delete version 3
this.versionService.deleteVersion(versionableNode, version3);
// Check the version history size
expectedVersions = new ArrayList(1);
expectedVersions.add(version1);
versionHistory = this.versionService.getVersionHistory(versionableNode);
assertEquals(1, versionHistory.getAllVersions().size());
CheckVersionHistory(versionHistory, expectedVersions);
// Check current version has changed to version 1
currentVersion = this.versionService.getCurrentVersion(versionableNode);
assertEquals(currentVersion.getVersionLabel(), version1.getVersionLabel());
assertEquals(currentVersion.getFrozenStateNodeRef(), version1.getFrozenStateNodeRef());
// Create version 4
Version version4 = createVersion(versionableNode);
// Check the version history size
expectedVersions = new ArrayList(2);
expectedVersions.add(version4);
expectedVersions.add(version1);
versionHistory = this.versionService.getVersionHistory(versionableNode);
assertEquals(2, versionHistory.getAllVersions().size());
CheckVersionHistory(versionHistory, expectedVersions);
// Check current version has changed to version 4
currentVersion = this.versionService.getCurrentVersion(versionableNode);
assertEquals(currentVersion.getVersionLabel(), version4.getVersionLabel());
assertEquals(currentVersion.getFrozenStateNodeRef(), version4.getFrozenStateNodeRef());
// Delete version 1
this.versionService.deleteVersion(versionableNode, version1);
// Delete version 4
this.versionService.deleteVersion(versionableNode, version4);
// Check the version history is empty
versionHistory = this.versionService.getVersionHistory(versionableNode);
CheckVersionHistory(versionHistory, null);
// Check that the current version property on the versionable node is no longer set
versionLabel = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
assertNull(versionLabel);
// Check that there is no current version
version = this.versionService.getCurrentVersion(versionableNode);
assertNull(version);
}
public void testAutoVersionOnInitialVersionOn()
{
// Create a versionable node
final NodeRef versionableNode = createNewVersionableNode();
setComplete();
endTransaction();
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback