diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties b/rm-server/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties index 40134471ca..ede402b625 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties @@ -71,3 +71,9 @@ rm.completerecord.mandatorypropertiescheck.enabled=true # deprecated model properties in the rma namespace. # rm.patch.v22.convertToStandardFilePlan=false + +# +# Extended auto-version behaviour. If true and other auto-version properties are satisified, then +# a document will be auto-versioned when it's type is changed. +# +version.store.enableAutoVersionOnTypeChange=false diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml index c9921401f7..bffe192a53 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml @@ -44,6 +44,16 @@ + + + + + + + + + + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/AlfrescoTransactionSupport.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/AlfrescoTransactionSupport.java index d2f9796300..8ac49d5ded 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/AlfrescoTransactionSupport.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/AlfrescoTransactionSupport.java @@ -18,6 +18,7 @@ */ package org.alfresco.module.org_alfresco_module_rm.util; + /** * Alfresco Transaction Support delegation bean. * @@ -42,4 +43,12 @@ public class AlfrescoTransactionSupport { org.alfresco.repo.transaction.AlfrescoTransactionSupport.unbindResource(key); } + + /** + * @see org.alfresco.repo.transaction.AlfrescoTransactionSupport#getResource(Object) + */ + public R getResource(Object key) + { + return org.alfresco.repo.transaction.AlfrescoTransactionSupport.getResource(key); + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/ExtendedVersionableAspect.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/ExtendedVersionableAspect.java new file mode 100644 index 0000000000..27c1257166 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/ExtendedVersionableAspect.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2005-2015 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 java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.util.AlfrescoTransactionSupport; +import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; +import org.alfresco.repo.lock.LockUtils; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.policy.Behaviour.NotificationFrequency; +import org.alfresco.repo.policy.annotation.Behaviour; +import org.alfresco.repo.policy.annotation.BehaviourBean; +import org.alfresco.repo.policy.annotation.BehaviourKind; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.service.cmr.lock.LockService; +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.VersionService; +import org.alfresco.service.namespace.QName; +import org.springframework.extensions.surf.util.I18NUtil; + +/** + * Extend versionable aspect auto-version behaviour to allow versions to be + * created when the content type is changed. + * + * Note: this behaviour should be merged into core asap + * + * @author Roy Wetherall + * @since 2.3.1 + */ +@BehaviourBean +public class ExtendedVersionableAspect implements NodeServicePolicies.OnSetNodeTypePolicy +{ + /** The i18n'ized messages */ + private static final String MSG_AUTO_VERSION = "create_version.auto_version"; + + /** Transaction resource key */ + private static final String KEY_VERSIONED_NODEREFS = "versioned_noderefs"; + + /** node service */ + private NodeService nodeService; + + /** version service */ + private VersionService versionService; + + /** lock service */ + private LockService lockService; + + /** alfresco transaction support */ + private AlfrescoTransactionSupport alfrescoTransactionSupport; + + /** authentication util */ + private AuthenticationUtil authenticationUtil; + + /** indicates whether auto version should be triggered on type change */ + private boolean isAutoVersionOnTypeChange = false; + + /** + * @param nodeService node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * @param versionService version service + */ + public void setVersionService(VersionService versionService) + { + this.versionService = versionService; + } + + /** + * @param lockService lock service + */ + public void setLockService(LockService lockService) + { + this.lockService = lockService; + } + + /** + * @param alfrescoTransactionSupport alfresco transaction support + */ + public void setAlfrescoTransactionSupport(AlfrescoTransactionSupport alfrescoTransactionSupport) + { + this.alfrescoTransactionSupport = alfrescoTransactionSupport; + } + + /** + * @param authenticationUtil authentication util + */ + public void setAuthenticationUtil(AuthenticationUtil authenticationUtil) + { + this.authenticationUtil = authenticationUtil; + } + + /** + * @param isAutoVersionOnTypeChange true if auto version on type change, false otherwise + */ + public void setAutoVersionOnTypeChange(boolean isAutoVersionOnTypeChange) + { + this.isAutoVersionOnTypeChange = isAutoVersionOnTypeChange; + } + + /** + * On set node type behaviour + * + * @param nodeRef node reference + * @param oldType old type + * @param newType new type + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + @Behaviour + ( + type="cm:versionable", + kind=BehaviourKind.CLASS, + notificationFrequency=NotificationFrequency.TRANSACTION_COMMIT + ) + public void onSetNodeType(NodeRef nodeRef, QName oldType, QName newType) + { + if (isAutoVersionOnTypeChange && + nodeService.exists(nodeRef) == true && + !LockUtils.isLockedAndReadOnly(nodeRef, lockService) && + nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true && + nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY) == false) + { + Map versionedNodeRefs = (Map)alfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS); + if (versionedNodeRefs == null || versionedNodeRefs.containsKey(nodeRef) == false) + { + // Determine whether the node is auto versionable (for content updates) or not + boolean autoVersion = false; + Boolean value = (Boolean)nodeService.getProperty(nodeRef, ContentModel.PROP_AUTO_VERSION); + if (value != null) + { + // If the value is not null then + autoVersion = value.booleanValue(); + } + + // NOTE: auto version on type change is a global setting, if thins extension was moved into the + // core then cm:versionable could be extended with a property consistent with the current + // implementation + + if (autoVersion) + { + // Create the auto-version + Map versionProperties = new HashMap(1); + versionProperties.put(Version.PROP_DESCRIPTION, I18NUtil.getMessage(MSG_AUTO_VERSION)); + + createVersionImpl(nodeRef, versionProperties); + } + } + } + } + + /** + * On create version implementation method. + * + * @param nodeRef node reference + * @param versionProperties version properties + */ + private void createVersionImpl(final NodeRef nodeRef, final Map versionProperties) + { + authenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() throws Exception + { + recordCreateVersion(nodeRef, null); + versionService.createVersion(nodeRef, versionProperties); + return null; + } + }); + } + + /** + * Record that the new version has been created + * + * @param versionableNode versionable node reference + * @param version version + */ + @SuppressWarnings("unchecked") + private void recordCreateVersion(NodeRef versionableNode, Version version) + { + Map versionedNodeRefs = (Map)alfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS); + if (versionedNodeRefs == null) + { + versionedNodeRefs = new HashMap(); + alfrescoTransactionSupport.bindResource(KEY_VERSIONED_NODEREFS, versionedNodeRefs); + } + versionedNodeRefs.put(versionableNode, versionableNode); + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java index eefca5f1c4..2be90e2dab 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java @@ -18,12 +18,11 @@ */ package org.alfresco.module.org_alfresco_module_rm.test; -import org.alfresco.module.org_alfresco_module_rm.test.integration.IntegrationTestSuite; -import org.alfresco.module.org_alfresco_module_rm.test.legacy.LegacyTestSuite; +import org.junit.extensions.cpsuite.ClasspathSuite; +import org.junit.extensions.cpsuite.ClasspathSuite.ClassnameFilters; +import org.junit.extensions.cpsuite.ClasspathSuite.SuiteTypes; +import org.junit.extensions.cpsuite.SuiteType; import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; - /** * Convenience test suite that runs all the tests. @@ -31,11 +30,27 @@ import org.junit.runners.Suite.SuiteClasses; * @author Roy Wetherall * @since 2.1 */ -@RunWith(Suite.class) -@SuiteClasses( -{ - LegacyTestSuite.class, - IntegrationTestSuite.class +@RunWith(ClasspathSuite.class) +@SuiteTypes({SuiteType.TEST_CLASSES, SuiteType.RUN_WITH_CLASSES, SuiteType.JUNIT38_TEST_CLASSES}) +@ClassnameFilters({ + // Execute all test classes ending with "Test" + ".*Test", + // Exclude the ones ending with "UnitTest" + "!.*UnitTest", + // Put the test classes you want to exclude here + "!.*DataLoadSystemTest", + "!.*RM2072Test", + "!.*RM2190Test", + "!.*RM981SystemTest", + "!.*RecordsManagementEventServiceImplTest", + "!.*RmRestApiTest", + "!.*NotificationServiceHelperSystemTest", + "!.*RetryingTransactionHelperBaseTest", + "!.*RMCaveatConfigServiceImplTest", + // This test is running successfully locally but not on bamboo (if executed as a single test). + // The problem can be reproduced if the whole test suite is run locally as well. + // Tests should not be dependent on other test classes and should run in any order without any problems. + "!.*EmailMapScriptTest" }) public class AllTestSuite { diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoVersionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoVersionTest.java index 99c6eec74d..bad197926f 100755 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoVersionTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/version/AutoVersionTest.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.Map; import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.version.ExtendedVersionableAspect; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.version.VersionHistory; import org.alfresco.service.namespace.QName; @@ -115,5 +116,117 @@ public class AutoVersionTest extends RecordableVersionsBaseTest }); } + /** + * Given a versionable document with initial version turned off + * And auto version on type change is set on + * When I specialise the type of the document + * Then the version history contains the initial version + */ + public void testSpecialisedNodeInitialVersionNotCreatedOnTypeChangeOn() + { + doBehaviourDrivenTest(new BehaviourDrivenTest(dmCollaborator) + { + private ExtendedVersionableAspect extendedVersionableAspect; + private NodeRef myDocument; + + public void given() throws Exception + { + // turn auto version on type change on + extendedVersionableAspect = (ExtendedVersionableAspect)applicationContext.getBean("rm.extendedVersionableAspect"); + assertNotNull(extendedVersionableAspect); + extendedVersionableAspect.setAutoVersionOnTypeChange(true); + + // create a document + myDocument = fileFolderService.create(dmFolder, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef(); + + // make versionable + Map props = new HashMap(1); + props.put(ContentModel.PROP_INITIAL_VERSION, false); + nodeService.addAspect(myDocument, ContentModel.ASPECT_VERSIONABLE, props); + } + + public void when() + { + // specialise document + nodeService.setType(myDocument, TYPE_CUSTOM_TYPE); + } + + public void then() + { + VersionHistory versionHistory = versionService.getVersionHistory(myDocument); + assertNotNull(versionHistory); + assertEquals(1, versionHistory.getAllVersions().size()); + + NodeRef frozenState = versionHistory.getHeadVersion().getFrozenStateNodeRef(); + assertEquals(TYPE_CUSTOM_TYPE, nodeService.getType(frozenState)); + assertEquals(TYPE_CUSTOM_TYPE, nodeService.getType(myDocument)); + } + + public void after() throws Exception + { + // reset auto version on type to default off + extendedVersionableAspect.setAutoVersionOnTypeChange(false); + } + }); + } + + /** + * Given a versionable document with initial version turned on + * And auto version on type change is set on + * When I specialise the type of the document + * Then the version history contains the initial version + */ + public void testSpecialisedNodeInitialVersionCreatedOnTypeChangeOn() + { + doBehaviourDrivenTest(new BehaviourDrivenTest(dmCollaborator) + { + private ExtendedVersionableAspect extendedVersionableAspect; + private NodeRef myDocument; + + public void given() throws Exception + { + // turn auto version on type change on + extendedVersionableAspect = (ExtendedVersionableAspect)applicationContext.getBean("rm.extendedVersionableAspect"); + assertNotNull(extendedVersionableAspect); + extendedVersionableAspect.setAutoVersionOnTypeChange(true); + + // create a document + myDocument = fileFolderService.create(dmFolder, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef(); + + // make versionable + Map props = new HashMap(1); + props.put(ContentModel.PROP_INITIAL_VERSION, true); + nodeService.addAspect(myDocument, ContentModel.ASPECT_VERSIONABLE, props); + } + + public void when() + { + // specialise document + nodeService.setType(myDocument, TYPE_CUSTOM_TYPE); + } + + public void then() + { + VersionHistory versionHistory = versionService.getVersionHistory(myDocument); + assertNotNull(versionHistory); + assertEquals(2, versionHistory.getAllVersions().size()); + + NodeRef frozenState = versionHistory.getHeadVersion().getFrozenStateNodeRef(); + assertEquals(TYPE_CUSTOM_TYPE, nodeService.getType(frozenState)); + assertEquals(TYPE_CUSTOM_TYPE, nodeService.getType(myDocument)); + + frozenState = versionHistory.getVersion("1.0").getFrozenStateNodeRef(); + assertEquals(ContentModel.TYPE_CONTENT, nodeService.getType(frozenState)); + assertEquals(TYPE_CUSTOM_TYPE, nodeService.getType(myDocument)); + } + + public void after() throws Exception + { + // reset auto version on type to default off + extendedVersionableAspect.setAutoVersionOnTypeChange(false); + } + }); + } + } diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/ExtendedVersionableAspectUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/ExtendedVersionableAspectUnitTest.java new file mode 100644 index 0000000000..8b6acb4195 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/version/ExtendedVersionableAspectUnitTest.java @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2005-2015 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 static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.times; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; +import org.alfresco.module.org_alfresco_module_rm.util.AlfrescoTransactionSupport; +import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.service.cmr.lock.LockService; +import org.alfresco.service.cmr.lock.LockStatus; +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.version.VersionService; +import org.alfresco.service.namespace.QName; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.springframework.extensions.webscripts.GUID; + +/** + * Extended versionable aspect unit test. + * + * @author Roy Wetherall + * @since 2.3.1 + */ +public class ExtendedVersionableAspectUnitTest implements RecordsManagementModel +{ + /** Transaction resource key */ + private static final String KEY_VERSIONED_NODEREFS = "versioned_noderefs"; + + /** test data */ + private NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, GUID.generate()); + private NodeRef anotherNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, GUID.generate()); + private QName oldType = QName.createQName(RM_URI, GUID.generate()); + private QName newType = QName.createQName(RM_URI, GUID.generate()); + + /** service mocks */ + private @Mock NodeService mockedNodeService; + private @Mock VersionService mockedVersionService; + private @Mock LockService mockedLockService; + private @Mock AlfrescoTransactionSupport mockedAlfrescoTransactionSupport; + private @Mock AuthenticationUtil mockedAuthenticationUtil; + + /** test instance of extended versionable aspect behaviour bean */ + private @InjectMocks ExtendedVersionableAspect extendedVersionableAspect; + + @SuppressWarnings("unchecked") + @Before + public void testSetup() + { + MockitoAnnotations.initMocks(this); + + // just do the work + doAnswer(new Answer() + { + @SuppressWarnings("rawtypes") + @Override + public Object answer(InvocationOnMock invocation) throws Throwable + { + RunAsWork work = (RunAsWork)invocation.getArguments()[0]; + return work.doWork(); + } + + }).when(mockedAuthenticationUtil).runAsSystem(any(RunAsWork.class)); + } + + /** + * given that autoversion on type change is configured off + * when the type set behvaiour is executed + * then a new version is not created + */ + @SuppressWarnings("unchecked") + @Test + public void autoVersionOff() + { + // auto version off + extendedVersionableAspect.setAutoVersionOnTypeChange(false); + + // execute behaviour + extendedVersionableAspect.onSetNodeType(nodeRef, oldType, newType); + + // assert the version was not created + verify(mockedVersionService, never()).createVersion(eq(nodeRef), any(Map.class)); + } + + /** + * given the node doesn't exist + * when the type set behaviour is executed + * then a new version is not created + */ + @SuppressWarnings("unchecked") + @Test + public void nodeDoesNotExist() + { + // auto version on + extendedVersionableAspect.setAutoVersionOnTypeChange(true); + + // node does not exist + when(mockedNodeService.exists(nodeRef)) + .thenReturn(false); + + // execute behaviour + extendedVersionableAspect.onSetNodeType(nodeRef, oldType, newType); + + // assert the version was not created + verify(mockedVersionService, never()).createVersion(eq(nodeRef), any(Map.class)); + } + + /** + * given that the node is locked + * when the type set behaviour is executed + * then a new version is not created + */ + @SuppressWarnings("unchecked") + @Test + public void nodeLocked() + { + // auto version on + extendedVersionableAspect.setAutoVersionOnTypeChange(true); + + // node does exists + when(mockedNodeService.exists(nodeRef)) + .thenReturn(true); + + // node is locked + when(mockedLockService.getLockStatus(nodeRef)) + .thenReturn(LockStatus.LOCKED); + + // execute behaviour + extendedVersionableAspect.onSetNodeType(nodeRef, oldType, newType); + + // verify other + verify(mockedNodeService).exists(nodeRef); + + // assert the version was not created + verify(mockedVersionService, never()).createVersion(eq(nodeRef), any(Map.class)); + } + + /** + * given that the node does not have the versionable aspect + * when the type set behaviour is executed + * then a new version is not created + */ + @SuppressWarnings("unchecked") + @Test + public void nodeIsNotVersionable() + { + // auto version on + extendedVersionableAspect.setAutoVersionOnTypeChange(true); + + // node does exists + when(mockedNodeService.exists(nodeRef)) + .thenReturn(true); + + // node is not locked + when(mockedLockService.getLockStatus(nodeRef)) + .thenReturn(LockStatus.NO_LOCK); + + // node does not have the versionable aspect + when(mockedNodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)) + .thenReturn(false); + + // execute behaviour + extendedVersionableAspect.onSetNodeType(nodeRef, oldType, newType); + + // verify other + verify(mockedNodeService).exists(nodeRef); + verify(mockedLockService).getLockStatus(nodeRef); + + // assert the version was not created + verify(mockedVersionService, never()).createVersion(eq(nodeRef), any(Map.class)); + } + + /** + * given that the node has the temporary aspect + * when the type set behaviour is executed + * then a new version is not created + */ + @SuppressWarnings("unchecked") + @Test + public void nodeIsTemporary() + { + // auto version on + extendedVersionableAspect.setAutoVersionOnTypeChange(true); + + // node does exists + when(mockedNodeService.exists(nodeRef)) + .thenReturn(true); + + // node is not locked + when(mockedLockService.getLockStatus(nodeRef)) + .thenReturn(LockStatus.NO_LOCK); + + // node has the versionable aspect + when(mockedNodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)) + .thenReturn(true); + + // node has the temporary aspect + when(mockedNodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY)) + .thenReturn(true); + + // execute behaviour + extendedVersionableAspect.onSetNodeType(nodeRef, oldType, newType); + + // verify other + verify(mockedNodeService).exists(nodeRef); + verify(mockedLockService).getLockStatus(nodeRef); + verify(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE); + + // assert the version was not created + verify(mockedVersionService, never()).createVersion(eq(nodeRef), any(Map.class)); + } + + /** + * given that the node is already being versioned + * when the type set behvaiour is executed + * then a new version is not created + */ + @SuppressWarnings("unchecked") + @Test + public void nodeIsBeingVersioned() + { + // auto version on + extendedVersionableAspect.setAutoVersionOnTypeChange(true); + + // node does exists + when(mockedNodeService.exists(nodeRef)) + .thenReturn(true); + + // node is not locked + when(mockedLockService.getLockStatus(nodeRef)) + .thenReturn(LockStatus.NO_LOCK); + + // node has the versionable aspect + when(mockedNodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)) + .thenReturn(true); + + // node does not have the temporary aspect + when(mockedNodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY)) + .thenReturn(false); + + // node is currently being processed for versioning + when(mockedAlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS)) + .thenReturn(Collections.singletonMap(nodeRef, nodeRef)); + + // execute behaviour + extendedVersionableAspect.onSetNodeType(nodeRef, oldType, newType); + + // verify other + verify(mockedNodeService).exists(nodeRef); + verify(mockedLockService).getLockStatus(nodeRef); + verify(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE); + verify(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY); + + // assert the version was not created + verify(mockedVersionService, never()).createVersion(eq(nodeRef), any(Map.class)); + } + + /** + * given that the node has the auto version property set to false + * when the type set behaviour is executed + * then a new version is not created + */ + @SuppressWarnings("unchecked") + @Test + public void autoVersionFalse() + { + // auto version on + extendedVersionableAspect.setAutoVersionOnTypeChange(true); + + // node does exists + when(mockedNodeService.exists(nodeRef)) + .thenReturn(true); + + // node is not locked + when(mockedLockService.getLockStatus(nodeRef)) + .thenReturn(LockStatus.NO_LOCK); + + // node has the versionable aspect + when(mockedNodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)) + .thenReturn(true); + + // node does not have the temporary aspect + when(mockedNodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY)) + .thenReturn(false); + + // node is not being processed for versioning + when(mockedAlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS)) + .thenReturn(Collections.singletonMap(anotherNodeRef, anotherNodeRef)); + + // auto version false + when(mockedNodeService.getProperty(nodeRef, ContentModel.PROP_AUTO_VERSION)) + .thenReturn(Boolean.FALSE); + + // execute behaviour + extendedVersionableAspect.onSetNodeType(nodeRef, oldType, newType); + + // verify other + verify(mockedNodeService).exists(nodeRef); + verify(mockedLockService).getLockStatus(nodeRef); + verify(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE); + verify(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY); + verify(mockedAlfrescoTransactionSupport).getResource(KEY_VERSIONED_NODEREFS); + + // assert the version was not created + verify(mockedVersionService, never()).createVersion(eq(nodeRef), any(Map.class)); + } + + /** + * given that autoversion on type change is configured on + * and the node exists + * and the node is not locked + * and the node has the versionable aspect + * and the node doesn't have the temporary aspect + * and the node isn't already being versioned + * and the auto version property is true + * when the type set behavour is executed + * then a new version is created + */ + @SuppressWarnings("unchecked") + @Test + public void createVersion() + { + // auto version on + extendedVersionableAspect.setAutoVersionOnTypeChange(true); + + // node does exists + when(mockedNodeService.exists(nodeRef)) + .thenReturn(true); + + // node is not locked + when(mockedLockService.getLockStatus(nodeRef)) + .thenReturn(LockStatus.NO_LOCK); + + // node has the versionable aspect + when(mockedNodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)) + .thenReturn(true); + + // node does not have the temporary aspect + when(mockedNodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY)) + .thenReturn(false); + + // node is not being processed for versioning + when(mockedAlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS)) + .thenReturn(new HashMap(Collections.singletonMap(anotherNodeRef, anotherNodeRef))); + + // auto version false + when(mockedNodeService.getProperty(nodeRef, ContentModel.PROP_AUTO_VERSION)) + .thenReturn(Boolean.TRUE); + + // execute behaviour + extendedVersionableAspect.onSetNodeType(nodeRef, oldType, newType); + + // verify other + verify(mockedNodeService).exists(nodeRef); + verify(mockedLockService).getLockStatus(nodeRef); + verify(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE); + verify(mockedNodeService).hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY); + verify(mockedAlfrescoTransactionSupport, times(2)).getResource(KEY_VERSIONED_NODEREFS); + verify(mockedNodeService).getProperty(nodeRef, ContentModel.PROP_AUTO_VERSION); + + // assert the version was not created + verify(mockedVersionService).createVersion(eq(nodeRef), any(Map.class)); + } + +}