/* 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.subprocess;
import java.util.Date;
import java.util.List;
import org.activiti.engine.impl.test.PluggableActivitiTestCase;
import org.activiti.engine.impl.util.ClockUtil;
import org.activiti.engine.impl.util.CollectionUtil;
import org.activiti.engine.runtime.Job;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.engine.test.Deployment;
/**
* @author Joram Barrez
* @author Falko Menge
*/
public class SubProcessTest extends PluggableActivitiTestCase {
@Deployment
public void testSimpleSubProcess() {
// After staring the process, the task in the subprocess should be active
ProcessInstance pi = runtimeService.startProcessInstanceByKey("simpleSubProcess");
Task subProcessTask = taskService.createTaskQuery()
.processInstanceId(pi.getId())
.singleResult();
assertEquals("Task in subprocess", subProcessTask.getName());
// After completing the task in the subprocess,
// the subprocess scope is destroyed and the complete process ends
taskService.complete(subProcessTask.getId());
assertNull(runtimeService.createProcessInstanceQuery().processInstanceId(pi.getId()).singleResult());
}
/**
* Same test case as before, but now with all automatic steps
*/
@Deployment
public void testSimpleAutomaticSubProcess() {
ProcessInstance pi = runtimeService.startProcessInstanceByKey("simpleSubProcessAutomatic");
assertTrue(pi.isEnded());
assertProcessEnded(pi.getId());
}
@Deployment
public void testSimpleSubProcessWithTimer() {
Date startTime = new Date();
// After staring the process, the task in the subprocess should be active
ProcessInstance pi = runtimeService.startProcessInstanceByKey("simpleSubProcess");
Task subProcessTask = taskService.createTaskQuery()
.processInstanceId(pi.getId())
.singleResult();
assertEquals("Task in subprocess", subProcessTask.getName());
// Setting the clock forward 2 hours 1 second (timer fires in 2 hours) and fire up the job executor
ClockUtil.setCurrentTime(new Date(startTime.getTime() + (2 * 60 * 60 * 1000 ) + 1000));
waitForJobExecutorToProcessAllJobs(5000L, 50L);
// The subprocess should be left, and the escalated task should be active
Task escalationTask = taskService.createTaskQuery()
.processInstanceId(pi.getId())
.singleResult();
assertEquals("Fix escalated problem", escalationTask.getName());
}
/**
* A test case that has a timer attached to the subprocess,
* where 2 concurrent paths are defined when the timer fires.
*/
@Deployment
public void IGNORE_testSimpleSubProcessWithConcurrentTimer() {
// After staring the process, the task in the subprocess should be active
ProcessInstance pi = runtimeService.startProcessInstanceByKey("simpleSubProcessWithConcurrentTimer");
TaskQuery taskQuery = taskService
.createTaskQuery()
.processInstanceId(pi.getId())
.orderByTaskName()
.asc();
Task subProcessTask = taskQuery.singleResult();
assertEquals("Task in subprocess", subProcessTask.getName());
// When the timer is fired (after 2 hours), two concurrent paths should be created
Job job = managementService.createJobQuery().singleResult();
managementService.executeJob(job.getId());
List<Task> tasksAfterTimer = taskQuery.list();
assertEquals(2, tasksAfterTimer.size());
Task taskAfterTimer1 = tasksAfterTimer.get(0);
Task taskAfterTimer2 = tasksAfterTimer.get(1);
assertEquals("Task after timer 1", taskAfterTimer1.getName());
assertEquals("Task after timer 2", taskAfterTimer2.getName());
// Completing the two tasks should end the process instance
taskService.complete(taskAfterTimer1.getId());
taskService.complete(taskAfterTimer2.getId());
assertProcessEnded(pi.getId());
}
/**
* Test case where the simple sub process of previous test cases
* is nested within another subprocess.
*/
@Deployment
public void testNestedSimpleSubProcess() {
// Start and delete a process with a nested subprocess when it is not yet ended
ProcessInstance pi = runtimeService.startProcessInstanceByKey("nestedSimpleSubProcess", CollectionUtil.singletonMap("someVar", "abc"));
runtimeService.deleteProcessInstance(pi.getId(), "deleted");
// After staring the process, the task in the inner subprocess must be active
pi = runtimeService.startProcessInstanceByKey("nestedSimpleSubProcess");
Task subProcessTask = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
assertEquals("Task in subprocess", subProcessTask.getName());
// After completing the task in the subprocess,
// both subprocesses are destroyed and the task after the subprocess should be active
taskService.complete(subProcessTask.getId());
Task taskAfterSubProcesses = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
assertNotNull(taskAfterSubProcesses);
assertEquals("Task after subprocesses", taskAfterSubProcesses.getName());
taskService.complete(taskAfterSubProcesses.getId());
assertProcessEnded(pi.getId());
}
@Deployment
public void testNestedSimpleSubprocessWithTimerOnInnerSubProcess() {
Date startTime = new Date();
// After staring the process, the task in the subprocess should be active
ProcessInstance pi = runtimeService.startProcessInstanceByKey("nestedSubProcessWithTimer");
Task subProcessTask = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
assertEquals("Task in subprocess", subProcessTask.getName());
// Setting the clock forward 1 hour 1 second (timer fires in 1 hour) and fire up the job executor
ClockUtil.setCurrentTime(new Date(startTime.getTime() + ( 60 * 60 * 1000 ) + 1000));
waitForJobExecutorToProcessAllJobs(5000L, 50L);
// The inner subprocess should be destoyed, and the escalated task should be active
Task escalationTask = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
assertEquals("Escalated task", escalationTask.getName());
// Completing the escalated task, destroys the outer scope and activates the task after the subprocess
taskService.complete(escalationTask.getId());
Task taskAfterSubProcess = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
assertEquals("Task after subprocesses", taskAfterSubProcess.getName());
}
/**
* Test case where the simple sub process of previous test cases
* is nested within two other sub processes
*/
@Deployment
public void testDoubleNestedSimpleSubProcess() {
// After staring the process, the task in the inner subprocess must be active
ProcessInstance pi = runtimeService.startProcessInstanceByKey("nestedSimpleSubProcess");
Task subProcessTask = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
assertEquals("Task in subprocess", subProcessTask.getName());
// After completing the task in the subprocess,
// both subprocesses are destroyed and the task after the subprocess should be active
taskService.complete(subProcessTask.getId());
Task taskAfterSubProcesses = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
assertEquals("Task after subprocesses", taskAfterSubProcesses.getName());
}
@Deployment
public void testSimpleParallelSubProcess() {
// After starting the process, the two task in the subprocess should be active
ProcessInstance pi = runtimeService.startProcessInstanceByKey("simpleParallelSubProcess");
List<Task> subProcessTasks = taskService.createTaskQuery().processInstanceId(pi.getId()).orderByTaskName().asc().list();
// Tasks are ordered by name (see query)
Task taskA = subProcessTasks.get(0);
Task taskB = subProcessTasks.get(1);
assertEquals("Task A", taskA.getName());
assertEquals("Task B", taskB.getName());
// Completing both tasks, should destroiy the subprocess and activate the task after the subprocess
taskService.complete(taskA.getId());
taskService.complete(taskB.getId());
Task taskAfterSubProcess = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
assertEquals("Task after sub process", taskAfterSubProcess.getName());
}
@Deployment
public void testSimpleParallelSubProcessWithTimer() {
// After staring the process, the tasks in the subprocess should be active
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("simpleParallelSubProcessWithTimer");
List<Task> subProcessTasks = taskService.createTaskQuery().processInstanceId(processInstance.getId()).orderByTaskName().asc().list();
// Tasks are ordered by name (see query)
Task taskA = subProcessTasks.get(0);
Task taskB = subProcessTasks.get(1);
assertEquals("Task A", taskA.getName());
assertEquals("Task B", taskB.getName());
Job job = managementService
.createJobQuery()
.processInstanceId(processInstance.getId())
.singleResult();
managementService.executeJob(job.getId());
// The inner subprocess should be destoyed, and the tsk after the timer should be active
Task taskAfterTimer = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
assertEquals("Task after timer", taskAfterTimer.getName());
// Completing the task after the timer ends the process instance
taskService.complete(taskAfterTimer.getId());
assertProcessEnded(processInstance.getId());
}
@Deployment
public void testTwoSubProcessInParallel() {
ProcessInstance pi = runtimeService.startProcessInstanceByKey("twoSubProcessInParallel");
TaskQuery taskQuery = taskService
.createTaskQuery()
.processInstanceId(pi.getId())
.orderByTaskName()
.asc();
List<Task> tasks = taskQuery.list();
// After process start, both tasks in the subprocesses should be active
assertEquals("Task in subprocess A", tasks.get(0).getName());
assertEquals("Task in subprocess B", tasks.get(1).getName());
// Completing both tasks should active the tasks outside the subprocesses
taskService.complete(tasks.get(0).getId());
tasks = taskQuery.list();
assertEquals("Task after subprocess A", tasks.get(0).getName());
assertEquals("Task in subprocess B", tasks.get(1).getName());
taskService.complete(tasks.get(1).getId());
tasks = taskQuery.list();
assertEquals("Task after subprocess A", tasks.get(0).getName());
assertEquals("Task after subprocess B", tasks.get(1).getName());
// Completing these tasks should end the process
taskService.complete(tasks.get(0).getId());
taskService.complete(tasks.get(1).getId());
assertProcessEnded(pi.getId());
}
@Deployment
public void testTwoSubProcessInParallelWithinSubProcess() {
ProcessInstance pi = runtimeService.startProcessInstanceByKey("twoSubProcessInParallelWithinSubProcess");
TaskQuery taskQuery = taskService
.createTaskQuery()
.processInstanceId(pi.getId())
.orderByTaskName()
.asc();
List<Task> tasks = taskQuery.list();
// After process start, both tasks in the subprocesses should be active
Task taskA = tasks.get(0);
Task taskB = tasks.get(1);
assertEquals("Task in subprocess A", taskA.getName());
assertEquals("Task in subprocess B", taskB.getName());
// Completing both tasks should active the tasks outside the subprocesses
taskService.complete(taskA.getId());
taskService.complete(taskB.getId());
Task taskAfterSubProcess = taskQuery.singleResult();
assertEquals("Task after subprocess", taskAfterSubProcess.getName());
// Completing this task should end the process
taskService.complete(taskAfterSubProcess.getId());
assertProcessEnded(pi.getId());
}
@Deployment
public void testTwoNestedSubProcessesInParallelWithTimer() {
// Date startTime = new Date();
ProcessInstance pi = runtimeService.startProcessInstanceByKey("nestedParallelSubProcessesWithTimer");
TaskQuery taskQuery = taskService
.createTaskQuery()
.processInstanceId(pi.getId())
.orderByTaskName()
.asc();
List<Task> tasks = taskQuery.list();
// After process start, both tasks in the subprocesses should be active
Task taskA = tasks.get(0);
Task taskB = tasks.get(1);
assertEquals("Task in subprocess A", taskA.getName());
assertEquals("Task in subprocess B", taskB.getName());
// Firing the timer should destroy all three subprocesses and activate the task after the timer
// ClockUtil.setCurrentTime(new Date(startTime.getTime() + (2 * 60 * 60 * 1000 ) + 1000));
// waitForJobExecutorToProcessAllJobs(5000L, 50L);
Job job = managementService.createJobQuery().singleResult();
managementService.executeJob(job.getId());
Task taskAfterTimer = taskQuery.singleResult();
assertEquals("Task after timer", taskAfterTimer.getName());
// Completing the task should end the process instance
taskService.complete(taskAfterTimer.getId());
assertProcessEnded(pi.getId());
}
/**
* @see http://jira.codehaus.org/browse/ACT-1072
*/
@Deployment
public void testNestedSimpleSubProcessWithoutEndEvent() {
testNestedSimpleSubProcess();
}
/**
* @see http://jira.codehaus.org/browse/ACT-1072
*/
@Deployment
public void testSimpleSubProcessWithoutEndEvent() {
ProcessInstance pi = runtimeService.startProcessInstanceByKey("testSimpleSubProcessWithoutEndEvent");
assertProcessEnded(pi.getId());
}
/**
* @see http://jira.codehaus.org/browse/ACT-1072
*/
@Deployment
public void testNestedSubProcessesWithoutEndEvents() {
ProcessInstance pi = runtimeService.startProcessInstanceByKey("testNestedSubProcessesWithoutEndEvents");
assertProcessEnded(pi.getId());
}
}