RM-1413: DispositionLifecycleJobExecuter does not execute the disposition action

* corrected logic error in job implementation
 * unit test
 * the disposition actions to execute are now configured via Spring configuration



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@67170 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2014-04-11 04:04:33 +00:00
parent 5a9c2056c1
commit 85e99b826e
6 changed files with 420 additions and 62 deletions

View File

@@ -0,0 +1,231 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.job;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.anyMap;
import static org.mockito.Mockito.contains;
import java.util.Collections;
import java.util.List;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
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.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
/**
* Disposition lifecycle job execution unit test.
*
* @author Roy Wetherall
* @since 2.2
*/
public class DispositionLifecycleJobExecuterUnitTest extends BaseUnitTest
{
/** disposition actions */
private static final String CUTOFF = "cutoff";
private static final String RETAIN = "retain";
private static final String DESTROY = "destroy";
/** test query snipit */
private static final String QUERY = "\"" + CUTOFF + "\" OR \"" + RETAIN + "\"";
/** mocked result set */
@Mock ResultSet mockedResultSet;
/** disposition lifecycle job executer */
@InjectMocks DispositionLifecycleJobExecuter executer;
/**
* @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest#before()
*/
@Override
@Before
public void before()
{
super.before();
// setup data
List<String> dispositionActions = buildList(CUTOFF, RETAIN);
executer.setDispositionActions(dispositionActions);
// setup interactions
doReturn(mockedResultSet).when(mockedSearchService).query(eq(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE), eq(SearchService.LANGUAGE_LUCENE), anyString());
}
/**
* Helper method to verify that the query has been executed and closed
*/
private void verifyQuery()
{
verify(mockedSearchService, times(1)).query(eq(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE), eq(SearchService.LANGUAGE_LUCENE), contains(QUERY));
verify(mockedResultSet, times(1)).getNodeRefs();
verify(mockedResultSet, times(1)).close();
}
/**
* When the are no results in query.
*/
@Test
public void noResultsInQuery()
{
// given
doReturn(Collections.EMPTY_LIST).when(mockedResultSet).getNodeRefs();
// when
executer.executeImpl();
// then
// ensure the query is executed and closed
verifyQuery();
// ensure nothing else happens becuase we have no results
verifyZeroInteractions(mockedNodeService, mockedRecordFolderService, mockedRetryingTransactionHelper);
}
/**
* When the disposition actions do not match those that can be processed automatically.
*/
@SuppressWarnings("unchecked")
@Test
public void dispositionActionDoesNotMatch()
{
// test data
NodeRef node1 = generateNodeRef();
NodeRef node2 = generateNodeRef();
List<NodeRef> nodeRefs = buildList(node1, node2);
// given
doReturn(nodeRefs).when(mockedResultSet).getNodeRefs();
doReturn(DESTROY).when(mockedNodeService).getProperty(node1, RecordsManagementModel.PROP_DISPOSITION_ACTION);
doReturn(DESTROY).when(mockedNodeService).getProperty(node2, RecordsManagementModel.PROP_DISPOSITION_ACTION);
// when
executer.executeImpl();
// then
// ensure the query is executed and closed
verifyQuery();
// ensure work is executed in transaction for each node processed
verify(mockedNodeService, times(2)).exists(any(NodeRef.class));
verify(mockedRetryingTransactionHelper, times(2)).doInTransaction(any(RetryingTransactionCallback.class));
// ensure each node is process correctly
verify(mockedNodeService, times(1)).getProperty(node1, RecordsManagementModel.PROP_DISPOSITION_ACTION);
verify(mockedNodeService, times(1)).getProperty(node2, RecordsManagementModel.PROP_DISPOSITION_ACTION);
// ensure no more interactions
verifyNoMoreInteractions(mockedNodeService);
verifyZeroInteractions(mockedRecordsManagementActionService);
}
/**
* When a node does not exist
*/
@Test
public void nodeDoesNotExist()
{
// test data
NodeRef node1 = generateNodeRef(null, false);
List<NodeRef> nodeRefs = buildList(node1);
// given
doReturn(nodeRefs).when(mockedResultSet).getNodeRefs();
// when
executer.executeImpl();
// then
// ensure the query is executed and closed
verifyQuery();
// ensure the node exist check is made for the node
verify(mockedNodeService, times(1)).exists(any(NodeRef.class));
// ensure no more interactions
verifyNoMoreInteractions(mockedNodeService);
verifyZeroInteractions(mockedRecordsManagementActionService, mockedRetryingTransactionHelper);
}
/**
* When there are disposition actions eligible for processing
*/
@SuppressWarnings("unchecked")
@Test
public void dispositionActionProcessed()
{
// test data
NodeRef node1 = generateNodeRef();
NodeRef node2 = generateNodeRef();
List<NodeRef> nodeRefs = buildList(node1, node2);
NodeRef parent = generateNodeRef();
ChildAssociationRef parentAssoc = new ChildAssociationRef(ASSOC_NEXT_DISPOSITION_ACTION, parent, generateQName(), generateNodeRef());
// given
doReturn(nodeRefs).when(mockedResultSet).getNodeRefs();
doReturn(CUTOFF).when(mockedNodeService).getProperty(node1, RecordsManagementModel.PROP_DISPOSITION_ACTION);
doReturn(RETAIN).when(mockedNodeService).getProperty(node2, RecordsManagementModel.PROP_DISPOSITION_ACTION);
doReturn(parentAssoc).when(mockedNodeService).getPrimaryParent(any(NodeRef.class));
// when
executer.executeImpl();
// then
// ensure the query is executed and closed
verifyQuery();
// ensure work is executed in transaction for each node processed
verify(mockedNodeService, times(2)).exists(any(NodeRef.class));
verify(mockedRetryingTransactionHelper, times(2)).doInTransaction(any(RetryingTransactionCallback.class));
// ensure each node is process correctly
// node1
verify(mockedNodeService, times(1)).getProperty(node1, RecordsManagementModel.PROP_DISPOSITION_ACTION);
verify(mockedNodeService, times(1)).getPrimaryParent(node1);
verify(mockedRecordsManagementActionService, times(1)).executeRecordsManagementAction(eq(parent), eq(CUTOFF), anyMap());
// node2
verify(mockedNodeService, times(1)).getProperty(node2, RecordsManagementModel.PROP_DISPOSITION_ACTION);
verify(mockedNodeService, times(1)).getPrimaryParent(node2);
verify(mockedRecordsManagementActionService, times(1)).executeRecordsManagementAction(eq(parent), eq(RETAIN), anyMap());
// ensure no more interactions
verifyNoMoreInteractions(mockedNodeService, mockedRecordsManagementActionService);
}
}

