/* 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.bpmn.deployment; import java.util.List; import org.activiti.engine.impl.EventSubscriptionQueryImpl; import org.activiti.engine.impl.history.HistoryLevel; import org.activiti.engine.impl.interceptor.Command; import org.activiti.engine.impl.interceptor.CommandContext; import org.activiti.engine.impl.persistence.entity.EventSubscriptionEntity; 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; /** * A test specifically written to test how events (start/boundary) are handled * when deploying a new version of a process definition. * * @author Joram Barrez */ public class SignalEventsAndNewVersionDeploymentsTest extends PluggableActivitiTestCase { private static final String TEST_PROCESS_GLOBAL_BOUNDARY_SIGNAL = "org/activiti/engine/test/bpmn/deployment/SignalEventsAndNewVersionDeploymentsTest.testGlobalSignalBoundaryEvent.bpmn20.xml"; private static final String TEST_PROCESS_START_SIGNAL = "org/activiti/engine/test/bpmn/deployment/SignalEventsAndNewVersionDeploymentsTest.testStartSignalEvent.bpmn20.xml"; private static final String TEST_PROCESS_NO_EVENTS = "org/activiti/engine/test/bpmn/deployment/SignalEventsAndNewVersionDeploymentsTest.processWithoutEvents.bpmn20.xml"; private static final String TEST_PROCESS_BOTH_START_AND_BOUNDARY_SIGNAL = "org/activiti/engine/test/bpmn/deployment/SignalEventsAndNewVersionDeploymentsTest.testBothBoundaryAndStartSignal.bpmn20.xml"; private static final String TEST_PROCESS_BOTH_START_AND_BOUNDARY_SIGNAL_SAME_SIGNAL = "org/activiti/engine/test/bpmn/deployment/SignalEventsAndNewVersionDeploymentsTest.testBothBoundaryAndStartSignalSameSignal.bpmn20.xml"; /* * BOUNDARY SIGNAL EVENT */ @Deployment public void testGlobalSignalBoundaryEvent() { runtimeService.startProcessInstanceByKey("signalTest"); // Deploy new version of the same process. Original process should still be reachable via signal String deploymentId = deployBoundarySignalTestProcess(); runtimeService.startProcessInstanceByKey("signalTest"); assertEquals(2, getAllEventSubscriptions().size()); runtimeService.signalEventReceived("mySignal"); assertEquals(0, getAllEventSubscriptions().size()); List<Task> tasks = taskService.createTaskQuery().list(); assertEquals(2, tasks.size()); for (Task task : tasks) { assertEquals("Task after signal", task.getName()); } cleanup(deploymentId); } /** * Verifying that the event subscriptions do get removed when removing a deployment. */ public void testBoundaryEventSubscriptionDeletedOnDeploymentDelete() { String deploymentId = deployBoundarySignalTestProcess(); runtimeService.startProcessInstanceByKey("signalTest"); assertEquals("My Task", taskService.createTaskQuery().singleResult().getName()); String deploymentId2 = deployBoundarySignalTestProcess(); runtimeService.startProcessInstanceByKey("signalTest"); assertEquals(2, taskService.createTaskQuery().count()); assertEquals(2, getAllEventSubscriptions().size()); repositoryService.deleteDeployment(deploymentId, true); assertEquals("My Task", taskService.createTaskQuery().singleResult().getName()); assertEquals(1, getAllEventSubscriptions().size()); repositoryService.deleteDeployment(deploymentId2, true); assertEquals(0, getAllEventSubscriptions().size()); } /** * Verifying that the event subscriptions do get removed when removing a process instance. */ public void testBoundaryEventSubscrptionsDeletedOnProcessInstanceDelete() { String deploymentId1 = deployBoundarySignalTestProcess(); runtimeService.startProcessInstanceByKey("signalTest"); assertEquals("My Task", taskService.createTaskQuery().singleResult().getName()); String deploymentId2 = deployBoundarySignalTestProcess(); ProcessInstance processInstance2 = runtimeService.startProcessInstanceByKey("signalTest"); assertEquals(2, taskService.createTaskQuery().count()); assertEquals(2, getAllEventSubscriptions().size()); // Deleting PI of second deployment runtimeService.deleteProcessInstance(processInstance2.getId(), "testing"); assertEquals("My Task", taskService.createTaskQuery().singleResult().getName()); assertEquals(1, getAllEventSubscriptions().size()); runtimeService.signalEventReceived("mySignal"); assertEquals(0, getAllEventSubscriptions().size()); assertEquals("Task after signal", taskService.createTaskQuery().singleResult().getName()); cleanup(deploymentId1, deploymentId2); } /* * START SIGNAL EVENT */ public void testStartSignalEvent() { String deploymentId1 = deployStartSignalTestProcess(); assertEquals(1, getAllEventSubscriptions().size()); assertEquals(0, runtimeService.createProcessInstanceQuery().count()); runtimeService.signalEventReceived("myStartSignal"); assertEquals(1, runtimeService.createProcessInstanceQuery().count()); String deploymentId2 = deployStartSignalTestProcess(); runtimeService.signalEventReceived("myStartSignal"); assertEquals(2, runtimeService.createProcessInstanceQuery().count()); assertEquals(1, getAllEventSubscriptions().size()); cleanup(deploymentId1, deploymentId2); } public void testSignalStartEventSubscriptionAfterDeploymentDelete() { // Deploy two version of process definition, delete latest and check if all is good String deploymentId1 = deployStartSignalTestProcess(); List<EventSubscriptionEntity> eventSubscriptions = getAllEventSubscriptions(); assertEquals(1, eventSubscriptions.size()); String deploymentId2 = deployStartSignalTestProcess(); eventSubscriptions = getAllEventSubscriptions(); assertEquals(1, eventSubscriptions.size()); repositoryService.deleteDeployment(deploymentId2, true); eventSubscriptions = getAllEventSubscriptions(); assertEquals(1, eventSubscriptions.size()); cleanup(deploymentId1); assertEquals(0, getAllEventSubscriptions().size()); // Deploy two versions of process definition, delete the first deploymentId1 = deployStartSignalTestProcess(); deploymentId2 = deployStartSignalTestProcess(); assertEquals(1, getAllEventSubscriptions().size()); repositoryService.deleteDeployment(deploymentId1, true); eventSubscriptions = getAllEventSubscriptions(); assertEquals(1, eventSubscriptions.size()); assertEquals(repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId2).singleResult().getId(), eventSubscriptions.get(0).getProcessDefinitionId()); cleanup(deploymentId2); assertEquals(0, getAllEventSubscriptions().size()); } /** * v1 -> has start signal event * v2 -> has no start signal event * v3 -> has start signal event */ public void testDeployIntermediateVersionWithoutSignalStartEvent() { String deploymentId1 = deployStartSignalTestProcess(); assertEquals(1, getAllEventSubscriptions().size()); assertEquals(0, runtimeService.createProcessInstanceQuery().count()); runtimeService.signalEventReceived("myStartSignal"); assertEquals(1, runtimeService.createProcessInstanceQuery().count()); assertEventSubscriptionsCount(1); String deploymentId2 = deployProcessWithoutEvents(); assertEquals(0, getAllEventSubscriptions().size()); assertEquals(1, runtimeService.createProcessInstanceQuery().count()); runtimeService.signalEventReceived("myStartSignal"); assertEquals(1, runtimeService.createProcessInstanceQuery().count()); assertEventSubscriptionsCount(0); String deploymentId3 = deployStartSignalTestProcess(); assertEquals(1, getAllEventSubscriptions().size()); assertEquals(1, runtimeService.createProcessInstanceQuery().count()); runtimeService.signalEventReceived("myStartSignal"); assertEquals(2, runtimeService.createProcessInstanceQuery().count()); assertEventSubscriptionsCount(1); List<EventSubscriptionEntity> eventSubscriptions = getAllEventSubscriptions(); assertEquals(repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId3).singleResult().getId(), eventSubscriptions.get(0).getProcessDefinitionId()); cleanup(deploymentId1, deploymentId2, deploymentId3); } public void testDeleteDeploymentWithStartSignalEvents1() { String deploymentId1, deploymentId2, deploymentId3; deploymentId1 = deployStartSignalTestProcess(); deploymentId2 = deployProcessWithoutEvents(); deploymentId3 = deployStartSignalTestProcess(); repositoryService.deleteDeployment(deploymentId3, true); assertEventSubscriptionsCount(0); // the latest is now the one without a signal start cleanup(deploymentId1, deploymentId2); } public void testDeleteDeploymentWithStartSignalEvents2() { String deploymentId1 = deployStartSignalTestProcess(); String deploymentId2 = deployProcessWithoutEvents(); String deploymentId3 = deployStartSignalTestProcess(); repositoryService.deleteDeployment(deploymentId2, true); assertEventSubscriptionsCount(1); // the latest is now the one with the signal runtimeService.signalEventReceived("myStartSignal"); assertEquals(repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId3).singleResult().getId(), runtimeService.createProcessInstanceQuery().singleResult().getProcessDefinitionId()); cleanup(deploymentId1, deploymentId3); } public void testDeleteDeploymentWithStartSignalEvents3() { String deploymentId1 = deployStartSignalTestProcess(); String deploymentId2 = deployProcessWithoutEvents(); String deploymentId3 = deployStartSignalTestProcess(); repositoryService.deleteDeployment(deploymentId1, true); assertEventSubscriptionsCount(1); // the latest is now the one with the signal runtimeService.signalEventReceived("myStartSignal"); assertEquals(repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId3).singleResult().getId(), runtimeService.createProcessInstanceQuery().singleResult().getProcessDefinitionId()); cleanup(deploymentId2, deploymentId3); } public void testDeleteDeploymentWithStartSignalEvents4() { String deploymentId1 = deployStartSignalTestProcess(); String deploymentId2 = deployProcessWithoutEvents(); String deploymentId3 = deployStartSignalTestProcess(); repositoryService.deleteDeployment(deploymentId2, true); repositoryService.deleteDeployment(deploymentId3, true); assertEventSubscriptionsCount(1); // the latest is now the one with the signal runtimeService.signalEventReceived("myStartSignal"); assertEquals(repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId1).singleResult().getId(), runtimeService.createProcessInstanceQuery().singleResult().getProcessDefinitionId()); cleanup(deploymentId1); } public void testDeleteDeploymentWithStartSignalEvents5() { String deploymentId1 = deployStartSignalTestProcess(); String deploymentId2 = deployProcessWithoutEvents(); assertEventSubscriptionsCount(0); runtimeService.signalEventReceived("myStartSignal"); assertEquals(0, runtimeService.createExecutionQuery().count()); repositoryService.deleteDeployment(deploymentId2, true); assertEventSubscriptionsCount(1); // the first is now the one with the signal runtimeService.signalEventReceived("myStartSignal"); assertEquals(repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId1).singleResult().getId(), runtimeService.createProcessInstanceQuery().singleResult().getProcessDefinitionId()); cleanup(deploymentId1); } public void testDeleteDeploymentWithStartSignalEvents6() { String deploymentId1 = deployStartSignalTestProcess(); String deploymentId2 = deployProcessWithoutEvents(); String deploymentId3 = deployStartSignalTestProcess(); String deploymentId4 = deployProcessWithoutEvents(); runtimeService.signalEventReceived("myStartSignal"); assertEquals(0, runtimeService.createExecutionQuery().count()); repositoryService.deleteDeployment(deploymentId2, true); repositoryService.deleteDeployment(deploymentId3, true); runtimeService.signalEventReceived("myStartSignal"); assertEquals(0, runtimeService.createExecutionQuery().count()); repositoryService.deleteDeployment(deploymentId1, true); runtimeService.signalEventReceived("myStartSignal"); assertEquals(0, runtimeService.createExecutionQuery().count()); cleanup(deploymentId4); } public void testDeleteDeploymentWithStartSignalEvents7() { String deploymentId1 = deployStartSignalTestProcess(); String deploymentId2 = deployProcessWithoutEvents(); String deploymentId3 = deployStartSignalTestProcess(); String deploymentId4 = deployProcessWithoutEvents(); runtimeService.signalEventReceived("myStartSignal"); assertEquals(0, runtimeService.createExecutionQuery().count()); repositoryService.deleteDeployment(deploymentId2, true); repositoryService.deleteDeployment(deploymentId3, true); runtimeService.signalEventReceived("myStartSignal"); assertEquals(0, runtimeService.createExecutionQuery().count()); repositoryService.deleteDeployment(deploymentId4, true); runtimeService.signalEventReceived("myStartSignal"); assertEquals(1, runtimeService.createExecutionQuery().count()); cleanup(deploymentId1); } /* * BOTH BOUNDARY AND START SIGNAL */ public void testBothBoundaryAndStartEvent() { // Deploy process with both boundary and start event String deploymentId1 = deployProcessWithBothStartAndBoundarySignal(); assertEventSubscriptionsCount(1); assertEquals(0, runtimeService.createExecutionQuery().count()); runtimeService.signalEventReceived("myStartSignal"); runtimeService.signalEventReceived("myStartSignal"); assertEquals(2, runtimeService.createProcessInstanceQuery().count()); assertEquals(3, getAllEventSubscriptions().size()); // 1 for the start, 2 for the boundary // Deploy version with only a boundary signal String deploymentId2 = deployBoundarySignalTestProcess(); runtimeService.signalEventReceived("myStartSignal"); assertEquals(2, runtimeService.createProcessInstanceQuery().count()); assertEventSubscriptionsCount(2); // Deploy version with signal start String deploymentId3 = deployStartSignalTestProcess(); runtimeService.signalEventReceived("myStartSignal"); assertEquals(3, runtimeService.createProcessInstanceQuery().count()); assertEventSubscriptionsCount(3); // Delete last version again, making the one with the boundary the latest repositoryService.deleteDeployment(deploymentId3, true); runtimeService.signalEventReceived("myStartSignal"); assertEquals(2, runtimeService.createProcessInstanceQuery().count()); // -1, cause process instance of deploymentId3 is gone too assertEventSubscriptionsCount(2); // Test the boundary signal runtimeService.signalEventReceived("myBoundarySignal"); assertEquals(2, taskService.createTaskQuery().taskName("Task after boundary signal").list().size()); // Delete second version repositoryService.deleteDeployment(deploymentId2, true); runtimeService.signalEventReceived("myStartSignal"); assertEquals(3, runtimeService.createProcessInstanceQuery().count()); // -1, cause process instance of deploymentId3 is gone too assertEventSubscriptionsCount(2); cleanup(deploymentId1); } public void testBothBoundaryAndStartSameSignalId() { // Deploy process with both boundary and start event String deploymentId1 = deployProcessWithBothStartAndBoundarySignalSameSignal(); assertEventSubscriptionsCount(1); assertEquals(0, runtimeService.createExecutionQuery().count()); for (int i=0; i<9; i++) { // Every iteration will signal the boundary event of the previous iteration! runtimeService.signalEventReceived("mySignal"); assertEquals(2, getAllEventSubscriptions().size()); } if (processEngineConfiguration.getHistoryLevel().isAtLeast(HistoryLevel.ACTIVITY)) { assertEquals(9, historyService.createHistoricProcessInstanceQuery().count()); } assertEquals(2, getAllEventSubscriptions().size()); runtimeService.signalEventReceived("myStartSignal"); // Deploy version with only a start signal. The boundary events should still react though! String deploymentId2 = deployStartSignalTestProcess(); runtimeService.signalEventReceived("myStartSignal"); assertEquals(2, runtimeService.createProcessInstanceQuery().count()); assertEventSubscriptionsCount(2); cleanup(deploymentId1, deploymentId2); } /* * HELPERS */ private String deployBoundarySignalTestProcess() { return deploy(TEST_PROCESS_GLOBAL_BOUNDARY_SIGNAL); } private String deployStartSignalTestProcess() { return deploy(TEST_PROCESS_START_SIGNAL); } private String deployProcessWithoutEvents() { return deploy(TEST_PROCESS_NO_EVENTS); } private String deployProcessWithBothStartAndBoundarySignal() { return deploy(TEST_PROCESS_BOTH_START_AND_BOUNDARY_SIGNAL); } private String deployProcessWithBothStartAndBoundarySignalSameSignal() { return deploy(TEST_PROCESS_BOTH_START_AND_BOUNDARY_SIGNAL_SAME_SIGNAL); } private String deploy(String path) { String deploymentId = repositoryService .createDeployment() .addClasspathResource(path) .deploy() .getId(); return deploymentId; } private void cleanup(String ... deploymentIds) { for (String deploymentId : deploymentIds) { repositoryService.deleteDeployment(deploymentId, true); } } private List<EventSubscriptionEntity> getAllEventSubscriptions() { return managementService.executeCommand(new Command<List<EventSubscriptionEntity>>() { public List<EventSubscriptionEntity> execute(CommandContext commandContext) { EventSubscriptionQueryImpl query = new EventSubscriptionQueryImpl(commandContext); query.orderByCreated().desc(); List<EventSubscriptionEntity> eventSubscriptionEntities = query.list(); for (EventSubscriptionEntity eventSubscriptionEntity : eventSubscriptionEntities) { assertEquals("signal", eventSubscriptionEntity.getEventType()); assertNotNull(eventSubscriptionEntity.getProcessDefinitionId()); } return eventSubscriptionEntities; } }); } private void assertEventSubscriptionsCount(long count) { assertEquals(count, getAllEventSubscriptions().size()); } }