/* * Copyright 2015 herd contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.finra.herd.service.activiti; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import org.activiti.bpmn.model.BpmnModel; import org.activiti.bpmn.model.EndEvent; import org.activiti.bpmn.model.Process; import org.activiti.bpmn.model.ScriptTask; import org.activiti.bpmn.model.SequenceFlow; import org.activiti.bpmn.model.StartEvent; import org.activiti.engine.history.HistoricVariableInstance; import org.activiti.engine.runtime.ProcessInstance; import org.junit.Test; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.finra.herd.service.activiti.task.HerdActivitiServiceTaskTest; public class HerdCommandInvokerTest extends HerdActivitiServiceTaskTest { /** * Tests the error handling behavior for asynchronous tasks. * This test proves 2 behaviors: when a asynchronous task is executed, and an error occurs, any variables written by the tasks are persisted, and the error * message and stack trace is recorded in the JobEntity which belongs to the execution. * Writing the exception in JobEntity ensures that we are able to retrieve the exception message in our GetJob API. * * This test must run outside of a transaction since the workflow will be executing asynchronously. * * @throws Exception */ @Test @Transactional(propagation = Propagation.NOT_SUPPORTED) public void testAssertAsynchronousTaskErrorWrittenToJobEntity() throws Exception { // Create a workflow BpmnModel bpmnModel = new BpmnModel(); Process process = new Process(); process.setId("test"); { StartEvent element = new StartEvent(); element.setId("start"); process.addFlowElement(element); } { ScriptTask element = new ScriptTask(); element.setId("script1"); element.setScriptFormat("js"); element.setAsynchronous(true); element.setScript("execution.setVariable('foo', 'bar');"); process.addFlowElement(element); } { ScriptTask element = new ScriptTask(); element.setId("script2"); element.setScriptFormat("js"); element.setScript("throw new Error()"); process.addFlowElement(element); } { EndEvent element = new EndEvent(); element.setId("end"); process.addFlowElement(element); } process.addFlowElement(new SequenceFlow("start", "script1")); process.addFlowElement(new SequenceFlow("script1", "script2")); process.addFlowElement(new SequenceFlow("script2", "end")); bpmnModel.addProcess(process); // Deploy the workflow activitiRepositoryService.createDeployment().addBpmnModel("bpmn20.xml", bpmnModel).deploy(); // Start the process instance ProcessInstance processInstance = activitiRuntimeService.startProcessInstanceByKey("test"); try { /* * Wait for process instance to run. * Note that we cannot use the convenience method waitUntilAllProcessCompleted() since the workflow will be in an error state and therefore stay * active. */ long startTime = System.currentTimeMillis(); HistoricVariableInstance persistedVariable = null; while (persistedVariable == null) { persistedVariable = activitiHistoryService.createHistoricVariableInstanceQuery().variableName("foo").singleResult(); Thread.sleep(10); if (System.currentTimeMillis() - startTime > 10000) { fail("workflow did not reach the desired state within a reasonable time"); } } // Make assertions // Assert variable is persisted assertEquals("bar", persistedVariable.getValue()); // Assert exception message is logged assertEquals("ActivitiException: problem evaluating script: Error in <eval> at line number 1 at column number 0", activitiManagementService .createJobQuery().executionId(processInstance.getProcessInstanceId()).singleResult().getExceptionMessage()); } finally { deleteActivitiDeployments(); } } }