/*
* Copyright 2014 Effektif GmbH.
*
* 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 com.effektif.workflow.test;
import com.effektif.workflow.api.Configuration;
import com.effektif.workflow.api.WorkflowEngine;
import com.effektif.workflow.api.activities.JavaServiceTask;
import com.effektif.workflow.api.model.Deployment;
import com.effektif.workflow.api.model.Message;
import com.effektif.workflow.api.model.TriggerInstance;
import com.effektif.workflow.api.query.WorkflowInstanceQuery;
import com.effektif.workflow.api.query.WorkflowQuery;
import com.effektif.workflow.api.workflow.ExecutableWorkflow;
import com.effektif.workflow.api.workflowinstance.ActivityInstance;
import com.effektif.workflow.api.workflowinstance.ScopeInstance;
import com.effektif.workflow.api.workflowinstance.WorkflowInstance;
import com.effektif.workflow.impl.WorkflowInstanceStore;
import com.effektif.workflow.impl.WorkflowStore;
import com.effektif.workflow.impl.job.Job;
import com.effektif.workflow.impl.job.JobStore;
import com.effektif.workflow.impl.json.JsonStreamMapper;
import com.effektif.workflow.impl.memory.TestConfiguration;
import com.effektif.workflow.impl.workflowinstance.WorkflowInstanceImpl;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/** Base class that allows to reuse tests and run them on different process engines. */
public class WorkflowTest {
public static final String FORM_INSTANCE_KEY = "formInstance";
public static String JOHN_ID = "john";
public static String MARY_ID = "mary";
public static String JACK_ID = "jack";
public static String DEV_ID = "dev";
public static String OPS_ID = "ops";
public static String TESTING_ID = "testing";
public static final Logger log = LoggerFactory.getLogger(WorkflowTest.class);
public static Configuration cachedConfiguration = null;
private static List<String> messages = null;
protected Configuration configuration = null;
protected WorkflowEngine workflowEngine = null;
@Rule public TestName name = new TestName();
@Before
public void initializeWorkflowEngine() {
log.debug("\n\n###### Test "+getClass().getSimpleName()+".class, \""+name.getMethodName()+"\" starting ######################################################## \n");
if (workflowEngine==null) {
if (cachedConfiguration==null) {
cachedConfiguration = createConfiguration();
}
configuration = cachedConfiguration;
workflowEngine = configuration.getWorkflowEngine();
}
}
@Before
public void initializeMessages() {
messages = new ArrayList<>();
}
public TestConfiguration createConfiguration() {
TestConfiguration testConfiguration = new TestConfiguration();
testConfiguration.get(JsonStreamMapper.class).pretty();
testConfiguration.start();
return testConfiguration;
}
@After
public void after() {
if (configuration!=null) {
logWorkflowEngineContents();
deleteWorkflowEngineContents();
}
}
public String getMessage(int index) {
return messages.get(index);
}
public List<String> getMessages() {
return messages;
}
@SuppressWarnings("unused") // invoked dynamically with reflection
private static void recordMessage(String message) {
messages.add(message);
}
public JavaServiceTask msgValue(String message) {
return new JavaServiceTask()
.javaClass(WorkflowTest.class)
.methodName("recordMessage")
.argValue(message);
}
public JavaServiceTask msgExpression(String messageExpression) {
return new JavaServiceTask()
.javaClass(WorkflowTest.class)
.methodName("recordMessage")
.argExpression(messageExpression);
}
public Deployment deploy(ExecutableWorkflow workflow) {
Deployment deployment = workflowEngine.deployWorkflow(workflow);
deployment.checkNoErrors();
workflow.setId(deployment.getWorkflowId());
return deployment;
}
public TriggerInstance createTriggerInstance(ExecutableWorkflow workflow) {
return new TriggerInstance().workflowId(workflow.getId());
}
public WorkflowInstance start(ExecutableWorkflow workflow) {
return workflowEngine.start(new TriggerInstance()
.workflowId(workflow.getId()));
}
public WorkflowInstance start(TriggerInstance triggerInstance) {
return workflowEngine.start(triggerInstance);
}
public WorkflowInstance sendMessage(WorkflowInstance workflowInstance, String activityInstanceId) {
return workflowEngine.send(new Message()
.workflowInstanceId(workflowInstance.getId())
.activityInstanceId(activityInstanceId));
}
public static void assertOpen(WorkflowInstance workflowInstance, String... expectedActivityNames) {
Map<String,Integer> expectedActivityCounts = new HashMap<String, Integer>();
if (expectedActivityNames!=null) {
for (String expectedActivityName: expectedActivityNames) {
Integer count = expectedActivityCounts.get(expectedActivityName);
expectedActivityCounts.put(expectedActivityName, count!=null ? count+1 : 1);
}
}
Map<String,Integer> activityCounts = new HashMap<String, Integer>();
scanActivityCounts(workflowInstance, activityCounts);
assertEquals("activity counts", expectedActivityCounts, activityCounts);
}
static void scanActivityCounts(ScopeInstance scopeInstance, Map<String, Integer> activityCounts) {
List< ? extends ActivityInstance> activityInstances = scopeInstance.getActivityInstances();
if (activityInstances!=null) {
for (ActivityInstance activityInstance : activityInstances) {
if (!activityInstance.isEnded()) {
Object activityId = activityInstance.getActivityId();
Integer count = activityCounts.get(activityId);
activityCounts.put(activityId.toString(), count != null ? count + 1 : 1);
scanActivityCounts(activityInstance, activityCounts);
}
}
}
}
public static String getActivityInstanceId(WorkflowInstance workflowInstance, String activityId) {
ActivityInstance activityInstance = workflowInstance.findOpenActivityInstance(activityId);
Assert.assertNotNull("No open activity instance found "+activityId+" not found", activityInstance);
return activityInstance.getId();
}
public WorkflowInstance endTask(WorkflowInstance workflowInstance, String activityId) {
ActivityInstance activityInstance = workflowInstance.findOpenActivityInstance(activityId);
assertNotNull("Activity '"+activityId+"' not in workflow instance", activityInstance);
return workflowEngine.send(new Message()
.workflowInstanceId(workflowInstance.getId())
.activityInstanceId(activityInstance.getId()));
}
protected void logWorkflowEngineContents() {
try {
log.debug("\n\n###### Test "+getClass().getSimpleName()+"."+name+" ending ######################################################## \n");
JsonStreamMapper jsonMapper = configuration.get(JsonStreamMapper.class);
WorkflowStore workflowStore = configuration.get(WorkflowStore.class);
WorkflowInstanceStore workflowInstanceStore = configuration.get(WorkflowInstanceStore.class);
JobStore jobStore = configuration.get(JobStore.class);
// TaskStore taskStore = configuration.get(TaskStore.class);
StringBuilder cleanLog = new StringBuilder();
cleanLog.append("Workflow engine contents\n");
List<Job> jobs = jobStore.findAllJobs();
if (jobs != null && !jobs.isEmpty()) {
int i = 0;
cleanLog.append("\n=== jobs ======================================================== \n");
for (Job job : jobs) {
cleanLog.append("--- Job ");
cleanLog.append(i);
cleanLog.append(" ---\n");
cleanLog.append(jsonMapper.write(job));
cleanLog.append("\n");
i++;
}
}
List<WorkflowInstanceImpl> workflowInstances = workflowInstanceStore.findWorkflowInstances(new WorkflowInstanceQuery());
if (workflowInstances != null && !workflowInstances.isEmpty()) {
int i = 0;
cleanLog.append("\n\n=== workflowInstances ================================================ \n");
for (WorkflowInstanceImpl workflowInstance : workflowInstances) {
cleanLog.append("--- Workflow instance ");
cleanLog.append(i);
cleanLog.append(" ---\n");
cleanLog.append(jsonMapper.write(workflowInstance.toWorkflowInstance()));
cleanLog.append("\n");
i++;
}
}
List<ExecutableWorkflow> workflows = workflowStore.findWorkflows(new WorkflowQuery());
if (workflows != null && !workflows.isEmpty()) {
int i = 0;
cleanLog.append("\n=== workflows ======================================================== \n");
for (ExecutableWorkflow workflow : workflows) {
cleanLog.append("--- Deleted workflow ");
cleanLog.append(i);
cleanLog.append(" ---\n");
cleanLog.append(jsonMapper.write(workflow));
cleanLog.append("\n");
i++;
}
}
log.debug(cleanLog.toString());
} catch (Exception e) {
log.error("ERROR in test "+getClass().getName()+"."+name, e);
}
}
protected void deleteWorkflowEngineContents() {
WorkflowStore workflowStore = configuration.get(WorkflowStore.class);
WorkflowInstanceStore workflowInstanceStore = configuration.get(WorkflowInstanceStore.class);
JobStore jobStore = configuration.get(JobStore.class);
workflowStore.deleteAllWorkflows();
workflowInstanceStore.deleteAllWorkflowInstances();
jobStore.deleteAllJobs();
jobStore.deleteAllArchivedJobs();
}
}