/* 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.api.repository;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.impl.test.PluggableActivitiTestCase;
import org.activiti.engine.impl.util.ClockUtil;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.test.Deployment;
/**
* @author Daniel Meyer
* @author Joram Barrez
*/
public class ProcessDefinitionSuspensionTest extends PluggableActivitiTestCase {
@Deployment(resources={"org/activiti/engine/test/db/processOne.bpmn20.xml"})
public void testProcessDefinitionActiveByDefault() {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
assertFalse(processDefinition.isSuspended());
}
@Deployment(resources={"org/activiti/engine/test/db/processOne.bpmn20.xml"})
public void testSuspendActivateProcessDefinitionById() {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
assertFalse(processDefinition.isSuspended());
// suspend
repositoryService.suspendProcessDefinitionById(processDefinition.getId());
processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
assertTrue(processDefinition.isSuspended());
// activate
repositoryService.activateProcessDefinitionById(processDefinition.getId());
processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
assertFalse(processDefinition.isSuspended());
}
@Deployment(resources={"org/activiti/engine/test/db/processOne.bpmn20.xml"})
public void testSuspendActivateProcessDefinitionByKey() {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
assertFalse(processDefinition.isSuspended());
//suspend
repositoryService.suspendProcessDefinitionByKey(processDefinition.getKey());
processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
assertTrue(processDefinition.isSuspended());
//activate
repositoryService.activateProcessDefinitionByKey(processDefinition.getKey());
processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
assertFalse(processDefinition.isSuspended());
}
@Deployment(resources={"org/activiti/engine/test/db/processOne.bpmn20.xml"})
public void testCannotActivateActiveProcessDefinition() {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
assertFalse(processDefinition.isSuspended());
try {
repositoryService.activateProcessDefinitionById(processDefinition.getId());
fail("Exception exprected");
}catch (ActivitiException e) {
// expected
}
}
@Deployment(resources={"org/activiti/engine/test/db/processOne.bpmn20.xml"})
public void testCannotSuspendActiveProcessDefinition() {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
assertFalse(processDefinition.isSuspended());
repositoryService.suspendProcessDefinitionById(processDefinition.getId());
try {
repositoryService.suspendProcessDefinitionById(processDefinition.getId());
fail("Exception exprected");
}catch (ActivitiException e) {
// expected
}
}
@Deployment(resources={
"org/activiti/engine/test/db/processOne.bpmn20.xml",
"org/activiti/engine/test/db/processTwo.bpmn20.xml"
})
public void testQueryForActiveDefinitions() {
// default = all definitions
List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery().list();
assertEquals(2, processDefinitionList.size());
assertEquals(2, repositoryService.createProcessDefinitionQuery().active().count());
ProcessDefinition processDefinition = processDefinitionList.get(0);
repositoryService.suspendProcessDefinitionById(processDefinition.getId());
assertEquals(2, repositoryService.createProcessDefinitionQuery().count());
assertEquals(1, repositoryService.createProcessDefinitionQuery().active().count());
}
@Deployment(resources={
"org/activiti/engine/test/db/processOne.bpmn20.xml",
"org/activiti/engine/test/db/processTwo.bpmn20.xml"
})
public void testQueryForSuspendedDefinitions() {
// default = all definitions
List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery()
.list();
assertEquals(2, processDefinitionList.size());
assertEquals(2, repositoryService.createProcessDefinitionQuery().active().count());
ProcessDefinition processDefinition = processDefinitionList.get(0);
repositoryService.suspendProcessDefinitionById(processDefinition.getId());
assertEquals(2, repositoryService.createProcessDefinitionQuery().count());
assertEquals(1, repositoryService.createProcessDefinitionQuery().suspended().count());
}
@Deployment(resources={"org/activiti/engine/test/db/processOne.bpmn20.xml"})
public void testStartProcessInstanceForSuspendedProcessDefinition() {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
repositoryService.suspendProcessDefinitionById(processDefinition.getId());
// By id
try {
runtimeService.startProcessInstanceById(processDefinition.getId());
fail("Exception is expected but not thrown");
} catch(ActivitiException e) {
assertTextPresentIgnoreCase("cannot start process instance", e.getMessage());
}
// By Key
try {
runtimeService.startProcessInstanceByKey(processDefinition.getKey());
fail("Exception is expected but not thrown");
} catch(ActivitiException e) {
assertTextPresentIgnoreCase("cannot start process instance", e.getMessage());
}
}
@Deployment(resources={"org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml"})
public void testContinueProcessAfterProcessDefinitionSuspend() {
// Start Process Instance
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
runtimeService.startProcessInstanceByKey(processDefinition.getKey());
// Verify one task is created
Task task = taskService.createTaskQuery().singleResult();
assertNotNull(task);
assertEquals(1, runtimeService.createProcessInstanceQuery().count());
// Suspend process definition
repositoryService.suspendProcessDefinitionById(processDefinition.getId());
// Process should be able to continue
taskService.complete(task.getId());
assertEquals(0, runtimeService.createProcessInstanceQuery().count());
}
@Deployment(resources={"org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml"})
public void testSuspendProcessInstancesDuringProcessDefinitionSuspend() {
int nrOfProcessInstances = 9;
// Fire up a few processes for the deployed process definition
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
for (int i=0; i<nrOfProcessInstances; i++) {
runtimeService.startProcessInstanceByKey(processDefinition.getKey());
}
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().count());
assertEquals(0, runtimeService.createProcessInstanceQuery().suspended().count());
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().active().count());
// Suspend process definitions and include process instances
repositoryService.suspendProcessDefinitionById(processDefinition.getId(), true, null);
// Verify all process instances are also suspended
for (ProcessInstance processInstance : runtimeService.createProcessInstanceQuery().list()) {
assertTrue(processInstance.isSuspended());
}
// Verify all process instances can't be continued
for (Task task : taskService.createTaskQuery().list()) {
try {
taskService.complete(task.getId());
fail("A suspended task shouldn't be able to be continued");
} catch(ActivitiException e) {
// This is good
}
}
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().count());
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().suspended().count());
assertEquals(0, runtimeService.createProcessInstanceQuery().active().count());
// Activate the process definition again
repositoryService.activateProcessDefinitionById(processDefinition.getId(), true, null);
// Verify that all process instances can be completed
for (Task task : taskService.createTaskQuery().list()) {
taskService.complete(task.getId());
}
assertEquals(0, runtimeService.createProcessInstanceQuery().count());
assertEquals(0, runtimeService.createProcessInstanceQuery().suspended().count());
assertEquals(0, runtimeService.createProcessInstanceQuery().active().count());
}
@Deployment(resources={"org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml"})
public void testSubmitStartFormAfterProcessDefinitionSuspend() {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
repositoryService.suspendProcessDefinitionById(processDefinition.getId());
try {
formService.submitStartFormData(processDefinition.getId(), new HashMap<String, String>());
fail();
} catch (ActivitiException e) {
// This is expected
}
try {
formService.submitStartFormData(processDefinition.getId(), "someKey", new HashMap<String, String>());
fail();
} catch (ActivitiException e) {
e.printStackTrace();
// This is expected
}
}
@Deployment
public void testJobIsExecutedOnProcessDefinitionSuspend() {
Date now = new Date();
ClockUtil.setCurrentTime(now);
// Suspending the process definition should not stop the execution of jobs
// Added this test because in previous implementations, this was the case.
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
runtimeService.startProcessInstanceById(processDefinition.getId());
repositoryService.suspendProcessDefinitionById(processDefinition.getId());
assertEquals(1, managementService.createJobQuery().count());
// The jobs should simply be executed
ClockUtil.setCurrentTime(new Date(now.getTime() + (60 * 60 * 1000))); // Timer is set to fire on 5 minutes
waitForJobExecutorToProcessAllJobs(2000L, 100L);
assertEquals(0, managementService.createJobQuery().count());
}
@Deployment(resources={"org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml"})
public void testDelayedSuspendProcessDefinition() {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
Date startTime = new Date();
ClockUtil.setCurrentTime(startTime);
// Suspend process definition in one week from now
long oneWeekFromStartTime = startTime.getTime() + (7 * 24 * 60 * 60 * 1000);
repositoryService.suspendProcessDefinitionById(processDefinition.getId(), false, new Date(oneWeekFromStartTime));
// Verify we can just start process instances
runtimeService.startProcessInstanceById(processDefinition.getId());
assertEquals(1, runtimeService.createProcessInstanceQuery().count());
assertEquals(1, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
// verify there is a job created
assertEquals(1, managementService.createJobQuery().processDefinitionId(processDefinition.getId()).count());
// Move clock 8 days further and let job executor run
long eightDaysSinceStartTime = oneWeekFromStartTime + (24 * 60 * 60 * 1000);
ClockUtil.setCurrentTime(new Date(eightDaysSinceStartTime));
waitForJobExecutorToProcessAllJobs(5000L, 50L);
// verify job is now removed
assertEquals(0, managementService.createJobQuery().processDefinitionId(processDefinition.getId()).count());
// Try to start process instance. It should fail now.
try {
runtimeService.startProcessInstanceById(processDefinition.getId());
fail();
} catch (ActivitiException e) {
assertTextPresentIgnoreCase("suspended", e.getMessage());
}
assertEquals(1, runtimeService.createProcessInstanceQuery().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(1, repositoryService.createProcessDefinitionQuery().suspended().count());
// Activate again
repositoryService.activateProcessDefinitionById(processDefinition.getId());
runtimeService.startProcessInstanceById(processDefinition.getId());
assertEquals(2, runtimeService.createProcessInstanceQuery().count());
assertEquals(1, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
}
@Deployment(resources={"org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml"})
public void testDelayedSuspendProcessDefinitionIncludingProcessInstances() {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
Date startTime = new Date();
ClockUtil.setCurrentTime(startTime);
// Start some process instances
int nrOfProcessInstances = 30;
for (int i=0; i<nrOfProcessInstances; i++) {
runtimeService.startProcessInstanceById(processDefinition.getId());
}
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().count());
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().active().count());
assertEquals(0, runtimeService.createProcessInstanceQuery().suspended().count());
assertEquals(0, taskService.createTaskQuery().suspended().count());
assertEquals(nrOfProcessInstances, taskService.createTaskQuery().active().count());
assertEquals(1, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
// Suspend process definition in one week from now
long oneWeekFromStartTime = startTime.getTime() + (7 * 24 * 60 * 60 * 1000);
repositoryService.suspendProcessDefinitionById(processDefinition.getId(), true, new Date(oneWeekFromStartTime));
// Verify we can start process instances
runtimeService.startProcessInstanceById(processDefinition.getId());
nrOfProcessInstances = nrOfProcessInstances + 1;
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().count());
// Move clock 9 days further and let job executor run
long eightDaysSinceStartTime = oneWeekFromStartTime + (2 * 24 * 60 * 60 * 1000);
ClockUtil.setCurrentTime(new Date(eightDaysSinceStartTime));
waitForJobExecutorToProcessAllJobs(5000L, 50L);
// Try to start process instance. It should fail now.
try {
runtimeService.startProcessInstanceById(processDefinition.getId());
fail();
} catch (ActivitiException e) {
assertTextPresentIgnoreCase("suspended", e.getMessage());
}
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().count());
assertEquals(0, runtimeService.createProcessInstanceQuery().active().count());
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().suspended().count());
assertEquals(nrOfProcessInstances, taskService.createTaskQuery().suspended().count());
assertEquals(0, taskService.createTaskQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(1, repositoryService.createProcessDefinitionQuery().suspended().count());
// Activate again
repositoryService.activateProcessDefinitionById(processDefinition.getId(), true, null);
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().count());
assertEquals(nrOfProcessInstances, runtimeService.createProcessInstanceQuery().active().count());
assertEquals(0, runtimeService.createProcessInstanceQuery().suspended().count());
assertEquals(0, taskService.createTaskQuery().suspended().count());
assertEquals(nrOfProcessInstances, taskService.createTaskQuery().active().count());
assertEquals(1, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
}
@Deployment(resources={"org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml"})
public void testDelayedActivateProcessDefinition() {
Date startTime = new Date();
ClockUtil.setCurrentTime(startTime);
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
repositoryService.suspendProcessDefinitionById(processDefinition.getId());
// Try to start process instance. It should fail now.
try {
runtimeService.startProcessInstanceById(processDefinition.getId());
fail();
} catch (ActivitiException e) {
assertTextPresentIgnoreCase("suspended", e.getMessage());
}
assertEquals(0, runtimeService.createProcessInstanceQuery().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(1, repositoryService.createProcessDefinitionQuery().suspended().count());
// Activate in a day from now
long oneDayFromStart = startTime.getTime() + (24 * 60 * 60 * 1000);
repositoryService.activateProcessDefinitionById(processDefinition.getId(), false, new Date(oneDayFromStart));
// Move clock two days and let job executor run
long twoDaysFromStart = startTime.getTime() + (2 * 24 * 60 * 60 * 1000);
ClockUtil.setCurrentTime(new Date(twoDaysFromStart));
waitForJobExecutorToProcessAllJobs(5000L, 50L);
// Starting a process instance should now succeed
runtimeService.startProcessInstanceById(processDefinition.getId());
assertEquals(1, runtimeService.createProcessInstanceQuery().count());
assertEquals(1, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
}
public void testSuspendMultipleProcessDefinitionsByKey () {
// Deploy three processes
int nrOfProcessDefinitions = 3;
for (int i=0; i<nrOfProcessDefinitions; i++) {
repositoryService.createDeployment()
.addClasspathResource("org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml").deploy();
}
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().count());
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
// Suspend all process definitions with same key
repositoryService.suspendProcessDefinitionByKey("oneTaskProcess");
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().suspended().count());
// Activate again
repositoryService.activateProcessDefinitionByKey("oneTaskProcess");
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().count());
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
// Start process instance
runtimeService.startProcessInstanceByKey("oneTaskProcess");
// And suspend again, cascading to process instances
repositoryService.suspendProcessDefinitionByKey("oneTaskProcess", true, null);
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().suspended().count());
assertEquals(1, runtimeService.createProcessInstanceQuery().suspended().count());
assertEquals(0, runtimeService.createProcessInstanceQuery().active().count());
assertEquals(1, runtimeService.createProcessInstanceQuery().count());
// Clean DB
for (org.activiti.engine.repository.Deployment deployment : repositoryService.createDeploymentQuery().list()) {
repositoryService.deleteDeployment(deployment.getId(), true);
}
}
public void testDelayedSuspendMultipleProcessDefinitionsByKey () {
Date startTime = new Date();
ClockUtil.setCurrentTime(startTime);
final long hourInMs = 60 * 60 * 1000;
// Deploy five versions of the same process
int nrOfProcessDefinitions = 5;
for (int i=0; i<nrOfProcessDefinitions; i++) {
repositoryService.createDeployment()
.addClasspathResource("org/activiti/engine/test/api/runtime/oneTaskProcess.bpmn20.xml").deploy();
}
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().count());
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
// Start process instance
runtimeService.startProcessInstanceByKey("oneTaskProcess");
// Suspend all process definitions with same key in 2 hourse from now
repositoryService.suspendProcessDefinitionByKey("oneTaskProcess", true, new Date(startTime.getTime() + (2 * hourInMs)));
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().count());
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
assertEquals(1, runtimeService.createProcessInstanceQuery().active().count());
// Verify a job is created for each process definition
assertEquals(nrOfProcessDefinitions, managementService.createJobQuery().count());
for (ProcessDefinition processDefinition : repositoryService.createProcessDefinitionQuery().list()) {
assertEquals(1, managementService.createJobQuery().processDefinitionId(processDefinition.getId()).count());
}
// Move time 3 hours and run job executor
ClockUtil.setCurrentTime(new Date(startTime.getTime() + (3 * hourInMs)));
waitForJobExecutorToProcessAllJobs(5000L, 50L);
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().suspended().count());
assertEquals(1, runtimeService.createProcessInstanceQuery().suspended().count());
// Activate again in 5 hourse from now
repositoryService.activateProcessDefinitionByKey("oneTaskProcess", true, new Date(startTime.getTime() + (5 * hourInMs)));
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().suspended().count());
assertEquals(1, runtimeService.createProcessInstanceQuery().suspended().count());
// Move time 6 hours and run job executor
ClockUtil.setCurrentTime(new Date(startTime.getTime() + (6 *hourInMs)));
waitForJobExecutorToProcessAllJobs(5000L, 50L);
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().count());
assertEquals(nrOfProcessDefinitions, repositoryService.createProcessDefinitionQuery().active().count());
assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
assertEquals(1, runtimeService.createProcessInstanceQuery().active().count());
// Clean DB
for (org.activiti.engine.repository.Deployment deployment : repositoryService.createDeploymentQuery().list()) {
repositoryService.deleteDeployment(deployment.getId(), true);
}
}
}