/* 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.event.timer;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;
import org.activiti.engine.impl.cmd.DeleteJobsCmd;
import org.activiti.engine.impl.interceptor.CommandExecutor;
import org.activiti.engine.impl.jobexecutor.JobExecutor;
import org.activiti.engine.impl.test.PluggableActivitiTestCase;
import org.activiti.engine.impl.util.ClockUtil;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.Job;
import org.activiti.engine.runtime.JobQuery;
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
*/
public class BoundaryTimerNonInterruptingEventTest extends PluggableActivitiTestCase {
@Deployment
public void testMultipleTimersOnUserTask() {
// Set the clock fixed
Date startTime = new Date();
// After process start, there should be 3 timers created
ProcessInstance pi = runtimeService.startProcessInstanceByKey("nonInterruptingTimersOnUserTask");
Task task1 = taskService.createTaskQuery().singleResult();
assertEquals("First Task", task1.getName());
JobQuery jobQuery = managementService.createJobQuery().processInstanceId(pi.getId());
List<Job> jobs = jobQuery.list();
assertEquals(2, jobs.size());
// After setting the clock to time '1 hour and 5 seconds', the first timer should fire
ClockUtil.setCurrentTime(new Date(startTime.getTime() + ((60 * 60 * 1000) + 5000)));
waitForJobExecutorToProcessAllJobs(5000L, 25L);
// we still have one timer more to fire
assertEquals(1L, jobQuery.count());
// and we are still in the first state, but in the second state as well!
assertEquals(2L, taskService.createTaskQuery().count());
List<Task> taskList = taskService.createTaskQuery().orderByTaskName().desc().list();
assertEquals("First Task", taskList.get(0).getName());
assertEquals("Escalation Task 1", taskList.get(1).getName());
// complete the task and end the forked execution
taskService.complete(taskList.get(1).getId());
// but we still have the original executions
assertEquals(1L, taskService.createTaskQuery().count());
assertEquals("First Task", taskService.createTaskQuery().singleResult().getName());
// After setting the clock to time '2 hour and 5 seconds', the second timer should fire
ClockUtil.setCurrentTime(new Date(startTime.getTime() + ((2 * 60 * 60 * 1000) + 5000)));
waitForJobExecutorToProcessAllJobs(5000L, 25L);
// no more timers to fire
assertEquals(0L, jobQuery.count());
// and we are still in the first state, but in the next escalation state as well
assertEquals(2L, taskService.createTaskQuery().count());
taskList = taskService.createTaskQuery().orderByTaskName().desc().list();
assertEquals("First Task", taskList.get(0).getName());
assertEquals("Escalation Task 2", taskList.get(1).getName());
// This time we end the main task
taskService.complete(taskList.get(0).getId());
// but we still have the escalation task
assertEquals(1L, taskService.createTaskQuery().count());
Task escalationTask = taskService.createTaskQuery().singleResult();
assertEquals("Escalation Task 2", escalationTask.getName());
taskService.complete(escalationTask.getId());
// now we are really done :-)
assertProcessEnded(pi.getId());
}
@Deployment
public void testJoin() {
// Set the clock fixed
Date startTime = new Date();
// After process start, there should be 3 timers created
ProcessInstance pi = runtimeService.startProcessInstanceByKey("testJoin");
Task task1 = taskService.createTaskQuery().singleResult();
assertEquals("Main Task", task1.getName());
JobQuery jobQuery = managementService.createJobQuery().processInstanceId(pi.getId());
List<Job> jobs = jobQuery.list();
assertEquals(1, jobs.size());
// After setting the clock to time '1 hour and 5 seconds', the first timer should fire
ClockUtil.setCurrentTime(new Date(startTime.getTime() + ((60 * 60 * 1000) + 5000)));
waitForJobExecutorToProcessAllJobs(5000L, 25L);
// timer has fired
assertEquals(0L, jobQuery.count());
// we now have both tasks
assertEquals(2L, taskService.createTaskQuery().count());
// end the first
taskService.complete(task1.getId());
// we now have one task left
assertEquals(1L, taskService.createTaskQuery().count());
Task task2 = taskService.createTaskQuery().singleResult();
assertEquals("Escalation Task", task2.getName());
// complete the task, the parallel gateway should fire
taskService.complete(task2.getId());
// and the process has ended
assertProcessEnded(pi.getId());
}
@Deployment
public void testTimerOnConcurrentTasks() {
String procId = runtimeService.startProcessInstanceByKey("nonInterruptingOnConcurrentTasks").getId();
assertEquals(2, taskService.createTaskQuery().count());
Job timer = managementService.createJobQuery().singleResult();
managementService.executeJob(timer.getId());
assertEquals(3, taskService.createTaskQuery().count());
// Complete task that was reached by non interrupting timer
Task task = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask").singleResult();
taskService.complete(task.getId());
assertEquals(2, taskService.createTaskQuery().count());
// Complete other tasks
for (Task t : taskService.createTaskQuery().list()) {
taskService.complete(t.getId());
}
assertProcessEnded(procId);
}
// Difference with previous test: now the join will be reached first
@Deployment(resources = {"org/activiti/engine/test/bpmn/event/timer/BoundaryTimerNonInterruptingEventTest.testTimerOnConcurrentTasks.bpmn20.xml"})
public void FAILING_testTimerOnConcurrentTasks2() {
String procId = runtimeService.startProcessInstanceByKey("nonInterruptingOnConcurrentTasks").getId();
assertEquals(2, taskService.createTaskQuery().count());
Job timer = managementService.createJobQuery().singleResult();
managementService.executeJob(timer.getId());
assertEquals(3, taskService.createTaskQuery().count());
// Complete 2 tasks that will trigger the join
Task task = taskService.createTaskQuery().taskDefinitionKey("firstTask").singleResult();
taskService.complete(task.getId());
task = taskService.createTaskQuery().taskDefinitionKey("secondTask").singleResult();
taskService.complete(task.getId());
assertEquals(1, taskService.createTaskQuery().count());
// Finally, complete the task that was created due to the timer
task = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask").singleResult();
taskService.complete(task.getId());
assertProcessEnded(procId);
}
@Deployment
public void testTimerWithCycle() throws Exception {
runtimeService.startProcessInstanceByKey("nonInterruptingCycle").getId();
TaskQuery tq = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask");
assertEquals(0, tq.count());
moveByHours(1);
assertEquals(1, tq.count());
moveByHours(1);
assertEquals(2, tq.count());
Task task = taskService.createTaskQuery().taskDefinitionKey("task").singleResult();
taskService.complete(task.getId());
moveByHours(1);
assertEquals(2, tq.count());
}
@Deployment
/**
* see http://jira.codehaus.org/browse/ACT-1106
*/
public void FAILING_testReceiveTaskWithBoundaryTimer(){
// Set the clock fixed
Date startTime = new Date();
HashMap<String, Object> variables = new HashMap<String, Object>();
variables.put("timeCycle", "R/PT1H");
// After process start, there should be a timer created
ProcessInstance pi = runtimeService.startProcessInstanceByKey("nonInterruptingCycle", variables);
JobQuery jobQuery = managementService.createJobQuery().processInstanceId(pi.getId());
List<Job> jobs = jobQuery.list();
assertEquals(1, jobs.size());
// The Execution Query should work normally and find executions in state "task"
List<Execution> executions = runtimeService.createExecutionQuery()
.activityId("task")
.variableValueEquals("timeCycle", "R/PT1H").list();
assertEquals(1, executions.size());
List<String> activeActivityIds = runtimeService.getActiveActivityIds(executions.get(0).getId());
assertEquals(1, activeActivityIds.size());
assertEquals("task", activeActivityIds.get(0));
runtimeService.signal(executions.get(0).getId());
// // After setting the clock to time '1 hour and 5 seconds', the second timer should fire
// ClockUtil.setCurrentTime(new Date(startTime.getTime() + ((60 * 60 * 1000) + 5000)));
// waitForJobExecutorToProcessAllJobs(5000L, 25L);
// assertEquals(0L, jobQuery.count());
// which means the process has ended
assertProcessEnded(pi.getId());
}
//we cannot use waitForExecutor... method since there will always be one job left
private void moveByHours(int hours) throws Exception {
ClockUtil.setCurrentTime(new Date(ClockUtil.getCurrentTime().getTime() + ((hours * 60 * 1000 * 60) + 5000)));
JobExecutor jobExecutor = processEngineConfiguration.getJobExecutor();
jobExecutor.start();
Thread.sleep(1000);
jobExecutor.shutdown();
}
}