diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index 0ed6c73149..271b40b23c 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -154,6 +154,7 @@ org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.getLastCompletedDispostionAction=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.isDisposableItemCutoff=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.cutoffDisposableItem=RM.Read.0 + org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.calculateAsOfDate=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.*=RM_DENY ]]> diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/BroadcastDispositionActionDefinitionUpdateAction.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/BroadcastDispositionActionDefinitionUpdateAction.java index 7dc22f9b65..cf262d2ca3 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/BroadcastDispositionActionDefinitionUpdateAction.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/BroadcastDispositionActionDefinitionUpdateAction.java @@ -237,17 +237,11 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx * @param dispositionActionDef The disposition action definition node * @param nextAction The next disposition action */ - private void persistPeriodChanges(NodeRef dispositionActionDef, DispositionAction nextAction) + protected void persistPeriodChanges(NodeRef dispositionActionDef, DispositionAction nextAction) { - Date newAsOfDate = null; - Period dispositionPeriod = (Period) getNodeService().getProperty(dispositionActionDef, PROP_DISPOSITION_PERIOD); - - if (dispositionPeriod != null) - { - // calculate the new as of date as we have been provided a new period - Date now = new Date(); - newAsOfDate = dispositionPeriod.getNextDate(now); - } + NodeRef dispositionedNode = getNodeService().getPrimaryParent(nextAction.getNodeRef()).getParentRef(); + DispositionActionDefinition definition = nextAction.getDispositionActionDefinition(); + Date newAsOfDate = getDispositionService().calculateAsOfDate(dispositionedNode, definition, false); if (logger.isDebugEnabled()) { diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java index 295397f1bd..734cb286ec 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java @@ -20,6 +20,7 @@ package org.alfresco.module.org_alfresco_module_rm.disposition; import java.io.Serializable; import java.util.Collection; +import java.util.Date; import java.util.List; import java.util.Map; @@ -232,4 +233,15 @@ public interface DispositionService * @param nodeRef node reference */ void refreshDispositionAction(NodeRef nodeRef); + + /** + * Compute the "disposition as of" date (if necessary) for a disposition action and a node. + * + * @param nodeRef The node which the schedule applies to. + * @param dispositionActionDefinition The definition of the disposition action. + * @param allowContextFromAsOf true if the context date is allowed to be obtained from the disposition "as of" property. + * @return The new "disposition as of" date. + */ + Date calculateAsOfDate(NodeRef nodeRef, DispositionActionDefinition dispositionActionDefinition, + boolean allowContextFromAsOf); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImpl.java index 70f0a43957..2f44f18bbe 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImpl.java @@ -53,8 +53,8 @@ import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.ParameterCheck; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Disposition service implementation. @@ -68,7 +68,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl RecordsManagementPolicies.OnFileRecord { /** Logger */ - private static Log logger = LogFactory.getLog(DispositionServiceImpl.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DispositionServiceImpl.class); /** Behaviour filter */ private BehaviourFilter behaviourFilter; @@ -217,7 +217,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl DispositionActionDefinition nextDispositionActionDefinition = dispositionActionDefinitions.get(0); // initialise the details of the next disposition action - initialiseDispositionAction(nodeRef, nextDispositionActionDefinition); + initialiseDispositionAction(nodeRef, nextDispositionActionDefinition, true); } } } @@ -387,12 +387,10 @@ public class DispositionServiceImpl extends ServiceBaseImpl { // TODO in the future we should be able to support disposition schedule reuse, but for now just warn that // only the first disposition schedule will be considered - if (logger.isWarnEnabled()) - { - logger.warn("Disposition schedule has more than one associated records management container. " + - "This is not currently supported so only the first container will be considered. " + - "(dispositionScheduleNodeRef=" + dispositionSchedule.getNodeRef().toString() + ")"); - } + LOGGER.warn("Disposition schedule has more than one associated records management container. " + + "This is not currently supported so only the first container will be considered. " + + "(dispositionScheduleNodeRef={})", + dispositionSchedule.getNodeRef().toString()); } // Get the container reference @@ -618,42 +616,16 @@ public class DispositionServiceImpl extends ServiceBaseImpl * Initialises the details of the next disposition action based on the details of a disposition * action definition. * - * @param nodeRef node reference - * @param dispositionActionDefinition disposition action definition + * @param nodeRef node reference + * @param dispositionActionDefinition disposition action definition + * @param allowContextFromAsOf true if the context date is allowed to be obtained from the disposition "as of" property. */ - private void initialiseDispositionAction(NodeRef nodeRef, DispositionActionDefinition dispositionActionDefinition) + private void initialiseDispositionAction(NodeRef nodeRef, DispositionActionDefinition dispositionActionDefinition, boolean allowContextFromAsOf) { // Create the properties Map props = new HashMap(10); - // Calculate the asOf date - Date asOfDate = null; - Period period = dispositionActionDefinition.getPeriod(); - if (period != null) - { - Date contextDate = null; - - // Get the period properties value - QName periodProperty = dispositionActionDefinition.getPeriodProperty(); - if (periodProperty != null) - { - // doesn't matter if the period property isn't set ... the asOfDate will get updated later - // when the value of the period property is set - contextDate = (Date)this.nodeService.getProperty(nodeRef, periodProperty); - } - else - { - // for now use 'NOW' as the default context date - // TODO set the default period property ... cut off date or last disposition date depending on context - contextDate = new Date(); - } - - // Calculate the as of date - if (contextDate != null) - { - asOfDate = period.getNextDate(contextDate); - } - } + Date asOfDate = calculateAsOfDate(nodeRef, dispositionActionDefinition, allowContextFromAsOf); // Set the property values props.put(PROP_DISPOSITION_ACTION_ID, dispositionActionDefinition.getId()); @@ -681,6 +653,50 @@ public class DispositionServiceImpl extends ServiceBaseImpl } } + /** + * Compute the "disposition as of" date (if necessary) for a disposition action and a node. + * + * @param nodeRef The node which the schedule applies to. + * @param dispositionActionDefinition The definition of the disposition action. + * @param allowContextFromAsOf true if the context date is allowed to be obtained from the disposition "as of" property. + * @return The new "disposition as of" date. + */ + @Override + public Date calculateAsOfDate(NodeRef nodeRef, DispositionActionDefinition dispositionActionDefinition, + boolean allowContextFromAsOf) + { + // Calculate the asOf date + Date asOfDate = null; + Period period = dispositionActionDefinition.getPeriod(); + if (period != null) + { + Date contextDate = null; + + // Get the period properties value + QName periodProperty = dispositionActionDefinition.getPeriodProperty(); + if (periodProperty != null && (allowContextFromAsOf + || !RecordsManagementModel.PROP_DISPOSITION_AS_OF.equals(periodProperty))) + { + // doesn't matter if the period property isn't set ... the asOfDate will get updated later + // when the value of the period property is set + contextDate = (Date)this.nodeService.getProperty(nodeRef, periodProperty); + } + else + { + // for now use 'NOW' as the default context date + // TODO set the default period property ... cut off date or last disposition date depending on context + contextDate = new Date(); + } + + // Calculate the as of date + if (contextDate != null) + { + asOfDate = period.getNextDate(contextDate); + } + } + return asOfDate; + } + /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#isNextDispositionActionEligible(org.alfresco.service.cmr.repository.NodeRef) */ @@ -898,63 +914,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl nodeService.addAspect(nodeRef, ASPECT_DISPOSITION_LIFECYCLE, null); } - // Create the properties - Map props = new HashMap(10); - - // Calculate the asOf date - Date asOfDate = null; - Period period = nextDispositionActionDefinition.getPeriod(); - if (period != null) - { - Date contextDate = null; - - // Get the period properties value - QName periodProperty = nextDispositionActionDefinition.getPeriodProperty(); - if (periodProperty != null && - !RecordsManagementModel.PROP_DISPOSITION_AS_OF.equals(periodProperty)) - { - // doesn't matter if the period property isn't set ... the asOfDate will get updated later - // when the value of the period property is set - contextDate = (Date) nodeService.getProperty(nodeRef, periodProperty); - } - else - { - // for now use 'NOW' as the default context date - // TODO set the default period property ... cut off date or last disposition date depending on context - contextDate = new Date(); - } - - // Calculate the as of date - if (contextDate != null) - { - asOfDate = period.getNextDate(contextDate); - } - } - - // Set the property values - props.put(PROP_DISPOSITION_ACTION_ID, nextDispositionActionDefinition.getId()); - props.put(PROP_DISPOSITION_ACTION, nextDispositionActionDefinition.getName()); - if (asOfDate != null) - { - props.put(PROP_DISPOSITION_AS_OF, asOfDate); - } - - // Create a new disposition action object - NodeRef dispositionActionNodeRef = nodeService.createNode( - nodeRef, - ASSOC_NEXT_DISPOSITION_ACTION, - ASSOC_NEXT_DISPOSITION_ACTION, - TYPE_DISPOSITION_ACTION, - props).getChildRef(); - DispositionAction da = new DispositionActionImpl(serviceRegistry, dispositionActionNodeRef); - - // Create the events - List events = nextDispositionActionDefinition.getEvents(); - for (RecordsManagementEvent event : events) - { - // For every event create an entry on the action - da.addEventCompletionDetails(event); - } + initialiseDispositionAction(nodeRef, nextDispositionActionDefinition, false); } } @@ -1009,7 +969,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl recordFolderService.closeRecordFolder(nodeRef); return null; } - }); + }); } } else diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionTestSuite.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionTestSuite.java index 71fe483156..e1938d1d28 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionTestSuite.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionTestSuite.java @@ -31,7 +31,8 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses( { - CutOffTest.class + CutOffTest.class, + UpdateDispositionScheduleTest.class }) public class DispositionTestSuite { diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateDispositionScheduleTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateDispositionScheduleTest.java new file mode 100644 index 0000000000..06ce6a5399 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateDispositionScheduleTest.java @@ -0,0 +1,164 @@ +/* + * 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.disposition; + +import static org.alfresco.module.org_alfresco_module_rm.test.util.bdt.BehaviourTest.test; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import com.google.common.collect.ImmutableMap; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.action.impl.CutOffAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.DestroyAction; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; +import org.alfresco.module.org_alfresco_module_rm.job.publish.DispositionActionDefinitionPublishExecutor; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils; +import org.alfresco.module.org_alfresco_module_rm.test.util.bdt.BehaviourTest; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.extensions.webscripts.GUID; + +/** + * Integration tests for updating the disposition schedule. + * + * @author Tom Page + * @since 2.3.1 + */ +public class UpdateDispositionScheduleTest extends BaseRMTestCase +{ + /** A unique prefix for the constants in this test. */ + protected static final String TEST_PREFIX = UpdateDispositionScheduleTest.class.getName() + GUID.generate() + "_"; + /** The name to use for the category. */ + protected static final String CATEGORY_NAME = TEST_PREFIX + "Category"; + /** The name to use for the folder. */ + protected static final String FOLDER_NAME = TEST_PREFIX + "Folder"; + /** The name to use for the record. */ + protected static final String RECORD_NAME = TEST_PREFIX + "Record"; + + /** The executor for the disposition update job. */ + private DispositionActionDefinitionPublishExecutor dispositionActionDefinitionPublishExecutor; + /** The internal disposition service is used to avoid permissions issues when updating the record. */ + private DispositionService internalDispositionService; + + /** The category node. */ + private NodeRef category; + /** The folder node. */ + private NodeRef folder; + /** The record node. */ + private NodeRef record; + /** The 'disposition as of' date from before the 'when' step. */ + private Date originalAsOfDate; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + BehaviourTest.initBehaviourTests(retryingTransactionHelper); + + // Get the application context + applicationContext = ApplicationContextHelper.getApplicationContext(getConfigLocations()); + dispositionActionDefinitionPublishExecutor = applicationContext.getBean(DispositionActionDefinitionPublishExecutor.class); + internalDispositionService = (DispositionService) applicationContext.getBean("dispositionService"); + } + + /** + * RM-3386 + *

+     * Given a record subject to a disposition schedule
+     * And the next step is due to run at some period after the date the content was created
+     * When I update the period of the next step (and wait for this to be processed)
+     * Then the "as of" date is updated to be at the new period after the creation date.
+     * 
+ */ + public void testUpdatePeriod() + { + test() + .given(() -> { + // Create a category. + category = filePlanService.createRecordCategory(filePlan, CATEGORY_NAME); + // Create a disposition schedule for the category (Cut off immediately, then Destroy 1 year after the creation date). + DispositionSchedule dispSched = utils.createBasicDispositionSchedule(category, "instructions", "authority", true, false); + Map cutOffParams = ImmutableMap.of(PROP_DISPOSITION_ACTION_NAME, CutOffAction.NAME, + PROP_DISPOSITION_DESCRIPTION, "description", + PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_IMMEDIATELY); + dispositionService.addDispositionActionDefinition(dispSched, cutOffParams); + Map destroyParams = ImmutableMap.of(PROP_DISPOSITION_ACTION_NAME, DestroyAction.NAME, + PROP_DISPOSITION_DESCRIPTION, "description", + PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_ONE_YEAR, + PROP_DISPOSITION_PERIOD_PROPERTY, ContentModel.PROP_CREATED); + dispositionService.addDispositionActionDefinition(dispSched, destroyParams); + // Create a folder containing a record within the category. + folder = recordFolderService.createRecordFolder(category, FOLDER_NAME); + record = fileFolderService.create(folder, RECORD_NAME, ContentModel.TYPE_CONTENT).getNodeRef(); + + dispositionService.cutoffDisposableItem(record); + // Ensure the update has been applied to the record. + internalDispositionService.updateNextDispositionAction(record); + + originalAsOfDate = dispositionService.getNextDispositionAction(record).getAsOfDate(); + }) + .when(() -> { + // Update the Destroy step to be 3 years after the creation date. + DispositionSchedule dispSched = dispositionService.getDispositionSchedule(category); + DispositionActionDefinition destroy = dispSched.getDispositionActionDefinitionByName(DestroyAction.NAME); + Map destroyParams = ImmutableMap.of(PROP_DISPOSITION_ACTION_NAME, DestroyAction.NAME, + PROP_DISPOSITION_DESCRIPTION, "description", + PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_THREE_YEARS, + PROP_DISPOSITION_PERIOD_PROPERTY, ContentModel.PROP_CREATED); + dispositionService.updateDispositionActionDefinition(destroy, destroyParams); + + // Make the disposition action definition update job run. + dispositionActionDefinitionPublishExecutor.publish(destroy.getNodeRef()); + }) + .then() + .expect(true) + .from(() -> aboutTwoYearsApart(originalAsOfDate, dispositionService.getNextDispositionAction(record).getAsOfDate())) + .because("Increasing the destroy period by two years should increase the 'as of' date by two years."); + } + + /** + * Check that the two given dates are approximately two years apart. + *

+ * This actually just checks that they're more than one and less than three years apart, because leap years make + * things hard to calculate. + * + * @return true if the two dates are about two years apart. + */ + private boolean aboutTwoYearsApart(Date start, Date end) + { + long days = daysBetween(start, end); + long yearInDays = 365; + return (yearInDays < days) && (days < 3 * yearInDays); + } + + /** Find the number of days between the two dates. */ + private long daysBetween(Date start, Date end) + { + return TimeUnit.MILLISECONDS.toDays(end.getTime() - start.getTime()); + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java index 3d66cb81bb..275dc089da 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java @@ -56,7 +56,7 @@ import org.springframework.context.ApplicationContext; /** * Common RM test utility methods. - * + * * @author Roy Wetherall */ public class CommonRMTestUtils implements RecordsManagementModel @@ -76,10 +76,12 @@ public class CommonRMTestUtils implements RecordsManagementModel public static final String DEFAULT_EVENT_NAME = "case_closed"; public static final String PERIOD_NONE = "none|0"; public static final String PERIOD_IMMEDIATELY = "immediately|0"; + public static final String PERIOD_ONE_YEAR = "year|1"; + public static final String PERIOD_THREE_YEARS = "year|3"; /** * Constructor - * + * * @param applicationContext application context */ public CommonRMTestUtils(ApplicationContext applicationContext) @@ -95,7 +97,7 @@ public class CommonRMTestUtils implements RecordsManagementModel /** * Create a disposition schedule - * + * * @param container record category * @return {@link DispositionSchedule} created disposition schedule node reference */ @@ -129,15 +131,15 @@ public class CommonRMTestUtils implements RecordsManagementModel boolean extendedDispositionSchedule) { return createDispositionSchedule( - container, - dispositionInstructions, - dispositionAuthority, - isRecordLevel, - defaultDispositionActions, - extendedDispositionSchedule, + container, + dispositionInstructions, + dispositionAuthority, + isRecordLevel, + defaultDispositionActions, + extendedDispositionSchedule, DEFAULT_EVENT_NAME); } - + /** * Create test disposition schedule */ @@ -241,8 +243,8 @@ public class CommonRMTestUtils implements RecordsManagementModel modelSecurityService.setEnabled(false); try { - nodeService.setProperty(record, RecordsManagementModel.PROP_DATE_FILED, new Date()); - nodeService.setProperty(record, ContentModel.PROP_TITLE, "titleValue"); + nodeService.setProperty(record, RecordsManagementModel.PROP_DATE_FILED, new Date()); + nodeService.setProperty(record, ContentModel.PROP_TITLE, "titleValue"); actionService.executeRecordsManagementAction(record, "declareRecord"); } finally @@ -255,7 +257,7 @@ public class CommonRMTestUtils implements RecordsManagementModel }, AuthenticationUtil.getAdminUserName()); - } + } public void closeFolder(final NodeRef recordFolder) { @@ -293,10 +295,10 @@ public class CommonRMTestUtils implements RecordsManagementModel return filePlanRoleService.createRole(filePlan, roleName, roleName, capabilities); } - + /** * Helper method to complete event on disposable item - * + * * @param disposableItem disposable item (record or record folder) * @param eventName event name */ @@ -305,8 +307,8 @@ public class CommonRMTestUtils implements RecordsManagementModel // build action properties Map params = new HashMap(1); params.put(CompleteEventAction.PARAM_EVENT_NAME, eventName); - + // complete event - actionService.executeRecordsManagementAction(disposableItem, CompleteEventAction.NAME, params); + actionService.executeRecordsManagementAction(disposableItem, CompleteEventAction.NAME, params); } } diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/BroadcastDispositionActionDefinitionUpdateActionUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/BroadcastDispositionActionDefinitionUpdateActionUnitTest.java new file mode 100644 index 0000000000..2a4f2df23b --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/action/impl/BroadcastDispositionActionDefinitionUpdateActionUnitTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2005-2016 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.impl; + +import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.PROP_DISPOSITION_AS_OF; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Date; + +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for {@link BroadcastDispositionActionDefinitionUpdateAction}. + * + * @author Tom Page + * @since 2.3.1 + */ +public class BroadcastDispositionActionDefinitionUpdateActionUnitTest +{ + /** The node under the category containing information about the definition of the action. */ + private static final NodeRef DISPOSITION_ACTION_DEF_NODE = new NodeRef("disposition://Action/Def"); + /** The node containing the details of the next disposition step for the content. */ + private static final NodeRef NEXT_ACTION_NODE_REF = new NodeRef("next://Step/"); + /** The node being subject to the disposition step. */ + private static final NodeRef CONTENT_NODE_REF = new NodeRef("content://Node/Ref"); + + /** The class under test. */ + private BroadcastDispositionActionDefinitionUpdateAction action = new BroadcastDispositionActionDefinitionUpdateAction(); + + private NodeService mockNodeService = mock(NodeService.class); + private DispositionService mockDispositionService = mock(DispositionService.class); + + /** Inject the mock services into the class under test and link the content and next action nodes. */ + @Before + public void setUp() + { + action.setNodeService(mockNodeService); + action.setDispositionService(mockDispositionService); + + ChildAssociationRef mockAssocRef = mock(ChildAssociationRef.class); + when(mockNodeService.getPrimaryParent(NEXT_ACTION_NODE_REF)).thenReturn(mockAssocRef); + when(mockAssocRef.getParentRef()).thenReturn(CONTENT_NODE_REF); + } + + /** + * Check that the disposition service is used to determine the "disposition as of" date when changes are made to the + * disposition period. + */ + @Test + public void testPersistPeriodChanges() + { + // Set up the data associated with the next disposition action. + DispositionAction mockAction = mock(DispositionAction.class); + when(mockAction.getNodeRef()).thenReturn(NEXT_ACTION_NODE_REF); + DispositionActionDefinition mockDispositionActionDefinition = mock(DispositionActionDefinition.class); + when(mockAction.getDispositionActionDefinition()).thenReturn(mockDispositionActionDefinition); + when(mockAction.getName()).thenReturn("mockAction"); + // Set up the disposition service to return a known "disposition as of" date. + Date asOfDate = new Date(); + when(mockDispositionService.calculateAsOfDate(CONTENT_NODE_REF, mockDispositionActionDefinition, false)) + .thenReturn(asOfDate); + + // Call the method under test. + action.persistPeriodChanges(DISPOSITION_ACTION_DEF_NODE, mockAction); + + // Check that the "disposition as of" date has been set on the next action. + verify(mockNodeService).setProperty(NEXT_ACTION_NODE_REF, PROP_DISPOSITION_AS_OF, asOfDate); + } +} diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImplUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImplUnitTest.java new file mode 100644 index 0000000000..8fb7ccbbb7 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImplUnitTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2005-2016 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.disposition; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Date; + +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.Period; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for {@link DispositionServiceImpl}. + * + * @author Tom Page + * @since 2.3.1 + */ +public class DispositionServiceImplUnitTest +{ + /** The node being subject to the disposition step. */ + NodeRef CONTENT_NODE_REF = new NodeRef("content://node/"); + + /** The class under test. */ + private DispositionServiceImpl dispositionService = new DispositionServiceImpl(); + + private NodeService mockNodeService = mock(NodeService.class); + + @Before + public void setUp() + { + dispositionService.setNodeService(mockNodeService); + } + + /** + * Check that the relevant information is retrieved from the DispositionActionDefinition in order to determine the + * "disposition as of" date. + */ + @Test + public void testCalculateAsOfDate() + { + // Set up a mock for the disposition action definition. + DispositionActionDefinition mockDispositionActionDefinition = mock(DispositionActionDefinition.class); + Period mockPeriod = mock(Period.class); + when(mockDispositionActionDefinition.getPeriod()).thenReturn(mockPeriod); + when(mockDispositionActionDefinition.getPeriodProperty()).thenReturn(ContentModel.PROP_CREATED); + // Set up a created date and another date that is some Period later. + Date createdDate = new Date(1234567890); + when(mockNodeService.getProperty(CONTENT_NODE_REF, ContentModel.PROP_CREATED)).thenReturn(createdDate); + Date nextDate = new Date(1240000000); + when(mockPeriod.getNextDate(createdDate)).thenReturn(nextDate); + + // Call the method under test. + Date asOfDate = dispositionService.calculateAsOfDate(CONTENT_NODE_REF, mockDispositionActionDefinition, true); + + assertEquals("Unexpected calculation for 'as of' date", nextDate, asOfDate); + } + + /** Check that the calculated "disposition as of" date is null if a null period is given. */ + @Test + public void testCalculateAsOfDate_nullPeriod() + { + DispositionActionDefinition mockDispositionActionDefinition = mock(DispositionActionDefinition.class); + when(mockDispositionActionDefinition.getPeriod()).thenReturn(null); + + // Call the method under test. + Date asOfDate = dispositionService.calculateAsOfDate(CONTENT_NODE_REF, mockDispositionActionDefinition, true); + + assertNull("It should not be possible to determine the 'as of' date.", asOfDate); + } +}