View File

@@ -21,6 +21,7 @@ package org.alfresco.module.org_alfresco_module_rm.test;
import org.alfresco.module.org_alfresco_module_rm.capability.declarative.condition.HoldCapabilityConditionUnitTest;
import org.alfresco.module.org_alfresco_module_rm.forms.RecordsManagementTypeFormFilterUnitTest;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldServiceImplUnitTest;
import org.alfresco.module.org_alfresco_module_rm.job.DispositionLifecycleJobExecuterUnitTest;
import org.alfresco.module.org_alfresco_module_rm.jscript.app.evaluator.FrozenEvaluatorUnitTest;
import org.alfresco.module.org_alfresco_module_rm.jscript.app.evaluator.TransferEvaluatorUnitTest;
import org.alfresco.module.org_alfresco_module_rm.record.RecordMetadataBootstrapUnitTest;
@@ -44,6 +45,7 @@ import org.junit.runners.Suite.SuiteClasses;
{
RecordMetadataBootstrapUnitTest.class,
RecordsManagementTypeFormFilterUnitTest.class,
DispositionLifecycleJobExecuterUnitTest.class,
// services
RecordServiceImplUnitTest.class,

View File

@@ -30,6 +30,7 @@ import java.util.Collections;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionService;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService;
@@ -38,11 +39,14 @@ import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
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.search.SearchService;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
@@ -78,18 +82,21 @@ public class BaseUnitTest implements RecordsManagementModel
protected NodeRef record;
/** core service mocks */
@Mock(name="nodeService") protected NodeService mockedNodeService;
@Mock(name="dictionaryService") protected DictionaryService mockedDictionaryService;
@Mock(name="namespaceService") protected NamespaceService mockedNamespaceService;
@Mock(name="identifierService") protected IdentifierService mockedIdentifierService;
@Mock(name="permissionService") protected PermissionService mockedPermissionService;
@Mock(name="ownableService") protected OwnableService mockedOwnableService;
@Mock(name="nodeService") protected NodeService mockedNodeService;
@Mock(name="dictionaryService") protected DictionaryService mockedDictionaryService;
@Mock(name="namespaceService") protected NamespaceService mockedNamespaceService;
@Mock(name="identifierService") protected IdentifierService mockedIdentifierService;
@Mock(name="permissionService") protected PermissionService mockedPermissionService;
@Mock(name="ownableService") protected OwnableService mockedOwnableService;
@Mock(name="searchService") protected SearchService mockedSearchService;
@Mock(name="retryingTransactionHelper") protected RetryingTransactionHelper mockedRetryingTransactionHelper;
/** rm service mocks */
@Mock(name="filePlanService") protected FilePlanService mockedFilePlanService;
@Mock(name="recordFolderService") protected RecordFolderService mockedRecordFolderService;
@Mock(name="recordService") protected RecordService mockedRecordService;
@Mock(name="holdService") protected HoldService mockedHoldService;
@Mock(name="filePlanService") protected FilePlanService mockedFilePlanService;
@Mock(name="recordFolderService") protected RecordFolderService mockedRecordFolderService;
@Mock(name="recordService") protected RecordService mockedRecordService;
@Mock(name="holdService") protected HoldService mockedHoldService;
@Mock(name="recordsManagementActionService") protected RecordsManagementActionService mockedRecordsManagementActionService;
/** application context mock */
@Mock(name="applicationContext") protected ApplicationContext mockedApplicationContext;
@@ -101,6 +108,7 @@ public class BaseUnitTest implements RecordsManagementModel
/**
* Test method setup
*/
@SuppressWarnings("unchecked")
@Before
public void before()
{
@@ -108,6 +116,19 @@ public class BaseUnitTest implements RecordsManagementModel
// setup application context
doReturn(mockedNodeService).when(mockedApplicationContext).getBean("nodeService");
// setup retrying transaction helper
Answer<Object> doInTransactionAnswer = new Answer<Object>()
{
@SuppressWarnings("rawtypes")
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
RetryingTransactionCallback callback = (RetryingTransactionCallback)invocation.getArguments()[0];
return callback.execute();
}
};
doAnswer(doInTransactionAnswer).when(mockedRetryingTransactionHelper).doInTransaction(any(RetryingTransactionCallback.class));
// setup file plan
filePlan = generateNodeRef(TYPE_FILE_PLAN);
@@ -217,9 +238,22 @@ public class BaseUnitTest implements RecordsManagementModel
* the content type provided
*/
protected NodeRef generateNodeRef(QName type)
{
return generateNodeRef(type, true);
}
/**
* Helper method to generate a node reference of a particular type with a given existence characteristic.
*
* @param type content type qualified name
* @param exists indicates whether this node should behave like a node that exists or not
* @return {@link NodeRef} node reference that behaves like a node that exists (or not) in the spaces store with
* the content type provided
*/
protected NodeRef generateNodeRef(QName type, boolean exists)
{
NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, GUID.generate());
when(mockedNodeService.exists(eq(nodeRef))).thenReturn(true);
when(mockedNodeService.exists(eq(nodeRef))).thenReturn(exists);
if (type != null)
{
when(mockedNodeService.getType(eq(nodeRef))).thenReturn(type);
@@ -294,4 +328,15 @@ public class BaseUnitTest implements RecordsManagementModel
}).when(service).runAs(any(RunAsWork.class), anyString());
}
@SuppressWarnings("unchecked")
protected <T> List<T> buildList(T ... values)
{
List<T> result = new ArrayList<T>(values.length);
for (T value : values)
{
result.add(value);
}
return result;
}
}