mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Action test refactoring
Reduce duplication between tests which all need working and failing actions that behave in a predictable, testable way git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21327 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
package org.alfresco.repo.action;
|
package org.alfresco.repo.action;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -44,6 +45,7 @@ import org.alfresco.service.cmr.action.Action;
|
|||||||
import org.alfresco.service.cmr.action.ActionCondition;
|
import org.alfresco.service.cmr.action.ActionCondition;
|
||||||
import org.alfresco.service.cmr.action.ActionConditionDefinition;
|
import org.alfresco.service.cmr.action.ActionConditionDefinition;
|
||||||
import org.alfresco.service.cmr.action.ActionDefinition;
|
import org.alfresco.service.cmr.action.ActionDefinition;
|
||||||
|
import org.alfresco.service.cmr.action.ActionService;
|
||||||
import org.alfresco.service.cmr.action.ActionStatus;
|
import org.alfresco.service.cmr.action.ActionStatus;
|
||||||
import org.alfresco.service.cmr.action.CompositeAction;
|
import org.alfresco.service.cmr.action.CompositeAction;
|
||||||
import org.alfresco.service.cmr.action.CompositeActionCondition;
|
import org.alfresco.service.cmr.action.CompositeActionCondition;
|
||||||
@@ -56,6 +58,7 @@ import org.alfresco.service.namespace.NamespaceService;
|
|||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
import org.alfresco.util.BaseAlfrescoSpringTest;
|
import org.alfresco.util.BaseAlfrescoSpringTest;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action service test
|
* Action service test
|
||||||
@@ -107,13 +110,7 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
|
|||||||
ContentModel.TYPE_FOLDER).getChildRef();
|
ContentModel.TYPE_FOLDER).getChildRef();
|
||||||
|
|
||||||
// Register the test executor, if needed
|
// Register the test executor, if needed
|
||||||
if(!applicationContext.containsBean(SleepActionExecuter.NAME))
|
SleepActionExecuter.registerIfNeeded(applicationContext);
|
||||||
{
|
|
||||||
applicationContext.getBeanFactory().registerSingleton(
|
|
||||||
SleepActionExecuter.NAME,
|
|
||||||
new SleepActionExecuter()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1214,8 +1211,29 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
|
|||||||
|
|
||||||
return failingAction;
|
return failingAction;
|
||||||
}
|
}
|
||||||
protected Action createWorkingSleepAction() {
|
|
||||||
|
protected Action createFailingSleepAction(String id) throws Exception {
|
||||||
|
return createFailingSleepAction(id, this.actionService);
|
||||||
|
}
|
||||||
|
protected static Action createFailingSleepAction(String id, ActionService actionService) throws Exception {
|
||||||
|
Action failingAction = createWorkingSleepAction(id, actionService);
|
||||||
|
failingAction.setParameterValue(SleepActionExecuter.GO_BANG, Boolean.TRUE);
|
||||||
|
return failingAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Action createWorkingSleepAction() throws Exception {
|
||||||
|
return createWorkingSleepAction(null);
|
||||||
|
}
|
||||||
|
protected Action createWorkingSleepAction(String id) throws Exception {
|
||||||
|
return createWorkingSleepAction(id, this.actionService);
|
||||||
|
}
|
||||||
|
protected static Action createWorkingSleepAction(String id, ActionService actionService) throws Exception {
|
||||||
Action workingAction = actionService.createAction(SleepActionExecuter.NAME);
|
Action workingAction = actionService.createAction(SleepActionExecuter.NAME);
|
||||||
|
if(id != null) {
|
||||||
|
Field idF = ParameterizedItemImpl.class.getDeclaredField("id");
|
||||||
|
idF.setAccessible(true);
|
||||||
|
idF.set(workingAction, id);
|
||||||
|
}
|
||||||
return workingAction;
|
return workingAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1240,47 +1258,78 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
|
|||||||
*/
|
*/
|
||||||
public static class SleepActionExecuter extends ActionExecuterAbstractBase
|
public static class SleepActionExecuter extends ActionExecuterAbstractBase
|
||||||
{
|
{
|
||||||
public static final String NAME = "sleep-action";
|
public static final String NAME = "sleep-action";
|
||||||
private int sleepMs;
|
public static final String GO_BANG = "GoBang";
|
||||||
|
private int sleepMs;
|
||||||
private int timesExecuted = 0;
|
|
||||||
private void incrementTimesExecutedCount() {timesExecuted++;}
|
private int timesExecuted = 0;
|
||||||
public int getTimesExecuted() {return timesExecuted;}
|
private void incrementTimesExecutedCount() {timesExecuted++;}
|
||||||
|
public int getTimesExecuted() {return timesExecuted;}
|
||||||
public int getSleepMs()
|
private Thread executingThread;
|
||||||
{
|
|
||||||
return sleepMs;
|
/**
|
||||||
}
|
* Loads this executor into the ApplicationContext, if it
|
||||||
|
* isn't already there
|
||||||
public void setSleepMs(int sleepMs)
|
*/
|
||||||
{
|
public static void registerIfNeeded(ConfigurableApplicationContext ctx)
|
||||||
this.sleepMs = sleepMs;
|
{
|
||||||
}
|
if(!ctx.containsBean(SleepActionExecuter.NAME))
|
||||||
|
{
|
||||||
/**
|
ctx.getBeanFactory().registerSingleton(
|
||||||
* Add parameter definitions
|
SleepActionExecuter.NAME,
|
||||||
*/
|
new SleepActionExecuter()
|
||||||
@Override
|
);
|
||||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
}
|
||||||
{
|
}
|
||||||
// Intentionally empty
|
|
||||||
}
|
public Thread getExecutingThread()
|
||||||
|
{
|
||||||
|
return executingThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSleepMs()
|
||||||
|
{
|
||||||
|
return sleepMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSleepMs(int sleepMs)
|
||||||
|
{
|
||||||
|
this.sleepMs = sleepMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add parameter definitions
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||||
|
{
|
||||||
|
// Intentionally empty
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
|
protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
|
||||||
try
|
executingThread = Thread.currentThread();
|
||||||
{
|
//System.err.println("Sleeping for " + sleepMs + " for " + action);
|
||||||
Thread.sleep(sleepMs);
|
|
||||||
}
|
try
|
||||||
catch (InterruptedException ignored)
|
{
|
||||||
{
|
Thread.sleep(sleepMs);
|
||||||
// Intentionally empty
|
}
|
||||||
}
|
catch (InterruptedException ignored)
|
||||||
finally
|
{
|
||||||
{
|
// Intentionally empty
|
||||||
incrementTimesExecutedCount();
|
}
|
||||||
}
|
finally
|
||||||
}
|
{
|
||||||
|
incrementTimesExecutedCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean fail = (Boolean)action.getParameterValue(GO_BANG);
|
||||||
|
if(fail != null && fail)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Bang!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertBefore(Date before, Date after)
|
public static void assertBefore(Date before, Date after)
|
||||||
|
@@ -1,502 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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.repo.action;
|
|
||||||
|
|
||||||
import static org.alfresco.repo.action.ActionServiceImplTest.assertBefore;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.transaction.UserTransaction;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
|
||||||
import org.alfresco.repo.action.ActionTrackingServiceImplTest.SleepActionExecuter;
|
|
||||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
|
||||||
import org.alfresco.repo.action.executer.MoveActionExecuter;
|
|
||||||
import org.alfresco.repo.content.MimetypeMap;
|
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
|
||||||
import org.alfresco.service.cmr.action.Action;
|
|
||||||
import org.alfresco.service.cmr.action.ActionService;
|
|
||||||
import org.alfresco.service.cmr.action.ActionStatus;
|
|
||||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentData;
|
|
||||||
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.namespace.QName;
|
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
|
||||||
import org.alfresco.util.ApplicationContextHelper;
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action service tests which need careful control
|
|
||||||
* over the transactions they use.
|
|
||||||
*
|
|
||||||
* @author Nick Burch
|
|
||||||
*/
|
|
||||||
public class ActionServiceImplTransactionalTest extends TestCase
|
|
||||||
{
|
|
||||||
private static ConfigurableApplicationContext ctx =
|
|
||||||
(ConfigurableApplicationContext)ApplicationContextHelper.getApplicationContext();
|
|
||||||
|
|
||||||
private StoreRef storeRef;
|
|
||||||
private NodeRef rootNodeRef;
|
|
||||||
|
|
||||||
private NodeRef nodeRef;
|
|
||||||
private NodeRef folder;
|
|
||||||
private NodeService nodeService;
|
|
||||||
private ActionService actionService;
|
|
||||||
private TransactionService transactionService;
|
|
||||||
private RuntimeActionService runtimeActionService;
|
|
||||||
private RetryingTransactionHelper transactionHelper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
this.transactionHelper = (RetryingTransactionHelper)ctx.getBean("retryingTransactionHelper");
|
|
||||||
this.nodeService = (NodeService)ctx.getBean("nodeService");
|
|
||||||
this.actionService = (ActionService)ctx.getBean("actionService");
|
|
||||||
this.runtimeActionService = (RuntimeActionService)ctx.getBean("actionService");
|
|
||||||
this.transactionService = (TransactionService)ctx.getBean("transactionService");
|
|
||||||
|
|
||||||
AuthenticationUtil.setRunAsUserSystem();
|
|
||||||
|
|
||||||
UserTransaction txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
|
|
||||||
// Where to put things
|
|
||||||
this.storeRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
|
|
||||||
this.rootNodeRef = this.nodeService.getRootNode(this.storeRef);
|
|
||||||
|
|
||||||
// Create the node used for tests
|
|
||||||
this.nodeRef = this.nodeService.createNode(
|
|
||||||
this.rootNodeRef,
|
|
||||||
ContentModel.ASSOC_CHILDREN,
|
|
||||||
QName.createQName("{test}testnode"),
|
|
||||||
ContentModel.TYPE_CONTENT).getChildRef();
|
|
||||||
this.nodeService.setProperty(
|
|
||||||
this.nodeRef,
|
|
||||||
ContentModel.PROP_CONTENT,
|
|
||||||
new ContentData(null, MimetypeMap.MIMETYPE_TEXT_PLAIN, 0L, null));
|
|
||||||
this.folder = this.nodeService.createNode(
|
|
||||||
this.rootNodeRef,
|
|
||||||
ContentModel.ASSOC_CHILDREN,
|
|
||||||
QName.createQName("{test}testFolder"),
|
|
||||||
ContentModel.TYPE_FOLDER).getChildRef();
|
|
||||||
|
|
||||||
txn.commit();
|
|
||||||
|
|
||||||
// Register the test executor, if needed
|
|
||||||
if(!ctx.containsBean(SleepActionExecuter.NAME))
|
|
||||||
{
|
|
||||||
ctx.getBeanFactory().registerSingleton(
|
|
||||||
SleepActionExecuter.NAME,
|
|
||||||
new SleepActionExecuter()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that when we run an action, either
|
|
||||||
* synchronously or asynchronously, with it
|
|
||||||
* working or failing, that the action execution
|
|
||||||
* service correctly sets the flags
|
|
||||||
*/
|
|
||||||
public void testExecutionTrackingOnExecution() throws Exception {
|
|
||||||
final SleepActionExecuter sleepActionExec =
|
|
||||||
(SleepActionExecuter)ctx.getBean(SleepActionExecuter.NAME);
|
|
||||||
sleepActionExec.setSleepMs(10);
|
|
||||||
Action action;
|
|
||||||
NodeRef actionNode;
|
|
||||||
|
|
||||||
// We need real transactions
|
|
||||||
UserTransaction txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================
|
|
||||||
// Execute a transient Action that works, synchronously
|
|
||||||
// ===========================================================
|
|
||||||
action = createWorkingSleepAction();
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
|
||||||
|
|
||||||
this.actionService.executeAction(action, this.nodeRef);
|
|
||||||
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================
|
|
||||||
// Execute a transient Action that fails, synchronously
|
|
||||||
// ===========================================================
|
|
||||||
action = createFailingMoveAction();
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.actionService.executeAction(action, this.nodeRef);
|
|
||||||
fail("Action should have failed, and the error been thrown");
|
|
||||||
} catch(Exception e) {}
|
|
||||||
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNotNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// Tidy up from the action failure
|
|
||||||
txn.rollback();
|
|
||||||
txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================
|
|
||||||
// Execute a stored Action that works, synchronously
|
|
||||||
// ===========================================================
|
|
||||||
action = createWorkingSleepAction();
|
|
||||||
this.actionService.saveAction(this.nodeRef, action);
|
|
||||||
actionNode = action.getNodeRef();
|
|
||||||
assertNotNull(actionNode);
|
|
||||||
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
|
||||||
|
|
||||||
this.actionService.executeAction(action, this.nodeRef);
|
|
||||||
|
|
||||||
// Check our copy
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// Now re-load and check the stored one
|
|
||||||
action = runtimeActionService.createAction(actionNode);
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================
|
|
||||||
// Execute a stored Action that fails, synchronously
|
|
||||||
// ===========================================================
|
|
||||||
action = createFailingMoveAction();
|
|
||||||
this.actionService.saveAction(this.nodeRef, action);
|
|
||||||
actionNode = action.getNodeRef();
|
|
||||||
String actionId = action.getId();
|
|
||||||
assertNotNull(actionNode);
|
|
||||||
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// Save this
|
|
||||||
txn.commit();
|
|
||||||
txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
|
|
||||||
// Run the action - will fail and trigger a rollback
|
|
||||||
try {
|
|
||||||
this.actionService.executeAction(action, this.nodeRef);
|
|
||||||
fail("Action should have failed, and the error been thrown");
|
|
||||||
} catch(Exception e) {}
|
|
||||||
|
|
||||||
// Check our copy
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNotNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// Wait for the post-rollback update to complete
|
|
||||||
// (The stored one gets updated asynchronously)
|
|
||||||
txn.rollback();
|
|
||||||
Thread.sleep(150);
|
|
||||||
txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
|
|
||||||
// Now re-load and check the stored one
|
|
||||||
action = runtimeActionService.createAction(actionNode);
|
|
||||||
assertEquals(actionId, action.getId());
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNotNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// Tidy up from the action failure
|
|
||||||
txn.commit();
|
|
||||||
txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================
|
|
||||||
// Execute a transient Action that works, asynchronously
|
|
||||||
// ===========================================================
|
|
||||||
action = createWorkingSleepAction();
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
|
||||||
|
|
||||||
this.actionService.executeAction(action, this.nodeRef, false, true);
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Pending, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// End the transaction. Should allow the async action
|
|
||||||
// to be executed
|
|
||||||
txn.commit();
|
|
||||||
Thread.sleep(150);
|
|
||||||
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// Put things back ready for the next check
|
|
||||||
txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================
|
|
||||||
// Execute a transient Action that fails, asynchronously
|
|
||||||
// ===========================================================
|
|
||||||
action = createFailingMoveAction();
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
|
||||||
|
|
||||||
this.actionService.executeAction(action, this.nodeRef, false, true);
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Pending, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// End the transaction. Should allow the async action
|
|
||||||
// to be executed
|
|
||||||
txn.commit();
|
|
||||||
Thread.sleep(150);
|
|
||||||
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNotNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// Put things back ready for the next check
|
|
||||||
txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================
|
|
||||||
// Execute a stored Action that works, asynchronously
|
|
||||||
// ===========================================================
|
|
||||||
action = createWorkingSleepAction();
|
|
||||||
this.actionService.saveAction(this.nodeRef, action);
|
|
||||||
actionNode = action.getNodeRef();
|
|
||||||
assertNotNull(actionNode);
|
|
||||||
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
|
||||||
|
|
||||||
this.actionService.executeAction(action, this.nodeRef, false, true);
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Pending, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// End the transaction. Should allow the async action
|
|
||||||
// to be executed
|
|
||||||
txn.commit();
|
|
||||||
Thread.sleep(150);
|
|
||||||
txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
|
|
||||||
// Check our copy
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// Now re-load and check the stored one
|
|
||||||
action = runtimeActionService.createAction(actionNode);
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================
|
|
||||||
// Execute a stored Action that fails, asynchronously
|
|
||||||
// ===========================================================
|
|
||||||
action = createFailingMoveAction();
|
|
||||||
this.actionService.saveAction(this.nodeRef, action);
|
|
||||||
actionNode = action.getNodeRef();
|
|
||||||
assertNotNull(actionNode);
|
|
||||||
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
|
||||||
|
|
||||||
this.actionService.executeAction(action, this.nodeRef, false, true);
|
|
||||||
assertNull(action.getExecutionStartDate());
|
|
||||||
assertNull(action.getExecutionEndDate());
|
|
||||||
assertNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Pending, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// End the transaction. Should allow the async action
|
|
||||||
// to be executed
|
|
||||||
// Need to wait longer, as we have two async actions
|
|
||||||
// that need to occur - action + record
|
|
||||||
txn.commit();
|
|
||||||
Thread.sleep(250);
|
|
||||||
txn = transactionService.getUserTransaction();
|
|
||||||
txn.begin();
|
|
||||||
|
|
||||||
// Check our copy
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNotNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
|
||||||
|
|
||||||
// Now re-load and check the stored one
|
|
||||||
action = runtimeActionService.createAction(actionNode);
|
|
||||||
assertNotNull(action.getExecutionStartDate());
|
|
||||||
assertNotNull(action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
|
||||||
assertBefore(action.getExecutionEndDate(), new Date());
|
|
||||||
assertNotNull(action.getExecutionFailureMessage());
|
|
||||||
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Action createFailingMoveAction() {
|
|
||||||
Action failingAction = this.actionService.createAction(MoveActionExecuter.NAME);
|
|
||||||
failingAction.setParameterValue(MoveActionExecuter.PARAM_ASSOC_TYPE_QNAME, ContentModel.ASSOC_CHILDREN);
|
|
||||||
failingAction.setParameterValue(MoveActionExecuter.PARAM_ASSOC_QNAME, ContentModel.ASSOC_CHILDREN);
|
|
||||||
// Create a bad node ref
|
|
||||||
NodeRef badNodeRef = new NodeRef(this.storeRef, "123123");
|
|
||||||
failingAction.setParameterValue(MoveActionExecuter.PARAM_DESTINATION_FOLDER, badNodeRef);
|
|
||||||
|
|
||||||
return failingAction;
|
|
||||||
}
|
|
||||||
private Action createWorkingSleepAction() {
|
|
||||||
Action workingAction = actionService.createAction(SleepActionExecuter.NAME);
|
|
||||||
return workingAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is only used during JUnit testing.
|
|
||||||
*
|
|
||||||
* @author Neil Mc Erlean
|
|
||||||
*/
|
|
||||||
public static class SleepActionFilter extends AbstractAsynchronousActionFilter
|
|
||||||
{
|
|
||||||
public int compare(OngoingAsyncAction sae1, OngoingAsyncAction sae2)
|
|
||||||
{
|
|
||||||
// Sleep actions are always equivalent.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is only intended for use in JUnit tests.
|
|
||||||
*
|
|
||||||
* @author Neil McErlean.
|
|
||||||
*/
|
|
||||||
public static class SleepActionExecuter extends ActionExecuterAbstractBase
|
|
||||||
{
|
|
||||||
public static final String NAME = "sleep-action";
|
|
||||||
private int sleepMs;
|
|
||||||
|
|
||||||
private int timesExecuted = 0;
|
|
||||||
private void incrementTimesExecutedCount() {timesExecuted++;}
|
|
||||||
public int getTimesExecuted() {return timesExecuted;}
|
|
||||||
|
|
||||||
public int getSleepMs()
|
|
||||||
{
|
|
||||||
return sleepMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSleepMs(int sleepMs)
|
|
||||||
{
|
|
||||||
this.sleepMs = sleepMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add parameter definitions
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
|
||||||
{
|
|
||||||
// Intentionally empty
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Thread.sleep(sleepMs);
|
|
||||||
}
|
|
||||||
catch (InterruptedException ignored)
|
|
||||||
{
|
|
||||||
// Intentionally empty
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
incrementTimesExecutedCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -20,21 +20,17 @@ package org.alfresco.repo.action;
|
|||||||
|
|
||||||
import static org.alfresco.repo.action.ActionServiceImplTest.assertBefore;
|
import static org.alfresco.repo.action.ActionServiceImplTest.assertBefore;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.transaction.UserTransaction;
|
import javax.transaction.UserTransaction;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.action.ActionServiceImplTransactionalTest.SleepActionExecuter;
|
import org.alfresco.repo.action.ActionServiceImplTest.SleepActionExecuter;
|
||||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
|
||||||
import org.alfresco.repo.action.executer.MoveActionExecuter;
|
import org.alfresco.repo.action.executer.MoveActionExecuter;
|
||||||
import org.alfresco.repo.cache.EhCacheAdapter;
|
import org.alfresco.repo.cache.EhCacheAdapter;
|
||||||
import org.alfresco.repo.content.MimetypeMap;
|
import org.alfresco.repo.content.MimetypeMap;
|
||||||
import org.alfresco.repo.search.impl.parsers.CMISParser.nullPredicate_return;
|
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
import org.alfresco.service.cmr.action.Action;
|
import org.alfresco.service.cmr.action.Action;
|
||||||
@@ -43,7 +39,6 @@ import org.alfresco.service.cmr.action.ActionStatus;
|
|||||||
import org.alfresco.service.cmr.action.ActionTrackingService;
|
import org.alfresco.service.cmr.action.ActionTrackingService;
|
||||||
import org.alfresco.service.cmr.action.ExecutionDetails;
|
import org.alfresco.service.cmr.action.ExecutionDetails;
|
||||||
import org.alfresco.service.cmr.action.ExecutionSummary;
|
import org.alfresco.service.cmr.action.ExecutionSummary;
|
||||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentData;
|
import org.alfresco.service.cmr.repository.ContentData;
|
||||||
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;
|
||||||
@@ -115,13 +110,7 @@ public class ActionTrackingServiceImplTest extends TestCase
|
|||||||
txn.commit();
|
txn.commit();
|
||||||
|
|
||||||
// Register the test executor, if needed
|
// Register the test executor, if needed
|
||||||
if(!ctx.containsBean(SleepActionExecuter.NAME))
|
SleepActionExecuter.registerIfNeeded(ctx);
|
||||||
{
|
|
||||||
ctx.getBeanFactory().registerSingleton(
|
|
||||||
SleepActionExecuter.NAME,
|
|
||||||
new SleepActionExecuter()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creating cache keys */
|
/** Creating cache keys */
|
||||||
@@ -276,7 +265,7 @@ public class ActionTrackingServiceImplTest extends TestCase
|
|||||||
|
|
||||||
|
|
||||||
// Tell it to stop sleeping
|
// Tell it to stop sleeping
|
||||||
sleepActionExec.executingThread.interrupt();
|
sleepActionExec.getExecutingThread().interrupt();
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
|
|
||||||
|
|
||||||
@@ -291,15 +280,381 @@ public class ActionTrackingServiceImplTest extends TestCase
|
|||||||
/** Failing actions go into the cache, then out */
|
/** Failing actions go into the cache, then out */
|
||||||
public void testFailingActions() throws Exception
|
public void testFailingActions() throws Exception
|
||||||
{
|
{
|
||||||
|
final SleepActionExecuter sleepActionExec =
|
||||||
|
(SleepActionExecuter)ctx.getBean(SleepActionExecuter.NAME);
|
||||||
|
sleepActionExec.setSleepMs(10000);
|
||||||
|
|
||||||
|
// Have it run asynchronously
|
||||||
|
UserTransaction txn = transactionService.getUserTransaction();
|
||||||
|
txn.begin();
|
||||||
|
Action action = createFailingSleepAction("54321");
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
||||||
|
|
||||||
|
String key = ActionTrackingServiceImpl.generateCacheKey(action);
|
||||||
|
assertEquals(null, executingActionsCache.get(key));
|
||||||
|
|
||||||
|
this.actionService.executeAction(action, this.nodeRef, false, true);
|
||||||
|
|
||||||
|
|
||||||
|
// End the transaction. Should allow the async action
|
||||||
|
// to be started
|
||||||
|
txn.commit();
|
||||||
|
Thread.sleep(150);
|
||||||
|
|
||||||
|
|
||||||
|
// Check it's in the cache
|
||||||
|
System.out.println("Checking the cache for " + key);
|
||||||
|
assertNotNull(executingActionsCache.get(key));
|
||||||
|
|
||||||
|
ExecutionSummary s = ActionTrackingServiceImpl.buildExecutionSummary(action);
|
||||||
|
ExecutionDetails d = actionTrackingService.getExecutionDetails(s);
|
||||||
|
assertNotNull(d.getExecutionSummary());
|
||||||
|
assertEquals("sleep-action", d.getActionType());
|
||||||
|
assertEquals("54321", d.getActionId());
|
||||||
|
assertEquals(1, d.getExecutionInstance());
|
||||||
|
assertEquals(null, d.getPersistedActionRef());
|
||||||
|
assertNotNull(null, d.getStartedAt());
|
||||||
|
|
||||||
|
|
||||||
|
// Tell it to stop sleeping
|
||||||
|
sleepActionExec.getExecutingThread().interrupt();
|
||||||
|
Thread.sleep(100);
|
||||||
|
|
||||||
|
|
||||||
|
// Ensure it went away again
|
||||||
|
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
||||||
|
assertEquals("Bang!", action.getExecutionFailureMessage());
|
||||||
|
assertEquals(null, executingActionsCache.get(key));
|
||||||
|
|
||||||
|
d = actionTrackingService.getExecutionDetails(s);
|
||||||
|
assertEquals(null, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the listing functions work
|
/** Ensure that the listing functions work */
|
||||||
// TODO
|
public void testListings() throws Exception
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Cancel related
|
||||||
|
|
||||||
|
|
||||||
// =================================================================== //
|
// =================================================================== //
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that when we run an action, either
|
||||||
|
* synchronously or asynchronously, with it
|
||||||
|
* working or failing, that the action execution
|
||||||
|
* service correctly sets the flags
|
||||||
|
*/
|
||||||
|
public void testExecutionTrackingOnExecution() throws Exception {
|
||||||
|
final SleepActionExecuter sleepActionExec =
|
||||||
|
(SleepActionExecuter)ctx.getBean(SleepActionExecuter.NAME);
|
||||||
|
sleepActionExec.setSleepMs(10);
|
||||||
|
Action action;
|
||||||
|
NodeRef actionNode;
|
||||||
|
|
||||||
|
// We need real transactions
|
||||||
|
UserTransaction txn = transactionService.getUserTransaction();
|
||||||
|
txn.begin();
|
||||||
|
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// Execute a transient Action that works, synchronously
|
||||||
|
// ===========================================================
|
||||||
|
action = createWorkingSleepAction(null);
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
||||||
|
|
||||||
|
this.actionService.executeAction(action, this.nodeRef);
|
||||||
|
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// Execute a transient Action that fails, synchronously
|
||||||
|
// ===========================================================
|
||||||
|
action = createFailingMoveAction();
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.actionService.executeAction(action, this.nodeRef);
|
||||||
|
fail("Action should have failed, and the error been thrown");
|
||||||
|
} catch(Exception e) {}
|
||||||
|
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNotNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// Tidy up from the action failure
|
||||||
|
txn.rollback();
|
||||||
|
txn = transactionService.getUserTransaction();
|
||||||
|
txn.begin();
|
||||||
|
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// Execute a stored Action that works, synchronously
|
||||||
|
// ===========================================================
|
||||||
|
action = createWorkingSleepAction(null);
|
||||||
|
this.actionService.saveAction(this.nodeRef, action);
|
||||||
|
actionNode = action.getNodeRef();
|
||||||
|
assertNotNull(actionNode);
|
||||||
|
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
||||||
|
|
||||||
|
this.actionService.executeAction(action, this.nodeRef);
|
||||||
|
|
||||||
|
// Check our copy
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// Now re-load and check the stored one
|
||||||
|
action = runtimeActionService.createAction(actionNode);
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// Execute a stored Action that fails, synchronously
|
||||||
|
// ===========================================================
|
||||||
|
action = createFailingMoveAction();
|
||||||
|
this.actionService.saveAction(this.nodeRef, action);
|
||||||
|
actionNode = action.getNodeRef();
|
||||||
|
String actionId = action.getId();
|
||||||
|
assertNotNull(actionNode);
|
||||||
|
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// Save this
|
||||||
|
txn.commit();
|
||||||
|
txn = transactionService.getUserTransaction();
|
||||||
|
txn.begin();
|
||||||
|
|
||||||
|
// Run the action - will fail and trigger a rollback
|
||||||
|
try {
|
||||||
|
this.actionService.executeAction(action, this.nodeRef);
|
||||||
|
fail("Action should have failed, and the error been thrown");
|
||||||
|
} catch(Exception e) {}
|
||||||
|
|
||||||
|
// Check our copy
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNotNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// Wait for the post-rollback update to complete
|
||||||
|
// (The stored one gets updated asynchronously)
|
||||||
|
txn.rollback();
|
||||||
|
Thread.sleep(150);
|
||||||
|
txn = transactionService.getUserTransaction();
|
||||||
|
txn.begin();
|
||||||
|
|
||||||
|
// Now re-load and check the stored one
|
||||||
|
action = runtimeActionService.createAction(actionNode);
|
||||||
|
assertEquals(actionId, action.getId());
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNotNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// Tidy up from the action failure
|
||||||
|
txn.commit();
|
||||||
|
txn = transactionService.getUserTransaction();
|
||||||
|
txn.begin();
|
||||||
|
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// Execute a transient Action that works, asynchronously
|
||||||
|
// ===========================================================
|
||||||
|
action = createWorkingSleepAction(null);
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
||||||
|
|
||||||
|
this.actionService.executeAction(action, this.nodeRef, false, true);
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Pending, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// End the transaction. Should allow the async action
|
||||||
|
// to be executed
|
||||||
|
txn.commit();
|
||||||
|
Thread.sleep(150);
|
||||||
|
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// Put things back ready for the next check
|
||||||
|
txn = transactionService.getUserTransaction();
|
||||||
|
txn.begin();
|
||||||
|
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// Execute a transient Action that fails, asynchronously
|
||||||
|
// ===========================================================
|
||||||
|
action = createFailingMoveAction();
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
||||||
|
|
||||||
|
this.actionService.executeAction(action, this.nodeRef, false, true);
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Pending, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// End the transaction. Should allow the async action
|
||||||
|
// to be executed
|
||||||
|
txn.commit();
|
||||||
|
Thread.sleep(150);
|
||||||
|
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNotNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// Put things back ready for the next check
|
||||||
|
txn = transactionService.getUserTransaction();
|
||||||
|
txn.begin();
|
||||||
|
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// Execute a stored Action that works, asynchronously
|
||||||
|
// ===========================================================
|
||||||
|
action = createWorkingSleepAction(null);
|
||||||
|
this.actionService.saveAction(this.nodeRef, action);
|
||||||
|
actionNode = action.getNodeRef();
|
||||||
|
assertNotNull(actionNode);
|
||||||
|
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
||||||
|
|
||||||
|
this.actionService.executeAction(action, this.nodeRef, false, true);
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Pending, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// End the transaction. Should allow the async action
|
||||||
|
// to be executed
|
||||||
|
txn.commit();
|
||||||
|
Thread.sleep(150);
|
||||||
|
txn = transactionService.getUserTransaction();
|
||||||
|
txn.begin();
|
||||||
|
|
||||||
|
// Check our copy
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// Now re-load and check the stored one
|
||||||
|
action = runtimeActionService.createAction(actionNode);
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Completed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// Execute a stored Action that fails, asynchronously
|
||||||
|
// ===========================================================
|
||||||
|
action = createFailingMoveAction();
|
||||||
|
this.actionService.saveAction(this.nodeRef, action);
|
||||||
|
actionNode = action.getNodeRef();
|
||||||
|
assertNotNull(actionNode);
|
||||||
|
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.New, action.getExecutionStatus());
|
||||||
|
|
||||||
|
this.actionService.executeAction(action, this.nodeRef, false, true);
|
||||||
|
assertNull(action.getExecutionStartDate());
|
||||||
|
assertNull(action.getExecutionEndDate());
|
||||||
|
assertNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Pending, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// End the transaction. Should allow the async action
|
||||||
|
// to be executed
|
||||||
|
// Need to wait longer, as we have two async actions
|
||||||
|
// that need to occur - action + record
|
||||||
|
txn.commit();
|
||||||
|
Thread.sleep(250);
|
||||||
|
txn = transactionService.getUserTransaction();
|
||||||
|
txn.begin();
|
||||||
|
|
||||||
|
// Check our copy
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNotNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
||||||
|
|
||||||
|
// Now re-load and check the stored one
|
||||||
|
action = runtimeActionService.createAction(actionNode);
|
||||||
|
assertNotNull(action.getExecutionStartDate());
|
||||||
|
assertNotNull(action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionStartDate(), action.getExecutionEndDate());
|
||||||
|
assertBefore(action.getExecutionEndDate(), new Date());
|
||||||
|
assertNotNull(action.getExecutionFailureMessage());
|
||||||
|
assertEquals(ActionStatus.Failed, action.getExecutionStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =================================================================== //
|
||||||
|
|
||||||
|
|
||||||
private Action createFailingMoveAction() {
|
private Action createFailingMoveAction() {
|
||||||
Action failingAction = this.actionService.createAction(MoveActionExecuter.NAME);
|
Action failingAction = this.actionService.createAction(MoveActionExecuter.NAME);
|
||||||
@@ -311,79 +666,12 @@ public class ActionTrackingServiceImplTest extends TestCase
|
|||||||
|
|
||||||
return failingAction;
|
return failingAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Action createFailingSleepAction(String id) throws Exception {
|
||||||
|
return ActionServiceImplTest.createFailingSleepAction(id, actionService);
|
||||||
|
}
|
||||||
private Action createWorkingSleepAction(String id) throws Exception {
|
private Action createWorkingSleepAction(String id) throws Exception {
|
||||||
Action workingAction = actionService.createAction(SleepActionExecuter.NAME);
|
return ActionServiceImplTest.createWorkingSleepAction(id, actionService);
|
||||||
Field idF = ParameterizedItemImpl.class.getDeclaredField("id");
|
|
||||||
idF.setAccessible(true);
|
|
||||||
idF.set(workingAction, id);
|
|
||||||
return workingAction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is only used during JUnit testing.
|
|
||||||
*
|
|
||||||
* @author Neil Mc Erlean
|
|
||||||
*/
|
|
||||||
public static class SleepActionFilter extends AbstractAsynchronousActionFilter
|
|
||||||
{
|
|
||||||
public int compare(OngoingAsyncAction sae1, OngoingAsyncAction sae2)
|
|
||||||
{
|
|
||||||
// Sleep actions are always equivalent.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is only intended for use in JUnit tests.
|
|
||||||
*
|
|
||||||
* @author Neil McErlean.
|
|
||||||
*/
|
|
||||||
public static class SleepActionExecuter extends ActionExecuterAbstractBase
|
|
||||||
{
|
|
||||||
public static final String NAME = "sleep-action";
|
|
||||||
private int sleepMs;
|
|
||||||
|
|
||||||
private int timesExecuted = 0;
|
|
||||||
private void incrementTimesExecutedCount() {timesExecuted++;}
|
|
||||||
public int getTimesExecuted() {return timesExecuted;}
|
|
||||||
private Thread executingThread;
|
|
||||||
|
|
||||||
public int getSleepMs()
|
|
||||||
{
|
|
||||||
return sleepMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSleepMs(int sleepMs)
|
|
||||||
{
|
|
||||||
this.sleepMs = sleepMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add parameter definitions
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
|
||||||
{
|
|
||||||
// Intentionally empty
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
|
|
||||||
executingThread = Thread.currentThread();
|
|
||||||
//System.err.println("Sleeping for " + sleepMs + " for " + action);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Thread.sleep(sleepMs);
|
|
||||||
}
|
|
||||||
catch (InterruptedException ignored)
|
|
||||||
{
|
|
||||||
// Intentionally empty
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
incrementTimesExecutedCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user