/* 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.activiti.engine.test.api.event; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertNotEquals; import java.util.ArrayList; import java.util.List; import org.activiti.engine.delegate.event.ActivitiActivityCancelledEvent; import org.activiti.engine.delegate.event.ActivitiCancelledEvent; import org.activiti.engine.delegate.event.ActivitiEntityEvent; import org.activiti.engine.delegate.event.ActivitiEvent; import org.activiti.engine.delegate.event.ActivitiEventListener; import org.activiti.engine.delegate.event.ActivitiEventType; import org.activiti.engine.delegate.event.ActivitiProcessStartedEvent; import org.activiti.engine.delegate.event.impl.ActivitiActivityCancelledEventImpl; import org.activiti.engine.delegate.event.impl.ActivitiProcessCancelledEventImpl; import org.activiti.engine.impl.persistence.entity.ExecutionEntity; import org.activiti.engine.impl.pvm.process.ActivityImpl; import org.activiti.engine.impl.test.PluggableActivitiTestCase; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.activiti.engine.test.Deployment; /** * Test case for all {@link ActivitiEvent}s related to process instances. * * @author Frederik Heremans */ public class ProcessInstanceEventsTest extends PluggableActivitiTestCase { private TestInitializedEntityEventListener listener; /** * Test create, update and delete events of process instances. */ @Deployment(resources= {"org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml"}) public void testProcessInstanceEvents() throws Exception { ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess"); assertNotNull(processInstance); // Check create-event assertEquals(3, listener.getEventsReceived().size()); assertTrue(listener.getEventsReceived().get(0) instanceof ActivitiEntityEvent); ActivitiEntityEvent event = (ActivitiEntityEvent) listener.getEventsReceived().get(0); assertEquals(ActivitiEventType.ENTITY_CREATED, event.getType()); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); assertEquals(processInstance.getId(), event.getProcessInstanceId()); assertEquals(processInstance.getId(), event.getExecutionId()); assertEquals(processInstance.getProcessDefinitionId(), event.getProcessDefinitionId()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(1); assertEquals(ActivitiEventType.ENTITY_INITIALIZED, event.getType()); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); assertEquals(processInstance.getId(), event.getProcessInstanceId()); assertEquals(processInstance.getId(), event.getExecutionId()); assertEquals(processInstance.getProcessDefinitionId(), event.getProcessDefinitionId()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(2); assertEquals(ActivitiEventType.PROCESS_STARTED, event.getType()); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); assertEquals(processInstance.getId(), event.getProcessInstanceId()); assertEquals(processInstance.getId(), event.getExecutionId()); assertEquals(processInstance.getProcessDefinitionId(), event.getProcessDefinitionId()); assertTrue(event instanceof ActivitiProcessStartedEvent); assertNull(((ActivitiProcessStartedEvent)event).getNestedProcessDefinitionId()); assertNull(((ActivitiProcessStartedEvent)event).getNestedProcessInstanceId()); listener.clearEventsReceived(); // Check update event when suspended/activated runtimeService.suspendProcessInstanceById(processInstance.getId()); runtimeService.activateProcessInstanceById(processInstance.getId()); assertEquals(2, listener.getEventsReceived().size()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(0); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); assertEquals(ActivitiEventType.ENTITY_SUSPENDED, event.getType()); assertEquals(processInstance.getId(), event.getProcessInstanceId()); assertEquals(processInstance.getId(), event.getExecutionId()); assertEquals(processInstance.getProcessDefinitionId(), event.getProcessDefinitionId()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(1); assertEquals(ActivitiEventType.ENTITY_ACTIVATED, event.getType()); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); assertEquals(processInstance.getId(), event.getProcessInstanceId()); assertEquals(processInstance.getId(), event.getExecutionId()); assertEquals(processInstance.getProcessDefinitionId(), event.getProcessDefinitionId()); listener.clearEventsReceived(); // Check update event when process-definition is supended (should cascade suspend/activate all process instances) repositoryService.suspendProcessDefinitionById(processInstance.getProcessDefinitionId(), true, null); repositoryService.activateProcessDefinitionById(processInstance.getProcessDefinitionId(), true, null); assertEquals(2, listener.getEventsReceived().size()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(0); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); assertEquals(ActivitiEventType.ENTITY_SUSPENDED, event.getType()); assertEquals(processInstance.getId(), event.getProcessInstanceId()); assertEquals(processInstance.getId(), event.getExecutionId()); assertEquals(processInstance.getProcessDefinitionId(), event.getProcessDefinitionId()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(1); assertEquals(ActivitiEventType.ENTITY_ACTIVATED, event.getType()); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); assertEquals(processInstance.getId(), event.getProcessInstanceId()); assertEquals(processInstance.getId(), event.getExecutionId()); assertEquals(processInstance.getProcessDefinitionId(), event.getProcessDefinitionId()); listener.clearEventsReceived(); // Check update-event when business-key is updated runtimeService.updateBusinessKey(processInstance.getId(), "thekey"); assertEquals(1, listener.getEventsReceived().size()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(0); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); assertEquals(ActivitiEventType.ENTITY_UPDATED, event.getType()); assertEquals(processInstance.getId(), event.getProcessInstanceId()); assertEquals(processInstance.getId(), event.getExecutionId()); assertEquals(processInstance.getProcessDefinitionId(), event.getProcessDefinitionId()); listener.clearEventsReceived(); runtimeService.deleteProcessInstance(processInstance.getId(), "Testing events"); List<ActivitiEvent> processCancelledEvents = listener.filterEvents(ActivitiEventType.PROCESS_CANCELLED); assertEquals(1, processCancelledEvents.size()); ActivitiCancelledEvent cancelledEvent = (ActivitiCancelledEvent) processCancelledEvents.get(0); assertEquals(ActivitiEventType.PROCESS_CANCELLED, cancelledEvent.getType()); assertEquals(processInstance.getId(), cancelledEvent.getProcessInstanceId()); assertEquals(processInstance.getId(), cancelledEvent.getExecutionId()); listener.clearEventsReceived(); } /** * Test create, update and delete events of process instances. */ @Deployment(resources = {"org/activiti/engine/test/api/runtime/nestedSubProcess.bpmn20.xml", "org/activiti/engine/test/api/runtime/subProcess.bpmn20.xml"}) public void testSubProcessInstanceEvents() throws Exception { ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("nestedSimpleSubProcess"); assertNotNull(processInstance); // Check create-event one main process the second one Scope execution, and the third one subprocess assertEquals(8, listener.getEventsReceived().size()); assertTrue(listener.getEventsReceived().get(0) instanceof ActivitiEntityEvent); ActivitiEntityEvent event = (ActivitiEntityEvent) listener.getEventsReceived().get(0); assertEquals(ActivitiEventType.ENTITY_CREATED, event.getType()); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); assertEquals(processInstance.getId(), event.getProcessInstanceId()); assertEquals(processInstance.getId(), event.getExecutionId()); assertEquals(processInstance.getProcessDefinitionId(), event.getProcessDefinitionId()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(1); assertEquals(ActivitiEventType.ENTITY_INITIALIZED, event.getType()); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(2); assertEquals(ActivitiEventType.PROCESS_STARTED, event.getType()); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getId()); assertEquals(processInstance.getId(), event.getProcessInstanceId()); assertEquals(processInstance.getId(), event.getExecutionId()); assertEquals(processInstance.getProcessDefinitionId(), event.getProcessDefinitionId()); assertTrue(event instanceof ActivitiProcessStartedEvent); assertNull(((ActivitiProcessStartedEvent)event).getNestedProcessDefinitionId()); assertNull(((ActivitiProcessStartedEvent)event).getNestedProcessInstanceId()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(3); assertEquals(ActivitiEventType.ENTITY_CREATED, event.getType()); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getParentId()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(4); assertEquals(ActivitiEventType.ENTITY_INITIALIZED, event.getType()); assertEquals(processInstance.getId(), ((ProcessInstance) event.getEntity()).getParentId()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(5); assertEquals(ActivitiEventType.ENTITY_CREATED, event.getType()); assertEquals("simpleSubProcess", ((ExecutionEntity) event.getEntity()).getProcessDefinition().getKey()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(6); assertEquals(ActivitiEventType.ENTITY_INITIALIZED, event.getType()); assertEquals("simpleSubProcess", ((ExecutionEntity) event.getEntity()).getProcessDefinition().getKey()); event = (ActivitiEntityEvent) listener.getEventsReceived().get(7); assertEquals(ActivitiEventType.PROCESS_STARTED, event.getType()); assertEquals("simpleSubProcess", ((ExecutionEntity) event.getEntity()).getProcessDefinition().getKey()); assertTrue(event instanceof ActivitiProcessStartedEvent); assertEquals(processInstance.getProcessDefinitionId(), ((ActivitiProcessStartedEvent)event).getNestedProcessDefinitionId()); assertEquals(processInstance.getId(), ((ActivitiProcessStartedEvent)event).getNestedProcessInstanceId()); listener.clearEventsReceived(); } /** * Test process with signals start. */ @Deployment(resources = {"org/activiti/engine/test/bpmn/event/signal/SignalEventTest.testSignalWithGlobalScope.bpmn20.xml"}) public void testSignalProcessInstanceStart() throws Exception { this.runtimeService.startProcessInstanceByKey("processWithSignalCatch"); listener.clearEventsReceived(); runtimeService.startProcessInstanceByKey("processWithSignalThrow"); listener.clearEventsReceived(); } /** * Test Start->End process on PROCESS_COMPLETED event */ @Deployment(resources = {"org/activiti/engine/test/api/event/ProcessInstanceEventsTest.noneTaskProcess.bpmn20.xml"}) public void testProcessCompleted_StartEnd() throws Exception { this.runtimeService.startProcessInstanceByKey("noneTaskProcess"); assertEquals("ActivitiEventType.PROCESS_COMPLETED was expected 1 time.", 1, listener.filterEvents(ActivitiEventType.PROCESS_COMPLETED).size()); } /** * Test Start->User Task process on PROCESS_COMPLETED event */ @Deployment(resources = {"org/activiti/engine/test/api/event/ProcessInstanceEventsTest.noEndProcess.bpmn20.xml"}) public void testProcessCompleted_NoEnd() throws Exception { ProcessInstance noEndProcess = this.runtimeService.startProcessInstanceByKey("noEndProcess"); Task task = taskService.createTaskQuery().processInstanceId(noEndProcess.getId()).singleResult(); taskService.complete(task.getId()); assertEquals("ActivitiEventType.PROCESS_COMPLETED was expected 1 time.", 1, listener.filterEvents(ActivitiEventType.PROCESS_COMPLETED).size()); } /** * Test * +-->Task1 * Start-<> * +-->Task1 * * process on PROCESS_COMPLETED event */ @Deployment(resources = {"org/activiti/engine/test/api/event/ProcessInstanceEventsTest.parallelGatewayNoEndProcess.bpmn20.xml"}) public void testProcessCompleted_ParallelGatewayNoEnd() throws Exception { this.runtimeService.startProcessInstanceByKey("noEndProcess"); assertEquals("ActivitiEventType.PROCESS_COMPLETED was expected 1 time.", 1, listener.filterEvents(ActivitiEventType.PROCESS_COMPLETED).size()); } /** * Test * +-->End1 * Start-<> * +-->End2 * <p/> * process on PROCESS_COMPLETED event */ @Deployment(resources = {"org/activiti/engine/test/api/event/ProcessInstanceEventsTest.parallelGatewayTwoEndsProcess.bpmn20.xml"}) public void testProcessCompleted_ParallelGatewayTwoEnds() throws Exception { this.runtimeService.startProcessInstanceByKey("noEndProcess"); assertEquals("ActivitiEventType.PROCESS_COMPLETED was expected 1 time.", 1, listener.filterEvents(ActivitiEventType.PROCESS_COMPLETED).size()); } @Deployment(resources = {"org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml"}) public void testProcessInstanceCancelledEvents_cancell() throws Exception { ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess"); assertNotNull(processInstance); listener.clearEventsReceived(); runtimeService.deleteProcessInstance(processInstance.getId(), "delete_test"); List<ActivitiEvent> processCancelledEvents = listener.filterEvents(ActivitiEventType.PROCESS_CANCELLED); assertEquals("ActivitiEventType.PROCESS_CANCELLED was expected 1 time.", 1, processCancelledEvents.size()); ActivitiCancelledEvent processCancelledEvent = (ActivitiCancelledEvent) processCancelledEvents.get(0); assertTrue("The cause has to be the same as deleteProcessInstance method call", ActivitiCancelledEvent.class.isAssignableFrom(processCancelledEvent.getClass())); assertEquals("The process instance has to be the same as in deleteProcessInstance method call", processInstance.getId(), processCancelledEvent.getProcessInstanceId()); assertEquals("The execution instance has to be the same as in deleteProcessInstance method call", processInstance.getId(), processCancelledEvent.getExecutionId()); assertEquals("The cause has to be the same as in deleteProcessInstance method call", "delete_test", processCancelledEvent.getCause()); List<ActivitiEvent> taskCancelledEvents = listener.filterEvents(ActivitiEventType.ACTIVITY_CANCELLED); assertEquals("ActivitiEventType.ACTIVITY_CANCELLED was expected 1 time.", 1, taskCancelledEvents.size()); ActivitiActivityCancelledEvent activityCancelledEvent = (ActivitiActivityCancelledEvent) taskCancelledEvents.get(0); assertTrue("The cause has to be the same as deleteProcessInstance method call", ActivitiActivityCancelledEvent.class.isAssignableFrom(activityCancelledEvent.getClass())); assertEquals("The activity id has to be the same as processInstance activity", processInstance.getActivityId(), activityCancelledEvent.getActivityId()); assertEquals("The process instance has to be the same as in deleteProcessInstance method call", processInstance.getId(), activityCancelledEvent.getProcessInstanceId()); assertEquals("The execution instance has to be the same as in deleteProcessInstance method call", processInstance.getId(), activityCancelledEvent.getExecutionId()); assertEquals("The cause has to be the same as in deleteProcessInstance method call", "delete_test", activityCancelledEvent.getCause()); listener.clearEventsReceived(); } @Deployment(resources = {"org/activiti/engine/test/api/runtime/nestedSubProcess.bpmn20.xml", "org/activiti/engine/test/api/runtime/subProcess.bpmn20.xml"}) public void testProcessInstanceCancelledEvents_cancelProcessHierarchy() throws Exception { ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("nestedSimpleSubProcess"); ProcessInstance subProcess = runtimeService.createProcessInstanceQuery().superProcessInstanceId(processInstance.getId()).singleResult(); assertNotNull(processInstance); listener.clearEventsReceived(); runtimeService.deleteProcessInstance(processInstance.getId(), "delete_test"); List<ActivitiEvent> processCancelledEvents = listener.filterEvents(ActivitiEventType.PROCESS_CANCELLED); assertEquals("ActivitiEventType.PROCESS_CANCELLED was expected 2 times.", 2, processCancelledEvents.size()); ActivitiCancelledEvent processCancelledEvent = (ActivitiCancelledEvent) processCancelledEvents.get(0); assertTrue("The cause has to be the same as deleteProcessInstance method call", ActivitiCancelledEvent.class.isAssignableFrom(processCancelledEvent.getClass())); assertEquals("The process instance has to be the same as in deleteProcessInstance method call", subProcess.getId(), processCancelledEvent.getProcessInstanceId()); assertEquals("The execution instance has to be the same as in deleteProcessInstance method call", subProcess.getId(), processCancelledEvent.getExecutionId()); assertEquals("The cause has to be the same as in deleteProcessInstance method call", "delete_test", processCancelledEvent.getCause()); processCancelledEvent = (ActivitiCancelledEvent) processCancelledEvents.get(1); assertTrue("The cause has to be the same as deleteProcessInstance method call", ActivitiCancelledEvent.class.isAssignableFrom(processCancelledEvent.getClass())); assertEquals("The process instance has to be the same as in deleteProcessInstance method call", processInstance.getId(), processCancelledEvent.getProcessInstanceId()); assertEquals("The execution instance has to be the same as in deleteProcessInstance method call", processInstance.getId(), processCancelledEvent.getExecutionId()); assertEquals("The cause has to be the same as in deleteProcessInstance method call", "delete_test", processCancelledEvent.getCause()); assertEquals("No task can be active for deleted process.", 0, this.taskService.createTaskQuery().processInstanceId(processInstance.getId()).count()); List<ActivitiEvent> taskCancelledEvents = listener.filterEvents(ActivitiEventType.ACTIVITY_CANCELLED); assertEquals("ActivitiEventType.ACTIVITY_CANCELLED was expected 1 time.", 1, taskCancelledEvents.size()); ActivitiActivityCancelledEvent activityCancelledEvent = (ActivitiActivityCancelledEvent) taskCancelledEvents.get(0); assertTrue("The cause has to be the same as deleteProcessInstance method call", ActivitiActivityCancelledEvent.class.isAssignableFrom(activityCancelledEvent.getClass())); assertEquals("The activity id has to point to the subprocess activity", subProcess.getActivityId(), activityCancelledEvent.getActivityId()); assertEquals("The process instance has to point to the subprocess", subProcess.getId(), activityCancelledEvent.getProcessInstanceId()); assertEquals("The execution instance has to point to the subprocess", subProcess.getId(), activityCancelledEvent.getExecutionId()); assertEquals("The cause has to be the same as in deleteProcessInstance method call", "delete_test", activityCancelledEvent.getCause()); listener.clearEventsReceived(); } @Deployment(resources = {"org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml"}) public void testProcessInstanceCancelledEvents_complete() throws Exception { ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess"); assertNotNull(processInstance); Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); taskService.complete(task.getId()); List<ActivitiEvent> processCancelledEvents = listener.filterEvents(ActivitiEventType.PROCESS_CANCELLED); assertEquals("There should be no ActivitiEventType.PROCESS_CANCELLED event after process complete.", 0, processCancelledEvents.size()); List<ActivitiEvent> taskCancelledEvents = listener.filterEvents(ActivitiEventType.ACTIVITY_CANCELLED); assertEquals("There should be no ActivitiEventType.ACTIVITY_CANCELLED event.", 0, taskCancelledEvents.size()); } @Deployment(resources = {"org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml"}) public void testProcessInstanceTerminatedEvents_complete() throws Exception { ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess"); assertNotNull(processInstance); Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); taskService.complete(task.getId()); List<ActivitiEvent> processTerminatedEvents = listener.filterEvents(ActivitiEventType.PROCESS_CANCELLED); assertEquals("There should be no ActivitiEventType.PROCESS_TERMINATED event after process complete.", 0, processTerminatedEvents.size()); } @Deployment(resources="org/activiti/engine/test/bpmn/event/end/TerminateEndEventTest.testProcessTerminate.bpmn") public void testProcessInstanceTerminatedEvents() throws Exception { ProcessInstance pi = runtimeService.startProcessInstanceByKey("terminateEndEventExample"); long executionEntities = runtimeService.createExecutionQuery().processInstanceId(pi.getId()).count(); assertEquals(3, executionEntities); Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).taskDefinitionKey("preTerminateTask").singleResult(); taskService.complete(task.getId()); List<ActivitiEvent> processTerminatedEvents = listener.filterEvents(ActivitiEventType.PROCESS_CANCELLED); assertEquals("There should be exactly one ActivitiEventType.PROCESS_CANCELLED event after the task complete.", 1, processTerminatedEvents.size()); ActivitiProcessCancelledEventImpl activitiEvent = (ActivitiProcessCancelledEventImpl) processTerminatedEvents.get(0); assertThat(activitiEvent.getProcessInstanceId(), is(pi.getProcessInstanceId())); assertThat(((ActivityImpl) activitiEvent.getCause()).getId(), is("EndEvent_2")); List<ActivitiEvent> activityTerminatedEvents = listener.filterEvents(ActivitiEventType.ACTIVITY_CANCELLED); assertThat("There should be exactly two ActivitiEventType.ACTIVITY_CANCELLED event after the task complete.", activityTerminatedEvents.size(), is(2)); ActivitiActivityCancelledEventImpl activityEvent = (ActivitiActivityCancelledEventImpl) activityTerminatedEvents.get(0); assertThat("The user task must be terminated", activityEvent.getActivityId(), is("preNormalTerminateTask")); assertThat("The cause must be terminate end event", ((ActivityImpl) activityEvent.getCause()).getId(), is("EndEvent_2")); activityEvent = (ActivitiActivityCancelledEventImpl) activityTerminatedEvents.get(1); assertThat("The gateway must be terminated", activityEvent.getActivityId(), is("ParallelGateway_1")); assertThat("The cause must be terminate end event", ((ActivityImpl) activityEvent.getCause()).getId(), is("EndEvent_2")); } @Deployment(resources = { "org/activiti/engine/test/bpmn/event/end/TerminateEndEventTest.testTerminateInCallActivity.bpmn", "org/activiti/engine/test/bpmn/event/end/TerminateEndEventTest.subProcessTerminate.bpmn" }) public void testProcessInstanceTerminatedEvents_callActivity() throws Exception { ProcessInstance pi = runtimeService.startProcessInstanceByKey("terminateEndEventExample"); // should terminate the called process and continue the parent long executionEntities = runtimeService.createExecutionQuery().count(); assertEquals(1, executionEntities); Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).taskDefinitionKey("preNormalEnd").singleResult(); taskService.complete(task.getId()); assertProcessEnded(pi.getId()); List<ActivitiEvent> processTerminatedEvents = listener.filterEvents(ActivitiEventType.PROCESS_CANCELLED); assertEquals("There should be exactly one ActivitiEventType.PROCESS_TERMINATED event after the task complete.", 1, processTerminatedEvents.size()); ActivitiProcessCancelledEventImpl processCancelledEvent = (ActivitiProcessCancelledEventImpl) processTerminatedEvents.get(0); assertNotEquals(pi.getProcessInstanceId(), processCancelledEvent.getProcessInstanceId()); assertThat(processCancelledEvent.getProcessDefinitionId(), containsString("terminateEndEventSubprocessExample")); List<ActivitiEvent> activityTerminatedEvents = listener.filterEvents(ActivitiEventType.ACTIVITY_CANCELLED); assertThat("There is no ActivitiEventType.ACTIVITY_CANCELLED event after the task complete.", activityTerminatedEvents.isEmpty(), is(true)); } @Deployment(resources = { "org/activiti/engine/test/bpmn/event/end/TerminateEndEventTest.testTerminateInParentProcess.bpmn", "org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml" }) public void testProcessInstanceTerminatedEvents_terminateInParentProcess() throws Exception { ProcessInstance pi = runtimeService.startProcessInstanceByKey("terminateParentProcess"); // should terminate the called process and continue the parent Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).taskDefinitionKey("preTerminateEnd").singleResult(); taskService.complete(task.getId()); assertProcessEnded(pi.getId()); List<ActivitiEvent> processTerminatedEvents = listener.filterEvents(ActivitiEventType.PROCESS_CANCELLED); assertEquals("There should be exactly one ActivitiEventType.PROCESS_TERMINATED event after the task complete.", 1, processTerminatedEvents.size()); ActivitiProcessCancelledEventImpl processCancelledEvent = (ActivitiProcessCancelledEventImpl) processTerminatedEvents.get(0); assertThat(processCancelledEvent.getProcessInstanceId(), is(pi.getProcessInstanceId())); assertThat(processCancelledEvent.getProcessDefinitionId(), containsString("terminateParentProcess")); List<ActivitiEvent> activityTerminatedEvents = listener.filterEvents(ActivitiEventType.ACTIVITY_CANCELLED); assertThat("3 activities must be cancelled.", activityTerminatedEvents.size(), is(3)); ActivitiActivityCancelledEventImpl activityEvent = (ActivitiActivityCancelledEventImpl) activityTerminatedEvents.get(0); assertThat("The user task must be terminated in the called sub process.", activityEvent.getActivityId(), is("theTask")); assertThat("The cause must be terminate end event", ((ActivityImpl) activityEvent.getCause()).getId(), is("EndEvent_3")); activityEvent = (ActivitiActivityCancelledEventImpl) activityTerminatedEvents.get(1); assertThat("The call activity must be terminated", activityEvent.getActivityId(), is("CallActivity_1")); assertThat("The cause must be terminate end event", ((ActivityImpl) activityEvent.getCause()).getId(), is("EndEvent_3")); activityEvent = (ActivitiActivityCancelledEventImpl) activityTerminatedEvents.get(2); assertThat("The gateway must be terminated", activityEvent.getActivityId(), is("ParallelGateway_1")); assertThat("The cause must be terminate end event", ((ActivityImpl) activityEvent.getCause()).getId(), is("EndEvent_3")); } @Deployment(resources = { "org/activiti/engine/test/bpmn/event/error/BoundaryErrorEventTest.testCatchErrorOnCallActivity-parent.bpmn20.xml", "org/activiti/engine/test/bpmn/event/error/BoundaryErrorEventTest.subprocess.bpmn20.xml" }) public void testProcessCompletedEvents_callActivityErrorEndEvent() throws Exception { ProcessInstance pi = runtimeService.startProcessInstanceByKey("catchErrorOnCallActivity"); Task task = taskService.createTaskQuery().singleResult(); assertEquals("Task in subprocess", task.getName()); List<ProcessInstance> subProcesses = runtimeService.createProcessInstanceQuery().superProcessInstanceId(pi.getId()).list(); assertEquals(1, subProcesses.size()); // Completing the task will reach the end error event, // which is caught on the call activity boundary taskService.complete(task.getId()); List<ActivitiEvent> processCompletedEvents = listener.filterEvents(ActivitiEventType.PROCESS_COMPLETED_WITH_ERROR_END_EVENT); assertEquals("There should be exactly one ActivitiEventType.PROCESS_COMPLETED_WITH_ERROR_END_EVENT event after the task complete.", 1, processCompletedEvents.size()); ActivitiEntityEvent processCompletedEvent = (ActivitiEntityEvent) processCompletedEvents.get(0); assertEquals(subProcesses.get(0).getId(), processCompletedEvent.getExecutionId()); task = taskService.createTaskQuery().singleResult(); assertEquals("Escalated Task", task.getName()); // Completing the task will end the process instance taskService.complete(task.getId()); assertProcessEnded(pi.getId()); } @Deployment(resources = { "org/activiti/engine/test/bpmn/multiinstance/MultiInstanceTest.testParallelCallActivity.bpmn20.xml", "org/activiti/engine/test/bpmn/multiinstance/MultiInstanceTest.externalSubProcess.bpmn20.xml"}) public void testDeleteMultiInstanceCallActivityProcessInstance() { assertEquals(0, taskService.createTaskQuery().count()); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("miParallelCallActivity"); assertEquals(7, runtimeService.createProcessInstanceQuery().count()); assertEquals(12, taskService.createTaskQuery().count()); this.listener.clearEventsReceived(); runtimeService.deleteProcessInstance(processInstance.getId(), "testing instance deletion"); assertThat("Task cancelled event has to be fired.", this.listener.getEventsReceived().get(0).getType(), is(ActivitiEventType.ACTIVITY_CANCELLED)); assertThat("SubProcess cancelled event has to be fired.", this.listener.getEventsReceived().get(2).getType(), is(ActivitiEventType.PROCESS_CANCELLED)); assertEquals(0, runtimeService.createProcessInstanceQuery().count()); assertEquals(0, taskService.createTaskQuery().count()); } @Override protected void initializeServices() { super.initializeServices(); this.listener = new TestInitializedEntityEventListener(); processEngineConfiguration.getEventDispatcher().addEventListener(this.listener); } @Override protected void tearDown() throws Exception { super.tearDown(); if(listener != null) { listener.clearEventsReceived(); processEngineConfiguration.getEventDispatcher().removeEventListener(listener); } } private class TestInitializedEntityEventListener implements ActivitiEventListener { private List<ActivitiEvent> eventsReceived; public TestInitializedEntityEventListener() { eventsReceived = new ArrayList<ActivitiEvent>(); } public List<ActivitiEvent> getEventsReceived() { return eventsReceived; } public void clearEventsReceived() { eventsReceived.clear(); } @Override public void onEvent(ActivitiEvent event) { if (event instanceof ActivitiEntityEvent && ProcessInstance.class.isAssignableFrom(((ActivitiEntityEvent) event).getEntity().getClass())) { // check whether entity in the event is initialized before adding to the list. assertNotNull(((ExecutionEntity) ((ActivitiEntityEvent) event).getEntity()).getId()); eventsReceived.add(event); } else if (ActivitiEventType.PROCESS_CANCELLED.equals(event.getType()) || ActivitiEventType.ACTIVITY_CANCELLED.equals(event.getType())) { eventsReceived.add(event); } } @Override public boolean isFailOnException() { return true; } public List<ActivitiEvent> filterEvents(ActivitiEventType eventType) {// count timer cancelled events List<ActivitiEvent> filteredEvents = new ArrayList<ActivitiEvent>(); List<ActivitiEvent> eventsReceived = listener.getEventsReceived(); for (ActivitiEvent eventReceived : eventsReceived) { if (eventType.equals(eventReceived.getType())) { filteredEvents.add(eventReceived); } } return filteredEvents; } } }