diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/model/SupportedParameters.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/model/SupportedParameters.java index 3555fcddad..13f6b5e3cb 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/model/SupportedParameters.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/model/SupportedParameters.java @@ -38,6 +38,10 @@ public class SupportedParameters { public static final String APPLY_NAMESPACE_SERVICES = "service-names"; public static final String APPLY_NAMESPACE_ROUTES = "app-routes"; + public static final String DEPLOY_MODE = "deploy_mode"; + + public static final String PATH = "path"; + // Module / module type parameters: public static final String APP_NAME = "app-name"; public static final String DEFAULT_APP_NAME = "default-app-name"; @@ -99,7 +103,8 @@ public class SupportedParameters { public static final String DOCKER = "docker"; public static final String TIMESTAMP = "timestamp"; public static final String ENABLE_PARALLEL_SERVICE_BINDINGS = "enable-parallel-service-bindings"; - + public static final String TCP_ROUTES = "tcp"; + public static final String TCPS_ROUTES = "tcps"; public static final String EXECUTE_APP = "execute-app"; public static final String SUCCESS_MARKER = "success-marker"; public static final String FAILURE_MARKER = "failure-marker"; @@ -117,6 +122,8 @@ public class SupportedParameters { public static final String SERVICE_BROKER_PASSWORD = "service-broker-password"; public static final String SERVICE_BROKER_URL = "service-broker-url"; public static final String SERVICE_BROKER_SPACE_SCOPED = "service-broker-space-scoped"; + public static final String MODULE_CONFIG = "config"; + public static final String HOOK_REQUIRES = "requires"; // Required dependency parameters: public static final String SERVICE_BINDING_CONFIG = "config"; @@ -172,6 +179,40 @@ public class SupportedParameters { @Deprecated public static final String DEPRECATED_CONFIG_MTA_PROVIDES_DEPENDENCY = "mta-provides-dependency"; + public static final Set MODULE_PARAMETERS = Set.of(APP_NAME, APPLY_NAMESPACE, BUILDPACK, BUILDPACKS, COMMAND, + CREATE_SERVICE_BROKER, DEFAULT_APP_NAME, DEFAULT_HOST, DEFAULT_INSTANCES, + DEFAULT_LIVE_APP_NAME, DEFAULT_LIVE_DOMAIN, DEFAULT_LIVE_HOST, + DEFAULT_LIVE_URI, DEFAULT_LIVE_URL, DEFAULT_URI, DEFAULT_URL, + DEPENDENCY_TYPE, DISK_QUOTA, DOCKER, DOMAIN, DOMAINS, DEFAULT_DOMAIN, + ENABLE_SSH, ENABLE_PARALLEL_SERVICE_BINDINGS, HEALTH_CHECK_HTTP_ENDPOINT, + HEALTH_CHECK_TIMEOUT, HEALTH_CHECK_INVOCATION_TIMEOUT, HEALTH_CHECK_TYPE, + HOST, HOSTS, IDLE_DOMAIN, IDLE_DOMAINS, IDLE_HOST, IDLE_HOSTS, IDLE_ROUTES, + INSTANCES, KEEP_EXISTING_APPLICATION_ATTRIBUTES_UPDATE_STRATEGY, + KEEP_EXISTING_ROUTES, MEMORY, NO_ROUTE, NO_START, RESTART_ON_ENV_CHANGE, + ROUTES, ROUTE_PATH, SERVICE_BROKER_NAME, SERVICE_BROKER_PASSWORD, + SERVICE_BROKER_SPACE_SCOPED, SERVICE_BROKER_URL, SERVICE_BROKER_USERNAME, + STACK, STAGE_TIMEOUT, START_TIMEOUT, TASK_EXECUTION_TIMEOUT, TASKS, + TCP_ROUTES, TCPS_ROUTES, TIMESTAMP, UPLOAD_TIMEOUT, ROUTE, EXECUTE_APP, + SUCCESS_MARKER, FAILURE_MARKER, STOP_APP, CHECK_DEPLOY_ID, + REGISTER_SERVICE_URL, REGISTER_SERVICE_URL_SERVICE_NAME, + REGISTER_SERVICE_URL_SERVICE_URL, MODULE_CONFIG, MANAGED, PATH, + APPS_UPLOAD_TIMEOUT, APPS_TASK_EXECUTION_TIMEOUT, + APPS_START_TIMEOUT, APPS_STAGE_TIMEOUT); + + public static final Set RESOURCE_PARAMETERS = Set.of(APPLY_NAMESPACE, SERVICE_CONFIG, SYSLOG_DRAIN_URL, DEFAULT_CONTAINER_NAME, + DEFAULT_SERVICE_NAME, DEFAULT_XS_APP_NAME, SERVICE, SERVICE_KEYS, + SERVICE_KEY_NAME, SERVICE_NAME, SERVICE_PLAN, SERVICE_TAGS, SERVICE_BROKER, + SKIP_SERVICE_UPDATES, TYPE, PROVIDER_ID, PROVIDER_NID, TARGET, + SERVICE_CONFIG_PATH, FILTER, MANAGED, VERSION, PATH, MEMORY); + public static final Set GLOBAL_PARAMETERS = Set.of(KEEP_EXISTING_ROUTES, APPS_UPLOAD_TIMEOUT, APPS_TASK_EXECUTION_TIMEOUT, + APPS_START_TIMEOUT, APPS_STAGE_TIMEOUT, APPLY_NAMESPACE, + ENABLE_PARALLEL_DEPLOYMENTS, DEPLOY_MODE); + + public static final Set DEPENDENCY_PARAMETERS = Set.of(BINDING_NAME, ENV_VAR_NAME, VISIBILITY, USE_LIVE_ROUTES, + SERVICE_BINDING_CONFIG); + + public static final Set MODULE_HOOK_PARAMETERS = Set.of(NAME, COMMAND, MEMORY, DISK_QUOTA, HOOK_REQUIRES); + public static final Set CONFIGURATION_REFERENCE_PARAMETERS = Set.of(PROVIDER_NID, PROVIDER_ID, TARGET, VERSION, DEPRECATED_CONFIG_MTA_ID, DEPRECATED_CONFIG_MTA_VERSION, DEPRECATED_CONFIG_MTA_PROVIDES_DEPENDENCY, NAMESPACE); diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java index 64477c41b5..59951deebe 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java @@ -258,6 +258,8 @@ public class Messages { public static final String SERVICE_KEY_0_IS_ALREADY_DELETED = "Service key \"{0}\" is already deleted"; public static final String FILE_WITH_ID_0_OPERATION_OWNERSHIP_CHANGED_FROM_0_TO_1 = "File with id \"{0}\" operation ownership was changed from \"{1}\" to \"{2}\" and won't be deleted"; + public static final String PARAMETERS_0_ARE_NOT_SUPPORTED_OR_REFERENCED_BY_ANY_OTHER_ENTITIES = "Parameter(s) \"{0}\" are not supported in the specified scope, or referenced by any other entities. These parameters will not be processed and can be lost after the operation completes."; + // INFO log messages public static final String ACQUIRING_LOCK = "Process \"{0}\" attempting to acquire lock for operation on MTA \"{1}\""; public static final String ACQUIRED_LOCK = "Process \"{0}\" acquired lock for operation on MTA \"{1}\""; diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/MergeDescriptorsStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/MergeDescriptorsStep.java index bb799f10c6..7ec5a8439b 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/MergeDescriptorsStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/MergeDescriptorsStep.java @@ -1,8 +1,12 @@ package org.cloudfoundry.multiapps.controller.process.steps; +import java.text.MessageFormat; import java.util.List; +import java.util.Map; import java.util.Objects; +import jakarta.inject.Inject; +import jakarta.inject.Named; import org.cloudfoundry.multiapps.controller.core.cf.CloudHandlerFactory; import org.cloudfoundry.multiapps.controller.core.helpers.MtaDescriptorMerger; import org.cloudfoundry.multiapps.controller.persistence.dto.BackupDescriptor; @@ -10,16 +14,16 @@ import org.cloudfoundry.multiapps.controller.persistence.services.DescriptorBackupService; import org.cloudfoundry.multiapps.controller.process.Messages; import org.cloudfoundry.multiapps.controller.process.util.NamespaceGlobalParameters; +import org.cloudfoundry.multiapps.controller.process.util.UnsupportedParameterFinder; import org.cloudfoundry.multiapps.controller.process.variables.Variables; import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor; import org.cloudfoundry.multiapps.mta.model.ExtensionDescriptor; import org.cloudfoundry.multiapps.mta.model.Platform; +import org.cloudfoundry.multiapps.mta.resolvers.ReferenceContainer; +import org.cloudfoundry.multiapps.mta.resolvers.ReferencesFinder; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; -import jakarta.inject.Inject; -import jakarta.inject.Named; - @Named("mergeDescriptorsStep") @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class MergeDescriptorsStep extends SyncFlowableStep { @@ -27,6 +31,9 @@ public class MergeDescriptorsStep extends SyncFlowableStep { @Inject private DescriptorBackupService descriptorBackupService; + @Inject + private UnsupportedParameterFinder unsupportedParameterFinder; + protected MtaDescriptorMerger getMtaDescriptorMerger(CloudHandlerFactory factory, Platform platform) { return new MtaDescriptorMerger(factory, platform, getStepLogger()); } @@ -42,11 +49,23 @@ protected StepPhase executeStep(ProcessContext context) { extensionDescriptors); context.setVariable(Variables.DEPLOYMENT_DESCRIPTOR, descriptor); + warnForUnsupportedParameters(descriptor); + backupDeploymentDescriptor(context, descriptor); getStepLogger().debug(Messages.DESCRIPTORS_MERGED); return StepPhase.DONE; } + private void warnForUnsupportedParameters(DeploymentDescriptor descriptor) { + List references = new ReferencesFinder().getAllReferences(descriptor); + Map> unsupportedParameters = unsupportedParameterFinder.findUnsupportedParameters(descriptor, + references); + if (!unsupportedParameters.isEmpty()) { + getStepLogger().warn(MessageFormat.format(Messages.PARAMETERS_0_ARE_NOT_SUPPORTED_OR_REFERENCED_BY_ANY_OTHER_ENTITIES, + unsupportedParameters)); + } + } + private void backupDeploymentDescriptor(ProcessContext context, DeploymentDescriptor descriptor) { boolean shouldBackupPreviousVersion = context.getVariable(Variables.SHOULD_BACKUP_PREVIOUS_VERSION); if (!shouldBackupPreviousVersion) { diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/CustomParameterContainerProcessor.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/CustomParameterContainerProcessor.java new file mode 100644 index 0000000000..7d41fe75a3 --- /dev/null +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/CustomParameterContainerProcessor.java @@ -0,0 +1,42 @@ +package org.cloudfoundry.multiapps.controller.process.util; + +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.cloudfoundry.multiapps.mta.resolvers.CustomParameterContainer; +import org.cloudfoundry.multiapps.mta.resolvers.ReferenceContainer; +import org.springframework.stereotype.Component; + +@Component +public class CustomParameterContainerProcessor { + private static final String GLOBAL_PARAMETER = "global-parameter"; + + public Map.Entry> processCustomParameterContainer(CustomParameterContainer container, + List references, + ReferenceContainerMatcher referenceMatcher) { + List unreferenced = filterUnreferencedParameters(container, references, referenceMatcher); + String prefixedName = getPrefixedName(container); + return new AbstractMap.SimpleEntry<>(prefixedName, unreferenced); + } + + private List filterUnreferencedParameters(CustomParameterContainer container, List references, + ReferenceContainerMatcher referenceMatcher) { + return container.getParameters() + .stream() + .filter(parameter -> !isParameterReferenced(references, container, parameter, referenceMatcher)) + .collect(Collectors.toList()); + } + + private boolean isParameterReferenced(List references, CustomParameterContainer container, String customParameter, + ReferenceContainerMatcher referenceMatcher) { + return references.stream() + .anyMatch(referenceContainer -> referenceMatcher.isReferenceContainerMatching(referenceContainer, container, + customParameter)); + } + + private String getPrefixedName(CustomParameterContainer container) { + return container.getPrefixedName() != null ? container.getPrefixedName() : GLOBAL_PARAMETER; + } +} diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ModuleHooksAggregator.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ModuleHooksAggregator.java index 0367e0d50b..c357f0909d 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ModuleHooksAggregator.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ModuleHooksAggregator.java @@ -1,4 +1,3 @@ - package org.cloudfoundry.multiapps.controller.process.util; import java.util.Collections; @@ -13,9 +12,7 @@ import org.flowable.engine.delegate.DelegateExecution; public class ModuleHooksAggregator { - private static final int MAJOR_SCHEMA_VERSION_THREE = 3; - private final DelegateExecution execution; private final Module moduleToDeploy; @@ -31,17 +28,17 @@ public List aggregateHooks(List currentHookPhasesForExecution) private List determineHooksForExecution(Map> alreadyExecutedHooks, List hookPhasesForCurrentStepPhase) { - List moduleHooksToExecuteOnCurrentStepPhase = collectHooksWithPhase(moduleToDeploy, hookPhasesForCurrentStepPhase); + List moduleHooksToExecuteOnCurrentStepPhase = collectHooksWithPhase(hookPhasesForCurrentStepPhase); return getHooksForExecution(alreadyExecutedHooks, moduleHooksToExecuteOnCurrentStepPhase, hookPhasesForCurrentStepPhase); } - private List collectHooksWithPhase(Module moduleToDeploy, List hookPhasesForCurrentStepPhase) { - return getModuleHooks(moduleToDeploy).stream() - .filter(hook -> shouldCollectHook(hook.getPhases(), hookPhasesForCurrentStepPhase)) - .collect(Collectors.toList()); + private List collectHooksWithPhase(List hookPhasesForCurrentStepPhase) { + return getModuleHooks().stream() + .filter(hook -> shouldCollectHook(hook.getPhases(), hookPhasesForCurrentStepPhase)) + .collect(Collectors.toList()); } - private List getModuleHooks(Module moduleToDeploy) { + private List getModuleHooks() { return moduleToDeploy.getMajorSchemaVersion() < MAJOR_SCHEMA_VERSION_THREE ? Collections.emptyList() : moduleToDeploy.getHooks(); } diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ReferenceContainerMatcher.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ReferenceContainerMatcher.java new file mode 100644 index 0000000000..39d4a095a3 --- /dev/null +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/ReferenceContainerMatcher.java @@ -0,0 +1,40 @@ +package org.cloudfoundry.multiapps.controller.process.util; + +import org.cloudfoundry.multiapps.mta.resolvers.CustomParameterContainer; +import org.cloudfoundry.multiapps.mta.resolvers.Reference; +import org.cloudfoundry.multiapps.mta.resolvers.ReferenceContainer; +import org.springframework.stereotype.Component; + +@Component +public class ReferenceContainerMatcher { + public boolean isReferenceContainerMatching(ReferenceContainer referenceContainer, + CustomParameterContainer container, + String customParameter) { + return isReferenceMatchingParameter(referenceContainer, customParameter, container) + && isReferenceOwnerMatched(referenceContainer.getReferenceOwner(), container.getParameterOwner()); + } + + private boolean isReferenceMatchingParameter(ReferenceContainer referenceContainer, + String customParameter, CustomParameterContainer container) { + return referenceContainer.getReferences() + .stream() + .anyMatch(reference -> isReferenceNameMatched(reference, customParameter) + && isReferenceDependencyMatched(reference, container)); + } + + private boolean isReferenceNameMatched(Reference reference, String customParameter) { + return reference.getKey() + .equals(customParameter); + } + + private boolean isReferenceDependencyMatched(Reference reference, CustomParameterContainer container) { + String dependencyName = reference.getDependencyName(); + String parameterOwner = container.getParameterOwner(); + + return dependencyName == null || parameterOwner == null || dependencyName.equals(parameterOwner); + } + + private boolean isReferenceOwnerMatched(String referenceOwner, String parameterOwner) { + return parameterOwner == null || parameterOwner.equals(referenceOwner); + } +} diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/SchemaVersionUtils.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/SchemaVersionUtils.java new file mode 100644 index 0000000000..4cdcf7a957 --- /dev/null +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/SchemaVersionUtils.java @@ -0,0 +1,14 @@ +package org.cloudfoundry.multiapps.controller.process.util; + +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +public class SchemaVersionUtils { + + private static final int MAJOR_SCHEMA_VERSION_THREE = 3; + + public static List getEntityData(T entity, Function versionGetter, Function> dataGetter) { + return versionGetter.apply(entity) < MAJOR_SCHEMA_VERSION_THREE ? Collections.emptyList() : dataGetter.apply(entity); + } +} diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/SupportedParameterChecker.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/SupportedParameterChecker.java new file mode 100644 index 0000000000..9ea4929e44 --- /dev/null +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/SupportedParameterChecker.java @@ -0,0 +1,51 @@ +package org.cloudfoundry.multiapps.controller.process.util; + +import java.util.HashSet; +import java.util.Set; + +import jakarta.inject.Named; +import org.cloudfoundry.multiapps.controller.core.model.SupportedParameters; +import org.cloudfoundry.multiapps.mta.resolvers.ParameterChecker; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Scope; + +@Named("supportedParameterChecker") +@Scope(BeanDefinition.SCOPE_PROTOTYPE) +public class SupportedParameterChecker extends ParameterChecker { + + private static final Set REQUIRED_AND_PROVIDED_DEPENDENCY_PARAMETERS = initializeDependencyParameters(); + + @Override + protected Set getModuleParametersToMatch() { + return SupportedParameters.MODULE_PARAMETERS; + } + + @Override + protected Set getModuleHookParametersToMatch() { + return SupportedParameters.MODULE_HOOK_PARAMETERS; + } + + @Override + protected Set getResourceParametersToMatch() { + return SupportedParameters.RESOURCE_PARAMETERS; + } + + @Override + protected Set getGlobalParametersToMatch() { + return SupportedParameters.GLOBAL_PARAMETERS; + } + + @Override + protected Set getDependencyParametersToMatch() { + return REQUIRED_AND_PROVIDED_DEPENDENCY_PARAMETERS; + } + + private static Set initializeDependencyParameters() { + Set dependencyParameters = new HashSet<>(); + dependencyParameters.addAll(SupportedParameters.DEPENDENCY_PARAMETERS); + dependencyParameters.addAll(SupportedParameters.MODULE_PARAMETERS); + dependencyParameters.addAll(SupportedParameters.RESOURCE_PARAMETERS); + return dependencyParameters; + } + +} diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/UnsupportedParameterFinder.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/UnsupportedParameterFinder.java new file mode 100644 index 0000000000..a5473a5d31 --- /dev/null +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/util/UnsupportedParameterFinder.java @@ -0,0 +1,56 @@ +package org.cloudfoundry.multiapps.controller.process.util; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +import jakarta.inject.Inject; +import jakarta.inject.Named; +import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor; +import org.cloudfoundry.multiapps.mta.resolvers.CustomParameterContainer; +import org.cloudfoundry.multiapps.mta.resolvers.ReferenceContainer; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Scope; + +@Named("UnsupportedParameterFinder") +@Scope(BeanDefinition.SCOPE_PROTOTYPE) +public class UnsupportedParameterFinder { + + @Inject + private SupportedParameterChecker supportedParameterChecker; + + @Inject + private ReferenceContainerMatcher referenceMatcher; + + @Inject + private CustomParameterContainerProcessor containerProcessor; + + public Map> findUnsupportedParameters(DeploymentDescriptor descriptor, List references) { + List unknownParametersContainer = supportedParameterChecker.getCustomParameters(descriptor); + return collectUnsupportedParametersByOwner(unknownParametersContainer, references); + } + + private Map> collectUnsupportedParametersByOwner(List containers, + List references) { + return containers.stream() + .map(container -> containerProcessor.processCustomParameterContainer(container, references, referenceMatcher)) + .filter(entry -> !entry.getValue() + .isEmpty()) + .collect(unsupportedParametersCollector()); + } + + private Collector>, ?, Map>> unsupportedParametersCollector() { + return Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, + this::mergeParameterLists + ); + } + + private List mergeParameterLists(List existing, List replacement) { + existing.addAll(replacement); + return existing; + } + +} diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/MergeDescriptorsStepTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/MergeDescriptorsStepTest.java index e22ced0446..97a16b4274 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/MergeDescriptorsStepTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/MergeDescriptorsStepTest.java @@ -1,10 +1,5 @@ package org.cloudfoundry.multiapps.controller.process.steps; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - import java.util.Collections; import org.cloudfoundry.multiapps.common.ContentException; @@ -13,12 +8,21 @@ import org.cloudfoundry.multiapps.controller.core.cf.CloudHandlerFactory; import org.cloudfoundry.multiapps.controller.core.helpers.MtaDescriptorMerger; import org.cloudfoundry.multiapps.controller.core.test.DescriptorTestUtil; +import org.cloudfoundry.multiapps.controller.process.util.UnsupportedParameterFinder; import org.cloudfoundry.multiapps.controller.process.variables.Variables; import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor; import org.cloudfoundry.multiapps.mta.model.Platform; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; +import org.mockito.Mockito; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; class MergeDescriptorsStepTest extends SyncFlowableStepTest { @@ -39,6 +43,9 @@ protected MtaDescriptorMerger getMtaDescriptorMerger(CloudHandlerFactory factory @Mock private MtaDescriptorMerger merger; + @Mock + private UnsupportedParameterFinder unsupportedParameterFinder; + @BeforeEach public void setUp() { prepareContext(); @@ -53,10 +60,11 @@ private void prepareContext() { @Test void testExecute1() { + when(unsupportedParameterFinder.findUnsupportedParameters(Mockito.any(), Mockito.any())).thenReturn(Collections.emptyMap()); when(merger.merge(any(), eq(Collections.emptyList()))).thenReturn(DEPLOYMENT_DESCRIPTOR); step.execute(execution); - + verify(unsupportedParameterFinder, times(1)).findUnsupportedParameters(Mockito.any(), Mockito.any()); assertStepFinishedSuccessfully(); tester.test(() -> context.getVariable(Variables.DEPLOYMENT_DESCRIPTOR), diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/CustomParameterContainerProcessorTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/CustomParameterContainerProcessorTest.java new file mode 100644 index 0000000000..3de0a9eef0 --- /dev/null +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/CustomParameterContainerProcessorTest.java @@ -0,0 +1,105 @@ +package org.cloudfoundry.multiapps.controller.process.util; + +import java.util.List; +import java.util.Map; + +import org.cloudfoundry.multiapps.mta.resolvers.CustomParameterContainer; +import org.cloudfoundry.multiapps.mta.resolvers.ReferenceContainer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +class CustomParameterContainerProcessorTest { + @Mock + private ReferenceContainerMatcher referenceMatcher; + + @Mock + private CustomParameterContainer container; + + @Mock + private ReferenceContainer referenceContainer; + + @InjectMocks + private CustomParameterContainerProcessor processor; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void testProcessCustomParameterContainer_WithNoUnreferencedParameters() { + String customParameter = "param1"; + List references = List.of(referenceContainer); + + when(container.getParameters()).thenReturn(List.of(customParameter)); + when(container.getPrefixedName()).thenReturn("module1"); + when(referenceMatcher.isReferenceContainerMatching(any(), eq(container), eq(customParameter))).thenReturn( + true); + + Map.Entry> result = processor.processCustomParameterContainer(container, references, referenceMatcher); + + assertEquals("module1", result.getKey()); + assertTrue(result.getValue() + .isEmpty()); + } + + @Test + void testProcessCustomParameterContainer_WithUnreferencedParameters() { + + String referencedParam = "param1"; + String unreferencedParam = "param2"; + List references = List.of(referenceContainer); + + when(container.getParameters()).thenReturn(List.of(referencedParam, unreferencedParam)); + when(container.getPrefixedName()).thenReturn("module1"); + when(referenceMatcher.isReferenceContainerMatching(any(), eq(container), eq(referencedParam))).thenReturn(true); + when(referenceMatcher.isReferenceContainerMatching(any(), eq(container), eq(unreferencedParam))).thenReturn( + false); + + Map.Entry> result = processor.processCustomParameterContainer(container, references, referenceMatcher); + + assertEquals("module1", result.getKey()); + assertEquals(List.of(unreferencedParam), result.getValue()); + } + + @Test + void testProcessCustomParameterContainer_WithNullPrefixedName() { + + String customParameter = "param1"; + List references = List.of(referenceContainer); + + when(container.getParameters()).thenReturn(List.of(customParameter)); + when(container.getPrefixedName()).thenReturn(null); + when(referenceMatcher.isReferenceContainerMatching(any(), eq(container), eq(customParameter))).thenReturn(false); + + Map.Entry> result = processor.processCustomParameterContainer(container, references, referenceMatcher); + + assertEquals("global-parameter", result.getKey()); + assertEquals(List.of(customParameter), result.getValue()); + } + + @Test + void testProcessCustomParameterContainer_WithNonNullPrefixedName() { + + String customParameter = "param1"; + List references = List.of(referenceContainer); + + when(container.getParameters()).thenReturn(List.of(customParameter)); + when(container.getPrefixedName()).thenReturn("custom-module"); + when(referenceMatcher.isReferenceContainerMatching(any(), eq(container), eq(customParameter))).thenReturn(false); + + Map.Entry> result = processor.processCustomParameterContainer(container, references, referenceMatcher); + + assertEquals("custom-module", result.getKey()); + assertEquals(List.of(customParameter), result.getValue()); + } +} diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ReferenceContainerMatcherTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ReferenceContainerMatcherTest.java new file mode 100644 index 0000000000..868b214f34 --- /dev/null +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/ReferenceContainerMatcherTest.java @@ -0,0 +1,128 @@ +package org.cloudfoundry.multiapps.controller.process.util; + +import java.util.List; + +import org.cloudfoundry.multiapps.mta.resolvers.CustomParameterContainer; +import org.cloudfoundry.multiapps.mta.resolvers.Reference; +import org.cloudfoundry.multiapps.mta.resolvers.ReferenceContainer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + +public class ReferenceContainerMatcherTest { + + @InjectMocks + private ReferenceContainerMatcher referenceContainerMatcher; + + @Mock + private ReferenceContainer referenceContainer; + + @Mock + private CustomParameterContainer customParameterContainer; + + @Mock + private Reference reference; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void testIsReferenceContainerMatching_WithMatchingParameters() { + String customParameter = "param1"; + String referenceOwner = "module1"; + String parameterOwner = "module1"; + + when(referenceContainer.getReferenceOwner()).thenReturn(referenceOwner); + when(referenceContainer.getReferences()).thenReturn(List.of(reference)); + when(reference.getKey()).thenReturn(customParameter); + when(reference.getDependencyName()).thenReturn(parameterOwner); + + when(customParameterContainer.getParameterOwner()).thenReturn(parameterOwner); + + boolean result = referenceContainerMatcher.isReferenceContainerMatching(referenceContainer, customParameterContainer, + customParameter); + assertTrue(result); + } + + @Test + void testIsReferenceContainerMatching_WithNonMatchingReferenceKey() { + String customParameter = "param1"; + String referenceOwner = "module1"; + String parameterOwner = "module1"; + + when(referenceContainer.getReferenceOwner()).thenReturn(referenceOwner); + when(referenceContainer.getReferences()).thenReturn(List.of(reference)); + when(reference.getKey()).thenReturn("param2"); + when(reference.getDependencyName()).thenReturn(parameterOwner); + + when(customParameterContainer.getParameterOwner()).thenReturn(parameterOwner); + + boolean result = referenceContainerMatcher.isReferenceContainerMatching(referenceContainer, customParameterContainer, + customParameter); + + assertFalse(result); + } + + @Test + void testIsReferenceContainerMatching_WithNonMatchingDependency() { + String customParameter = "param1"; + String referenceOwner = "module1"; + String parameterOwner = "module1"; + + when(referenceContainer.getReferenceOwner()).thenReturn(referenceOwner); + when(referenceContainer.getReferences()).thenReturn(List.of(reference)); + when(reference.getKey()).thenReturn(customParameter); + when(reference.getDependencyName()).thenReturn("module2"); + + when(customParameterContainer.getParameterOwner()).thenReturn(parameterOwner); + + boolean result = referenceContainerMatcher.isReferenceContainerMatching(referenceContainer, customParameterContainer, + customParameter); + + assertFalse(result); + } + + @Test + void testIsReferenceContainerMatching_WithMatchingOwnerButNullDependency() { + String customParameter = "param1"; + String referenceOwner = "module1"; + String parameterOwner = "module1"; + + when(referenceContainer.getReferenceOwner()).thenReturn(referenceOwner); + when(referenceContainer.getReferences()).thenReturn(List.of(reference)); + when(reference.getKey()).thenReturn(customParameter); + when(reference.getDependencyName()).thenReturn(null); + when(customParameterContainer.getParameterOwner()).thenReturn(parameterOwner); + + boolean result = referenceContainerMatcher.isReferenceContainerMatching(referenceContainer, customParameterContainer, + customParameter); + assertTrue(result); + } + + @Test + void testDoesReferenceMatchOwner_WithNonMatchingOwner() { + String customParameter = "param1"; + String referenceOwner = "module1"; + String parameterOwner = "module2"; + + when(referenceContainer.getReferenceOwner()).thenReturn(referenceOwner); + when(referenceContainer.getReferences()).thenReturn(List.of(reference)); + when(reference.getKey()).thenReturn(customParameter); + when(reference.getDependencyName()).thenReturn(parameterOwner); + + when(customParameterContainer.getParameterOwner()).thenReturn(parameterOwner); + + boolean result = referenceContainerMatcher.isReferenceContainerMatching(referenceContainer, customParameterContainer, + customParameter); + + assertFalse(result); + } +} diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/UnsupportedParameterFinderTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/UnsupportedParameterFinderTest.java new file mode 100644 index 0000000000..85690aaa9e --- /dev/null +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/util/UnsupportedParameterFinderTest.java @@ -0,0 +1,111 @@ +package org.cloudfoundry.multiapps.controller.process.util; + +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; + +import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor; +import org.cloudfoundry.multiapps.mta.resolvers.CustomParameterContainer; +import org.cloudfoundry.multiapps.mta.resolvers.Reference; +import org.cloudfoundry.multiapps.mta.resolvers.ReferenceContainer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class UnsupportedParameterFinderTest { + + @Mock + private SupportedParameterChecker supportedParameterChecker; + + @InjectMocks + private UnsupportedParameterFinder finder; + + @Mock + private ReferenceContainerMatcher referenceMatcher; + + @Mock + private CustomParameterContainerProcessor customParameterProcessor; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void testNoUnsupportedParameters() { + DeploymentDescriptor descriptor = mock(DeploymentDescriptor.class); + List referenceContainers = List.of( + new ReferenceContainer("module1", List.of(new Reference("~{param1}", "param1", null)))); + CustomParameterContainer container = mock(CustomParameterContainer.class); + when(container.getParameters()).thenReturn(List.of("param1")); + when(container.getPrefixedName()).thenReturn("module1"); + when(container.getParameterOwner()).thenReturn("module1"); + + when(supportedParameterChecker.getCustomParameters(descriptor)).thenReturn(List.of(container)); + + when(customParameterProcessor.processCustomParameterContainer(any(), eq(referenceContainers), eq(referenceMatcher))) + .thenReturn(new AbstractMap.SimpleEntry<>("module1", List.of())); + + Map> result = finder.findUnsupportedParameters(descriptor, referenceContainers); + + assertTrue(result.isEmpty()); + } + + @Test + void testUnsupportedParameters() { + DeploymentDescriptor descriptor = mock(DeploymentDescriptor.class); + List referenceContainers = List.of( + new ReferenceContainer("module1", List.of(new Reference("~{param1}", "param1", null)))); + CustomParameterContainer container = mock(CustomParameterContainer.class); + when(container.getParameters()).thenReturn(List.of("param1", "param2")); + when(container.getPrefixedName()).thenReturn("module1"); + when(container.getParameterOwner()).thenReturn("module1"); + + when(supportedParameterChecker.getCustomParameters(descriptor)).thenReturn(List.of(container)); + when(customParameterProcessor.processCustomParameterContainer(any(), eq(referenceContainers), eq(referenceMatcher))) + .thenReturn(new AbstractMap.SimpleEntry<>("module1", List.of("param2"))); + + Map> result = finder.findUnsupportedParameters(descriptor, referenceContainers); + + assertEquals(1, result.size()); + assertEquals(List.of("param2"), result.get("module1")); + } + + @Test + void testMultipleCustomParameters() { + DeploymentDescriptor descriptor = mock(DeploymentDescriptor.class); + List referenceContainers = List.of( + new ReferenceContainer("module1", List.of(new Reference("~{param1}", "param1", "module1")))); + + CustomParameterContainer container1 = mock(CustomParameterContainer.class); + when(container1.getParameters()).thenReturn(List.of("param1", "param2")); + when(container1.getPrefixedName()).thenReturn("module1"); + when(container1.getParameterOwner()).thenReturn("module1"); + + CustomParameterContainer container2 = mock(CustomParameterContainer.class); + when(container2.getParameters()).thenReturn(List.of("param3")); + when(container2.getPrefixedName()).thenReturn("module2"); + when(container2.getParameterOwner()).thenReturn("module2"); + + when(supportedParameterChecker.getCustomParameters(descriptor)).thenReturn(List.of(container1, container2)); + when(customParameterProcessor.processCustomParameterContainer(eq(container1), eq(referenceContainers), eq(referenceMatcher))) + .thenReturn(new AbstractMap.SimpleEntry<>("module1", List.of("param2"))); + when(customParameterProcessor.processCustomParameterContainer(eq(container2), eq(referenceContainers), eq(referenceMatcher))) + .thenReturn(new AbstractMap.SimpleEntry<>("module2", List.of("param3"))); + + Map> result = finder.findUnsupportedParameters(descriptor, referenceContainers); + + assertEquals(2, result.size()); + assertEquals(List.of("param2"), result.get("module1")); + assertEquals(List.of("param3"), result.get("module2")); + } +}