package org.orienteer.bpm;
import org.orienteer.bpm.camunda.OProcessApplicationReference;
import org.orienteer.bpm.camunda.OProcessEngineConfiguration;
import org.orienteer.bpm.camunda.handler.ExecutionEntityHandler;
import org.orienteer.bpm.camunda.handler.HandlersManager;
import org.orienteer.bpm.camunda.handler.TaskEntityHandler;
import org.orienteer.bpm.camunda.handler.UserEntityHandler;
import org.orienteer.core.OrienteerWebApplication;
import org.orienteer.core.module.IOrienteerModule;
import org.orienteer.junit.OrienteerTestRunner;
import org.orienteer.junit.OrienteerTester;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import org.camunda.bpm.BpmPlatform;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.ProcessEngineException;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.externaltask.ExternalTask;
import org.camunda.bpm.engine.externaltask.LockedExternalTask;
import org.camunda.bpm.engine.impl.cfg.IdGenerator;
import org.camunda.bpm.engine.impl.jobexecutor.JobExecutor;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;
import org.camunda.bpm.engine.impl.util.ClockUtil;
import org.camunda.bpm.engine.runtime.Execution;
import org.camunda.bpm.engine.runtime.Job;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.engine.test.Deployment;
import org.camunda.bpm.engine.test.ProcessEngineRule;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.Message;
import org.camunda.bpm.model.bpmn.instance.Process;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.sun.jna.platform.win32.WinNT.LOGICAL_PROCESSOR_RELATIONSHIP;
import junit.framework.AssertionFailedError;
@RunWith(OrienteerTestRunner.class)
@Singleton
public class TestBPMModule {
private static final Logger LOG = LoggerFactory.getLogger(TestBPMModule.class);
@Inject
private OrienteerTester tester;
@Rule
public ProcessEngineRule processEngineRule = new ProcessEngineRule(
BpmPlatform.getProcessEngineService().getDefaultProcessEngine());
@Test
public void testModuleLoaded() {
OrienteerWebApplication app = tester.getApplication();
assertNotNull(app);
IOrienteerModule module = app.getModuleByName("bpm");
assertNotNull(module);
assertTrue(module instanceof BPMModule);
}
@Test
public void testDeployProcess() {
BpmnModelInstance model = Bpmn.createExecutableProcess("testProcess").done();
Message message1 = model.newInstance(Message.class);
message1.setName("orderCancelled");
model.getDefinitions().addChildElement(message1);
Message message2 = model.newInstance(Message.class);
message2.setName("orderCompleted");
model.getDefinitions().addChildElement(message2);
BpmnModelInstance theProcess = model.<Process> getModelElementById("testProcess").builder().startEvent()
.parallelGateway().receiveTask().message(message1).endEvent().moveToLastGateway().receiveTask()
.message(message2).endEvent().done();
ProcessEngine processEngine = processEngineRule.getProcessEngine();
org.camunda.bpm.engine.repository.Deployment deployment = processEngine.getRepositoryService()
.createDeployment().addModelInstance("test.bpmn", theProcess).deploy();
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("testVar", "testVarValue");
ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey("testProcess",
vars);
String varValue = (String) processEngine.getRuntimeService().getVariable(processInstance.getId(), "testVar");
assertEquals("testVarValue", varValue);
processEngine.getRuntimeService().setVariable(processInstance.getId(), "testVar2", new Boolean(true));
Boolean varValue2 = (Boolean) processEngine.getRuntimeService().getVariable(processInstance.getId(),
"testVar2");
assertEquals(new Boolean(true), varValue2);
List<Execution> executions = processEngine.getRuntimeService().createExecutionQuery()
.processInstanceId(processInstance.getId()).list();
String executionId = null;
for (Execution execution : executions) {
if (!execution.getId().equals(processInstance.getId())) {
executionId = execution.getId();
LOG.info("Creating local variable for execution id: " + executionId);
processEngine.getRuntimeService().setVariableLocal(executionId, "testVarLocal", "testVarLocalValue");
break;
}
}
assertNotNull(executionId);
String varValueLocal = (String) processEngine.getRuntimeService().getVariableLocal(executionId, "testVarLocal");
assertEquals("testVarLocalValue", varValueLocal);
processEngine.getRuntimeService().createMessageCorrelation("orderCancelled")
.processInstanceId(processInstance.getId()).correlate();
processEngine.getRuntimeService().createMessageCorrelation("orderCompleted")
.processInstanceId(processInstance.getId()).correlate();
assertProcessEnded(processInstance.getId());
processEngine.getRepositoryService().deleteDeployment(deployment.getId(), true);
}
@Test
@Deployment(resources = { "example.bpmn" })
public void testEndProcessByCancelMessage() {
RuntimeService runtimeService = processEngineRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process_1");
assertProcessNotEnded(processInstance.getId());
runtimeService.createMessageCorrelation("Message-Cancel").processInstanceId(processInstance.getId())
.correlate();
}
@Test
@Deployment(resources = { "example-simple.bpmn" })
public void testEndProcessByCancelMessageSimple() {
RuntimeService runtimeService = processEngineRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process_1");
assertProcessNotEnded(processInstance.getId());
runtimeService.createMessageCorrelation("Message-Approve").processInstanceId(processInstance.getId())
.correlate();
assertProcessEnded(processInstance.getId());
}
@Test
@Deployment(resources = { "example-sequence.bpmn" })
public void testEndProcessByCancelMessageSequence() {
RuntimeService runtimeService = processEngineRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process_1");
assertProcessNotEnded(processInstance.getId());
runtimeService.createMessageCorrelation("Message-Request").processInstanceId(processInstance.getId())
.correlate();
assertProcessNotEnded(processInstance.getId());
runtimeService.createMessageCorrelation("Message-Approve").processInstanceId(processInstance.getId())
.correlate();
assertProcessEnded(processInstance.getId());
}
@Test
@Deployment(resources = { "example-sequence.bpmn" })
public void testCorrelateByMessageName() {
RuntimeService runtimeService = processEngineRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process_1");
assertProcessNotEnded(processInstance.getId());
// correlate by message name
runtimeService.createMessageCorrelation("Message-Request").correlate();
assertProcessNotEnded(processInstance.getId());
// correlate by message name and process id
runtimeService.createMessageCorrelation("Message-Approve").processInstanceId(processInstance.getId())
.correlate();
assertProcessEnded(processInstance.getId());
}
@Test
@Deployment(resources = { "example-sequence.bpmn" })
public void testCorrelateByBusinessKey() {
RuntimeService runtimeService = processEngineRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process_1", "business key");
assertProcessNotEnded(processInstance.getId());
runtimeService.createMessageCorrelation("Message-Request")
.processInstanceBusinessKey(processInstance.getBusinessKey()).correlate();
assertProcessNotEnded(processInstance.getId());
runtimeService.createMessageCorrelation(null).processInstanceBusinessKey(processInstance.getBusinessKey())
.correlateAll();
assertProcessEnded(processInstance.getId());
}
@Test
@Deployment(resources = { "example-sequence.bpmn" })
public void testCorrelateByVariables() {
RuntimeService runtimeService = processEngineRule.getRuntimeService();
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("testString", "testVarString");
vars.put("testBoolean", new Boolean(true));
vars.put("testLong", new Long(15));
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process_1", vars);
assertProcessNotEnded(processInstance.getId());
runtimeService.createMessageCorrelation("Message-Request")
.processInstanceVariableEquals("testString", "testVarString").correlate();
assertProcessNotEnded(processInstance.getId());
runtimeService.createMessageCorrelation(null).processInstanceVariableEquals("testString", "NonExisting")
.correlateAll();
assertProcessNotEnded(processInstance.getId());
runtimeService.createMessageCorrelation(null).processInstanceVariableEquals("testString", "testVarString")
.correlate();
assertProcessEnded(processInstance.getId());
}
@Test
@Deployment(resources = { "loop.bpmn" })
public void testLoop() {
RuntimeService runtimeService = processEngineRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process_1");
for (int i = 0; i < 2; i++) {
runtimeService.createMessageCorrelation("continue").processInstanceId(processInstance.getId())
.correlateAll();
if (i % 10 == 0) {
LOG.info("Iteration: " + i);
}
}
runtimeService.createMessageCorrelation("stop").processInstanceId(processInstance.getId()).correlateAll();
assertProcessEnded(processInstance.getId());
}
@Test
@Deployment(resources = { "asynch-test.bpmn" })
public void testParallelExecution() throws InterruptedException {
AsynchTestDelegate.resetExecuted();
ProcessInstance processInstance = processEngineRule.getRuntimeService().startProcessInstanceByKey("asynchtest");
// describeProcess(processInstance);
waitForJobExecutorToProcessAllJobs(10000);
// assertEquals(2, AsynchTestDelegate.getExecuted());
assertTrue(AsynchTestDelegate.getExecuted()>=2);
// waitForProcessCompletion(processInstance.getProcessInstanceId(),
// 20000);
assertProcessEnded(processInstance.getId(), true);
}
/**
* Test external task entities
*/
@Test
@Deployment(resources = {"external-task.bpmn"})
public void testExternalTask() {
ProcessInstance processInstance = processEngineRule.getRuntimeService().startProcessInstanceByKey("externaltask");
assertProcessNotEnded(processInstance.getId());
List<ExternalTask> tasks = processEngineRule.getExternalTaskService().createExternalTaskQuery()
.topicName("ExternalTopic")
.processInstanceId(processInstance.getId()).list();
assertEquals(1, tasks.size());
List<LockedExternalTask> lockedTasks = processEngineRule.getExternalTaskService().fetchAndLock(100, "JUnit")
.topic("ExternalTopic", 5000).execute();
assertFalse(lockedTasks.isEmpty());
for(LockedExternalTask task : lockedTasks) {
processEngineRule.getExternalTaskService().complete(task.getId(), "JUnit");
}
tasks = processEngineRule.getExternalTaskService().createExternalTaskQuery()
.topicName("ExternalTopic")
.processInstanceId(processInstance.getId()).list();
assertTrue(tasks.isEmpty());
assertProcessEnded(processInstance.getId());
}
@Test
@Deployment(resources = {"user-task.bpmn"})
public void testUserTask() {
ProcessInstance processInstance = processEngineRule.getRuntimeService().startProcessInstanceByKey("user-task");
assertProcessNotEnded(processInstance.getId());
ODatabaseDocument db = tester.getDatabase();
for(ODocument doc : db.browseClass(TaskEntityHandler.OCLASS_NAME)){
System.out.println("Task: "+doc);
}
List<Task> tasks = processEngineRule.getTaskService().createTaskQuery().taskAssignee("admin").processInstanceId(processInstance.getId()).list();
assertNotNull(tasks);
assertFalse(tasks.isEmpty());
assertEquals(1, tasks.size());
tasks = processEngineRule.getTaskService().createTaskQuery().taskCandidateGroup("writer").processInstanceId(processInstance.getId()).list();
assertNotNull(tasks);
assertFalse(tasks.isEmpty());
assertEquals(1, tasks.size());
Task task = tasks.get(0);
processEngineRule.getTaskService().complete(task.getId());
assertProcessEnded(processInstance.getId());
}
private static boolean touchedFromScript = false;
public static void touchFromScript() {
touchedFromScript = true;
}
@Test
@Deployment(resources = {"execute-script.bpmn"})
public void testExecuteScriptSimple() {
touchedFromScript=false;
Map<String, Object> variables = new HashMap<>();
variables.put("script", "org.orienteer.bpm.TestBPMModule.touchFromScript();");
ProcessInstance processInstance = processEngineRule.getRuntimeService().startProcessInstanceByKey("execute-script", variables);
assertProcessEnded(processInstance.getId());
assertTrue(touchedFromScript);
}
@Test
@Deployment(resources = {"execute-script.bpmn"})
public void testExecuteOrientDBScript() {
touchedFromScript=false;
Map<String, Object> variables = new HashMap<>();
variables.put("script", "org.orienteer.bpm.TestBPMModule.touchFromScript();");
ProcessInstance processInstance = processEngineRule.getRuntimeService().startProcessInstanceByKey("execute-script", variables);
assertProcessEnded(processInstance.getId());
assertTrue(touchedFromScript);
}
private static class InterruptTask extends TimerTask {
protected boolean timeLimitExceeded = false;
protected Thread thread;
public InterruptTask(Thread thread) {
this.thread = thread;
}
public boolean isTimeLimitExceeded() {
return timeLimitExceeded;
}
@Override
public void run() {
timeLimitExceeded = true;
thread.interrupt();
}
}
public boolean areJobsAvailable() {
List<Job> list = processEngineRule.getManagementService().createJobQuery().list();
for (Job job : list) {
if (!job.isSuspended() && job.getRetries() > 0
&& (job.getDuedate() == null || ClockUtil.getCurrentTime().after(job.getDuedate()))) {
return true;
}
}
return false;
}
public void waitForJobExecutorToProcessAllJobs(long maxMillisToWait) {
long intervalMillis = 1000;
Timer timer = new Timer();
InterruptTask task = new InterruptTask(Thread.currentThread());
timer.schedule(task, maxMillisToWait);
boolean areJobsAvailable = true;
try {
while (areJobsAvailable && !task.isTimeLimitExceeded()) {
Thread.sleep(intervalMillis);
try {
areJobsAvailable = areJobsAvailable();
} catch (Throwable t) {
// Ignore, possible that exception occurs due to
// locking/updating of table on MSSQL when
// isolation level doesn't allow READ of the table
}
}
} catch (InterruptedException e) {
} finally {
timer.cancel();
}
if (areJobsAvailable) {
throw new ProcessEngineException("time limit of " + maxMillisToWait + " was exceeded");
}
}
public void waitForProcessCompletion(String processIsntanceId, long maxMillisToWait) {
long intervalMillis = 500;
Timer timer = new Timer();
InterruptTask task = new InterruptTask(Thread.currentThread());
timer.schedule(task, maxMillisToWait);
boolean isProcessFinished = isProcessFinished(processIsntanceId);
try {
while (!isProcessFinished && !task.isTimeLimitExceeded()) {
Thread.sleep(intervalMillis);
try {
isProcessFinished = isProcessFinished(processIsntanceId);
} catch (Throwable t) {
// Ignore, possible that exception occurs due to
// locking/updating of table on MSSQL when
// isolation level doesn't allow READ of the table
}
}
} catch (InterruptedException e) {
} finally {
timer.cancel();
}
if (!isProcessFinished) {
throw new ProcessEngineException(
"Process not finished: time limit of " + maxMillisToWait + " was exceeded");
}
}
public boolean isProcessFinished(String processInstanceId) {
ProcessInstance processInstance = processEngineRule.getProcessEngine().getRuntimeService()
.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
return processInstance == null || processInstance.isEnded();
}
public void assertProcessNotEnded(String processInstanceId) {
ProcessInstance processInstance = processEngineRule.getProcessEngine().getRuntimeService()
.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (processInstance == null) {
throw new AssertionFailedError(
"Expected not finished process instance '" + processInstanceId + "' but it was not in the db");
}
}
public void assertProcessEnded(String processInstanceId) {
assertProcessEnded(processInstanceId, false);
}
public void assertProcessEnded(String processInstanceId, boolean soft) {
ProcessInstance processInstance = processEngineRule.getProcessEngine().getRuntimeService()
.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (processInstance != null && (!soft || !processInstance.isEnded())) {
throw new AssertionFailedError(
"expected finished process instance '" + processInstanceId + "' but it was still in the db");
}
}
}