diff --git a/pom.xml b/pom.xml
index 066229e..7783f15 100644
--- a/pom.xml
+++ b/pom.xml
@@ -100,6 +100,9 @@
4.13.2
0.8.8
3.9.1.2184
+ 1.17.3
+ 0.0.9
+ 4.2.0
3.10.1
@@ -108,6 +111,7 @@
2.1.1
3.0.12
3.0.0-M7
+ 3.0.0-M7
1.6.13
3.4.1
3.2.1
@@ -118,6 +122,7 @@
https://sonarcloud.io
+
@@ -132,6 +137,13 @@
jackson-core
provided
+
+ org.testcontainers
+ testcontainers-bom
+ ${testcontainers.version}
+ pom
+ import
+
@@ -196,7 +208,24 @@
ch.qos.logback
logback-classic
- 1.4.0
+ 1.2.11
+ test
+
+
+ org.testcontainers
+ testcontainers
+ test
+
+
+ org.bonitasoft.web
+ bonita-java-client
+ ${bonita-java-client.version}
+ test
+
+
+ org.awaitility
+ awaitility
+ ${awaitility.version}
test
@@ -216,11 +245,21 @@
-
+
org.apache.maven.plugins
maven-compiler-plugin
${maven-compiler-plugin.version}
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ ${maven-failsafe-plugin.version}
+
maven-assembly-plugin
${maven-assembly-plugin.version}
@@ -252,11 +291,6 @@
-
- org.apache.maven.plugins
- maven-surefire-plugin
- ${maven-surefire-plugin.version}
-
org.jacoco
jacoco-maven-plugin
@@ -355,6 +389,39 @@
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+ integration-tests-7.13
+
+ integration-test
+
+
+
+ 7.13.0
+
+
+
+
+ integration-tests-7.14
+
+ integration-test
+
+
+
+ 7.14.0
+
+
+
+
+
+ verify
+
+
+
+
diff --git a/src/test/java/org/bonitasoft/connectors/rest/ConnectorTestToolkit.java b/src/test/java/org/bonitasoft/connectors/rest/ConnectorTestToolkit.java
new file mode 100644
index 0000000..da6b62d
--- /dev/null
+++ b/src/test/java/org/bonitasoft/connectors/rest/ConnectorTestToolkit.java
@@ -0,0 +1,218 @@
+package org.bonitasoft.connectors.rest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.bonitasoft.engine.bpm.bar.BarResource;
+import org.bonitasoft.engine.bpm.bar.BusinessArchive;
+import org.bonitasoft.engine.bpm.bar.BusinessArchiveBuilder;
+import org.bonitasoft.engine.bpm.bar.BusinessArchiveFactory;
+import org.bonitasoft.engine.bpm.bar.actorMapping.Actor;
+import org.bonitasoft.engine.bpm.bar.actorMapping.ActorMapping;
+import org.bonitasoft.engine.bpm.connector.ConnectorEvent;
+import org.bonitasoft.engine.bpm.process.DesignProcessDefinition;
+import org.bonitasoft.engine.bpm.process.impl.ProcessDefinitionBuilder;
+import org.bonitasoft.engine.expression.ExpressionBuilder;
+import org.bonitasoft.engine.expression.InvalidExpressionException;
+import org.bonitasoft.engine.operation.OperationBuilder;
+import org.bonitasoft.web.client.BonitaClient;
+import org.bonitasoft.web.client.api.ProcessInstanceVariableApi;
+import org.bonitasoft.web.client.model.ProcessInstantiationResponse;
+import org.bonitasoft.web.client.services.policies.ProcessImportPolicy;
+
+/**
+ * Helper for testing connector in a docker image of Bonita studio.
+ */
+public class ConnectorTestToolkit {
+
+ /**
+ * Build a connector and then install it into a dummy process with input and output process variables.
+ * Those variables will help to verify the input and output specified in the implementation of the connector to be tested.
+ *
+ * @param connectorId The identifier of the connector specified in the pom.xml and the definition file.
+ * @param versionId The version of the connector to be tested.
+ * @param inputs A map of variables with a content specified to be tested.
+ * @param outputs A map of results variables.
+ * @param locationJar The Jar containing the class and dependencies used by the connector.
+ * @return A {@link BusinessArchive}
+ * @throws Exception
+ */
+ public static BusinessArchive buildConnectorToTest(String connectorId, String versionId, Map inputs,
+ Map outputs, String locationJar) throws Exception {
+
+ // Building process with connector to setup
+ var process = buildConnectorInProcess(connectorId, versionId, inputs, outputs);
+
+ // Building business archive with the process and connector
+ return buildBusinessArchive(process, connectorId, locationJar);
+ }
+
+ private static BusinessArchive buildBusinessArchive(DesignProcessDefinition process, String connectorId,
+ String artifactId) throws Exception {
+ var barBuilder = new BusinessArchiveBuilder();
+ barBuilder.createNewBusinessArchive();
+ barBuilder.setProcessDefinition(process);
+ var foundFiles = new File("").getAbsoluteFile().toPath()
+ .resolve("target")
+ .toFile()
+ .listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return Pattern.matches(artifactId + "-.*.jar", name)
+ && !name.endsWith("-sources.jar")
+ && !name.endsWith("-javadoc.jar");
+ }
+ });
+
+ assertThat(foundFiles).hasSize(1);
+ var connectorJar = foundFiles[0];
+ assertThat(connectorJar).exists();
+ List jarEntries = findJarEntries(connectorJar,
+ entry -> entry.getName().equals(connectorId + ".impl"));
+ assertThat(jarEntries).hasSize(1);
+ var implEntry = jarEntries.get(0);
+
+ byte[] content = null;
+ try (JarFile jarFile = new JarFile(connectorJar)) {
+ InputStream inputStream = jarFile.getInputStream(implEntry);
+ content = inputStream.readAllBytes();
+ }
+
+ barBuilder.addConnectorImplementation(
+ new BarResource(connectorId + ".impl", content));
+ barBuilder.addClasspathResource(
+ new BarResource(connectorJar.getName(), Files.readAllBytes(connectorJar.toPath())));
+ ActorMapping actorMapping = new ActorMapping();
+ var systemActor = new Actor("system");
+ systemActor.addRole("member");
+ actorMapping.addActor(systemActor);
+ barBuilder.setActorMapping(actorMapping);
+
+ return barBuilder.done();
+ }
+
+ private static DesignProcessDefinition buildConnectorInProcess(String connectorId, String versionId,
+ Map inputs, Map outputs) throws Exception {
+ var processBuilder = new ProcessDefinitionBuilder();
+ var expBuilder = new ExpressionBuilder();
+ processBuilder.createNewInstance("PROCESS_UNDER_TEST", "1.0");
+ processBuilder.addActor("system");
+ var connectorBuilder = processBuilder.addConnector("connector-under-test", connectorId, versionId,
+ ConnectorEvent.ON_ENTER);
+ inputs.forEach((name, content) -> {
+ try {
+ connectorBuilder.addInput(name, expBuilder.createConstantStringExpression(
+ content));
+ } catch (InvalidExpressionException e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ if (outputs != null) {
+ outputs.forEach((name, output) -> {
+ try {
+ processBuilder.addData(name, output.getType(), null);
+ connectorBuilder.addOutput(new OperationBuilder().createSetDataOperation(name,
+ new ExpressionBuilder().createDataExpression(output.getName(), output.getType())));
+ } catch (InvalidExpressionException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
+ // Add a user task to avoid the process to be already completed as soon as it's launched.
+ processBuilder.addUserTask("waiting task", "system");
+
+ return processBuilder.done();
+ }
+
+ /**
+ * Import the {@link BusinessArchive} and launch the dummy process containing the connector to be tested.
+ *
+ * @param barArchive The file containing the {@link BusinessArchive}
+ * @param client A {@link BonitaClient}
+ * @return The process started.
+ * @throws IOException
+ */
+ public static ProcessInstantiationResponse importAndLaunchProcess(BusinessArchive barArchive, BonitaClient client)
+ throws IOException {
+ var process = barArchive.getProcessDefinition();
+ File processFile = null;
+ try {
+ processFile = Files.createTempFile("process", ".bar").toFile();
+ processFile.delete();
+ BusinessArchiveFactory.writeBusinessArchiveToFile(barArchive, processFile);
+ client.login("install", "install");
+ client.processes().importProcess(processFile, ProcessImportPolicy.REPLACE_DUPLICATES);
+ } finally {
+ if (processFile != null) {
+ processFile.delete();
+ }
+ }
+
+ var processId = client.processes().getProcess(process.getName(), process.getVersion()).getId();
+ return client.processes().startProcess(processId, Map.of());
+
+ }
+
+ private static List findJarEntries(File file, Predicate super JarEntry> entryPredicate)
+ throws IOException {
+ try (JarFile jarFile = new JarFile(file)) {
+ return jarFile.stream()
+ .filter(entryPredicate)
+ .collect(Collectors.toList());
+ }
+ }
+
+ /**
+ * Getting the content value of a specific variable process.
+ *
+ * @param client A {@link BonitaClient}
+ * @param caseId A process instance id.
+ * @param variableProcessName The name of the variable process, it must have been already declared in the output map of the connector before building the
+ * connector to test.
+ * @return The content of the variable. Can be null.
+ */
+ public static String getProcessVariableValue(BonitaClient client, String caseId, String variableProcessName) {
+ return client.get(ProcessInstanceVariableApi.class).getVariableByProcessInstanceId(caseId, variableProcessName)
+ .getValue();
+
+ }
+
+ static class Output {
+
+ private final String name;
+ private final String type;
+
+ public static Output create(String name, String type) {
+ return new Output(name, type);
+ }
+
+ private Output(String name, String type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ }
+}
diff --git a/src/test/java/org/bonitasoft/connectors/rest/RestConnectorIT.java b/src/test/java/org/bonitasoft/connectors/rest/RestConnectorIT.java
new file mode 100644
index 0000000..2071803
--- /dev/null
+++ b/src/test/java/org/bonitasoft/connectors/rest/RestConnectorIT.java
@@ -0,0 +1,319 @@
+package org.bonitasoft.connectors.rest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.awaitility.Awaitility.await;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.Callable;
+
+import org.bonitasoft.connectors.rest.ConnectorTestToolkit.Output;
+import org.bonitasoft.web.client.BonitaClient;
+import org.bonitasoft.web.client.api.ArchivedProcessInstanceApi;
+import org.bonitasoft.web.client.api.ProcessInstanceApi;
+import org.bonitasoft.web.client.exception.NotFoundException;
+import org.bonitasoft.web.client.model.ArchivedProcessInstance;
+import org.bonitasoft.web.client.services.policies.OrganizationImportPolicy;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.DockerImageName;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class RestConnectorIT {
+
+ private static final String REST_HEAD_DEF_VERSION = "1.0.0";
+ private static final String REST_HEAD_DEF_ID = "rest-head";
+
+ private static final String REST_GET_DEF_VERSION = "1.2.0";
+ private static final String REST_GET_DEF_ID = "rest-get";
+
+ private static final String REST_POST_DEF_VERSION = "1.3.0";
+ private static final String REST_POST_DEF_ID = "rest-post";
+
+ private static final String REST_FILE_POST_DEF_VERSION = "1.0.0";
+ private static final String REST_FILE_POST_DEF_ID = "rest-file-post";
+
+ private static final String REST_PUT_DEF_VERSION = "1.3.0";
+ private static final String REST_PUT_DEF_ID = "rest-put";
+
+ private static final String REST_FILE_PUT_DEF_VERSION = "1.0.0";
+ private static final String REST_FILE_PUT_DEF_ID = "rest-file-put";
+
+ private static final String REST_DELETE_DEF_VERSION = "1.2.0";
+ private static final String REST_DELETE_DEF_ID = "rest-delete";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(RestConnectorIT.class);
+
+ private static final String ARTIFACT_ID = "bonita-connector-rest";
+ private static final String BONITA_VERSION = Objects.requireNonNull(System.getProperty("bonita.version"), "'bonita.version' system property not defined !");
+
+ @ClassRule
+ public static GenericContainer> BONITA_CONTAINER = new GenericContainer<>(
+ DockerImageName.parse(String.format("bonita:%s", BONITA_VERSION)))
+ .withExposedPorts(8080)
+ .waitingFor(Wait.forHttp("/bonita"))
+ .withLogConsumer(new Slf4jLogConsumer(LOGGER));
+
+ @BeforeClass
+ public static void installOrganization() {
+ var client = BonitaClient
+ .builder(String.format("http://%s:%s/bonita", BONITA_CONTAINER.getHost(),
+ BONITA_CONTAINER.getFirstMappedPort()))
+ .build();
+ client.login("install", "install");
+ client.users().importOrganization(new File(RestConnectorIT.class.getResource("/ACME.xml").getFile()),
+ OrganizationImportPolicy.IGNORE_DUPLICATES);
+ client.logout();
+ }
+
+ private BonitaClient client;
+
+ @Before
+ public void login() {
+ client = BonitaClient
+ .builder(String.format("http://%s:%s/bonita", BONITA_CONTAINER.getHost(),
+ BONITA_CONTAINER.getFirstMappedPort()))
+ .build();
+ client.login("install", "install");
+ }
+
+ @After
+ public void logout() {
+ client.logout();
+ }
+
+ @Test
+ public void testRestGetConnectorIntegration() throws Exception {
+ // Inputs
+ Map inputsConnector = new HashMap<>();
+ inputsConnector.put("url", "https://jsonplaceholder.typicode.com/todos/1");
+
+ // Outputs
+ Map outputsConnector = new HashMap<>();
+ outputsConnector.put("resultRestGet", Output.create("bodyAsString", String.class.getName()));
+
+ // Building process with connector
+ var barFile = ConnectorTestToolkit.buildConnectorToTest(REST_GET_DEF_ID, REST_GET_DEF_VERSION, inputsConnector,
+ outputsConnector, ARTIFACT_ID);
+
+ // Importing and launching the process contained in the business archive
+ var processResponse = ConnectorTestToolkit.importAndLaunchProcess(barFile, client);
+
+ // Wait until the process launched is started (and not failed)
+ await().until(pollInstanceState(client, processResponse.getCaseId()), "started"::equals);
+
+ // Getting the result of the rest call.
+ String resultRestGetResult = (String) ConnectorTestToolkit.getProcessVariableValue(client,
+ processResponse.getCaseId(), "resultRestGet");
+ assertNotNull(resultRestGetResult);
+
+ ObjectMapper mapper = new ObjectMapper();
+ var map = mapper.readValue(resultRestGetResult, Map.class);
+ assertEquals(1, map.get("userId"));
+ assertEquals(1, map.get("id"));
+ assertEquals("delectus aut autem", map.get("title"));
+ assertFalse((boolean) map.get("completed"));
+ }
+
+ @Test
+ public void testRestHeadConnectorIntegration() throws Exception {
+ // Inputs
+ Map inputsConnector = new HashMap<>();
+ inputsConnector.put("url", "https://jsonplaceholder.typicode.com/posts/1");
+
+ // Outputs
+ var connectorOuput = Map.ofEntries(entry("headerResult", Output.create("headers", Map.class.getName())),
+ entry("statusResult", Output.create("status_code", Integer.class.getName())));
+
+ // Building process with connector
+ var barFile = ConnectorTestToolkit.buildConnectorToTest(REST_HEAD_DEF_ID, REST_HEAD_DEF_VERSION, inputsConnector, connectorOuput,
+ ARTIFACT_ID);
+
+ // Importing and launching the process contained in the business archive
+ var processResponse = ConnectorTestToolkit.importAndLaunchProcess(barFile, client);
+
+ // Wait until the process launched is started (and not failed)
+ await().until(pollInstanceState(client, processResponse.getCaseId()), "started"::equals);
+
+ // Getting the results of the rest call.
+ String status = ConnectorTestToolkit.getProcessVariableValue(client,
+ processResponse.getCaseId(), "statusResult");
+ assertThat(Integer.parseInt(status)).isEqualTo(200);
+
+ String headers = ConnectorTestToolkit.getProcessVariableValue(client,
+ processResponse.getCaseId(), "headerResult");
+ assertNotNull(headers);
+ assertThat(headers).containsIgnoringCase("Content-Type=application/json");
+ }
+
+ @Test
+ public void testRestPostConnectorIntegration() throws Exception {
+ // Inputs
+ Map inputsConnector = new HashMap<>();
+ inputsConnector.put("url", "https://jsonplaceholder.typicode.com/posts/");
+ inputsConnector.put("contentType", "application/json");
+ inputsConnector.put("charset", "UTF-8");
+
+ // Outputs
+ var connectorOuput = Map.ofEntries(entry("response", Output.create("bodyAsString", String.class.getName())),
+ entry("statusResult", Output.create("status_code", Integer.class.getName())));
+
+ // Building process with connector
+ var barFile = ConnectorTestToolkit.buildConnectorToTest(REST_POST_DEF_ID, REST_POST_DEF_VERSION, inputsConnector, connectorOuput,
+ ARTIFACT_ID);
+
+ // Importing and launching the process contained in the business archive
+ var processResponse = ConnectorTestToolkit.importAndLaunchProcess(barFile, client);
+
+ // Wait until the process launched is started (and not failed)
+ await().until(pollInstanceState(client, processResponse.getCaseId()), "started"::equals);
+
+ String status = ConnectorTestToolkit.getProcessVariableValue(client,
+ processResponse.getCaseId(), "statusResult");
+ assertThat(Integer.parseInt(status)).isEqualTo(201);
+ String response = ConnectorTestToolkit.getProcessVariableValue(client,
+ processResponse.getCaseId(), "response");
+ ObjectMapper mapper = new ObjectMapper();
+ var map = mapper.readValue(response, Map.class);
+ assertThat(map).containsExactly(entry("id", 101));
+ }
+
+ @Test
+ public void testRestPutConnectorIntegration() throws Exception {
+ // Inputs
+ Map inputsConnector = new HashMap<>();
+ inputsConnector.put("url", "https://jsonplaceholder.typicode.com/posts/1");
+ inputsConnector.put("contentType", "application/json");
+ inputsConnector.put("charset", "UTF-8");
+ inputsConnector.put("body", "{ \"title\" : \"updated\"}");
+
+ // Outputs
+ var connectorOuput = Map.ofEntries(entry("statusResult", Output.create("status_code", Integer.class.getName())),
+ entry("response", Output.create("bodyAsString", String.class.getName())));
+
+ // Building process with connector
+ var barFile = ConnectorTestToolkit.buildConnectorToTest(REST_PUT_DEF_ID, REST_PUT_DEF_VERSION, inputsConnector, connectorOuput,
+ ARTIFACT_ID);
+
+ // Importing and launching the process contained in the business archive
+ var processResponse = ConnectorTestToolkit.importAndLaunchProcess(barFile, client);
+
+ // Wait until the process launched is started (and not failed)
+ await().until(pollInstanceState(client, processResponse.getCaseId()), "started"::equals);
+
+ String status = ConnectorTestToolkit.getProcessVariableValue(client,
+ processResponse.getCaseId(), "statusResult");
+ assertThat(Integer.parseInt(status)).isEqualTo(200);
+ var response = ConnectorTestToolkit.getProcessVariableValue(client,
+ processResponse.getCaseId(), "response");
+ assertThat(response).contains("updated");
+ }
+
+ @Test
+ public void testRestFilePutConnectorIntegration() throws Exception {
+ // Inputs
+ Map inputsConnector = new HashMap<>();
+ inputsConnector.put("url", "https://jsonplaceholder.typicode.com/posts/1");
+ inputsConnector.put("contentType", "application/json");
+ inputsConnector.put("charset", "UTF-8");
+
+ // Outputs
+
+ // Building process with connector
+ var barFile = ConnectorTestToolkit.buildConnectorToTest(REST_FILE_PUT_DEF_ID, REST_FILE_PUT_DEF_VERSION, inputsConnector, null,
+ ARTIFACT_ID);
+
+ // Importing and launching the process contained in the business archive
+ var processResponse = ConnectorTestToolkit.importAndLaunchProcess(barFile, client);
+
+ // Wait until the process launched is started (and not failed)
+ await().until(pollInstanceState(client, processResponse.getCaseId()), "started"::equals);
+ }
+
+ @Test
+ public void testRestFilePostConnectorIntegration() throws Exception {
+ // Inputs
+ Map inputsConnector = new HashMap<>();
+ inputsConnector.put("url", "https://jsonplaceholder.typicode.com/posts/1");
+ inputsConnector.put("contentType", "application/json");
+ inputsConnector.put("charset", "UTF-8");
+
+ // Outputs
+
+ // Building process with connector
+ var barFile = ConnectorTestToolkit.buildConnectorToTest(REST_FILE_POST_DEF_ID, REST_FILE_POST_DEF_VERSION, inputsConnector, null,
+ ARTIFACT_ID);
+
+ // Importing and launching the process contained in the business archive
+ var processResponse = ConnectorTestToolkit.importAndLaunchProcess(barFile, client);
+
+ // Wait until the process launched is started (and not failed)
+ await().until(pollInstanceState(client, processResponse.getCaseId()), "started"::equals);
+ }
+
+ @Test
+ public void testRestDeleteConnectorIntegration() throws Exception {
+ // Inputs
+ Map inputsConnector = new HashMap<>();
+ inputsConnector.put("url", "https://jsonplaceholder.typicode.com/posts/1");
+
+ // Outputs
+ var connectorOuput = Map.ofEntries(entry("statusResult", Output.create("status_code", Integer.class.getName())));
+
+
+ // Building process with connector
+ var barFile = ConnectorTestToolkit.buildConnectorToTest(REST_DELETE_DEF_ID, REST_DELETE_DEF_VERSION, inputsConnector, connectorOuput,
+ ARTIFACT_ID);
+
+ // Importing and launching the process contained in the business archive
+ var processResponse = ConnectorTestToolkit.importAndLaunchProcess(barFile, client);
+
+ // Wait until the process launched is started (and not failed)
+ await().until(pollInstanceState(client, processResponse.getCaseId()), "started"::equals);
+
+ String status = ConnectorTestToolkit.getProcessVariableValue(client,
+ processResponse.getCaseId(), "statusResult");
+ assertThat(Integer.parseInt(status)).isEqualTo(200);
+ }
+
+ private Callable pollInstanceState(BonitaClient client, String id) {
+ return () -> {
+ try {
+ var instance = client.get(ProcessInstanceApi.class).getProcessInstanceById(id, (String) null);
+ return instance.getState().toLowerCase();
+ } catch (NotFoundException e) {
+ return getCompletedProcess(id).getState().toLowerCase();
+ }
+ };
+ }
+
+ private ArchivedProcessInstance getCompletedProcess(String id) {
+ var archivedInstances = client.get(ArchivedProcessInstanceApi.class)
+ .searchArchivedProcessInstances(
+ new ArchivedProcessInstanceApi.SearchArchivedProcessInstancesQueryParams()
+ .c(1)
+ .p(0)
+ .f(List.of("caller=any", "sourceObjectId=" + id)));
+ if (!archivedInstances.isEmpty()) {
+ return archivedInstances.get(0);
+ }
+ return null;
+ }
+
+}
diff --git a/src/test/resources/ACME.xml b/src/test/resources/ACME.xml
new file mode 100644
index 0000000..78f0b37
--- /dev/null
+++ b/src/test/resources/ACME.xml
@@ -0,0 +1,869 @@
+
+
+
+
+ asdasdasd
+
+
+
+
+
+ William
+ Jobs
+ Mr
+ Chief Executive Officer
+
+
+ william.jobs@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ April
+ Sanchez
+ Mrs
+ Compensation specialist
+ helen.kelly
+
+
+ april.sanchez@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Helen
+ Kelly
+ Mrs
+ Human resource manager
+ william.jobs
+
+
+ helen.kelly@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Walter
+ Bates
+ Mr
+ Human resources benefits
+ helen.kelly
+
+
+ walter.bates@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Zachary
+ Williamson
+ Mr
+ Chief Financial Officer
+ william.jobs
+
+
+ zachary.williamson@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Patrick
+ Gardenier
+ Mr
+ Financial controller
+ zachary.williamson
+
+
+ patrick.gardenier@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Virginie
+ Jomphe
+ Mrs
+ Accountant
+ zachary.williamson
+
+
+ virginie.jomphe@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Thorsten
+ Hartmann
+ Mr
+ Financial planning manager
+ zachary.williamson
+
+
+ thorsten.hartmann@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Jan
+ Fisher
+ Mr
+ Infrastucture specialist
+ favio.riviera
+
+
+ jan.fisher@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Isabel
+ Bleasdale
+ Mrs
+ Product marketing manager
+ favio.riviera
+
+
+ isabel.bleasdale@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Favio
+ Riviera
+ Mr
+ Vice President of Marketing
+ william.jobs
+
+
+ favio.riviera@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Michael
+ Morrison
+ Mr
+ Chief Technical Officer
+ william.jobs
+
+
+ michael.morrison@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Marc
+ Marseau
+ Mr
+ Engineer
+ michael.morrison
+
+
+ marc.marseau@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Joseph
+ Hovell
+ Mr
+ Engineer
+ michael.morrison
+
+
+ joseph.hovell@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Mauro
+ Zetticci
+ Mr
+ Consultant
+ michael.morrison
+
+
+ mauro.zetticci@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Thomas
+ Wallis
+ Mr
+ Consultant
+ michael.morrison
+
+
+ thomas.wallis@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Daniela
+ Angelo
+ Mrs
+ Vice President of Sales
+ william.jobs
+
+
+ daniela.angelo@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Anthony
+ Nichols
+ Mr
+ Account manager
+ daniela.angelo
+
+
+ anthony.nichols@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Misa
+ Kumagai
+ Mrs
+ Account manager
+ daniela.angelo
+
+
+ misa.kumagai@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Norio
+ Yamazaki
+ Mr
+ Account manager
+ daniela.angelo
+
+
+ norio.yamazaki@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+ Giovanna
+ Almeida
+ Mrs
+ Account manager
+ daniela.angelo
+
+
+ giovanna.almeida@acme.com
+ 484-302-5000
+ 484-302-0000
+ 70
+ Renwick Drive
+ 19108
+ Philadelphia
+ PA
+ United States
+
+
+
+
+
+
+ true
+ bpm
+
+
+ asdasdasd
+
+
+
+
+
+
+
+ Member
+
+
+
+
+
+ Acme
+ This group represents the acme department of the ACME organization
+
+
+ Human Resources
+ This group represents the human resources department of the ACME organization
+
+
+ Finance
+ This group represents the finance department of the ACME organization
+
+
+ Infrastructure
+ This group represents the infrastructure department of the ACME organization
+
+
+ Marketing
+ This group represents the marketing department of the ACME organization
+
+
+ Production
+ This group represents the production department of the ACME organization
+
+
+ Sales
+ This group represents the sales department of the ACME organization
+
+
+ Europe
+ This group represents the europe department of the ACME organization
+
+
+ Asia
+ This group represents the asia department of the ACME organization
+
+
+ Latin America
+ This group represents the latin america department of the ACME organization
+
+
+ North America
+ This group represents the north america department of the ACME organization
+
+
+ Research & Development
+ This group represents the research & development department of the ACME organization
+
+
+ Services
+ This group represents the services department of the ACME organization
+
+
+
+
+ william.jobs
+ member
+ acme
+
+
+ april.sanchez
+ member
+ hr
+ /acme
+
+
+ helen.kelly
+ member
+ hr
+ /acme
+
+
+ walter.bates
+ member
+ hr
+ /acme
+
+
+ zachary.williamson
+ member
+ finance
+ /acme
+
+
+ patrick.gardenier
+ member
+ finance
+ /acme
+
+
+ virginie.jomphe
+ member
+ finance
+ /acme
+
+
+ thorsten.hartmann
+ member
+ finance
+ /acme
+
+
+ jan.fisher
+ member
+ it
+ /acme
+
+
+ isabel.bleasdale
+ member
+ marketing
+ /acme
+
+
+ favio.riviera
+ member
+ marketing
+ /acme
+
+
+ michael.morrison
+ member
+ production
+ /acme
+
+
+ marc.marseau
+ member
+ rd
+ /acme/production
+
+
+ joseph.hovell
+ member
+ rd
+ /acme/production
+
+
+ mauro.zetticci
+ member
+ services
+ /acme/production
+
+
+ thomas.wallis
+ member
+ services
+ /acme/production
+
+
+ daniela.angelo
+ member
+ europe
+ /acme/sales
+
+
+ misa.kumagai
+ member
+ asia
+ /acme/sales
+
+
+ norio.yamazaki
+ member
+ asia
+ /acme/sales
+
+
+ giovanna.almeida
+ member
+ latin_america
+ /acme/sales
+
+
+ anthony.nichols
+ member
+ north_america
+ /acme/sales
+
+
+
\ No newline at end of file