/* 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.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.impl.test.PluggableActivitiTestCase;
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.test.Deployment;
/**
* @author Joram Barrez
*/
public class BoundaryTimerEventTest extends PluggableActivitiTestCase {
private static boolean listenerExecutedStartEvent = false;
private static boolean listenerExecutedEndEvent = false;
public static class MyExecutionListener implements ExecutionListener {
private static final long serialVersionUID = 1L;
public void notify(DelegateExecution execution) throws Exception {
if ("end".equals(execution.getEventName())) {
listenerExecutedEndEvent = true;
} else if ("start".equals(execution.getEventName())) {
listenerExecutedStartEvent = true;
}
}
}
/*
* Test for when multiple boundary timer events are defined on the same user
* task
*
* Configuration: - timer 1 -> 2 hours -> secondTask - timer 2 -> 1 hour ->
* thirdTask - timer 3 -> 3 hours -> fourthTask
*
* See process image next to the process xml resource
*/
@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("multipleTimersOnUserTask");
JobQuery jobQuery = managementService.createJobQuery().processInstanceId(pi.getId());
List<Job> jobs = jobQuery.list();
assertEquals(3, jobs.size());
// After setting the clock to time '1 hour and 5 seconds', the second timer should fire
processEngineConfiguration.getClock().setCurrentTime(new Date(startTime.getTime() + ((60 * 60 * 1000) + 5000)));
waitForJobExecutorToProcessAllJobs(5000L, 25L);
assertEquals(0L, jobQuery.count());
// which means that the third task is reached
Task task = taskService.createTaskQuery().singleResult();
assertEquals("Third Task", task.getName());
}
@Deployment
public void testTimerOnNestingOfSubprocesses() {
Date testStartTime = processEngineConfiguration.getClock().getCurrentTime();
runtimeService.startProcessInstanceByKey("timerOnNestedSubprocesses");
List<Task> tasks = taskService.createTaskQuery().orderByTaskName().asc().list();
assertEquals(2, tasks.size());
assertEquals("Inner subprocess task 1", tasks.get(0).getName());
assertEquals("Inner subprocess task 2", tasks.get(1).getName());
// Timer will fire in 2 hours
processEngineConfiguration.getClock().setCurrentTime(new Date(testStartTime.getTime() + ((2 * 60 * 60 * 1000) + 5000)));
Job timer = managementService.createJobQuery().timers().singleResult();
managementService.executeJob(timer.getId());
Task task = taskService.createTaskQuery().singleResult();
assertEquals("task outside subprocess", task.getName());
}
@Deployment
public void testExpressionOnTimer(){
// Set the clock fixed
Date startTime = new Date();
HashMap<String, Object> variables = new HashMap<String, Object>();
variables.put("duration", "PT1H");
// After process start, there should be a timer created
ProcessInstance pi = runtimeService.startProcessInstanceByKey("testExpressionOnTimer", variables);
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 second timer should fire
processEngineConfiguration.getClock().setCurrentTime(new Date(startTime.getTime() + ((60 * 60 * 1000) + 5000)));
waitForJobExecutorToProcessAllJobs(5000L, 25L);
assertEquals(0L, jobQuery.count());
// start execution listener is not executed
assertFalse(listenerExecutedStartEvent);
assertTrue(listenerExecutedEndEvent);
// which means the process has ended
assertProcessEnded(pi.getId());
}
@Deployment
public void testNullExpressionOnTimer(){
HashMap<String, Object> variables = new HashMap<String, Object>();
variables.put("duration", null);
// After process start, there should be a timer created
ProcessInstance pi = runtimeService.startProcessInstanceByKey("testNullExpressionOnTimer", variables);
//NO job scheduled as null expression set
JobQuery jobQuery = managementService.createJobQuery().processInstanceId(pi.getId());
List<Job> jobs = jobQuery.list();
assertEquals(0, jobs.size());
// which means the process is still running waiting for human task input.
ProcessInstance processInstance = processEngine
.getRuntimeService()
.createProcessInstanceQuery()
.processInstanceId(pi.getId())
.singleResult();
assertNotNull(processInstance);
}
@Deployment
public void testTimerInSingleTransactionProcess() {
// make sure that if a PI completes in single transaction, JobEntities associated with the execution are deleted.
// broken before 5.10, see ACT-1133
runtimeService.startProcessInstanceByKey("timerOnSubprocesses");
assertEquals(0, managementService.createJobQuery().count());
}
@Deployment
public void testRepeatingTimerWithCancelActivity() {
runtimeService.startProcessInstanceByKey("repeatingTimerAndCallActivity");
assertEquals(1, managementService.createJobQuery().count());
assertEquals(1, taskService.createTaskQuery().count());
// Firing job should cancel the user task, destroy the scope,
// re-enter the task and recreate the task. A new timer should also be created.
// This didn't happen before 5.11 (new jobs kept being created). See ACT-1427
Job job = managementService.createJobQuery().singleResult();
managementService.executeJob(job.getId());
assertEquals(1, managementService.createJobQuery().count());
assertEquals(1, taskService.createTaskQuery().count());
}
@Deployment
public void testInfiniteRepeatingTimer() throws Exception {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyy.MM.dd hh:mm");
Date currentTime = simpleDateFormat.parse("2015.10.01 11:01");
processEngineConfiguration.getClock().setCurrentTime(currentTime);
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("timerString", "R/2015-10-01T11:00:00/PT24H");
runtimeService.startProcessInstanceByKey("testTimerErrors", vars);
long twentyFourHours = 24L * 60L * 60L * 1000L;
Date previousDueDate = null;
// Move clock, job should fire
for (int i=0; i<30; i++) {
Job job = managementService.createJobQuery().singleResult();
// Verify due date
if (previousDueDate != null) {
assertTrue(job.getDuedate().getTime() - previousDueDate.getTime() >= twentyFourHours);
}
previousDueDate = job.getDuedate();
currentTime = new Date(currentTime.getTime() + twentyFourHours + (60 * 1000));
processEngineConfiguration.getClock().setCurrentTime(currentTime);
managementService.executeJob(managementService.createJobQuery().executable().singleResult().getId());
}
}
@Deployment
public void testRepeatTimerDuration() throws Exception {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyy.MM.dd hh:mm");
Date currentTime = simpleDateFormat.parse("2015.10.01 11:01");
processEngineConfiguration.getClock().setCurrentTime(currentTime);
runtimeService.startProcessInstanceByKey("repeattimertest");
long twentyFourHours = 24L * 60L * 60L * 1000L;
Date previousDueDate = null;
// Move clock, job should fire
for (int i = 0; i < 3; i++) {
Job job = managementService.createJobQuery().singleResult();
// Verify due date
if (previousDueDate != null) {
assertTrue(job.getDuedate().getTime() - previousDueDate.getTime() >= twentyFourHours);
}
previousDueDate = job.getDuedate();
currentTime = new Date(currentTime.getTime() + twentyFourHours + (60 * 1000));
processEngineConfiguration.getClock().setCurrentTime(currentTime);
managementService.executeJob(job.getId());
}
}
@Deployment
public void testBoundaryTimerEvent() throws Exception {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyy.MM.dd hh:mm");
Date currentTime = simpleDateFormat.parse("2015.10.01 11:01");
processEngineConfiguration.getClock().setCurrentTime(currentTime);
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("patient","kermit");
runtimeService.startProcessInstanceByKey("process1", vars);
// just wait for 2 seconds to run any job if it's the case
try {
waitForJobExecutorToProcessAllJobs(2000, 200);
} catch (Exception ex) {
//expected exception because the boundary timer event created a timer job to be executed after 10 minutes
}
// there should be a userTask waiting for user input
List<Task> tasks = taskService.createTaskQuery().list();
assertEquals(1,tasks.size());
assertEquals("First Task",tasks.get(0).getName());
List<Job> jobList = managementService.createJobQuery().list();
assertEquals(1,jobList.size());
// let's see what's happening after 2 minutes
// nothing should change since the timer have to executed after 10 minutes
long twoMinutes = 2L * 60L * 1000L;
currentTime = new Date(currentTime.getTime() + twoMinutes + 1000L);
processEngineConfiguration.getClock().setCurrentTime(currentTime);
try {
waitForJobExecutorToProcessAllJobs(2000, 200);
} catch (Exception ex) {
//expected exception because the boundary timer event created a timer job to be executed after 10 minutes
}
tasks = taskService.createTaskQuery().list();
assertEquals(1,tasks.size());
assertEquals("First Task",tasks.get(0).getName());
jobList = managementService.createJobQuery().list();
assertEquals(1,jobList.size());
// after another 8 minutes (the timer will have to execute because it wasa set to be executed @ 10 minutes after process start)
long tenMinutes = 8L * 60L * 1000L;
currentTime = new Date(currentTime.getTime() + tenMinutes);
processEngineConfiguration.getClock().setCurrentTime(currentTime);
try {
waitForJobExecutorToProcessAllJobs(2000, 200);
} catch (Exception ex) {
ex.getCause();
//expected exception because a new job is prepared
}
// there should be only one userTask and it should be the one triggered by the boundary timer event.
// after the boundary event is triggered there should be no active job.
tasks = taskService.createTaskQuery().list();
assertEquals(1,tasks.size());
assertEquals("Second Task",tasks.get(0).getName());
jobList = managementService.createJobQuery().list();
assertEquals(0,jobList.size());
}
@Deployment
public void testBoundaryTimerEvent2() throws Exception {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyy.MM.dd hh:mm");
Date currentTime = simpleDateFormat.parse("2015.10.01 11:01");
processEngineConfiguration.getClock().setCurrentTime(currentTime);
runtimeService.startProcessInstanceByKey("timerprocess");
// just wait for 2 seconds to run any job if it's the case
try {
waitForJobExecutorToProcessAllJobs(2000, 200);
} catch (Exception ex) {
//expected exception because the boundary timer event created a timer job to be executed after 10 minutes
}
// there should be a userTask waiting for user input
List<Task> tasks = taskService.createTaskQuery().list();
assertEquals(1,tasks.size());
assertEquals("Start",tasks.get(0).getName());
List<Job> jobList = managementService.createJobQuery().list();
assertEquals(1,jobList.size());
// after another 2 minutes
long tenMinutes = 2L * 60L * 1000L;
currentTime = new Date(currentTime.getTime() + tenMinutes);
processEngineConfiguration.getClock().setCurrentTime(currentTime);
try {
waitForJobExecutorToProcessAllJobs(2000, 200);
} catch (Exception ex) {
ex.getCause();
//expected exception because a new job is prepared
}
// there should be no userTask
tasks = taskService.createTaskQuery().list();
assertEquals(0,tasks.size());
jobList = managementService.createJobQuery().list();
assertEquals(0,jobList.size());
}
}