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

@@ -21,6 +21,11 @@ log4j.logger.org.alfresco.module.org_alfresco_module_rm.patch=info
# #
#log4j.logger.org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService=debug #log4j.logger.org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService=debug
#
# Job debug
#
#log4j.logger.org.alfresco.module.org_alfresco_module_rm.job=debug
# #
# Behaviour debug # Behaviour debug
# #

View File

@@ -72,6 +72,15 @@
<bean id="dispositionLifecycleJobExecuter" <bean id="dispositionLifecycleJobExecuter"
class="org.alfresco.module.org_alfresco_module_rm.job.DispositionLifecycleJobExecuter" class="org.alfresco.module.org_alfresco_module_rm.job.DispositionLifecycleJobExecuter"
parent="baseRMJobExecuter"> parent="baseRMJobExecuter">
<!-- list of disposition actions to automatically execute when eligible -->
<property name="dispositionActions">
<list>
<value>cutoff</value>
<value>retain</value>
</list>
</property>
<property name="nodeService" ref="nodeService" /> <property name="nodeService" ref="nodeService" />
<property name="searchService" ref="searchService" /> <property name="searchService" ref="searchService" />
<property name="recordsManagementActionService" ref="recordsManagementActionService" /> <property name="recordsManagementActionService" ref="recordsManagementActionService" />
@@ -86,7 +95,7 @@
</property> </property>
<property name="cronExpression"> <property name="cronExpression">
<!-- <value>0 30 3 * * ?</value> --> <!-- <value>0 30 3 * * ?</value> -->
<value>0 0/15 * * * ?</value> <value>0/30 * * * * ?</value>
</property> </property>
</bean> </bean>

View File

