/* 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.db;
import java.util.List;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.cmd.SetProcessDefinitionVersionCmd;
import org.activiti.engine.impl.history.HistoryLevel;
import org.activiti.engine.impl.interceptor.CommandExecutor;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.test.PluggableActivitiTestCase;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.test.Deployment;
/**
* @author Falko Menge
*/
public class ProcessInstanceMigrationTest extends PluggableActivitiTestCase {
private static final String TEST_PROCESS_WITH_PARALLEL_GATEWAY = "org/activiti/examples/bpmn/gateway/ParallelGatewayTest.testForkJoin.bpmn20.xml";
private static final String TEST_PROCESS = "org/activiti/engine/test/db/ProcessInstanceMigrationTest.testSetProcessDefinitionVersion.bpmn20.xml";
private static final String TEST_PROCESS_ACTIVITY_MISSING = "org/activiti/engine/test/db/ProcessInstanceMigrationTest.testSetProcessDefinitionVersionActivityMissing.bpmn20.xml";
private static final String TEST_PROCESS_CALL_ACTIVITY = "org/activiti/engine/test/db/ProcessInstanceMigrationTest.withCallActivity.bpmn20.xml";
private static final String TEST_PROCESS_USER_TASK_V1 = "org/activiti/engine/test/db/ProcessInstanceMigrationTest.testSetProcessDefinitionVersionWithTask.bpmn20.xml";
private static final String TEST_PROCESS_USER_TASK_V2 = "org/activiti/engine/test/db/ProcessInstanceMigrationTest.testSetProcessDefinitionVersionWithTaskV2.bpmn20.xml";
public void testSetProcessDefinitionVersionEmptyArguments() {
try {
new SetProcessDefinitionVersionCmd(null, 23);
fail("ActivitiException expected");
} catch (ActivitiException ae) {
assertTextPresent("The process instance id is mandatory, but 'null' has been provided.", ae.getMessage());
}
try {
new SetProcessDefinitionVersionCmd("", 23);
fail("ActivitiException expected");
} catch (ActivitiException ae) {
assertTextPresent("The process instance id is mandatory, but '' has been provided.", ae.getMessage());
}
try {
new SetProcessDefinitionVersionCmd("42", null);
fail("ActivitiException expected");
} catch (ActivitiException ae) {
assertTextPresent("The process definition version is mandatory, but 'null' has been provided.", ae.getMessage());
}
try {
new SetProcessDefinitionVersionCmd("42", -1);
fail("ActivitiException expected");
} catch (ActivitiException ae) {
assertTextPresent("The process definition version must be positive, but '-1' has been provided.", ae.getMessage());
}
}
public void testSetProcessDefinitionVersionNonExistingPI() {
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutorTxRequired();
try {
commandExecutor.execute(new SetProcessDefinitionVersionCmd("42", 23));
fail("ActivitiException expected");
} catch (ActivitiException ae) {
assertTextPresent("No process instance found for id = '42'.", ae.getMessage());
}
}
@Deployment(resources = {TEST_PROCESS_WITH_PARALLEL_GATEWAY})
public void testSetProcessDefinitionVersionPIIsSubExecution() {
// start process instance
ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin");
Execution execution = runtimeService.createExecutionQuery()
.activityId("receivePayment")
.singleResult();
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutorTxRequired();
SetProcessDefinitionVersionCmd command = new SetProcessDefinitionVersionCmd(execution.getId(), 1);
try {
commandExecutor.execute(command);
fail("ActivitiException expected");
} catch (ActivitiException ae) {
assertTextPresent("A process instance id is required, but the provided id '"+execution.getId()+"' points to a child execution of process instance '"+pi.getId()+"'. Please invoke the "+command.getClass().getSimpleName()+" with a root execution id.", ae.getMessage());
}
}
@Deployment(resources = {TEST_PROCESS})
public void testSetProcessDefinitionVersionNonExistingPD() {
// start process instance
ProcessInstance pi = runtimeService.startProcessInstanceByKey("receiveTask");
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutorTxRequired();
try {
commandExecutor.execute(new SetProcessDefinitionVersionCmd(pi.getId(), 23));
fail("ActivitiException expected");
} catch (ActivitiException ae) {
assertTextPresent("no processes deployed with key = 'receiveTask' and version = '23'", ae.getMessage());
}
}
@Deployment(resources = {TEST_PROCESS})
public void testSetProcessDefinitionVersionActivityMissing() {
// start process instance
ProcessInstance pi = runtimeService.startProcessInstanceByKey("receiveTask");
// check that receive task has been reached
Execution execution = runtimeService.createExecutionQuery()
.activityId("waitState1")
.singleResult();
assertNotNull(execution);
// deploy new version of the process definition
org.activiti.engine.repository.Deployment deployment = repositoryService
.createDeployment()
.addClasspathResource(TEST_PROCESS_ACTIVITY_MISSING)
.deploy();
assertEquals(2, repositoryService.createProcessDefinitionQuery().count());
// migrate process instance to new process definition version
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutorTxRequired();
SetProcessDefinitionVersionCmd setProcessDefinitionVersionCmd = new SetProcessDefinitionVersionCmd(pi.getId(), 2);
try {
commandExecutor.execute(setProcessDefinitionVersionCmd);
fail("ActivitiException expected");
} catch (ActivitiException ae) {
assertTextPresent("The new process definition (key = 'receiveTask') does not contain the current activity (id = 'waitState1') of the process instance (id = '", ae.getMessage());
}
// undeploy "manually" deployed process definition
repositoryService.deleteDeployment(deployment.getId(), true);
}
@Deployment
public void testSetProcessDefinitionVersion() {
// start process instance
ProcessInstance pi = runtimeService.startProcessInstanceByKey("receiveTask");
// check that receive task has been reached
Execution execution = runtimeService.createExecutionQuery()
.processInstanceId(pi.getId())
.activityId("waitState1")
.singleResult();
assertNotNull(execution);
// deploy new version of the process definition
org.activiti.engine.repository.Deployment deployment = repositoryService
.createDeployment()
.addClasspathResource(TEST_PROCESS)
.deploy();
assertEquals(2, repositoryService.createProcessDefinitionQuery().count());
// migrate process instance to new process definition version
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutorTxRequired();
commandExecutor.execute(new SetProcessDefinitionVersionCmd(pi.getId(), 2));
// signal process instance
runtimeService.signal(execution.getId());
// check that the instance now uses the new process definition version
ProcessDefinition newProcessDefinition = repositoryService
.createProcessDefinitionQuery()
.processDefinitionVersion(2)
.singleResult();
pi = runtimeService
.createProcessInstanceQuery()
.processInstanceId(pi.getId())
.singleResult();
assertEquals(newProcessDefinition.getId(), pi.getProcessDefinitionId());
// check history
if (processEngineConfiguration.getHistoryLevel().isAtLeast(HistoryLevel.ACTIVITY)) {
HistoricProcessInstance historicPI = historyService
.createHistoricProcessInstanceQuery()
.processInstanceId(pi.getId())
.singleResult();
assertEquals(newProcessDefinition.getId(), historicPI.getProcessDefinitionId());
}
// undeploy "manually" deployed process definition
repositoryService.deleteDeployment(deployment.getId(), true);
}
@Deployment(resources = {TEST_PROCESS_WITH_PARALLEL_GATEWAY})
public void testSetProcessDefinitionVersionSubExecutions() {
// start process instance
ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin");
// check that the user tasks have been reached
assertEquals(2, taskService.createTaskQuery().count());
// deploy new version of the process definition
org.activiti.engine.repository.Deployment deployment = repositoryService
.createDeployment()
.addClasspathResource(TEST_PROCESS_WITH_PARALLEL_GATEWAY)
.deploy();
assertEquals(2, repositoryService.createProcessDefinitionQuery().count());
// migrate process instance to new process definition version
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutorTxRequired();
commandExecutor.execute(new SetProcessDefinitionVersionCmd(pi.getId(), 2));
// check that all executions of the instance now use the new process definition version
ProcessDefinition newProcessDefinition = repositoryService
.createProcessDefinitionQuery()
.processDefinitionVersion(2)
.singleResult();
List<Execution> executions = runtimeService
.createExecutionQuery()
.processInstanceId(pi.getId())
.list();
for (Execution execution : executions) {
assertEquals(newProcessDefinition.getId(), ((ExecutionEntity) execution).getProcessDefinitionId());
}
// undeploy "manually" deployed process definition
repositoryService.deleteDeployment(deployment.getId(), true);
}
@Deployment(resources = {TEST_PROCESS_CALL_ACTIVITY})
public void testSetProcessDefinitionVersionWithCallActivity() {
// start process instance
ProcessInstance pi = runtimeService.startProcessInstanceByKey("parentProcess");
// check that receive task has been reached
Execution execution = runtimeService.createExecutionQuery()
.activityId("waitState1")
.processDefinitionKey("childProcess")
.singleResult();
assertNotNull(execution);
// deploy new version of the process definition
org.activiti.engine.repository.Deployment deployment = repositoryService
.createDeployment()
.addClasspathResource(TEST_PROCESS_CALL_ACTIVITY)
.deploy();
assertEquals(2, repositoryService.createProcessDefinitionQuery().processDefinitionKey("parentProcess").count());
// migrate process instance to new process definition version
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutorTxRequired();
commandExecutor.execute(new SetProcessDefinitionVersionCmd(pi.getId(), 2));
// signal process instance
runtimeService.signal(execution.getId());
// should be finished now
assertEquals(0, runtimeService.createProcessInstanceQuery().processInstanceId(pi.getId()).count());
// undeploy "manually" deployed process definition
repositoryService.deleteDeployment(deployment.getId(), true);
}
@Deployment(resources = {TEST_PROCESS_USER_TASK_V1})
public void testSetProcessDefinitionVersionWithWithTask() {
try {
// start process instance
ProcessInstance pi = runtimeService.startProcessInstanceByKey("userTask");
// check that user task has been reached
assertEquals(1, taskService.createTaskQuery().processInstanceId(pi.getId()).count());
// deploy new version of the process definition
org.activiti.engine.repository.Deployment deployment = repositoryService
.createDeployment()
.addClasspathResource(TEST_PROCESS_USER_TASK_V2)
.deploy();
assertEquals(2, repositoryService.createProcessDefinitionQuery().processDefinitionKey("userTask").count());
ProcessDefinition newProcessDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("userTask").processDefinitionVersion(2).singleResult();
// migrate process instance to new process definition version
processEngineConfiguration.getCommandExecutorTxRequired().execute(new SetProcessDefinitionVersionCmd(pi.getId(), 2));
// check UserTask
Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
assertEquals(newProcessDefinition.getId(), task.getProcessDefinitionId());
assertEquals("testFormKey", formService.getTaskFormData(task.getId()).getFormKey());
// continue
taskService.complete(task.getId());
assertProcessEnded(pi.getId());
// undeploy "manually" deployed process definition
repositoryService.deleteDeployment(deployment.getId(), true);
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}