Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
gclaussn committed May 11, 2024
1 parent 817520a commit f4471fc
Show file tree
Hide file tree
Showing 22 changed files with 485 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package org.camunda.community.bpmndt;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.camunda.community.bpmndt.model.BpmnElement;
import org.camunda.community.bpmndt.model.BpmnElementScope;
import org.camunda.community.bpmndt.model.TestCase;

public class TestCaseContext {

private final List<BpmnElement> multiInstances = new LinkedList<>();
private final List<BpmnElementScope> multiInstanceScopes = new LinkedList<>();
private final Map<String, GeneratorStrategy> strategies = new HashMap<>();

private String className;
Expand All @@ -16,6 +22,14 @@ public class TestCaseContext {
private String resourceName;
private TestCase testCase;

public void addMultiInstance(BpmnElement element) {
multiInstances.add(element);
}

public void addMultiInstanceScope(BpmnElementScope scope) {
multiInstanceScopes.add(scope);
}

public void addStrategy(GeneratorStrategy strategy) {
strategies.put(strategy.getElement().getId(), strategy);
}
Expand All @@ -29,6 +43,14 @@ public String getClassName() {
return className;
}

public List<BpmnElement> getMultiInstances() {
return multiInstances;
}

public List<BpmnElementScope> getMultiInstanceScopes() {
return multiInstanceScopes;
}

public String getName() {
return name;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ void apply(TestCaseInstance instance, long processInstanceKey) {
}

if (variables != null) {
instance.client.newCompleteCommand(job.key).variables(variables).send();
instance.getClient().newCompleteCommand(job.key).variables(variables).send();
} else {
instance.client.newCompleteCommand(job.key).variables(variableMap).send();
instance.getClient().newCompleteCommand(job.key).variables(variableMap).send();
}

instance.hasPassed(processInstanceKey, element.id);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package org.camunda.community.bpmndt.api;

import java.util.function.BiConsumer;
import java.util.function.Consumer;

import org.camunda.community.bpmndt.api.TestCaseInstanceElement.MultiInstanceElement;

import io.camunda.zeebe.process.test.assertions.BpmnAssert;
import io.camunda.zeebe.process.test.assertions.ProcessInstanceAssert;

/**
* Fluent API to handle multi instances and multi instance scopes, using custom code.
*/
public class CustomMultiInstanceHandler {

private final MultiInstanceElement element;

private Consumer<ProcessInstanceAssert> verifier;
private BiConsumer<TestCaseInstance, Long> action;

private Boolean expectedSequential;

public CustomMultiInstanceHandler(MultiInstanceElement element) {
this.element = element;
}

void apply(TestCaseInstance instance, long processInstanceKey) {
if (verifier != null) {
verifier.accept(new ProcessInstanceAssert(processInstanceKey, BpmnAssert.getRecordStream()));
}

if (expectedSequential != null && expectedSequential != element.sequential) {
var message = "expected multi instance %s to be %s, but was %s";
throw new AssertionError(String.format(message, element.id, getText(expectedSequential), getText(element.sequential)));
}

if (action != null) {
action.accept(instance, processInstanceKey);
}
}

/**
* Executes a custom action that handles the multi instance or the multi instance scope.
*
* @param action A specific action that accepts a {@link TestCaseInstance} and the related process instance key.
*/
public void execute(BiConsumer<TestCaseInstance, Long> action) {
if (action == null) {
throw new IllegalArgumentException("action is null");
}
this.action = action;
}

/**
* Verifies the multi instance state.
* <p>
* <b>Please note</b>: An application specific job worker may have already completed the related job and updated some variables.
*
* @param verifier Verifier that accepts an {@link ProcessInstanceAssert} instance.
* @return The handler.
*/
public CustomMultiInstanceHandler verify(Consumer<ProcessInstanceAssert> verifier) {
this.verifier = verifier;
return this;
}

/**
* Verifies that the multi instance loop execution is done in parallel.
*
* @return The handler.
*/
public CustomMultiInstanceHandler verifyParallel() {
this.expectedSequential = Boolean.FALSE;
return this;
}

/**
* Verifies that the multi instance loop is sequentially executed.
*
* @return The handler.
*/
public CustomMultiInstanceHandler verifySequential() {
this.expectedSequential = Boolean.TRUE;
return this;
}

private String getText(boolean sequential) {
return sequential ? "sequential" : "parallel";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void apply(TestCaseInstance instance, long processInstanceKey) {
}

if (action != null) {
action.accept(instance.client, job.key);
action.accept(instance.getClient(), job.key);

if (element.errorCode == null) {
instance.hasPassed(processInstanceKey, element.id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void apply(TestCaseInstance instance, long processInstanceKey) {
messageNameConsumer.accept(messageSubscription.messageName);
}

action.correlate(instance.client, messageSubscription.messageName, messageSubscription.correlationKey);
action.correlate(instance.getClient(), messageSubscription.messageName, messageSubscription.correlationKey);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void apply(TestCaseInstance instance, long processInstanceKey) {
signalNameConsumer.accept(signalSubscription.signalName);
}

action.accept(instance.client, signalSubscription.signalName);
action.accept(instance.getClient(), signalSubscription.signalName);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.camunda.community.bpmndt.api;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
Expand Down Expand Up @@ -30,8 +29,8 @@
*/
public class TestCaseInstance implements AutoCloseable {

final ZeebeTestEngine engine;
final ZeebeClient client;
private final ZeebeTestEngine engine;
private final ZeebeClient client;

private final long taskTimeout;

Expand Down Expand Up @@ -73,6 +72,10 @@ public void apply(long processInstanceKey, CallActivityHandler handler) {
handler.apply(this, processInstanceKey);
}

public void apply(long processInstanceKey, CustomMultiInstanceHandler handler) {
handler.apply(this, processInstanceKey);
}

public void apply(long processInstanceKey, JobHandler handler) {
handler.apply(this, processInstanceKey);
}
Expand All @@ -93,6 +96,14 @@ public void apply(long processInstanceKey, UserTaskHandler handler) {
handler.apply(this, processInstanceKey);
}

public ZeebeClient getClient() {
return client;
}

public ZeebeTestEngine getEngine() {
return engine;
}

public void hasPassed(long processInstanceKey, String bpmnElementId) {
boolean hasPassed = selectAndTest(memo -> {
var processInstance = memo.processInstances.get(processInstanceKey);
Expand All @@ -105,7 +116,7 @@ public void hasPassed(long processInstanceKey, String bpmnElementId) {
});

if (!hasPassed) {
var message = "expected process instance %d to have passed BPMN element %s, but has not";
var message = withIncidents("expected process instance %d to have passed BPMN element %s, but has not", processInstanceKey);
throw new AssertionError(String.format(message, processInstanceKey, bpmnElementId));
}
}
Expand All @@ -122,7 +133,7 @@ public void hasTerminated(long processInstanceKey, String bpmnElementId) {
});

if (!hasTerminated) {
var message = "expected process instance %d to have terminated BPMN element %s, but has not";
var message = withIncidents("expected process instance %d to have terminated BPMN element %s, but has not", processInstanceKey);
throw new AssertionError(String.format(message, processInstanceKey, bpmnElementId));
}
}
Expand All @@ -138,7 +149,7 @@ public void isCompleted(long processInstanceKey) {
});

if (!isCompleted) {
String message = "expected process instance %d to be completed, but was not";
String message = withIncidents("expected process instance %d to be completed, but was not", processInstanceKey);
throw new AssertionError(String.format(message, processInstanceKey));
}
}
Expand Down Expand Up @@ -169,25 +180,7 @@ public void isWaitingAt(long processInstanceKey, String bpmnElementId) {
});

if (!isWaitingAt) {
var message = "expected process instance %d to be waiting at BPMN element %s, but was not";

var incidents = findIncidents(processInstanceKey);
if (!incidents.isEmpty()) {
var messageBuilder = new StringBuilder(message);
messageBuilder.append("\nfound incidents:");

for (IncidentRecordValue incident : incidents) {
messageBuilder.append("\n - element ");
messageBuilder.append(incident.getElementId());
messageBuilder.append(": ");
messageBuilder.append(incident.getErrorType().name());
messageBuilder.append(": ");
messageBuilder.append(incident.getErrorMessage());
}

message = messageBuilder.toString();
}

var message = withIncidents("expected process instance %d to be waiting at BPMN element %s, but was not", processInstanceKey);
throw new AssertionError(String.format(message, processInstanceKey, bpmnElementId));
}
}
Expand Down Expand Up @@ -357,22 +350,6 @@ private void consumeRecordStream() {
}
}

private List<IncidentRecordValue> findIncidents(long processInstanceKey) {
var incidents = new LinkedList<IncidentRecordValue>();

var recordStream = RecordStream.of(engine.getRecordStreamSource());
for (Record<?> record : recordStream.records()) {
if (record.getValueType() == ValueType.INCIDENT && record.getIntent() == IncidentIntent.CREATED) {
var incident = (IncidentRecordValue) record.getValue();
if (incident.getProcessInstanceKey() == processInstanceKey) {
incidents.add(incident);
}
}
}

return incidents;
}

private <T> T select(Function<TestCaseInstanceMemo, T> selector) {
SelectTask<T> task = new SelectTask<>(selector);

Expand Down Expand Up @@ -406,6 +383,38 @@ private boolean selectAndTest(Predicate<TestCaseInstanceMemo> predicate) {
return selectAndTestTask == null;
}

private String withIncidents(String message, long processInstanceKey) {
var incidents = new LinkedList<IncidentRecordValue>();

var recordStream = RecordStream.of(engine.getRecordStreamSource());
for (Record<?> record : recordStream.records()) {
if (record.getValueType() == ValueType.INCIDENT && record.getIntent() == IncidentIntent.CREATED) {
var incident = (IncidentRecordValue) record.getValue();
if (incident.getProcessInstanceKey() == processInstanceKey) {
incidents.add(incident);
}
}
}

if (incidents.isEmpty()) {
return message;
}

var messageBuilder = new StringBuilder(message);
messageBuilder.append("\nfound incidents:");

for (IncidentRecordValue incident : incidents) {
messageBuilder.append("\n - element ");
messageBuilder.append(incident.getElementId());
messageBuilder.append(": ");
messageBuilder.append(incident.getErrorType().name());
messageBuilder.append(": ");
messageBuilder.append(incident.getErrorMessage());
}

return messageBuilder.toString();
}

private static class SelectTask<T> {

final Function<TestCaseInstanceMemo, T> selector;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public static class MessageEventElement extends TestCaseInstanceElement {
public String messageName;
}

public static class MultiInstanceElement extends TestCaseInstanceElement {

public boolean sequential;
}

public static class SignalEventElement extends TestCaseInstanceElement {

public String signalName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ void apply(Record<?> record) {
return;
}

System.out.println(record);

switch (record.getValueType()) {
case JOB:
handleJob(record);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void apply(TestCaseInstance instance, long processInstanceKey) {
timeDurationConsumer.accept(toDuration(timer.dueDate, timer.creationDate));
}

instance.engine.increaseTime(Duration.ofMillis(timer.dueDate - System.currentTimeMillis()));
instance.getEngine().increaseTime(Duration.ofMillis(timer.dueDate - System.currentTimeMillis()));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void apply(TestCaseInstance instance, long processInstanceKey) {
assigneeConsumer.accept(assignee);
}

var jsonMapper = instance.client.getConfiguration().getJsonMapper();
var jsonMapper = instance.getClient().getConfiguration().getJsonMapper();

var candidateGroupsHeader = job.getCustomHeader(Protocol.USER_TASK_CANDIDATE_GROUPS_HEADER_NAME);

Expand Down Expand Up @@ -160,7 +160,7 @@ void apply(TestCaseInstance instance, long processInstanceKey) {
}

if (action != null) {
action.accept(instance.client, job.key);
action.accept(instance.getClient(), job.key);

if (element.errorCode != null) {
instance.hasTerminated(processInstanceKey, element.id);
Expand Down
Loading

0 comments on commit f4471fc

Please sign in to comment.