@@ -40,38 +40,110 @@ import org.apache.commons.logging.LogFactory;
/** /**
* The Disposition Lifecycle Job Finds all disposition action nodes which are * The Disposition Lifecycle Job Finds all disposition action nodes which are
* for "retain" or "cutOff" actions Where asOf > now OR * for disposition actions specified Where asOf > now OR
* dispositionEventsEligible = true; * dispositionEventsEligible = true;
* *
* Runs the cut off or retain action for * Runs the cut off or retain action for
* elligible records. * eligible records.
* *
* @author mrogers * @author mrogers
* @author Roy Wetherall
*/ */
public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecuter public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecuter
{ {
/** logger */
private static Log logger = LogFactory.getLog(DispositionLifecycleJobExecuter.class); private static Log logger = LogFactory.getLog(DispositionLifecycleJobExecuter.class);
/** list of disposition actions to automatically execute */
private List<String> dispositionActions;
/** query string */
private String query;
/** records management action service */
private RecordsManagementActionService recordsManagementActionService; private RecordsManagementActionService recordsManagementActionService;
/** node service */
private NodeService nodeService; private NodeService nodeService;
/** search service */
private SearchService searchService; private SearchService searchService;
/**
* List of disposition actions to automatically execute when eligible.
*
* @param dispositionActions disposition actions
*/
public void setDispositionActions(List<String> dispositionActions)
{
this.dispositionActions = dispositionActions;
}
/**
* @param recordsManagementActionService records management action service
*/
public void setRecordsManagementActionService(RecordsManagementActionService recordsManagementActionService) public void setRecordsManagementActionService(RecordsManagementActionService recordsManagementActionService)
{ {
this.recordsManagementActionService = recordsManagementActionService; this.recordsManagementActionService = recordsManagementActionService;
} }
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
{ {
this.nodeService = nodeService; this.nodeService = nodeService;
} }
/**
* @param searchService search service
*/
public void setSearchService(SearchService searchService) public void setSearchService(SearchService searchService)
{ {
this.searchService = searchService; this.searchService = searchService;
} }
/**
* Get the search query string.
*
* @return job query string
*/
private String getQuery()
{
if (query == null)
{
StringBuilder sb = new StringBuilder();
sb.append("+TYPE:\"rma:dispositionAction\" ");
sb.append("+(@rma\\:dispositionAction:(");
boolean bFirst = true;
for (String dispositionAction : dispositionActions)
{
if (bFirst)
{
bFirst = false;
}
else
{
sb.append(" OR ");
}
sb.append("\"").append(dispositionAction).append("\"");
}
sb.append("))");
sb.append("+ISNULL:\"rma:dispositionActionCompletedAt\" ");
sb.append("+( ");
sb.append("@rma\\:dispositionEventsEligible:true ");
sb.append("OR @rma\\:dispositionAsOf:[MIN TO NOW] ");
sb.append(") ");
query = sb.toString();
}
return query;
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.job.RecordsManagementJobExecuter#execute() * @see org.alfresco.module.org_alfresco_module_rm.job.RecordsManagementJobExecuter#execute()
@@ -81,64 +153,58 @@ public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecute
try try
{ {
logger.debug("Job Starting"); logger.debug("Job Starting");
StringBuilder sb = new StringBuilder(); if (dispositionActions != null && !dispositionActions.isEmpty())
sb.append("+TYPE:\"rma:dispositionAction\" ");
sb.append("+(@rma\\:dispositionAction:(\"cutoff\" OR \"retain\"))");
sb.append("+ISNULL:\"rma:dispositionActionCompletedAt\" ");
sb.append("+( ");
sb.append("@rma\\:dispositionEventsEligible:true ");
sb.append("OR @rma\\:dispositionAsOf:[MIN TO NOW] ");
sb.append(") ");
String query = sb.toString();
ResultSet results = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
SearchService.LANGUAGE_LUCENE, query);
List<NodeRef> resultNodes = results.getNodeRefs();
results.close();
for (NodeRef node : resultNodes)
{ {
final NodeRef currentNode = node; // execute search
ResultSet results = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_LUCENE, getQuery());
RetryingTransactionCallback<Boolean> processTranCB = new RetryingTransactionCallback<Boolean>() List<NodeRef> resultNodes = results.getNodeRefs();
results.close();
if (logger.isDebugEnabled())
{ {
public Boolean execute() throws Throwable logger.debug("Processing " + resultNodes.size() + " nodes");
}
// process search results
for (NodeRef node : resultNodes)
{
final NodeRef currentNode = node;
RetryingTransactionCallback<Boolean> processTranCB = new RetryingTransactionCallback<Boolean>()
{ {
final String dispAction = (String) nodeService.getProperty(currentNode, public Boolean execute() throws Throwable
RecordsManagementModel.PROP_DISPOSITION_ACTION);
// Run "retain" and "cutoff" actions.
if (dispAction != null && (dispAction.equalsIgnoreCase("cutoff") ||
dispAction.equalsIgnoreCase("retain")))
{ {
ChildAssociationRef parent = nodeService.getPrimaryParent(currentNode); final String dispAction = (String) nodeService.getProperty(currentNode, RecordsManagementModel.PROP_DISPOSITION_ACTION);
if (parent.getTypeQName().equals(RecordsManagementModel.ASSOC_NEXT_DISPOSITION_ACTION))
// Run disposition action
if (dispAction != null && dispositionActions.contains(dispAction))
{ {
Map<String, Serializable> props = new HashMap<String, Serializable>(1); ChildAssociationRef parent = nodeService.getPrimaryParent(currentNode);
props.put(RMDispositionActionExecuterAbstractBase.PARAM_NO_ERROR_CHECK, Boolean.FALSE); if (parent.getTypeQName().equals(RecordsManagementModel.ASSOC_NEXT_DISPOSITION_ACTION))
recordsManagementActionService.executeRecordsManagementAction(parent.getParentRef(), dispAction, props);
if (logger.isDebugEnabled())
{ {
logger.debug("Processed action: " + dispAction + "on" + parent); Map<String, Serializable> props = new HashMap<String, Serializable>(1);
props.put(RMDispositionActionExecuterAbstractBase.PARAM_NO_ERROR_CHECK, Boolean.FALSE);
// execute disposition action
recordsManagementActionService.executeRecordsManagementAction(parent.getParentRef(), dispAction, props);
if (logger.isDebugEnabled())
{
logger.debug("Processed action: " + dispAction + "on" + parent);
}
} }
} }
return null;
return Boolean.TRUE;
} }
return Boolean.TRUE; };
// if exists
if (nodeService.exists(currentNode))
{
retryingTransactionHelper.doInTransaction(processTranCB);
} }
};
/**
* Now do the work, one action in each transaction
*/
if (!nodeService.exists(currentNode))
{
retryingTransactionHelper.doInTransaction(processTranCB);
} }
} }

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.capability.declarative.condition.HoldCapabilityConditionUnitTest;
import org.alfresco.module.org_alfresco_module_rm.forms.RecordsManagementTypeFormFilterUnitTest; 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.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.FrozenEvaluatorUnitTest;
import org.alfresco.module.org_alfresco_module_rm.jscript.app.evaluator.TransferEvaluatorUnitTest; import org.alfresco.module.org_alfresco_module_rm.jscript.app.evaluator.TransferEvaluatorUnitTest;
import org.alfresco.module.org_alfresco_module_rm.record.RecordMetadataBootstrapUnitTest; import org.alfresco.module.org_alfresco_module_rm.record.RecordMetadataBootstrapUnitTest;
@@ -44,6 +45,7 @@ import org.junit.runners.Suite.SuiteClasses;
{ {
RecordMetadataBootstrapUnitTest.class, RecordMetadataBootstrapUnitTest.class,
RecordsManagementTypeFormFilterUnitTest.class, RecordsManagementTypeFormFilterUnitTest.class,
DispositionLifecycleJobExecuterUnitTest.class,
// services // services
RecordServiceImplUnitTest.class, RecordServiceImplUnitTest.class,

View File

@@ -30,6 +30,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import org.alfresco.model.ContentModel; 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.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService; import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService; 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.recordfolder.RecordFolderService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; 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.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; 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.OwnableService;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
@@ -78,18 +82,21 @@ public class BaseUnitTest implements RecordsManagementModel
protected NodeRef record; protected NodeRef record;
/** core service mocks */ /** core service mocks */
@Mock(name="nodeService") protected NodeService mockedNodeService; @Mock(name="nodeService") protected NodeService mockedNodeService;
@Mock(name="dictionaryService") protected DictionaryService mockedDictionaryService; @Mock(name="dictionaryService") protected DictionaryService mockedDictionaryService;
@Mock(name="namespaceService") protected NamespaceService mockedNamespaceService; @Mock(name="namespaceService") protected NamespaceService mockedNamespaceService;
@Mock(name="identifierService") protected IdentifierService mockedIdentifierService; @Mock(name="identifierService") protected IdentifierService mockedIdentifierService;
@Mock(name="permissionService") protected PermissionService mockedPermissionService; @Mock(name="permissionService") protected PermissionService mockedPermissionService;
@Mock(name="ownableService") protected OwnableService mockedOwnableService; @Mock(name="ownableService") protected OwnableService mockedOwnableService;
@Mock(name="searchService") protected SearchService mockedSearchService;
@Mock(name="retryingTransactionHelper") protected RetryingTransactionHelper mockedRetryingTransactionHelper;
/** rm service mocks */ /** rm service mocks */
@Mock(name="filePlanService") protected FilePlanService mockedFilePlanService; @Mock(name="filePlanService") protected FilePlanService mockedFilePlanService;
@Mock(name="recordFolderService") protected RecordFolderService mockedRecordFolderService; @Mock(name="recordFolderService") protected RecordFolderService mockedRecordFolderService;
@Mock(name="recordService") protected RecordService mockedRecordService; @Mock(name="recordService") protected RecordService mockedRecordService;
@Mock(name="holdService") protected HoldService mockedHoldService; @Mock(name="holdService") protected HoldService mockedHoldService;
@Mock(name="recordsManagementActionService") protected RecordsManagementActionService mockedRecordsManagementActionService;
/** application context mock */ /** application context mock */
@Mock(name="applicationContext") protected ApplicationContext mockedApplicationContext; @Mock(name="applicationContext") protected ApplicationContext mockedApplicationContext;
@@ -101,6 +108,7 @@ public class BaseUnitTest implements RecordsManagementModel
/** /**
* Test method setup * Test method setup
*/ */
@SuppressWarnings("unchecked")
@Before @Before
public void before() public void before()
{ {
@@ -108,6 +116,19 @@ public class BaseUnitTest implements RecordsManagementModel
// setup application context // setup application context
doReturn(mockedNodeService).when(mockedApplicationContext).getBean("nodeService"); 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 // setup file plan
filePlan = generateNodeRef(TYPE_FILE_PLAN); filePlan = generateNodeRef(TYPE_FILE_PLAN);
@@ -217,9 +238,22 @@ public class BaseUnitTest implements RecordsManagementModel
* the content type provided * the content type provided
*/ */
protected NodeRef generateNodeRef(QName type) 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()); 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) if (type != null)
{ {
when(mockedNodeService.getType(eq(nodeRef))).thenReturn(type); when(mockedNodeService.getType(eq(nodeRef))).thenReturn(type);
@@ -294,4 +328,15 @@ public class BaseUnitTest implements RecordsManagementModel
}).when(service).runAs(any(RunAsWork.class), anyString()); }).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;
}
} }