(writers);
- combinedWriters.add(owner);
+ if (owner != null && !owner.isEmpty() && !owner.equals(OwnableService.NO_OWNER))
+ {
+ combinedWriters.add(owner);
+ }
combinedWriters.add(AuthenticationUtil.getFullyAuthenticatedUser());
-
extendedSecurityService.addExtendedSecurity(nodeRef, readers, combinedWriters);
}
finally
@@ -1187,6 +1186,9 @@ public class RecordServiceImpl extends BaseBehaviourBean
// remove versionable aspect(s)
nodeService.removeAspect(document, RecordableVersionModel.ASPECT_VERSIONABLE);
+
+ // remove the owner
+ ownableService.setOwner(document, OwnableService.NO_OWNER);
}
catch (FileNotFoundException e)
{
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java
new file mode 100755
index 0000000000..e5b0c8c6f2
--- /dev/null
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionService.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2005-2014 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.module.org_alfresco_module_rm.version;
+
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.version.Version;
+
+/**
+ * Recordable version service interface.
+ *
+ * @author Roy Wetherall
+ * @since 2.3
+ */
+public interface RecordableVersionService
+{
+ /**
+ * Indicates whether the current version of a node is recorded or not.
+ *
+ * Returns false if not versionable or no version.
+ *
+ * @param nodeRef node reference
+ * @return boolean true if latest version recorded, false otherwise
+ */
+ boolean isCurrentVersionRecorded(NodeRef nodeRef);
+
+ /**
+ * Indicates whether a version is recorded or not.
+ *
+ * @param version version
+ * @return boolean true if recorded version, false otherwise
+ */
+ boolean isRecordedVersion(Version version);
+
+ /**
+ * Creates a record from the latest version, marking it as recorded.
+ *
+ * Does not create a record if the node is not versionable or the latest
+ * version is already recorded.
+ *
+ * @param nodeRef node reference
+ * @return NodeRef node reference to the crated record.
+ */
+ NodeRef createRecordFromLatestVersion(NodeRef filePlan, NodeRef nodeRef);
+
+}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java
index cc7e90df1e..a148fd3016 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java
@@ -25,7 +25,9 @@ import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
@@ -34,19 +36,24 @@ import org.alfresco.module.org_alfresco_module_rm.model.rma.type.CmObjectType;
import org.alfresco.module.org_alfresco_module_rm.model.security.ModelSecurityService;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipService;
+import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
import org.alfresco.repo.policy.PolicyScope;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
+import org.alfresco.repo.security.permissions.impl.ExtendedPermissionService;
import org.alfresco.repo.version.Version2Model;
import org.alfresco.repo.version.Version2ServiceImpl;
import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.version.ReservedVersionNameException;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory;
import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.service.namespace.QName;
+import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -58,7 +65,8 @@ import org.apache.commons.logging.LogFactory;
* @since 2.3
*/
public class RecordableVersionServiceImpl extends Version2ServiceImpl
- implements RecordableVersionModel
+ implements RecordableVersionModel,
+ RecordableVersionService
{
/** share logger with version2ServiceImpl */
private static Log logger = LogFactory.getLog(Version2ServiceImpl.class);
@@ -69,6 +77,23 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
/** version record property */
public static final String PROP_VERSION_RECORD = "RecordVersion";
+
+ /** version aspect property names */
+ private static final String[] VERSION_PROPERTY_NAMES = new String[]
+ {
+ Version2Model.PROP_CREATED_DATE,
+ Version2Model.PROP_VERSION_LABEL,
+ Version2Model.PROP_VERSION_DESCRIPTION,
+
+ Version2Model.PROP_FROZEN_NODE_DBID,
+ Version2Model.PROP_FROZEN_NODE_REF,
+
+ Version2Model.PROP_FROZEN_CREATED,
+ Version2Model.PROP_FROZEN_CREATOR,
+ Version2Model.PROP_FROZEN_MODIFIED,
+ Version2Model.PROP_FROZEN_MODIFIER,
+ Version2Model.PROP_FROZEN_ACCESSED
+ };
/** file plan service */
private FilePlanService filePlanService;
@@ -87,6 +112,15 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
/** cm object type */
private CmObjectType cmObjectType;
+
+ /** extended permission service */
+ private ExtendedPermissionService extendedPermissionService;
+
+ /** extended security service */
+ private ExtendedSecurityService extendedSecurityService;
+
+ /** ownable service */
+ private OwnableService ownableService;
/**
* @param filePlanService file plan service
@@ -135,6 +169,30 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
{
this.cmObjectType = cmObjectType;
}
+
+ /**
+ * @param extendedPermissionService extended permission service
+ */
+ public void setExtendedPermissionService(ExtendedPermissionService extendedPermissionService)
+ {
+ this.extendedPermissionService = extendedPermissionService;
+ }
+
+ /**
+ * @param extendedSecurityService extended security service
+ */
+ public void setExtendedSecurityService(ExtendedSecurityService extendedSecurityService)
+ {
+ this.extendedSecurityService = extendedSecurityService;
+ }
+
+ /**
+ * @param ownableService ownable service
+ */
+ public void setOwnableService(OwnableService ownableService)
+ {
+ this.ownableService = ownableService;
+ }
/**
* @see org.alfresco.repo.version.Version2ServiceImpl#createVersion(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, int)
@@ -499,4 +557,245 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
dbNodeService.setProperty(nodeRef, PROP_RECORDABLE_VERSION_POLICY, versionPolicy);
}
}
+
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#isLatestVersionRecorded(org.alfresco.service.cmr.repository.NodeRef)
+ */
+ @Override
+ public boolean isCurrentVersionRecorded(NodeRef nodeRef)
+ {
+ boolean result = false;
+ Version version = getCurrentVersion(nodeRef);
+ if (version != null)
+ {
+ result = isRecordedVersion(version);
+ }
+ return result;
+ }
+
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#isRecordedVersion(org.alfresco.service.cmr.version.Version)
+ */
+ @Override
+ public boolean isRecordedVersion(Version version)
+ {
+ boolean result = true;
+ if (version.getVersionProperties().get(PROP_VERSION_RECORD) == null)
+ {
+ result = false;
+ }
+ return result;
+ }
+
+ /**
+ * Create Version Store Ref
+ *
+ * @param store ref
+ * @return store ref for version store
+ */
+ public StoreRef convertStoreRef(StoreRef storeRef)
+ {
+ return new StoreRef(StoreRef.PROTOCOL_WORKSPACE, storeRef.getIdentifier());
+ }
+
+ /**
+ * Convert the incomming node ref (with the version store protocol specified)
+ * to the internal representation with the workspace protocol.
+ *
+ * @param nodeRef the incomming verison protocol node reference
+ * @return the internal version node reference
+ */
+ public NodeRef convertNodeRef(NodeRef nodeRef)
+ {
+ return new NodeRef(convertStoreRef(nodeRef.getStoreRef()), nodeRef.getId());
+ }
+
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService#createRecordFromLatestVersion(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef)
+ */
+ @Override
+ public NodeRef createRecordFromLatestVersion(final NodeRef filePlan, final NodeRef nodeRef)
+ {
+ ParameterCheck.mandatory("filePlan", filePlan);
+ ParameterCheck.mandatory("nodeRef", nodeRef);
+
+ NodeRef record = null;
+
+ // check for versionable aspect
+ if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE))
+ {
+ // get the latest version
+ final Version currentVersion = getCurrentVersion(nodeRef);
+
+ if (currentVersion != null &&
+ !isRecordedVersion(currentVersion))
+ {
+ // create the record from the current frozen state
+ record = authenticationUtil.runAsSystem(new RunAsWork()
+ {
+ public NodeRef doWork() throws Exception
+ {
+ // get the documents readers
+ Long aclId = nodeService.getNodeAclId(nodeRef);
+ Set readers = extendedPermissionService.getReaders(aclId);
+ Set writers = extendedPermissionService.getWriters(aclId);
+
+ // add the current owner to the list of extended writers
+ String owner = ownableService.getOwner(nodeRef);
+
+ // grab the frozen state
+ NodeRef currentFrozenState = currentVersion.getFrozenStateNodeRef();
+
+ // determine the type of the object
+ QName type = nodeService.getType(currentFrozenState);
+
+ // grab all the properties
+ Map properties = nodeService.getProperties(currentFrozenState);
+
+ // grab all the aspects
+ Set aspects = nodeService.getAspects(currentFrozenState);
+
+ // create the record
+ NodeRef record = recordService.createRecordFromContent(
+ filePlan,
+ (String)properties.get(ContentModel.PROP_NAME),
+ type,
+ properties,
+ null);
+
+ // apply aspects to record
+ for (QName aspect : aspects)
+ {
+ // add the aspect, properties have already been set
+ nodeService.addAspect(record, aspect, null);
+ }
+
+ // apply version record aspect to record
+ PropertyMap versionRecordProps = new PropertyMap(3);
+ versionRecordProps.put(PROP_VERSIONED_NODEREF, nodeRef);
+ versionRecordProps.put(RecordableVersionModel.PROP_VERSION_LABEL, currentVersion.getVersionLabel());
+ versionRecordProps.put(RecordableVersionModel.PROP_VERSION_DESCRIPTION, currentVersion.getDescription());
+ nodeService.addAspect(record, ASPECT_VERSION_RECORD, versionRecordProps);
+
+ // wire record up to previous record
+ linkToPreviousVersionRecord(nodeRef, record);
+
+ // set the extended security
+ Set combinedWriters = new HashSet(writers);
+ if (owner != null && !owner.isEmpty() && !owner.equals(OwnableService.NO_OWNER))
+ {
+ combinedWriters.add(owner);
+ }
+ combinedWriters.add(authenticationUtil.getFullyAuthenticatedUser());
+ extendedSecurityService.addExtendedSecurity(record, readers, combinedWriters);
+
+ return record;
+ }
+ });
+
+ // get the version history
+ NodeRef versionHistoryRef = getVersionHistoryNodeRef(nodeRef);
+
+ // get details from the version before we remove it
+ int versionNumber = getVersionNumber(currentVersion);
+ Map versionProperties = getVersionAspectProperties(currentVersion);
+ QName sourceTypeRef = getVersionType(currentVersion);
+
+ // patch-up owner information, which needs to be frozen for recorded versions
+ String owner = (String)nodeService.getProperty(currentVersion.getFrozenStateNodeRef(), ContentModel.PROP_OWNER);
+ if (owner != null)
+ {
+ versionProperties.put(PROP_FROZEN_OWNER, owner);
+ }
+
+ // delete the current version
+ this.dbNodeService.deleteNode(convertNodeRef(currentVersion.getFrozenStateNodeRef()));
+
+ // create a new version history if we need to
+ if (!nodeService.exists(versionHistoryRef))
+ {
+ versionHistoryRef = createVersionHistory(nodeRef);
+ }
+
+ // create recorded version nodeRef
+ ChildAssociationRef childAssocRef = dbNodeService.createNode(
+ versionHistoryRef,
+ Version2Model.CHILD_QNAME_VERSIONS,
+ QName.createQName(Version2Model.NAMESPACE_URI, Version2Model.CHILD_VERSIONS + "-" + versionNumber),
+ sourceTypeRef,
+ null);
+ NodeRef versionNodeRef = childAssocRef.getChildRef();
+
+ // add aspect with the standard version properties to the 'version' node
+ nodeService.addAspect(versionNodeRef, Version2Model.ASPECT_VERSION, versionProperties);
+
+ // add the recordedVersion aspect with link to record
+ nodeService.addAspect(versionNodeRef, ASPECT_RECORDED_VERSION, Collections.singletonMap(PROP_RECORD_NODE_REF, (Serializable)record));
+ }
+ }
+
+ return record;
+ }
+
+ /**
+ * Helper method to get the version number of a given version by inspecting the
+ * name of the parent association.
+ *
+ * @param version version
+ * @return int version number
+ */
+ private int getVersionNumber(Version version)
+ {
+ NodeRef versionNodeRef = getVersionNodeRef(version);
+ ChildAssociationRef assoc = dbNodeService.getPrimaryParent(versionNodeRef);
+ String fullVersionNumber = assoc.getQName().getLocalName();
+ String versionNumber = fullVersionNumber.substring(fullVersionNumber.indexOf("-") + 1);
+ return Integer.parseInt(versionNumber);
+ }
+
+ /**
+ * Helper method to get all the version aspect properties from an existing version
+ *
+ * @param version version
+ * @return Map property values
+ */
+ private Map getVersionAspectProperties(Version version)
+ {
+ NodeRef versionNodeRef = getVersionNodeRef(version);
+ Map versionProps = dbNodeService.getProperties(versionNodeRef);
+ Map result = new HashMap(9);
+ for (String propertyName : VERSION_PROPERTY_NAMES)
+ {
+ QName propertyQName = QName.createQName(Version2Model.NAMESPACE_URI, propertyName);
+ result.put(propertyQName, versionProps.get(propertyQName));
+
+ if (propertyName.equals(Version2Model.PROP_FROZEN_NODE_DBID))
+ {
+ System.out.println(versionProps.get(propertyQName));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Helper method to get the type of a versions frozen state
+ *
+ * @param currentVersion
+ * @return
+ */
+ private QName getVersionType(Version version)
+ {
+ return nodeService.getType(getVersionNodeRef(version));
+ }
+
+ /**
+ * Helper method to get the internal node reference of a version
+ *
+ * @param version version
+ * @return NodeRef internal node reference to version
+ */
+ private NodeRef getVersionNodeRef(Version version)
+ {
+ return convertNodeRef(version.getFrozenStateNodeRef());
+ }
}
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AdHocRecordableVersions.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AdHocRecordableVersionsTest.java
similarity index 96%
rename from rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AdHocRecordableVersions.java
rename to rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AdHocRecordableVersionsTest.java
index 4ac4106b6c..c7b1e08f4c 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AdHocRecordableVersions.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AdHocRecordableVersionsTest.java
@@ -38,7 +38,7 @@ import org.alfresco.service.cmr.version.VersionType;
* @author Roy Wetherall
* @since 2.3
*/
-public class AdHocRecordableVersions extends RecordableVersionsBaseTest
+public class AdHocRecordableVersionsTest extends RecordableVersionsBaseTest
{
/**
* Adhoc recorded version creation, with no policy defined as site collaborator
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoRecordableVersions.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoRecordableVersionsTest.java
similarity index 87%
rename from rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoRecordableVersions.java
rename to rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoRecordableVersionsTest.java
index 21af34b743..a9e4d678a3 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoRecordableVersions.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoRecordableVersionsTest.java
@@ -32,15 +32,15 @@ import org.alfresco.util.PropertyMap;
/**
* Auto Recordable Versions Integration Test
- *
+ *
* @author Roy Wetherall
* @since 2.3
*/
-public class AutoRecordableVersions extends RecordableVersionsBaseTest
+public class AutoRecordableVersionsTest extends RecordableVersionsBaseTest
{
/** example content */
public final static String MY_NEW_CONTENT = "this is some new content that I have changed to trigger auto version";
-
+
/**
* Given that all revisions will be recorded,
* When I update the content of a document,
@@ -51,34 +51,34 @@ public class AutoRecordableVersions extends RecordableVersionsBaseTest
doBehaviourDrivenTest(new BehaviourDrivenTest(dmCollaborator)
{
public void given() throws Exception
- {
+ {
// set the recordable version policy
PropertyMap recordableVersionProperties = new PropertyMap(1);
recordableVersionProperties.put(PROP_RECORDABLE_VERSION_POLICY, RecordableVersionPolicy.ALL);
recordableVersionProperties.put(PROP_FILE_PLAN, filePlan);
- nodeService.addAspect(dmDocument, RecordableVersionModel.ASPECT_VERSIONABLE, recordableVersionProperties);
-
+ nodeService.addAspect(dmDocument, RecordableVersionModel.ASPECT_VERSIONABLE, recordableVersionProperties);
+
// make the node versionable
PropertyMap versionableProperties = new PropertyMap(1);
versionableProperties.put(ContentModel.PROP_INITIAL_VERSION, false);
- nodeService.addAspect(dmDocument, ContentModel.ASPECT_VERSIONABLE, versionableProperties);
+ nodeService.addAspect(dmDocument, ContentModel.ASPECT_VERSIONABLE, versionableProperties);
}
-
+
public void when()
- {
+ {
// generate new version by updating content
ContentWriter writer = contentService.getWriter(dmDocument, ContentModel.PROP_CONTENT, true);
writer.putContent(MY_NEW_CONTENT);
- }
-
+ }
+
public void then()
{
// check that the record has been recorded
checkRecordedVersion(dmDocument, null, "0.1");
}
- });
- }
-
+ });
+ }
+
/**
* Given that all revisions will be automatically recorded,
* When I update a document 3 times,
@@ -90,18 +90,18 @@ public class AutoRecordableVersions extends RecordableVersionsBaseTest
{
/** given **/
public void given() throws Exception
- {
+ {
doTestInTransaction(new VoidTest()
{
@Override
public void runImpl() throws Exception
- {
+ {
// set the recordable version policy
PropertyMap recordableVersionProperties = new PropertyMap(1);
recordableVersionProperties.put(PROP_RECORDABLE_VERSION_POLICY, RecordableVersionPolicy.ALL);
recordableVersionProperties.put(PROP_FILE_PLAN, filePlan);
- nodeService.addAspect(dmDocument, RecordableVersionModel.ASPECT_VERSIONABLE, recordableVersionProperties);
-
+ nodeService.addAspect(dmDocument, RecordableVersionModel.ASPECT_VERSIONABLE, recordableVersionProperties);
+
// make the node versionable
PropertyMap versionableProperties = new PropertyMap(1);
versionableProperties.put(ContentModel.PROP_INITIAL_VERSION, false);
@@ -109,16 +109,16 @@ public class AutoRecordableVersions extends RecordableVersionsBaseTest
}
});
}
-
+
/** when **/
public void when()
- {
+ {
// update the content 3 times
updateContent();
updateContent();
updateContent();
- }
-
+ }
+
/** then */
public void then()
{
@@ -129,10 +129,10 @@ public class AutoRecordableVersions extends RecordableVersionsBaseTest
{
// check that the record has been recorded
checkRecordedVersion(dmDocument, null, "0.3");
-
- Version version = versionService.getCurrentVersion(dmDocument);
+
+ Version version = versionService.getCurrentVersion(dmDocument);
NodeRef record = (NodeRef)version.getVersionProperties().get(RecordableVersionServiceImpl.PROP_VERSION_RECORD);
-
+
boolean foundPrevious = false;
Set relationships = relationshipService.getRelationshipsFrom(record);
assertNotNull(relationships);
@@ -150,9 +150,9 @@ public class AutoRecordableVersions extends RecordableVersionsBaseTest
}
});
}
-
+
/**
- * Helper method to update content of dmDocument
+ * Helper method to update content of dmDocument
*/
private void updateContent()
{
@@ -165,7 +165,7 @@ public class AutoRecordableVersions extends RecordableVersionsBaseTest
writer.putContent(MY_NEW_CONTENT);
}
});
- }
- });
- }
+ }
+ });
+ }
}
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeclareAsRecordVersionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeclareAsRecordVersionTest.java
new file mode 100755
index 0000000000..d6e33fb515
--- /dev/null
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/DeclareAsRecordVersionTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2005-2014 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.module.org_alfresco_module_rm.test.integration.version;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService;
+import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionServiceImpl;
+import org.alfresco.repo.version.VersionModel;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.version.Version;
+import org.alfresco.service.cmr.version.VersionType;
+
+/**
+ * Declare as record version integration tests
+ *
+ * @author Roy Wetherall
+ * @since 2.3
+ */
+public class DeclareAsRecordVersionTest extends RecordableVersionsBaseTest
+{
+ /** recordable version service */
+ private RecordableVersionService recordableVersionService;
+
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#initServices()
+ */
+ @Override
+ protected void initServices()
+ {
+ super.initServices();
+ recordableVersionService = (RecordableVersionService)applicationContext.getBean("RecordableVersionService");
+ }
+
+ /**
+ * Given versionable content with a non-recorded latest version
+ * When I declare a version record
+ * Then the latest version is recorded and a record is created
+ */
+ public void testDeclareLatestVersionAsRecord()
+ {
+ doBehaviourDrivenTest(new BehaviourDrivenTest(dmCollaborator)
+ {
+ private NodeRef versionRecord;
+ private Map versionProperties;
+
+ public void given() throws Exception
+ {
+ // setup version properties
+ versionProperties = new HashMap(4);
+ versionProperties.put(Version.PROP_DESCRIPTION, DESCRIPTION);
+ versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR);
+
+ // create version
+ versionService.createVersion(dmDocument, versionProperties);
+
+ // assert that the latest version is not recorded
+ assertFalse(recordableVersionService.isCurrentVersionRecorded(dmDocument));
+ }
+
+ public void when()
+ {
+ // create version record from latest version
+ versionRecord = recordableVersionService.createRecordFromLatestVersion(filePlan, dmDocument);
+ }
+
+ public void then()
+ {
+ // check the created record
+ assertNotNull(versionRecord);
+ assertTrue(recordService.isRecord(versionRecord));
+
+ // assert the current version is recorded
+ assertTrue(recordableVersionService.isCurrentVersionRecorded(dmDocument));
+
+ // check the recorded version
+ checkRecordedVersion(dmDocument, DESCRIPTION, "0.1");
+ }
+ });
+ }
+
+ /**
+ * Given versionable content with a recorded latest version
+ * When I delcare a version record
+ * Then nothing happens since the latest version is already recorded
+ * And a warning is logged
+ */
+ public void testDeclareLatestVersionAsRecordButAlreadyRecorded()
+ {
+ doBehaviourDrivenTest(new BehaviourDrivenTest(dmCollaborator)
+ {
+ private NodeRef versionRecord;
+ private Map versionProperties;
+
+ public void given() throws Exception
+ {
+ // setup version properties
+ versionProperties = new HashMap(4);
+ versionProperties.put(Version.PROP_DESCRIPTION, DESCRIPTION);
+ versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR);
+ versionProperties.put(RecordableVersionServiceImpl.KEY_RECORDABLE_VERSION, true);
+ versionProperties.put(RecordableVersionServiceImpl.KEY_FILE_PLAN, filePlan);
+
+ // create version
+ versionService.createVersion(dmDocument, versionProperties);
+
+ // assert that the latest version is not recorded
+ assertTrue(recordableVersionService.isCurrentVersionRecorded(dmDocument));
+ }
+
+ public void when()
+ {
+ // create version record from latest version
+ versionRecord = recordableVersionService.createRecordFromLatestVersion(filePlan, dmDocument);
+ }
+
+ public void then()
+ {
+ // check that a record was not created
+ assertNull(versionRecord);
+
+ // assert the current version is recorded
+ assertTrue(recordableVersionService.isCurrentVersionRecorded(dmDocument));
+
+ // check the recorded version
+ checkRecordedVersion(dmDocument, DESCRIPTION, "0.1");
+ }
+ });
+ }
+
+
+}
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/RecordableVersionsBaseTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/RecordableVersionsBaseTest.java
index 886bf6e351..767f3d2ec8 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/RecordableVersionsBaseTest.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/RecordableVersionsBaseTest.java
@@ -49,24 +49,33 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen
protected static final String DESCRIPTION = "description";
protected static final String PUBLISHER = "publisher";
protected static final String SUBJECT = "subject";
- protected static final String OWNER = "Grace Wetherall";
+ protected static final String OWNER = "GracieWetherall";
protected static final String CONTENT =
"Simple + Smart. A smarter way to build, a smarter way to deploy. Its simple because we focus on the end "
+ "user and smart because we support more open standards than any other ECM platform, while delivering all "
+ "the value a traditional platform provides.";
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#isCollaborationSiteTest()
+ */
@Override
protected boolean isCollaborationSiteTest()
{
return true;
}
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#setupCollaborationSiteTestDataImpl()
+ */
@Override
protected void setupCollaborationSiteTestDataImpl()
{
super.setupCollaborationSiteTestDataImpl();
+ // create authentication for owner
+ createPerson(OWNER);
+
// add titled aspect
PropertyMap titledProperties = new PropertyMap(2);
titledProperties.put(ContentModel.PROP_TITLE, "document title");
@@ -91,6 +100,18 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen
writer.putContent(CONTENT);
}
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#tearDownImpl()
+ */
+ @Override
+ protected void tearDownImpl()
+ {
+ super.tearDownImpl();
+
+ // remove owner
+ personService.deletePerson(OWNER);
+ }
+
/**
* Helper to check that the current version is recorded
*/
@@ -145,6 +166,9 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen
assertNotNull(headVersion);
}
+ /**
+ * Helper method to check that the current version is not recorded
+ */
protected void checkNotRecordedAspect(NodeRef document, String description, String versionLabel)
{
// double check that the document is not a record
@@ -197,6 +221,16 @@ public abstract class RecordableVersionsBaseTest extends BaseRMTestCase implemen
}
}
+ // filter out missing properties with null values
+ for (Map.Entry entry : frozenProperties.entrySet())
+ {
+ if (entry.getValue() == null)
+ {
+ cloneFrozenProperties.remove(entry.getKey());
+ }
+ }
+
+
// frozen properties should be empty
assertTrue("Properties in frozen state, but not in origional. " + cloneFrozenProperties.keySet(), cloneFrozenProperties.isEmpty());
}
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/VersionTestSuite.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/VersionTestSuite.java
index 2f4a360ae5..c2d39cf2b6 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/VersionTestSuite.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/VersionTestSuite.java
@@ -31,8 +31,9 @@ import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses(
{
- AdHocRecordableVersions.class,
- AutoRecordableVersions.class
+ AdHocRecordableVersionsTest.class,
+ AutoRecordableVersionsTest.class,
+ DeclareAsRecordVersionTest.class
})
public class VersionTestSuite
{
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/BaseActionUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/BaseActionUnitTest.java
new file mode 100644
index 0000000000..3a6207aa7b
--- /dev/null
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/BaseActionUnitTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2005-2014 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.module.org_alfresco_module_rm.action;
+
+import static org.mockito.Mockito.doReturn;
+
+import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.service.cmr.action.Action;
+import org.mockito.Mock;
+
+/**
+ * Declare as version record action unit test.
+ *
+ * @author Roy Wetherall
+ * @since 2.3
+ */
+public abstract class BaseActionUnitTest extends BaseUnitTest
+{
+ /** mocked action */
+ private @Mock Action mockedAction;
+
+ /**
+ * @return mocked action
+ */
+ protected Action getMockedAction()
+ {
+ return mockedAction;
+ }
+
+ /**
+ * Helper to mock an action parameter value
+ */
+ protected void mockActionParameterValue(String name, Object value)
+ {
+ doReturn(value).when(mockedAction).getParameterValue(name);
+ }
+
+}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/dm/DeclareAsVersionRecordActionUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/dm/DeclareAsVersionRecordActionUnitTest.java
new file mode 100644
index 0000000000..b66367cf6d
--- /dev/null
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/dm/DeclareAsVersionRecordActionUnitTest.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2005-2014 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.module.org_alfresco_module_rm.action.dm;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.model.ContentModel;
+import org.alfresco.module.org_alfresco_module_rm.action.BaseActionUnitTest;
+import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
+import org.alfresco.service.cmr.action.Action;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+
+/**
+ * Declare as version record action unit test.
+ *
+ * @author Roy Wetherall
+ * @since 2.3
+ */
+public class DeclareAsVersionRecordActionUnitTest extends BaseActionUnitTest
+{
+ /** Sync Model */
+ private static final String SYNC_MODEL_1_0_URI = "http://www.alfresco.org/model/sync/1.0";
+ private static final QName ASPECT_SYNCED = QName.createQName(SYNC_MODEL_1_0_URI, "synced");
+
+ /** actioned upon node reference */
+ private NodeRef actionedUponNodeRef;
+
+ /** declare as version record action */
+ private @InjectMocks DeclareAsVersionRecordAction declareAsVersionRecordAction;
+
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest#before()
+ */
+ @Override
+ public void before() throws Exception
+ {
+ super.before();
+
+ // mocked action
+ declareAsVersionRecordAction.setAuditable(false);
+
+ // mocked actioned upon noderef
+ actionedUponNodeRef = generateNodeRef();
+ }
+
+ /**
+ * Given that the actioned upon node reference doesn't exist
+ * When I execute the action
+ * Then nothing happens
+ */
+ @Test
+ public void actionedUponNodeRefDoesntExist()
+ {
+ doReturn(false).when(mockedNodeService).exists(actionedUponNodeRef);
+ declareAsVersionRecordAction.executeImpl(mock(Action.class), actionedUponNodeRef);
+ verify(mockedRecordableVersionService, never()).createRecordFromLatestVersion(filePlan, actionedUponNodeRef);
+ }
+
+ /**
+ * Given that the actioned upon node reference isn't a subtype of cm:content
+ * When I execute the action
+ * Then nothing happens
+ */
+ @Test
+ public void aciontedUponNodeRefIsntSubTypeOfCmContent()
+ {
+ doReturn(true).when(mockedNodeService).exists(actionedUponNodeRef);
+ doReturn(false).when(mockedDictionaryService).isSubClass(any(QName.class), eq(ContentModel.TYPE_CONTENT));
+ declareAsVersionRecordAction.executeImpl(mock(Action.class), actionedUponNodeRef);
+ verify(mockedRecordableVersionService, never()).createRecordFromLatestVersion(filePlan, actionedUponNodeRef);
+ }
+
+ /**
+ * Given that the actioned upon node reference doesn't have the versionable aspect applied
+ * When I executed the action
+ * Then nothing happens
+ */
+ @Test
+ public void actionedUponNodeRefDoesntHaveVersionableApplied()
+ {
+ doReturn(true).when(mockedNodeService).exists(actionedUponNodeRef);
+ doReturn(true).when(mockedDictionaryService).isSubClass(any(QName.class), eq(ContentModel.TYPE_CONTENT));
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_VERSIONABLE);
+ declareAsVersionRecordAction.executeImpl(mock(Action.class), actionedUponNodeRef);
+ verify(mockedRecordableVersionService, never()).createRecordFromLatestVersion(filePlan, actionedUponNodeRef);
+ }
+
+ /**
+ * Given that the actioned upon node reference is already an record
+ * When I execute the action
+ * Then nothing happens
+ */
+ @Test
+ public void actionedUponNodeRefAlreadyRecord()
+ {
+ doReturn(true).when(mockedNodeService).exists(actionedUponNodeRef);
+ doReturn(true).when(mockedDictionaryService).isSubClass(any(QName.class), eq(ContentModel.TYPE_CONTENT));
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_VERSIONABLE);
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD);
+ declareAsVersionRecordAction.executeImpl(mock(Action.class), actionedUponNodeRef);
+ verify(mockedRecordableVersionService, never()).createRecordFromLatestVersion(filePlan, actionedUponNodeRef);
+ }
+
+ /**
+ * Given that the actioned upon node reference is a working copy
+ * When I execute the action
+ * Then nothing happens
+ */
+ @Test
+ public void actionedUponNodeRefWorkingCopy()
+ {
+ doReturn(true).when(mockedNodeService).exists(actionedUponNodeRef);
+ doReturn(true).when(mockedDictionaryService).isSubClass(any(QName.class), eq(ContentModel.TYPE_CONTENT));
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_VERSIONABLE);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD);
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_WORKING_COPY);
+ declareAsVersionRecordAction.executeImpl(mock(Action.class), actionedUponNodeRef);
+ verify(mockedRecordableVersionService, never()).createRecordFromLatestVersion(filePlan, actionedUponNodeRef);
+ }
+
+ /**
+ * Given that the actioned upon node reference is a rejected record
+ * When I execute the action
+ * Then nothing happens
+ */
+ @Test
+ public void actionedUponNodeRefRejectedRecord()
+ {
+ doReturn(true).when(mockedNodeService).exists(actionedUponNodeRef);
+ doReturn(true).when(mockedDictionaryService).isSubClass(any(QName.class), eq(ContentModel.TYPE_CONTENT));
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_VERSIONABLE);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_WORKING_COPY);
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD_REJECTION_DETAILS);
+ declareAsVersionRecordAction.executeImpl(mock(Action.class), actionedUponNodeRef);
+ verify(mockedRecordableVersionService, never()).createRecordFromLatestVersion(filePlan, actionedUponNodeRef);
+ }
+
+ /**
+ * Given that the actioned upon node reference is synced to the cloud
+ * When I execute the action
+ * Then nothing happens
+ */
+ @Test
+ public void actionedUponNodeRefSynced()
+ {
+ doReturn(true).when(mockedNodeService).exists(actionedUponNodeRef);
+ doReturn(true).when(mockedDictionaryService).isSubClass(any(QName.class), eq(ContentModel.TYPE_CONTENT));
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_VERSIONABLE);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_WORKING_COPY);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD_REJECTION_DETAILS);
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_SYNCED);
+ declareAsVersionRecordAction.executeImpl(mock(Action.class), actionedUponNodeRef);
+ verify(mockedRecordableVersionService, never()).createRecordFromLatestVersion(filePlan, actionedUponNodeRef);
+ }
+
+ /**
+ * Given that no file plan is provided
+ * And no default file plan exists
+ * When I execute the action
+ * Then an exception is thrown
+ */
+ @Test
+ public void noFilePlanParameterNoDefaultFilePlan()
+ {
+ // setup
+ doReturn(true).when(mockedNodeService).exists(actionedUponNodeRef);
+ doReturn(true).when(mockedDictionaryService).isSubClass(any(QName.class), eq(ContentModel.TYPE_CONTENT));
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_VERSIONABLE);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_WORKING_COPY);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD_REJECTION_DETAILS);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_SYNCED);
+
+ // no default file plan
+ doReturn(null).when(mockedFilePlanService).getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID);
+
+ // expect exception
+ exception.expect(AlfrescoRuntimeException.class);
+
+ // exceute action
+ declareAsVersionRecordAction.executeImpl(mock(Action.class), actionedUponNodeRef);
+ }
+
+ /**
+ * Given that no file plan is provided
+ * And adefault file plan exists
+ * When I execute the action
+ * Then a version record is declared
+ */
+ @Test
+ public void noFilePlanParameterDefaultFilePlan()
+ {
+ // setup
+ doReturn(true).when(mockedNodeService).exists(actionedUponNodeRef);
+ doReturn(true).when(mockedDictionaryService).isSubClass(any(QName.class), eq(ContentModel.TYPE_CONTENT));
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_VERSIONABLE);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_WORKING_COPY);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD_REJECTION_DETAILS);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_SYNCED);
+
+ // no default file plan
+ doReturn(filePlan).when(mockedFilePlanService).getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID);
+
+ // exceute action
+ declareAsVersionRecordAction.executeImpl(mock(Action.class), actionedUponNodeRef);
+ verify(mockedRecordableVersionService, times(1)).createRecordFromLatestVersion(filePlan, actionedUponNodeRef);
+ }
+
+ /**
+ * Given that a file plan is provided
+ * And it isn't a file plan
+ * When I execute the action
+ * Then an exception is thrown
+ */
+ @Test
+ public void invalidFilePlanParameter()
+ {
+ // setup
+ doReturn(true).when(mockedNodeService).exists(actionedUponNodeRef);
+ doReturn(true).when(mockedDictionaryService).isSubClass(any(QName.class), eq(ContentModel.TYPE_CONTENT));
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_VERSIONABLE);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_WORKING_COPY);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD_REJECTION_DETAILS);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_SYNCED);
+
+ // not a file plan is provided in the parameters
+ mockActionParameterValue(DeclareAsVersionRecordAction.PARAM_FILE_PLAN, generateNodeRef());
+
+ // expect exception
+ exception.expect(AlfrescoRuntimeException.class);
+
+ // exceute action
+ declareAsVersionRecordAction.executeImpl(getMockedAction(), actionedUponNodeRef);
+ }
+
+ /**
+ * Given that a file plan is provided
+ * And it is a file plan
+ * When I execute the action
+ * Then a version record is declared
+ */
+ @Test
+ public void validFilePlanParameter()
+ {
+ // setup
+ doReturn(true).when(mockedNodeService).exists(actionedUponNodeRef);
+ doReturn(true).when(mockedDictionaryService).isSubClass(any(QName.class), eq(ContentModel.TYPE_CONTENT));
+ doReturn(true).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_VERSIONABLE);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ContentModel.ASPECT_WORKING_COPY);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_RECORD_REJECTION_DETAILS);
+ doReturn(false).when(mockedNodeService).hasAspect(actionedUponNodeRef, ASPECT_SYNCED);
+
+ // not a file plan is provided in the parameters
+ NodeRef myFilePlan = generateNodeRef(TYPE_FILE_PLAN);
+ doReturn(true).when(mockedFilePlanService).isFilePlan(myFilePlan);
+ mockActionParameterValue(DeclareAsVersionRecordAction.PARAM_FILE_PLAN, myFilePlan);
+
+ // exceute action
+ declareAsVersionRecordAction.executeImpl(getMockedAction(), actionedUponNodeRef);
+ verify(mockedRecordableVersionService, times(1)).createRecordFromLatestVersion(myFilePlan, actionedUponNodeRef);
+ }
+}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FileReportActionUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FileReportActionUnitTest.java
index b24e20089a..a3cbd6bc97 100644
--- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FileReportActionUnitTest.java
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FileReportActionUnitTest.java
@@ -18,17 +18,14 @@
*/
package org.alfresco.module.org_alfresco_module_rm.action.impl;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verifyZeroInteractions;
import org.alfresco.error.AlfrescoRuntimeException;
-import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.module.org_alfresco_module_rm.action.BaseActionUnitTest;
import org.alfresco.repo.content.MimetypeMap;
-import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
import org.junit.Test;
import org.mockito.InjectMocks;
-import org.mockito.Mock;
/**
* Unit test for file report action.
@@ -36,14 +33,11 @@ import org.mockito.Mock;
* @author Roy Wetherall
* @since 2.2
*/
-public class FileReportActionUnitTest extends BaseUnitTest
+public class FileReportActionUnitTest extends BaseActionUnitTest
{
/** actioned upon node reference */
private NodeRef actionedUponNodeRef;
- /** mocked action */
- private @Mock Action mockedAction;
-
/** file report action */
private @InjectMocks FileReportAction fileReportAction;
@@ -62,14 +56,6 @@ public class FileReportActionUnitTest extends BaseUnitTest
fileReportAction.setAuditable(false);
}
- /**
- * Helper to mock an action parameter value
- */
- private void mockActionParameterValue(String name, String value)
- {
- doReturn(value).when(mockedAction).getParameterValue(name);
- }
-
/**
* given the destination is not set, ensure that an exception is thrown
*/
@@ -88,7 +74,7 @@ public class FileReportActionUnitTest extends BaseUnitTest
// == when ==
// execute action
- fileReportAction.executeImpl(mockedAction, actionedUponNodeRef);
+ fileReportAction.executeImpl(getMockedAction(), actionedUponNodeRef);
// == then ==
verifyZeroInteractions(mockedReportService, mockedNodeService);
@@ -112,7 +98,7 @@ public class FileReportActionUnitTest extends BaseUnitTest
// == when ==
// execute action
- fileReportAction.executeImpl(mockedAction, actionedUponNodeRef);
+ fileReportAction.executeImpl(getMockedAction(), actionedUponNodeRef);
// == then ==
verifyZeroInteractions(mockedReportService, mockedNodeService);
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/UnlinkFromActionUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/UnlinkFromActionUnitTest.java
index 60aa6f56f0..312bcda9f3 100644
--- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/UnlinkFromActionUnitTest.java
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/UnlinkFromActionUnitTest.java
@@ -18,10 +18,15 @@
*/
package org.alfresco.module.org_alfresco_module_rm.action.impl;
-import static org.mockito.Mockito.*;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import org.alfresco.error.AlfrescoRuntimeException;
-import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.module.org_alfresco_module_rm.action.BaseActionUnitTest;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
import org.junit.Before;
@@ -34,7 +39,7 @@ import org.mockito.InjectMocks;
* @author Roy Wetherall
* @since 2.3
*/
-public class UnlinkFromActionUnitTest extends BaseUnitTest
+public class UnlinkFromActionUnitTest extends BaseActionUnitTest
{
private NodeRef record;
private NodeRef recordFolder;
@@ -107,11 +112,10 @@ public class UnlinkFromActionUnitTest extends BaseUnitTest
doReturn(false).when(mockedNodeService).hasAspect(record, ASPECT_PENDING_DELETE);
// create action mock
- Action mockedAction = mock(Action.class);
- doReturn(null).when(mockedAction).getParameterValue(UnlinkFromAction.PARAM_RECORD_FOLDER);
+ mockActionParameterValue(UnlinkFromAction.PARAM_RECORD_FOLDER, null);
// execute action
- action.executeImpl(mockedAction, record);
+ action.executeImpl(getMockedAction(), record);
}
/**
@@ -127,11 +131,10 @@ public class UnlinkFromActionUnitTest extends BaseUnitTest
doReturn(false).when(mockedNodeService).hasAspect(record, ASPECT_PENDING_DELETE);
// create action mock
- Action mockedAction = mock(Action.class);
- doReturn(recordFolder.toString()).when(mockedAction).getParameterValue(UnlinkFromAction.PARAM_RECORD_FOLDER);
+ mockActionParameterValue(UnlinkFromAction.PARAM_RECORD_FOLDER, recordFolder.toString());
// execute action
- action.executeImpl(mockedAction, record);
+ action.executeImpl(getMockedAction(), record);
// verify unlink
verify(mockedRecordService, times(1)).unlink(record, recordFolder);
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java
index 6e23e8abc8..0882c65579 100644
--- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/AllUnitTestSuite.java
@@ -18,6 +18,7 @@
*/
package org.alfresco.module.org_alfresco_module_rm.test;
+import org.alfresco.module.org_alfresco_module_rm.action.dm.DeclareAsVersionRecordActionUnitTest;
import org.alfresco.module.org_alfresco_module_rm.action.impl.FileReportActionUnitTest;
import org.alfresco.module.org_alfresco_module_rm.action.impl.UnlinkFromActionUnitTest;
import org.alfresco.module.org_alfresco_module_rm.bootstrap.BootstrapImporterModuleComponentUnitTest;
@@ -79,6 +80,7 @@ import org.junit.runners.Suite.SuiteClasses;
// action implementations
FileReportActionUnitTest.class,
UnlinkFromActionUnitTest.class,
+ DeclareAsVersionRecordActionUnitTest.class,
// patches
RMv22RemoveInPlaceRolesFromAllPatchUnitTest.class,
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java
index f684370515..3cce7a93a1 100644
--- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseUnitTest.java
@@ -47,6 +47,7 @@ import org.alfresco.module.org_alfresco_module_rm.report.ReportService;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
+import org.alfresco.module.org_alfresco_module_rm.version.RecordableVersionService;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
@@ -125,7 +126,8 @@ public class BaseUnitTest implements RecordsManagementModel, ContentModel
@Mock(name="extendedPermissionService") protected ExtendedPermissionService mockedExtendedPermissionService;
@Mock(name="extendedSecurityService") protected ExtendedSecurityService mockedExtendedSecurityService;
@Mock(name="recordableVersionConfigService") protected RecordableVersionConfigService mockedRecordableVersionConfigService;
- @Mock(name="cmObjectType") protected CmObjectType cmObjectType;
+ @Mock(name="cmObjectType") protected CmObjectType mockedCmObjectType;
+ @Mock(name="recordableVersionService") protected RecordableVersionService mockedRecordableVersionService;
/** application context mock */
@Mock(name="applicationContext") protected ApplicationContext mockedApplicationContext;
@@ -386,7 +388,17 @@ public class BaseUnitTest implements RecordsManagementModel, ContentModel
*/
protected void makePrimaryParentOf(NodeRef child, NodeRef parent)
{
- doReturn(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, parent, generateQName(), child))
+ makePrimaryParentOf(child, parent, ContentModel.ASSOC_CONTAINS, generateQName());
+ }
+
+ protected void makePrimaryParentOf(NodeRef child, NodeRef parent, QName assocType, QName assocName)
+ {
+ makePrimaryParentOf(child, parent, assocType, assocName, mockedNodeService);
+ }
+
+ protected void makePrimaryParentOf(NodeRef child, NodeRef parent, QName assocType, QName assocName, NodeService mockedNodeService)
+ {
+ doReturn(new ChildAssociationRef(assocType, parent, assocName, child))
.when(mockedNodeService)
.getPrimaryParent(child);
}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImplUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImplUnitTest.java
index 2020334a0c..21d590dd27 100644
--- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImplUnitTest.java
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImplUnitTest.java
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.io.Serializable;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -38,14 +39,19 @@ import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
import org.alfresco.repo.version.Version2Model;
import org.alfresco.repo.version.VersionModel;
+import org.alfresco.repo.version.common.VersionImpl;
import org.alfresco.service.cmr.model.FileInfo;
+import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionType;
+import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.mockito.Spy;
/**
* Recordable version service implementation unit test.
@@ -71,7 +77,7 @@ public class RecordableVersionServiceImplUnitTest extends BaseUnitTest
private @Mock(name="dbNodeService") NodeService mockedDbNodeService;
/** recordable version service */
- private @InjectMocks TestRecordableVersionServiceImpl recordableVersionService;
+ private @InjectMocks @Spy TestRecordableVersionServiceImpl recordableVersionService;
/**
* @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest#before()
@@ -384,4 +390,109 @@ public class RecordableVersionServiceImplUnitTest extends BaseUnitTest
// then the recorded version is created
verify(mockedRecordService, times(1)).createRecordFromCopy(filePlan, nodeRef);
}
+
+ /**
+ * Given that a node is not versionable
+ * When I try and create a record from the latest version
+ * Then nothing will happen, because there is not version to record
+ */
+ @Test
+ public void notVersionableCreateRecordFromVersion()
+ {
+ // content node is not versionable
+ doReturn(false).when(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE);
+
+ // create record from version
+ recordableVersionService.createRecordFromLatestVersion(filePlan, nodeRef);
+
+ // nothing happens
+ verify(mockedRecordService, never()).createRecordFromCopy(eq(filePlan), any(NodeRef.class));
+ }
+
+ /**
+ * Given that a nodes last version is recorded
+ * When I try and create a record from the latest version
+ * Then nothing will happen, because the latest version is already recorded
+ */
+ @Test
+ public void alreadyRecordedCreateRecordFromVersion()
+ {
+ // latest version is already recorded
+ Version mockedVersion = mock(VersionImpl.class);
+ doReturn(Collections.singletonMap(RecordableVersionServiceImpl.PROP_VERSION_RECORD, generateNodeRef())).when(mockedVersion).getVersionProperties();
+ doReturn(true).when(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE);
+ doReturn(mockedVersion).when(recordableVersionService).getCurrentVersion(nodeRef);
+
+ // create record from version
+ recordableVersionService.createRecordFromLatestVersion(filePlan, nodeRef);
+
+ // nothing happens
+ verify(mockedRecordService, never()).createRecordFromCopy(eq(filePlan), any(NodeRef.class));
+ }
+
+ /**
+ * Given that a nodes last version is not recorded
+ * When I try to create a record from the latest version
+ * Then the latest version is marked as record and a new record version is created to store the version state
+ */
+ @SuppressWarnings("unchecked")
+ @Test
+ public void notRecordedCreateRecordFromVersion()
+ {
+ // latest version is not recorded
+ Version mockedVersion = mock(VersionImpl.class);
+ NodeRef versionNodeRef = generateNodeRef();
+ doReturn(Collections.emptyMap()).when(mockedVersion).getVersionProperties();
+ doReturn(true).when(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE);
+
+ // version history
+ NodeRef versionHistoryNodeRef = generateNodeRef();
+ doReturn(versionHistoryNodeRef).when(mockedDbNodeService).getChildByName(any(NodeRef.class), eq(Version2Model.CHILD_QNAME_VERSION_HISTORIES), any(String.class));
+
+ // version number
+ doReturn(mockedVersion).when(recordableVersionService).getCurrentVersion(nodeRef);
+ doReturn(versionNodeRef).when(recordableVersionService).convertNodeRef(any(NodeRef.class));
+ makePrimaryParentOf(versionNodeRef, versionHistoryNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "something-0"), mockedDbNodeService);
+
+ // created version
+ NodeRef newVersionNodeRef = generateNodeRef();
+ doReturn(generateChildAssociationRef(versionHistoryNodeRef, newVersionNodeRef)).when(mockedDbNodeService).createNode(
+ eq(versionHistoryNodeRef),
+ eq(Version2Model.CHILD_QNAME_VERSIONS),
+ any(QName.class),
+ any(QName.class),
+ any(Map.class));
+
+ // created record
+ NodeRef newRecordNodeRef = generateNodeRef();
+ doReturn(newRecordNodeRef).when(mockedRecordService).createRecordFromContent(
+ eq(filePlan),
+ any(String.class),
+ any(QName.class),
+ any(Map.class),
+ any(ContentReader.class));
+
+ // create record from version
+ recordableVersionService.createRecordFromLatestVersion(filePlan, nodeRef);
+
+ // verify that the version is converted to a recorded version
+ verify(mockedRecordService, times(1)).createRecordFromContent(
+ eq(filePlan),
+ any(String.class),
+ any(QName.class),
+ any(Map.class),
+ any(ContentReader.class));
+ verify(mockedDbNodeService, times(1)).deleteNode(any(NodeRef.class));
+ verify(mockedDbNodeService, times(1)).createNode(
+ eq(versionHistoryNodeRef),
+ eq(Version2Model.CHILD_QNAME_VERSIONS),
+ any(QName.class),
+ any(QName.class),
+ any(Map.class));
+ verify(mockedNodeService, times(1)).addAspect(eq(newVersionNodeRef), eq(Version2Model.ASPECT_VERSION), any(Map.class));
+ verify(mockedNodeService, times(1)).addAspect(
+ newVersionNodeRef,
+ RecordableVersionModel.ASPECT_RECORDED_VERSION,
+ Collections.singletonMap(RecordableVersionModel.PROP_RECORD_NODE_REF, (Serializable)newRecordNodeRef));
+ }
}
\ No newline at end of file