/*
* Copyright 2015 herd contributors
*
* 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.finra.herd.service.activiti.task;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.List;
import java.util.Map;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FieldExtension;
import org.activiti.bpmn.model.ServiceTask;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.runtime.Execution;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.finra.herd.model.api.xml.Job;
import org.finra.herd.model.api.xml.Parameter;
import org.finra.herd.service.AbstractServiceTest;
import org.finra.herd.service.activiti.ActivitiRuntimeHelper;
/**
* Base class to tests the Activiti tasks for services.
*/
public abstract class HerdActivitiServiceTaskTest extends AbstractServiceTest
{
private static Logger LOGGER = LoggerFactory.getLogger(HerdActivitiServiceTaskTest.class);
private final String serviceTaskId = "testServiceTask";
public final String VARIABLE_VALUE_NOT_NULL = "NOT_NULL";
public final String VARIABLE_VALUE_IS_NULL = "IS_NULL";
protected FieldExtension buildFieldExtension(String name, String expression)
{
FieldExtension exceptionField = new FieldExtension();
exceptionField.setFieldName(name);
exceptionField.setExpression(expression);
return exceptionField;
}
protected Parameter buildParameter(String name, String value)
{
return new Parameter(name, value);
}
protected String buildActivitiXml(String implementation, List<FieldExtension> fieldExtensionList) throws Exception
{
BpmnModel bpmnModel = getBpmnModelForXmlResource(ACTIVITI_XML_TEST_SERVICE_TASK_WITH_CLASSPATH);
ServiceTask serviceTask = (ServiceTask) bpmnModel.getProcesses().get(0).getFlowElement(serviceTaskId);
serviceTask.setImplementation(implementation);
serviceTask.getFieldExtensions().addAll(fieldExtensionList);
return getActivitiXmlFromBpmnModel(bpmnModel);
}
protected Job testActivitiServiceTaskSuccess(String implementation, List<FieldExtension> fieldExtensionList, List<Parameter> parameters,
Map<String, Object> variableValuesToValidate) throws Exception
{
String activitiXml = buildActivitiXml(implementation, fieldExtensionList);
return createJobAndCheckTaskStatusSuccess(activitiXml, parameters, variableValuesToValidate);
}
private Job createJobAndCheckTaskStatusSuccess(String activitiXml, List<Parameter> parameters, Map<String, Object> variableValuesToValidate)
throws Exception
{
Job job = jobServiceTestHelper.createJobFromActivitiXml(activitiXml, parameters);
assertNotNull(job);
HistoricProcessInstance hisInstance =
activitiHistoryService.createHistoricProcessInstanceQuery().processInstanceId(job.getId()).includeProcessVariables().singleResult();
Map<String, Object> variables = hisInstance.getProcessVariables();
String serviceTaskStatus = (String) variables.get(getServiceTaskVariableName(ActivitiRuntimeHelper.VARIABLE_STATUS));
assertEquals(ActivitiRuntimeHelper.TASK_STATUS_SUCCESS, serviceTaskStatus);
if (variableValuesToValidate != null)
{
for (Map.Entry<String, Object> varEntry : variableValuesToValidate.entrySet())
{
Object wfVariableValue = variables.get(getServiceTaskVariableName(varEntry.getKey()));
Object expectedVariableValue = varEntry.getValue();
if (expectedVariableValue.equals(VARIABLE_VALUE_NOT_NULL))
{
assertNotNull(wfVariableValue);
}
else if (expectedVariableValue.equals(VARIABLE_VALUE_IS_NULL))
{
assertNull(wfVariableValue);
}
else
{
assertEquals(expectedVariableValue, wfVariableValue);
}
}
}
return job;
}
protected Job testActivitiServiceTaskFailure(String implementation, List<FieldExtension> fieldExtensionList, List<Parameter> parameters,
Map<String, Object> variableValuesToValidate) throws Exception
{
String activitiXml = buildActivitiXml(implementation, fieldExtensionList);
return createJobAndCheckTaskStatusFailure(activitiXml, parameters, variableValuesToValidate);
}
private Job createJobAndCheckTaskStatusFailure(String activitiXml, List<Parameter> parameters, Map<String, Object> variableValuesToValidate)
throws Exception
{
Job job = jobServiceTestHelper.createJobFromActivitiXml(activitiXml, parameters);
assertNotNull(job);
HistoricProcessInstance hisInstance =
activitiHistoryService.createHistoricProcessInstanceQuery().processInstanceId(job.getId()).includeProcessVariables().singleResult();
Map<String, Object> variables = hisInstance.getProcessVariables();
String serviceTaskStatus = (String) variables.get(getServiceTaskVariableName(ActivitiRuntimeHelper.VARIABLE_STATUS));
assertEquals(ActivitiRuntimeHelper.TASK_STATUS_ERROR, serviceTaskStatus);
if (variableValuesToValidate != null)
{
for (Map.Entry<String, Object> varEntry : variableValuesToValidate.entrySet())
{
Object wfVariableValue = variables.get(getServiceTaskVariableName(varEntry.getKey()));
Object expectedVariableValue = varEntry.getValue();
if (expectedVariableValue.equals(VARIABLE_VALUE_NOT_NULL))
{
assertNotNull(wfVariableValue);
}
else if (expectedVariableValue.equals(VARIABLE_VALUE_IS_NULL))
{
assertNull(wfVariableValue);
}
else
{
assertEquals(expectedVariableValue, wfVariableValue);
}
}
}
return job;
}
protected String getServiceTaskVariableName(String variableName)
{
return serviceTaskId + ActivitiRuntimeHelper.TASK_VARIABLE_MARKER + variableName;
}
/**
* Blocks the current calling thread until ALL processes are considered not active. This method will timeout with an assertion error if the waiting takes
* longer than 10,000ms. This is a reasonable amount of time for the JUnits that use this method.
*/
protected void waitUntilAllProcessCompleted()
{
long startTime = System.currentTimeMillis();
// Run while there is at least 1 active instance
while (activitiRuntimeService.createProcessInstanceQuery().active().count() > 0)
{
long currentTime = System.currentTimeMillis();
long elapsedTime = currentTime - startTime;
// If time spent waiting is longer than 15,000 ms
if (elapsedTime > 15000)
{
// Dump the current runtime variables into the error log to make it easier to debug
StringBuilder builder = new StringBuilder("dumping workflow variables due to error:\n");
List<Execution> executions = activitiRuntimeService.createExecutionQuery().list();
for (Execution execution : executions)
{
Map<String, Object> executionVariables = activitiRuntimeService.getVariables(execution.getId());
builder.append(execution).append('\n');
for (Map.Entry<String, Object> variable : executionVariables.entrySet())
{
builder.append(variable).append('\n');
}
}
LOGGER.error(builder.toString());
// Fail assertion
Assert.fail("The test did not finished in the specified timeout (15s). See error logs for variable dump.");
}
}
}
}