diff --git a/multiapps-controller-persistence-test/src/main/java/org/cloudfoundry/multiapps/controller/persistence/test/TestDataSourceProvider.java b/multiapps-controller-persistence-test/src/main/java/org/cloudfoundry/multiapps/controller/persistence/test/TestDataSourceProvider.java
index 65e4b37eef..ab9fe0a9b8 100644
--- a/multiapps-controller-persistence-test/src/main/java/org/cloudfoundry/multiapps/controller/persistence/test/TestDataSourceProvider.java
+++ b/multiapps-controller-persistence-test/src/main/java/org/cloudfoundry/multiapps/controller/persistence/test/TestDataSourceProvider.java
@@ -3,16 +3,14 @@
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
-
import javax.sql.DataSource;
-import org.springframework.jdbc.datasource.SingleConnectionDataSource;
-
import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.resource.ClassLoaderResourceAccessor;
+import org.springframework.jdbc.datasource.SingleConnectionDataSource;
public final class TestDataSourceProvider {
@@ -20,6 +18,11 @@ private TestDataSourceProvider() {
}
+ public static DataSource getDataSource() throws Exception {
+ Connection connection = createH2InMemoryConnection();
+ return new SingleConnectionDataSource(connection, true);
+ }
+
public static DataSource getDataSource(String liquibaseChangelogLocation) throws Exception {
// Liquibase closes the connection after it's done, so we need a separate one for it.
Connection connectionForLiquibase = createH2InMemoryConnection();
diff --git a/multiapps-controller-process/pom.xml b/multiapps-controller-process/pom.xml
index 06d5c2d465..9066ec03b5 100644
--- a/multiapps-controller-process/pom.xml
+++ b/multiapps-controller-process/pom.xml
@@ -1,5 +1,5 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
multiapps-controller-process
@@ -96,5 +96,15 @@
jakarta.xml.bind
jakarta.xml.bind-api
+
+ org.cloudfoundry.multiapps
+ multiapps-controller-persistence-test
+ test
+
+
+ com.h2database
+ h2
+ test
+
\ No newline at end of file
diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/flowable/FlowableEngineTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/flowable/FlowableEngineTest.java
new file mode 100644
index 0000000000..6dd2381b84
--- /dev/null
+++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/flowable/FlowableEngineTest.java
@@ -0,0 +1,217 @@
+package org.cloudfoundry.multiapps.controller.process.flowable;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.sql.DataSource;
+
+import org.cloudfoundry.multiapps.common.util.JsonSerializationStrategy;
+import org.cloudfoundry.multiapps.common.util.JsonUtil;
+import org.cloudfoundry.multiapps.controller.persistence.test.TestDataSourceProvider;
+import org.cloudfoundry.multiapps.controller.process.variables.Serializer;
+import org.cloudfoundry.multiapps.controller.process.variables.Variable;
+import org.cloudfoundry.multiapps.controller.process.variables.Variables;
+import org.flowable.engine.ProcessEngine;
+import org.flowable.engine.ProcessEngineConfiguration;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.delegate.DelegateExecution;
+import org.flowable.engine.delegate.JavaDelegate;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.flowable.mail.common.api.client.FlowableMailClient;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+/**
+ * Integration test for Flowable engine with in-memory H2 database. Tests real BPMN process creation, variable setting and retrieval using
+ * the multiapps-controller variable handling system.
+ */
+class FlowableEngineTest {
+
+ private static final String TEST_PROCESS_KEY = "mtaDeploymentTest";
+ private static final String MTA_DEPLOYMENT_TEST_PROCESS = "MTA Deployment Test Process";
+ private static final String FLOWABLE_DB_SCHEMA_STRATEGY_CREATE_DROP = "create-drop";
+ private static final String TEST_VARIABLE_TASK_BEAN_NAME = "testVariableTask";
+ private static final String DEPLOYMENT_NAME_OF_DIAGRAM = "MTA Deployment Test";
+ private static final String TEST_BPMN_DIAGRAM_RESOURCE =
+ "org/cloudfoundry/multiapps/controller/process/flowable/test-bpmn-diagram.bpmn";
+
+ @Mock
+ private FlowableMailClient flowableMailClient;
+
+ private ProcessEngine processEngine;
+ private RepositoryService repositoryService;
+ private RuntimeService runtimeService;
+ private String deploymentId;
+ private TestVariableTask testVariableTask;
+
+ @BeforeEach
+ void setUp() throws Exception {
+ MockitoAnnotations.openMocks(this);
+ testVariableTask = new TestVariableTask();
+ DataSource dataSource = TestDataSourceProvider.getDataSource();
+ ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();
+ configuration.setDataSource(dataSource);
+ configuration.setDefaultMailClient(flowableMailClient);
+ configuration.setDatabaseSchemaUpdate(FLOWABLE_DB_SCHEMA_STRATEGY_CREATE_DROP);
+ configuration.setBeans(Map.of(TEST_VARIABLE_TASK_BEAN_NAME, testVariableTask));
+ processEngine = configuration.buildProcessEngine();
+ repositoryService = processEngine.getRepositoryService();
+ runtimeService = processEngine.getRuntimeService();
+ deploymentId = repositoryService.createDeployment()
+ .name(DEPLOYMENT_NAME_OF_DIAGRAM)
+ .addClasspathResource(
+ TEST_BPMN_DIAGRAM_RESOURCE)
+ .deploy()
+ .getId();
+ }
+
+ @AfterEach
+ void tearDown() {
+ if (deploymentId != null) {
+ repositoryService.deleteDeployment(deploymentId, true);
+ }
+ if (processEngine != null) {
+ processEngine.close();
+ }
+ }
+
+ @Test
+ void testProcessDeployment() {
+ List processDefinitions = repositoryService.createProcessDefinitionQuery()
+ .processDefinitionKey(TEST_PROCESS_KEY)
+ .list();
+
+ assertEquals(1, processDefinitions.size());
+ assertEquals(TEST_PROCESS_KEY, processDefinitions.get(0)
+ .getKey());
+ assertEquals(MTA_DEPLOYMENT_TEST_PROCESS, processDefinitions.get(0)
+ .getName());
+ }
+
+ @Test
+ void testProcessWithPredefinedVariables() {
+ FlowableProcessTestData data = FlowableProcessTestDataUtils.predefinedScenario();
+ runtimeService.startProcessInstanceByKey(TEST_PROCESS_KEY, buildVariablesMap(data));
+ assertCapturedVariables(data, true);
+ }
+
+ @Test
+ void testVariableUpdateAndRetrieval() {
+ FlowableProcessTestDataUtils.UpdateScenario updateScenario = FlowableProcessTestDataUtils.updateScenario();
+ testVariableTask.variablesToSetInContext = buildVariablesMap(updateScenario.updated());
+ runtimeService.startProcessInstanceByKey(TEST_PROCESS_KEY, buildVariablesMap(updateScenario.initial()));
+ // This assertion intentionally checks that the modified deployment descriptor is different from the initially set one because of flowable caching regression
+ // https://github.com/flowable/flowable-engine/issues/4130
+ // The original behaviour must be to have same deployment descriptor as it was set in the task. Modify the test to assert for matching values when the issue is fixed.
+ assertCapturedVariables(updateScenario.updated(), false);
+ }
+
+ @Test
+ void testSetVariablesInsideStep() {
+ FlowableProcessTestData data = FlowableProcessTestDataUtils.insideStepScenario();
+ testVariableTask.variablesToSetInContext = buildVariablesMap(data);
+ runtimeService.startProcessInstanceByKey(TEST_PROCESS_KEY);
+ assertCapturedVariables(data, true);
+ }
+
+ private Map buildVariablesMap(FlowableProcessTestData flowableProcessTestData) {
+ Map vars = new HashMap<>();
+ setSerializedValueInMap(vars, Variables.CORRELATION_ID, flowableProcessTestData.getCorrelationId());
+ setSerializedValueInMap(vars, Variables.SPACE_GUID, flowableProcessTestData.getSpaceGuid());
+ setSerializedValueInMap(vars, Variables.ORGANIZATION_GUID, flowableProcessTestData.getOrgGuid());
+ setSerializedValueInMap(vars, Variables.USER, flowableProcessTestData.getUsername());
+ setSerializedValueInMap(vars, Variables.USER_GUID, flowableProcessTestData.getUserGuid());
+ setSerializedValueInMap(vars, Variables.MTA_ID, flowableProcessTestData.getMtaId());
+ setSerializedValueInMap(vars, Variables.KEEP_FILES, flowableProcessTestData.keepFiles());
+ setSerializedValueInMap(vars, Variables.DELETE_SERVICES, flowableProcessTestData.deleteServices());
+ setSerializedValueInMap(vars, Variables.APPS_STAGE_TIMEOUT_PROCESS_VARIABLE, flowableProcessTestData.getAppsStageTimeout());
+ setSerializedValueInMap(vars, Variables.MODULES_COUNT, flowableProcessTestData.getModulesCount());
+ setSerializedValueInMap(vars, Variables.DEPLOYMENT_DESCRIPTOR_WITH_SYSTEM_PARAMETERS, flowableProcessTestData.getSmallDescriptor());
+ setSerializedValueInMap(vars, Variables.DEPLOYMENT_DESCRIPTOR, flowableProcessTestData.getBigDescriptor());
+ setSerializedValueInMap(vars, Variables.DEPLOYED_MTA, flowableProcessTestData.getDeployedMta());
+ setSerializedValueInMap(vars, Variables.CURRENT_ROUTES, flowableProcessTestData.getRoutes());
+ setSerializedValueInMap(vars, Variables.STEP_PHASE, flowableProcessTestData.getStepPhase());
+ setSerializedValueInMap(vars, Variables.APP_STATE_ACTIONS_TO_EXECUTE, flowableProcessTestData.getAppActions());
+ setSerializedValueInMap(vars, Variables.CLOUD_SERVICE_KEYS_TO_CREATE, flowableProcessTestData.getServiceKeys());
+ setSerializedValueInMap(vars, Variables.MODULES_FOR_DEPLOYMENT, flowableProcessTestData.getModulesForDeployment());
+ setSerializedValueInMap(vars, Variables.MTA_EXTENSION_DESCRIPTOR_CHAIN, flowableProcessTestData.getExtensionDescriptors());
+ return vars;
+ }
+
+ private void setSerializedValueInMap(Map variables, Variable variable, T value) {
+ if (value == null) {
+ variables.put(variable.getName(), null);
+ return;
+ }
+ Serializer serializer = variable.getSerializer();
+ variables.put(variable.getName(), serializer.serialize(value));
+ }
+
+ private T getDeserializedValue(Map variables, Variable variable) {
+ Object serializedValue = variables.get(variable.getName());
+ if (serializedValue == null) {
+ return variable.getDefaultValue();
+ }
+ Serializer serializer = variable.getSerializer();
+ return serializer.deserialize(serializedValue);
+ }
+
+ private void assertCapturedVariables(FlowableProcessTestData expected, boolean expectBigDescriptorMatch) {
+ Map actual = testVariableTask.capturedVariables;
+ assertEquals(expected.getCorrelationId(), getDeserializedValue(actual, Variables.CORRELATION_ID));
+ assertEquals(expected.getSpaceGuid(), getDeserializedValue(actual, Variables.SPACE_GUID));
+ assertEquals(expected.getOrgGuid(), getDeserializedValue(actual, Variables.ORGANIZATION_GUID));
+ assertEquals(expected.getUsername(), getDeserializedValue(actual, Variables.USER));
+ assertEquals(expected.getUserGuid(), getDeserializedValue(actual, Variables.USER_GUID));
+ assertEquals(expected.getMtaId(), getDeserializedValue(actual, Variables.MTA_ID));
+ assertEquals(expected.keepFiles(), getDeserializedValue(actual, Variables.KEEP_FILES));
+ assertEquals(expected.deleteServices(), getDeserializedValue(actual, Variables.DELETE_SERVICES));
+ assertEquals(expected.getAppsStageTimeout(), getDeserializedValue(actual, Variables.APPS_STAGE_TIMEOUT_PROCESS_VARIABLE));
+ assertEquals(expected.getModulesCount(), getDeserializedValue(actual, Variables.MODULES_COUNT));
+ assertEquals(JsonUtil.toJson(expected.getSmallDescriptor()),
+ JsonUtil.toJson(getDeserializedValue(actual, Variables.DEPLOYMENT_DESCRIPTOR_WITH_SYSTEM_PARAMETERS)));
+
+ String expectedBigDescriptor = JsonUtil.toJson(expected.getBigDescriptor());
+ String actualBigDescriptor = JsonUtil.toJson(getDeserializedValue(actual, Variables.DEPLOYMENT_DESCRIPTOR));
+ assertBigDescriptor(expectBigDescriptorMatch, expectedBigDescriptor, actualBigDescriptor);
+
+ assertEquals(expected.getDeployedMta(), getDeserializedValue(actual, Variables.DEPLOYED_MTA));
+ assertEquals(expected.getRoutes(), getDeserializedValue(actual, Variables.CURRENT_ROUTES));
+ assertEquals(expected.getStepPhase(), getDeserializedValue(actual, Variables.STEP_PHASE));
+ assertEquals(expected.getAppActions(), getDeserializedValue(actual, Variables.APP_STATE_ACTIONS_TO_EXECUTE));
+ assertEquals(expected.getServiceKeys(), getDeserializedValue(actual, Variables.CLOUD_SERVICE_KEYS_TO_CREATE));
+ assertEquals(expected.getModulesForDeployment(), getDeserializedValue(actual, Variables.MODULES_FOR_DEPLOYMENT));
+ assertEquals(JsonUtil.toJson(expected.getExtensionDescriptors(), JsonSerializationStrategy.ALLOW_NULLS),
+ JsonUtil.toJson(getDeserializedValue(actual, Variables.MTA_EXTENSION_DESCRIPTOR_CHAIN),
+ JsonSerializationStrategy.ALLOW_NULLS));
+ }
+
+ private static void assertBigDescriptor(boolean expectBigDescriptorMatch, String expectedBigDescriptor, String actualBigDescriptor) {
+ if (expectBigDescriptorMatch) {
+ assertEquals(expectedBigDescriptor, actualBigDescriptor);
+ return;
+ }
+ assertNotEquals(expectedBigDescriptor, actualBigDescriptor);
+
+ }
+
+ private class TestVariableTask implements JavaDelegate {
+
+ Map variablesToSetInContext = new HashMap<>();
+ Map capturedVariables = new HashMap<>();
+
+ @Override
+ public void execute(DelegateExecution execution) {
+ execution.setVariables(variablesToSetInContext);
+ capturedVariables = execution.getVariables();
+ }
+ }
+
+}
diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/flowable/FlowableProcessTestData.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/flowable/FlowableProcessTestData.java
new file mode 100644
index 0000000000..dc1db91811
--- /dev/null
+++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/flowable/FlowableProcessTestData.java
@@ -0,0 +1,67 @@
+package org.cloudfoundry.multiapps.controller.process.flowable;
+
+import java.time.Duration;
+import java.util.List;
+
+import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudRoute;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceKey;
+import org.cloudfoundry.multiapps.controller.core.cf.apps.ApplicationStateAction;
+import org.cloudfoundry.multiapps.controller.core.model.DeployedMta;
+import org.cloudfoundry.multiapps.controller.process.steps.StepPhase;
+import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor;
+import org.cloudfoundry.multiapps.mta.model.ExtensionDescriptor;
+import org.immutables.value.Value;
+
+@Value.Immutable
+public interface FlowableProcessTestData {
+
+ String getCorrelationId();
+
+ String getSpaceGuid();
+
+ String getOrgGuid();
+
+ String getUsername();
+
+ String getUserGuid();
+
+ String getMtaId();
+
+ String getMtaVersion();
+
+ @Value.Default
+ default boolean keepFiles() {
+ return false;
+ }
+
+ @Value.Default
+ default boolean deleteServices() {
+ return false;
+ }
+
+ Duration getAppsStageTimeout();
+
+ @Value.Default
+ default int getModulesCount() {
+ return 0;
+ }
+
+ DeploymentDescriptor getSmallDescriptor();
+
+ DeploymentDescriptor getBigDescriptor();
+
+ DeployedMta getDeployedMta();
+
+ List getRoutes();
+
+ StepPhase getStepPhase();
+
+ List getAppActions();
+
+ List getServiceKeys();
+
+ List getModulesForDeployment();
+
+ List getExtensionDescriptors();
+
+}
diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/flowable/FlowableProcessTestDataUtils.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/flowable/FlowableProcessTestDataUtils.java
new file mode 100644
index 0000000000..82909fdd58
--- /dev/null
+++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/flowable/FlowableProcessTestDataUtils.java
@@ -0,0 +1,380 @@
+package org.cloudfoundry.multiapps.controller.process.flowable;
+
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudRoute;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceKey;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudServiceKey;
+import org.cloudfoundry.multiapps.controller.core.cf.apps.ApplicationStateAction;
+import org.cloudfoundry.multiapps.controller.core.cf.metadata.ImmutableMtaMetadata;
+import org.cloudfoundry.multiapps.controller.core.model.DeployedMta;
+import org.cloudfoundry.multiapps.controller.core.model.DeployedMtaApplication;
+import org.cloudfoundry.multiapps.controller.core.model.DeployedMtaService;
+import org.cloudfoundry.multiapps.controller.core.model.ImmutableDeployedMta;
+import org.cloudfoundry.multiapps.controller.core.model.ImmutableDeployedMtaApplication;
+import org.cloudfoundry.multiapps.controller.core.model.ImmutableDeployedMtaService;
+import org.cloudfoundry.multiapps.controller.core.model.SupportedParameters;
+import org.cloudfoundry.multiapps.controller.core.util.ApplicationURI;
+import org.cloudfoundry.multiapps.controller.process.steps.StepPhase;
+import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor;
+import org.cloudfoundry.multiapps.mta.model.ExtensionDescriptor;
+import org.cloudfoundry.multiapps.mta.model.ExtensionModule;
+import org.cloudfoundry.multiapps.mta.model.ExtensionResource;
+import org.cloudfoundry.multiapps.mta.model.Module;
+import org.cloudfoundry.multiapps.mta.model.ProvidedDependency;
+import org.cloudfoundry.multiapps.mta.model.RequiredDependency;
+import org.cloudfoundry.multiapps.mta.model.Resource;
+import org.cloudfoundry.multiapps.mta.model.Version;
+
+public class FlowableProcessTestDataUtils {
+
+ // MTA and test identifiers
+ private static final String DEFAULT_MTA_ID = "test-mta";
+ private static final String DEFAULT_MTA_VERSION = "1.0.0";
+ private static final String UPDATE_SCENARIO_MTA_ID = "test-mta-2";
+ private static final String UPDATE_SCENARIO_VERSION_V2 = "2.0.0";
+ private static final String TEST_USER_EMAIL = "test-user@example.com";
+
+ // Module names and types
+ private static final String MODULE_1_NAME = "module-1";
+ private static final String MODULE_2_NAME = "module-2";
+ private static final String MODULE_3_NAME = "module-3";
+ private static final String MEMORY_1G = "1G";
+ private static final String MODULE_TYPE_JAVASCRIPT = "javascript";
+ private static final String MODULE_TYPE_JAVA = "java";
+ private static final int MODULES_COUNT = 5;
+
+ // Memory and disk quota values
+ private static final String MEMORY_512M = "512M";
+ private static final String DISK_QUOTA_256M = "256M";
+ private static final String DISK_QUOTA_4096M = "4096M";
+ private static final int INSTANCES_COUNT_2 = 2;
+
+ // Route configurations
+ private static final String ROUTE_1_EXAMPLE_COM = "route-1.example.com/foo-bar";
+ private static final String ROUTE_2_EXAMPLE_COM = "route-2.example.com";
+ private static final String ROUTE_3_EXAMPLE_COM = "route-3.example.com";
+ private static final String ROUTE_1_IDLE_EXAMPLE_COM = "route-1-idle.example.com/bar-foo";
+ private static final String ROUTE_2_IDLE_EXAMPLE_COM = "route-2-idle.example.com";
+ private static final String MODULE_1_ROUTE_EXAMPLE_COM = "module-1-route.example.com";
+ private static final String MODULE_2_ROUTE_EXAMPLE_COM = "module-2-route.example.com";
+ private static final String MODULE_3_ROUTE_EXAMPLE_COM = "module-3-route.example.com";
+
+ // Resource names
+ private static final String RESOURCE_DB_NAME = "db";
+ private static final String RESOURCE_CACHE_NAME = "cache";
+ private static final String RESOURCE_AUTOSCALER_NAME = "autoscaler";
+ private static final String RESOURCE_APPLICATION_LOGS_NAME = "application-logs";
+
+ // Service configurations
+ private static final String SERVICE_TYPE_MANAGED = "org.cloudfoundry.managed-service";
+ private static final String SERVICE_TYPE_USER_PROVIDED = "org.cloudfoundry.user-provided-service";
+ private static final String TEST_DB_SERVICE = "test-db-service";
+ private static final String TEST_CACHE_SERVICE = "test-cache-service";
+ private static final String APP_AUTOSCALER_SERVICE = "app-autoscaler";
+ private static final String SERVICE_PLAN_FREE = "free";
+ private static final String SERVICE_PLAN_DEFAULT = "default";
+
+ // Task configurations
+ private static final String TASK_1_NAME = "task-1";
+ private static final String TASK_1_COMMAND = "migrate-db.sh";
+ private static final String TASK_NAME_KEY = "name";
+ private static final String TASK_COMMAND_KEY = "command";
+
+ // Application and service names
+ private static final String APP_1_NAME = "app-1";
+ private static final String APP_2_NAME = "app-2";
+ private static final String APP_3_NAME = "app-3";
+ private static final String SERVICE_1_NAME = "service-1";
+ private static final String SERVICE_2_NAME = "service-2";
+ private static final String SERVICE_3_NAME = "service-3";
+
+ // Service key names
+ private static final String SERVICE_KEY_1_NAME = "service-key-1";
+ private static final String SERVICE_KEY_2_NAME = "service-key-2";
+
+ // Extension descriptor configurations
+ private static final String TEST_EXTENSION_ID = "test-extension";
+ private static final String TEST_PARAMETER_KEY = "test-parameter";
+
+ // API configurations
+ private static final String PROVIDED_DEPENDENCY_MY_API = "my-api";
+ private static final String API_URL_KEY = "url";
+ private static final String API_URL_VALUE = "https://api.example.com";
+
+ // Parameter values
+ private static final String NEW_PARAM_KEY = "new-param";
+ private static final String NEW_PARAM_VALUE = "new-value";
+ private static final String SYSLOG_DRAIN_URL_VALUE = "syslog://logs.example.com:514";
+
+ private FlowableProcessTestDataUtils() {
+ }
+
+ public record UpdateScenario(FlowableProcessTestData initial, FlowableProcessTestData updated) {
+ }
+
+ public static FlowableProcessTestData predefinedScenario() {
+ return baseBuilder(DEFAULT_MTA_ID, DEFAULT_MTA_VERSION).keepFiles(true)
+ .modulesCount(MODULES_COUNT)
+ .bigDescriptor(createBigDescriptor(DEFAULT_MTA_ID, DEFAULT_MTA_VERSION))
+ .routes(createRoutes(ROUTE_1_EXAMPLE_COM, ROUTE_2_EXAMPLE_COM,
+ ROUTE_3_EXAMPLE_COM))
+ .stepPhase(StepPhase.DONE)
+ .appActions(
+ List.of(ApplicationStateAction.STAGE, ApplicationStateAction.START))
+ .build();
+ }
+
+ public static UpdateScenario updateScenario() {
+ DeploymentDescriptor bigDescriptorV1 = createBigDescriptor(UPDATE_SCENARIO_MTA_ID, DEFAULT_MTA_VERSION);
+ DeploymentDescriptor bigDescriptorV2 = DeploymentDescriptor.copyOf(
+ createBigDescriptor(UPDATE_SCENARIO_MTA_ID, UPDATE_SCENARIO_VERSION_V2))
+ .setParameters(Map.of(NEW_PARAM_KEY, NEW_PARAM_VALUE));
+ FlowableProcessTestData initial = baseBuilder(UPDATE_SCENARIO_MTA_ID, DEFAULT_MTA_VERSION).deleteServices(true)
+ .bigDescriptor(bigDescriptorV1)
+ .deployedMta(
+ createDeployed(UPDATE_SCENARIO_MTA_ID,
+ DEFAULT_MTA_VERSION))
+ .routes(
+ createRoutes(ROUTE_1_IDLE_EXAMPLE_COM,
+ ROUTE_2_IDLE_EXAMPLE_COM))
+ .stepPhase(
+ org.cloudfoundry.multiapps.controller.process.steps.StepPhase.POLL)
+ .appActions(
+ List.of(ApplicationStateAction.STAGE,
+ ApplicationStateAction.START))
+ .build();
+ FlowableProcessTestData updated = baseBuilder(UPDATE_SCENARIO_MTA_ID, UPDATE_SCENARIO_VERSION_V2).deleteServices(true)
+ .smallDescriptor(
+ createSmallDescriptor(
+ UPDATE_SCENARIO_MTA_ID,
+ UPDATE_SCENARIO_VERSION_V2))
+ .bigDescriptor(bigDescriptorV2)
+ .deployedMta(createDeployed(
+ UPDATE_SCENARIO_MTA_ID,
+ UPDATE_SCENARIO_VERSION_V2))
+ .routes(createRoutes(
+ ROUTE_1_EXAMPLE_COM,
+ ROUTE_2_EXAMPLE_COM,
+ ROUTE_3_EXAMPLE_COM))
+ .stepPhase(
+ org.cloudfoundry.multiapps.controller.process.steps.StepPhase.DONE)
+ .appActions(List.of(
+ ApplicationStateAction.EXECUTE,
+ ApplicationStateAction.STOP))
+ .build();
+ return new UpdateScenario(initial, updated);
+ }
+
+ public static FlowableProcessTestData insideStepScenario() {
+ return baseBuilder(UPDATE_SCENARIO_MTA_ID, UPDATE_SCENARIO_VERSION_V2).deleteServices(true)
+ .smallDescriptor(createSmallDescriptor(UPDATE_SCENARIO_MTA_ID,
+ UPDATE_SCENARIO_VERSION_V2))
+ .bigDescriptor(createBigDescriptor(UPDATE_SCENARIO_MTA_ID,
+ UPDATE_SCENARIO_VERSION_V2))
+ .deployedMta(createDeployed(UPDATE_SCENARIO_MTA_ID,
+ UPDATE_SCENARIO_VERSION_V2))
+ .routes(createRoutes(ROUTE_1_EXAMPLE_COM, ROUTE_2_EXAMPLE_COM,
+ ROUTE_3_EXAMPLE_COM))
+ .stepPhase(StepPhase.DONE)
+ .appActions(List.of(ApplicationStateAction.STAGE,
+ ApplicationStateAction.START))
+ .build();
+ }
+
+ private static ImmutableFlowableProcessTestData.Builder baseBuilder(String mtaId, String mtaVersion) {
+ return ImmutableFlowableProcessTestData.builder()
+ .correlationId(UUID.randomUUID()
+ .toString())
+ .spaceGuid(UUID.randomUUID()
+ .toString())
+ .orgGuid(UUID.randomUUID()
+ .toString())
+ .username(TEST_USER_EMAIL)
+ .userGuid(UUID.randomUUID()
+ .toString())
+ .mtaId(mtaId)
+ .mtaVersion(mtaVersion)
+ .appsStageTimeout(Duration.ofMinutes(15))
+ .smallDescriptor(createSmallDescriptor(mtaId, mtaVersion))
+ .deployedMta(createDeployed(mtaId, mtaVersion))
+ .stepPhase(StepPhase.DONE)
+ .serviceKeys(createServiceKeys())
+ .modulesForDeployment(List.of(MODULE_1_NAME, MODULE_2_NAME, MODULE_3_NAME))
+ .extensionDescriptors(createExtensionDescriptorsWithNullValues(mtaId));
+ }
+
+ private static DeploymentDescriptor createSmallDescriptor(String id, String mtaVersion) {
+ return DeploymentDescriptor.createV3()
+ .setId(id)
+ .setVersion(mtaVersion)
+ .setModules(List.of(Module.createV3()
+ .setName(MODULE_1_NAME)
+ .setType(MODULE_TYPE_JAVASCRIPT)
+ .setParameters(Map.of(SupportedParameters.MEMORY, MEMORY_512M,
+ SupportedParameters.DISK_QUOTA, DISK_QUOTA_256M,
+ SupportedParameters.ROUTES,
+ List.of(SupportedParameters.ROUTE,
+ MODULE_1_ROUTE_EXAMPLE_COM)))
+ .setRequiredDependencies(List.of(RequiredDependency.createV3()
+ .setName(
+ RESOURCE_DB_NAME)))))
+ .setResources(List.of(Resource.createV3()
+ .setName(RESOURCE_DB_NAME)
+ .setType(SERVICE_TYPE_MANAGED)
+ .setParameters(Map.of(SupportedParameters.SERVICE, TEST_DB_SERVICE,
+ SupportedParameters.SERVICE_PLAN,
+ SERVICE_PLAN_FREE))));
+ }
+
+ private static DeploymentDescriptor createBigDescriptor(String id, String mtaVersion) {
+ return DeploymentDescriptor.createV3()
+ .setId(id)
+ .setVersion(mtaVersion)
+ .setParameters(Map.of(SupportedParameters.ENABLE_PARALLEL_DEPLOYMENTS, true))
+ .setModules(List.of(Module.createV3()
+ .setName(MODULE_1_NAME)
+ .setType(MODULE_TYPE_JAVASCRIPT)
+ .setParameters(Map.of(SupportedParameters.MEMORY, MEMORY_512M,
+ SupportedParameters.DISK_QUOTA, DISK_QUOTA_256M,
+ SupportedParameters.ROUTES,
+ List.of(SupportedParameters.ROUTE,
+ MODULE_1_ROUTE_EXAMPLE_COM),
+ SupportedParameters.TASKS, List.of(
+ Map.of(TASK_NAME_KEY, TASK_1_NAME, TASK_COMMAND_KEY, TASK_1_COMMAND))))
+ .setRequiredDependencies(List.of(RequiredDependency.createV3()
+ .setName(RESOURCE_DB_NAME),
+ RequiredDependency.createV3()
+ .setName(
+ RESOURCE_APPLICATION_LOGS_NAME))),
+ Module.createV3()
+ .setName(MODULE_2_NAME)
+ .setType(MODULE_TYPE_JAVA)
+ .setParameters(Map.of(SupportedParameters.MEMORY, MEMORY_1G,
+ SupportedParameters.DISK_QUOTA, DISK_QUOTA_4096M,
+ SupportedParameters.INSTANCES, INSTANCES_COUNT_2,
+ SupportedParameters.ROUTES,
+ List.of(SupportedParameters.ROUTE,
+ MODULE_2_ROUTE_EXAMPLE_COM)))
+ .setRequiredDependencies(List.of(RequiredDependency.createV3()
+ .setName(RESOURCE_DB_NAME),
+ RequiredDependency.createV3()
+ .setName(
+ RESOURCE_CACHE_NAME),
+ RequiredDependency.createV3()
+ .setName(
+ RESOURCE_AUTOSCALER_NAME),
+ RequiredDependency.createV3()
+ .setName(
+ RESOURCE_APPLICATION_LOGS_NAME))),
+ Module.createV3()
+ .setName(MODULE_3_NAME)
+ .setType(MODULE_TYPE_JAVASCRIPT)
+ .setParameters(
+ Map.of(SupportedParameters.MEMORY, MEMORY_512M,
+ SupportedParameters.DISK_QUOTA,
+ DISK_QUOTA_256M, SupportedParameters.ROUTES,
+ List.of(SupportedParameters.ROUTE, MODULE_3_ROUTE_EXAMPLE_COM)))
+ .setRequiredDependencies(List.of(RequiredDependency.createV3()
+ .setName(RESOURCE_DB_NAME),
+ RequiredDependency.createV3()
+ .setName(
+ RESOURCE_CACHE_NAME),
+ RequiredDependency.createV3()
+ .setName(
+ RESOURCE_AUTOSCALER_NAME),
+ RequiredDependency.createV3()
+ .setName(
+ RESOURCE_APPLICATION_LOGS_NAME)))
+ .setProvidedDependencies(List.of(ProvidedDependency.createV3()
+ .setName(
+ PROVIDED_DEPENDENCY_MY_API)
+ .setProperties(
+ Map.of(API_URL_KEY,
+ API_URL_VALUE))))))
+ .setResources(List.of(Resource.createV3()
+ .setName(RESOURCE_DB_NAME)
+ .setType(SERVICE_TYPE_MANAGED)
+ .setParameters(Map.of(SupportedParameters.SERVICE, TEST_DB_SERVICE,
+ SupportedParameters.SERVICE_PLAN,
+ SERVICE_PLAN_FREE)),
+ Resource.createV3()
+ .setName(RESOURCE_CACHE_NAME)
+ .setType(SERVICE_TYPE_MANAGED)
+ .setParameters(Map.of(SupportedParameters.SERVICE, TEST_CACHE_SERVICE,
+ SupportedParameters.SERVICE_PLAN,
+ SERVICE_PLAN_FREE)),
+ Resource.createV3()
+ .setName(RESOURCE_AUTOSCALER_NAME)
+ .setType(SERVICE_TYPE_MANAGED)
+ .setParameters(Map.of(SupportedParameters.SERVICE, APP_AUTOSCALER_SERVICE,
+ SupportedParameters.SERVICE_PLAN,
+ SERVICE_PLAN_DEFAULT)),
+ Resource.createV3()
+ .setName(RESOURCE_APPLICATION_LOGS_NAME)
+ .setType(SERVICE_TYPE_USER_PROVIDED)
+ .setParameters(Map.of(SupportedParameters.SYSLOG_DRAIN_URL,
+ SYSLOG_DRAIN_URL_VALUE))));
+ }
+
+ private static DeployedMta createDeployed(String id, String mtaVersion) {
+ List apps = Stream.of(APP_1_NAME, APP_2_NAME, APP_3_NAME)
+ .map(app -> ImmutableDeployedMtaApplication.builder()
+ .name(app)
+ .moduleName(app)
+ .build())
+ .collect(Collectors.toList());
+ List services = Stream.of(SERVICE_1_NAME, SERVICE_2_NAME, SERVICE_3_NAME)
+ .map(service -> ImmutableDeployedMtaService.builder()
+ .name(service)
+ .build())
+ .collect(Collectors.toList());
+ return ImmutableDeployedMta.builder()
+ .metadata(ImmutableMtaMetadata.builder()
+ .id(id)
+ .version(Version.parseVersion(mtaVersion))
+ .build())
+ .applications(apps)
+ .services(services)
+ .build();
+ }
+
+ private static List createRoutes(String... routes) {
+ return Stream.of(routes)
+ .map(route -> new ApplicationURI(route, false, null).toCloudRoute())
+ .collect(Collectors.toList());
+ }
+
+ private static List createServiceKeys() {
+ return List.of(ImmutableCloudServiceKey.builder()
+ .name(SERVICE_KEY_1_NAME)
+ .build(), ImmutableCloudServiceKey.builder()
+ .name(SERVICE_KEY_2_NAME)
+ .build());
+ }
+
+ private static List createExtensionDescriptorsWithNullValues(String mtaId) {
+ Map moduleParams = new HashMap<>();
+ moduleParams.put(SupportedParameters.MEMORY, null);
+ moduleParams.put(SupportedParameters.DISK_QUOTA, DISK_QUOTA_256M);
+ moduleParams.put(SupportedParameters.ROUTES, List.of(SupportedParameters.ROUTE, MODULE_1_ROUTE_EXAMPLE_COM));
+ Map resourceParams = new HashMap<>();
+ resourceParams.put(TEST_PARAMETER_KEY, null);
+ return List.of(ExtensionDescriptor.createV3()
+ .setId(TEST_EXTENSION_ID)
+ .setParentId(mtaId)
+ .setModules(List.of(ExtensionModule.createV3()
+ .setName(MODULE_1_NAME)
+ .setParameters(moduleParams)))
+ .setResources(List.of(ExtensionResource.createV3()
+ .setName(RESOURCE_DB_NAME)
+ .setParameters(resourceParams))));
+ }
+
+}
diff --git a/multiapps-controller-process/src/test/resources/META-INF/persistence.xml b/multiapps-controller-process/src/test/resources/META-INF/persistence.xml
new file mode 100644
index 0000000000..cda667cd28
--- /dev/null
+++ b/multiapps-controller-process/src/test/resources/META-INF/persistence.xml
@@ -0,0 +1,18 @@
+
+
+
+ org.eclipse.persistence.jpa.PersistenceProvider
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/multiapps-controller-process/src/test/resources/org/cloudfoundry/multiapps/controller/process/flowable/test-bpmn-diagram.bpmn b/multiapps-controller-process/src/test/resources/org/cloudfoundry/multiapps/controller/process/flowable/test-bpmn-diagram.bpmn
new file mode 100644
index 0000000000..736d665177
--- /dev/null
+++ b/multiapps-controller-process/src/test/resources/org/cloudfoundry/multiapps/controller/process/flowable/test-bpmn-diagram.bpmn
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file