mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
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:
@@ -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);
|
||||
}
|
||||
}
|
@@ -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,
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user