/* 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.ArrayList;
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;
/**
* 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 MessageEventsAndNewVersionDeploymentsTest extends PluggableActivitiTestCase {
private static final String TEST_PROCESS_GLOBAL_BOUNDARY_MESSAGE =
"org/activiti/engine/test/bpmn/deployment/MessageEventsAndNewVersionDeploymentsTest.testGlobalMessageBoundaryEvent.bpmn20.xml";
private static final String TEST_PROCESS_START_MESSAGE =
"org/activiti/engine/test/bpmn/deployment/MessageEventsAndNewVersionDeploymentsTest.testStartMessageEvent.bpmn20.xml";
private static final String TEST_PROCESS_NO_EVENTS =
"org/activiti/engine/test/bpmn/deployment/MessageEventsAndNewVersionDeploymentsTest.processWithoutEvents.bpmn20.xml";
private static final String TEST_PROCESS_BOTH_START_AND_BOUNDARY_MESSAGE =
"org/activiti/engine/test/bpmn/deployment/MessageEventsAndNewVersionDeploymentsTest.testBothBoundaryAndStartMessage.bpmn20.xml";
private static final String TEST_PROCESS_BOTH_START_AND_BOUNDARY_MESSAGE_SAME_MESSAGE =
"org/activiti/engine/test/bpmn/deployment/MessageEventsAndNewVersionDeploymentsTest.testBothBoundaryAndStartMessageSameMessage.bpmn20.xml";
/*
* BOUNDARY MESSAGE EVENT
*/
public void testMessageBoundaryEvent() {
String deploymentId1 = deployBoundaryMessageTestProcess();
runtimeService.startProcessInstanceByKey("messageTest");
assertEquals(1, getAllEventSubscriptions().size());
String deploymentId2 = deployBoundaryMessageTestProcess();
runtimeService.startProcessInstanceByKey("messageTest");
assertEquals(2, getAllEventSubscriptions().size());
assertReceiveMessage("myMessage", 2);
List<Task> tasks = taskService.createTaskQuery().list();
assertEquals(2, tasks.size());
for (Task task : tasks) {
assertEquals("Task after message", task.getName());
}
cleanup(deploymentId1, deploymentId2);
}
/**
* Verifying that the event subscriptions do get removed when removing a deployment.
*/
public void testBoundaryEventSubscriptionDeletedOnDeploymentDelete() {
String deploymentId = deployBoundaryMessageTestProcess();
runtimeService.startProcessInstanceByKey("messageTest");
assertEquals("My Task", taskService.createTaskQuery().singleResult().getName());
String deploymentId2 = deployBoundaryMessageTestProcess();
runtimeService.startProcessInstanceByKey("messageTest");
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 = deployBoundaryMessageTestProcess();
runtimeService.startProcessInstanceByKey("messageTest");
assertEquals("My Task", taskService.createTaskQuery().singleResult().getName());
String deploymentId2 = deployBoundaryMessageTestProcess();
ProcessInstance processInstance2 = runtimeService.startProcessInstanceByKey("messageTest");
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.messageEventReceived("myMessage", getExecutionIdsForMessageEventSubscription("myMessage").get(0));
assertEquals(0, getAllEventSubscriptions().size());
assertEquals("Task after message", taskService.createTaskQuery().singleResult().getName());
cleanup(deploymentId1, deploymentId2);
}
/*
* START MESSAGE EVENT
*/
public void testStartMessageEvent() {
String deploymentId1 = deployStartMessageTestProcess();
assertEquals(1, getAllEventSubscriptions().size());
assertEventSubscriptionsCount(1);
assertEquals(0, runtimeService.createProcessInstanceQuery().count());
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(1, runtimeService.createProcessInstanceQuery().count());
String deploymentId2 = deployStartMessageTestProcess();
assertEventSubscriptionsCount(1);
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(2, runtimeService.createProcessInstanceQuery().count());
assertEventSubscriptionsCount(1);
cleanup(deploymentId1, deploymentId2);
}
public void testMessageStartEventSubscriptionAfterDeploymentDelete() {
// Deploy two version of process definition, delete latest and check if all is good
String deploymentId1 = deployStartMessageTestProcess();
List<EventSubscriptionEntity> eventSubscriptions = getAllEventSubscriptions();
assertEquals(1, eventSubscriptions.size());
String deploymentId2 = deployStartMessageTestProcess();
eventSubscriptions = getAllEventSubscriptions();
assertEventSubscriptionsCount(1);
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 = deployStartMessageTestProcess();
deploymentId2 = deployStartMessageTestProcess();
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 message event
* v2 -> has no start message event
* v3 -> has start message event
*/
public void testDeployIntermediateVersionWithoutMessageStartEvent() {
String deploymentId1 = deployStartMessageTestProcess();
assertEquals(1, getAllEventSubscriptions().size());
assertEquals(0, runtimeService.createProcessInstanceQuery().count());
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(1, runtimeService.createProcessInstanceQuery().count());
assertEventSubscriptionsCount(1);
String deploymentId2 = deployProcessWithoutEvents();
assertEquals(0, getAllEventSubscriptions().size());
assertEquals(1, runtimeService.createProcessInstanceQuery().count());
try {
runtimeService.startProcessInstanceByMessage("myStartMessage");
fail();
} catch (Exception e) { }
assertEquals(1, runtimeService.createProcessInstanceQuery().count());
assertEventSubscriptionsCount(0);
String deploymentId3 = deployStartMessageTestProcess();
assertEquals(1, getAllEventSubscriptions().size());
assertEquals(1, runtimeService.createProcessInstanceQuery().count());
runtimeService.startProcessInstanceByMessage("myStartMessage");
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 testDeleteDeploymentWithStartMessageEvents1() {
String deploymentId1, deploymentId2, deploymentId3;
deploymentId1 = deployStartMessageTestProcess();
deploymentId2 = deployProcessWithoutEvents();
deploymentId3 = deployStartMessageTestProcess();
repositoryService.deleteDeployment(deploymentId3, true);
assertEventSubscriptionsCount(0); // the latest is now the one without a message start
cleanup(deploymentId1, deploymentId2);
}
public void testDeleteDeploymentWithStartMessageEvents2() {
String deploymentId1 = deployStartMessageTestProcess();
String deploymentId2 = deployProcessWithoutEvents();
String deploymentId3 = deployStartMessageTestProcess();
repositoryService.deleteDeployment(deploymentId2, true);
assertEventSubscriptionsCount(1); // the latest is now the one with the message
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId3).singleResult().getId(),
runtimeService.createProcessInstanceQuery().singleResult().getProcessDefinitionId());
cleanup(deploymentId1, deploymentId3);
}
public void testDeleteDeploymentWithStartMessageEvents3() {
String deploymentId1 = deployStartMessageTestProcess();
String deploymentId2 = deployProcessWithoutEvents();
String deploymentId3 = deployStartMessageTestProcess();
repositoryService.deleteDeployment(deploymentId1, true);
assertEventSubscriptionsCount(1); // the latest is now the one with the message
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId3).singleResult().getId(),
runtimeService.createProcessInstanceQuery().singleResult().getProcessDefinitionId());
cleanup(deploymentId2, deploymentId3);
}
public void testDeleteDeploymentWithStartMessageEvents4() {
String deploymentId1 = deployStartMessageTestProcess();
String deploymentId2 = deployProcessWithoutEvents();
String deploymentId3 = deployStartMessageTestProcess();
repositoryService.deleteDeployment(deploymentId2, true);
repositoryService.deleteDeployment(deploymentId3, true);
assertEventSubscriptionsCount(1); // the latest is now the one with the message start
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId1).singleResult().getId(),
runtimeService.createProcessInstanceQuery().singleResult().getProcessDefinitionId());
cleanup(deploymentId1);
}
public void testDeleteDeploymentWithStartMessageEvents5() {
String deploymentId1 = deployStartMessageTestProcess();
String deploymentId2 = deployProcessWithoutEvents();
assertEventSubscriptionsCount(0);
try {
runtimeService.startProcessInstanceByMessage("myStartMessage");
fail();
} catch (Exception e) {}
assertEquals(0, runtimeService.createExecutionQuery().count());
repositoryService.deleteDeployment(deploymentId2, true);
assertEventSubscriptionsCount(1); // the first is now the one with the signal
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId1).singleResult().getId(),
runtimeService.createProcessInstanceQuery().singleResult().getProcessDefinitionId());
cleanup(deploymentId1);
}
public void testDeleteDeploymentWithStartMessageEvents6() {
String deploymentId1 = deployStartMessageTestProcess();
String deploymentId2 = deployProcessWithoutEvents();
String deploymentId3 = deployStartMessageTestProcess();
String deploymentId4 = deployProcessWithoutEvents();
try {
runtimeService.startProcessInstanceByMessage("myStartMessage");
fail();
} catch (Exception e) {}
assertEquals(0, runtimeService.createExecutionQuery().count());
repositoryService.deleteDeployment(deploymentId2, true);
repositoryService.deleteDeployment(deploymentId3, true);
try {
runtimeService.startProcessInstanceByMessage("myStartMessage");
fail();
} catch (Exception e) {}
assertEquals(0, runtimeService.createExecutionQuery().count());
repositoryService.deleteDeployment(deploymentId1, true);
try {
runtimeService.startProcessInstanceByMessage("myStartMessage");
fail();
} catch (Exception e) {}
assertEquals(0, runtimeService.createExecutionQuery().count());
cleanup(deploymentId4);
}
public void testDeleteDeploymentWithStartMessageEvents7() {
String deploymentId1 = deployStartMessageTestProcess();
String deploymentId2 = deployProcessWithoutEvents();
String deploymentId3 = deployStartMessageTestProcess();
String deploymentId4 = deployProcessWithoutEvents();
try {
runtimeService.startProcessInstanceByMessage("myStartMessage");
fail();
} catch (Exception e) {}
assertEquals(0, runtimeService.createExecutionQuery().count());
repositoryService.deleteDeployment(deploymentId2, true);
repositoryService.deleteDeployment(deploymentId3, true);
try {
runtimeService.startProcessInstanceByMessage("myStartMessage");
fail();
} catch (Exception e) {}
assertEquals(0, runtimeService.createExecutionQuery().count());
repositoryService.deleteDeployment(deploymentId4, true);
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(1, runtimeService.createExecutionQuery().count());
cleanup(deploymentId1);
}
/*
* BOTH BOUNDARY AND START MESSAGE
*/
public void testBothBoundaryAndStartEvent() {
// Deploy process with both boundary and start event
String deploymentId1 = deployProcessWithBothStartAndBoundaryMessage();
assertEventSubscriptionsCount(1);
assertEquals(0, runtimeService.createExecutionQuery().count());
runtimeService.startProcessInstanceByMessage("myStartMessage");
runtimeService.startProcessInstanceByMessage("myStartMessage");
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 = deployBoundaryMessageTestProcess();
try {
runtimeService.startProcessInstanceByMessage("myStartMessage");
fail();
} catch (Exception e) {}
assertEquals(2, runtimeService.createProcessInstanceQuery().count());
assertEventSubscriptionsCount(2); // 2 boundary events remain
// Deploy version with signal start
String deploymentId3 = deployStartMessageTestProcess();
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(3, runtimeService.createProcessInstanceQuery().count());
assertEventSubscriptionsCount(3);
// Delete last version again, making the one with the boundary the latest
repositoryService.deleteDeployment(deploymentId3, true);
try {
runtimeService.startProcessInstanceByMessage("myStartMessage");
fail();
} catch (Exception e) {}
assertEquals(2, runtimeService.createProcessInstanceQuery().count()); // -1, cause process instance of deploymentId3 is gone too
assertEventSubscriptionsCount(2); // The 2 boundary remains
// Test the boundary signal
assertReceiveMessage("myBoundaryMessage", 2);
assertEquals(2, taskService.createTaskQuery().taskName("Task after boundary message").list().size());
// Delete second version
repositoryService.deleteDeployment(deploymentId2, true);
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(3, runtimeService.createProcessInstanceQuery().count()); // -1, cause process instance of deploymentId3 is gone too
assertEventSubscriptionsCount(2); // 2 boundaries
cleanup(deploymentId1);
}
public void testBothBoundaryAndStartSameMessageId() {
// Deploy process with both boundary and start event
String deploymentId1 = deployProcessWithBothStartAndBoundarySameMessage();
assertEquals(1, getAllEventSubscriptions().size());
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.startProcessInstanceByMessage("myMessage");
}
if (processEngineConfiguration.getHistoryLevel().isAtLeast(HistoryLevel.ACTIVITY)) {
assertEquals(9, historyService.createHistoricProcessInstanceQuery().count());
}
assertEquals(10, getAllEventSubscriptions().size()); // 1 for the start, 9 for boundary
// Deploy version with only a start signal. The boundary events should still react though!
String deploymentId2 = deployStartMessageTestProcess();
runtimeService.startProcessInstanceByMessage("myStartMessage");
assertEquals(10, runtimeService.createProcessInstanceQuery().count());
assertEventSubscriptionsCount(10); // Remains 10: 1 one was removed, but one added for the new message
try {
runtimeService.startProcessInstanceByMessage("myMessage");
fail();
} catch (Exception e) {}
cleanup(deploymentId1, deploymentId2);
}
/*
* HELPERS
*/
private String deployBoundaryMessageTestProcess() {
return deploy(TEST_PROCESS_GLOBAL_BOUNDARY_MESSAGE);
}
private String deployStartMessageTestProcess() {
return deploy(TEST_PROCESS_START_MESSAGE);
}
private String deployProcessWithoutEvents() {
return deploy(TEST_PROCESS_NO_EVENTS);
}
private String deployProcessWithBothStartAndBoundaryMessage() {
return deploy(TEST_PROCESS_BOTH_START_AND_BOUNDARY_MESSAGE);
}
private String deployProcessWithBothStartAndBoundarySameMessage() {
return deploy(TEST_PROCESS_BOTH_START_AND_BOUNDARY_MESSAGE_SAME_MESSAGE);
}
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<String> getExecutionIdsForMessageEventSubscription(final String messageName) {
return managementService.executeCommand(new Command<List<String>>() {
public List<String> execute(CommandContext commandContext) {
EventSubscriptionQueryImpl query = new EventSubscriptionQueryImpl(commandContext);
query.eventType("message");
query.eventName(messageName);
query.orderByCreated().desc();
List<EventSubscriptionEntity> eventSubscriptions = query.list();
List<String> executionIds = new ArrayList<String>();
for (EventSubscriptionEntity eventSubscription : eventSubscriptions) {
executionIds.add(eventSubscription.getExecutionId());
}
return executionIds;
}
});
}
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 entity : eventSubscriptionEntities) {
assertEquals("message", entity.getEventType());
assertNotNull(entity.getProcessDefinitionId());
}
return eventSubscriptionEntities;
}
});
}
private void assertReceiveMessage(String messageName, int executionIdsCount) {
List<String> executionIds =getExecutionIdsForMessageEventSubscription(messageName);
assertEquals(executionIdsCount, executionIds.size());
for (String executionId : executionIds) {
runtimeService.messageEventReceived(messageName, executionId);
}
}
private void assertEventSubscriptionsCount(long count) {
assertEquals(count, getAllEventSubscriptions().size());
}
}