diff options
Diffstat (limited to 'participant/participant-intermediary')
36 files changed, 2024 insertions, 366 deletions
diff --git a/participant/participant-intermediary/pom.xml b/participant/participant-intermediary/pom.xml index 97c98f6dd..d16e17a86 100644 --- a/participant/participant-intermediary/pom.xml +++ b/participant/participant-intermediary/pom.xml @@ -25,7 +25,7 @@ <parent> <groupId>org.onap.policy.clamp.participant</groupId> <artifactId>policy-clamp-participant</artifactId> - <version>8.0.0-SNAPSHOT</version> + <version>8.0.1-SNAPSHOT</version> </parent> <artifactId>policy-clamp-participant-intermediary</artifactId> diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java index 6f4039254..5994328d5 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java @@ -89,12 +89,23 @@ public interface AutomationCompositionElementListener { /** * Handle an update on a automation composition element. * - * @param compositionElement the information of the Automation Composition Definition Element + * @param compositionElement the information of the Automation Composition Definition Element * @param compositionElementTarget the information of the Automation Composition Definition Element Target - * @param instanceElement the information of the Automation Composition Instance Element - * @param instanceElementMigrate the information of the Automation Composition Instance Element updated + * @param instanceElement the information of the Automation Composition Instance Element + * @param instanceElementMigrate the information of the Automation Composition Instance Element updated + * @param nextStage the next stage * @throws PfModelException from Policy framework */ void migrate(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget, + InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate, + int nextStage) throws PfModelException; + + void migratePrecheck(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate) throws PfModelException; + + void review(CompositionElementDto compositionElement, InstanceElementDto instanceElement) + throws PfModelException; + + void prepare(CompositionElementDto compositionElement, InstanceElementDto instanceElement) + throws PfModelException; } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/CompositionElementDto.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/CompositionElementDto.java index d203f90cb..50699e22c 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/CompositionElementDto.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/CompositionElementDto.java @@ -25,5 +25,12 @@ import java.util.UUID; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; public record CompositionElementDto(UUID compositionId, ToscaConceptIdentifier elementDefinitionId, - Map<String, Object> inProperties, Map<String, Object> outProperties) { + Map<String, Object> inProperties, Map<String, Object> outProperties, + ElementState state) { + + public CompositionElementDto(UUID compositionId, ToscaConceptIdentifier elementDefinitionId, + Map<String, Object> inProperties, Map<String, Object> outProperties) { + this(compositionId, elementDefinitionId, inProperties, outProperties, ElementState.PRESENT); + + } } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ElementState.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ElementState.java new file mode 100644 index 000000000..afb01d014 --- /dev/null +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ElementState.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.acm.participant.intermediary.api; + +public enum ElementState { + PRESENT, + NOT_PRESENT, + REMOVED, + NEW +} diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/InstanceElementDto.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/InstanceElementDto.java index 297af6c43..b4fdefbf3 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/InstanceElementDto.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/InstanceElementDto.java @@ -25,5 +25,11 @@ import java.util.UUID; import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; public record InstanceElementDto(UUID instanceId, UUID elementId, ToscaServiceTemplate toscaServiceTemplateFragment, - Map<String, Object> inProperties, Map<String, Object> outProperties) { + Map<String, Object> inProperties, Map<String, Object> outProperties, + ElementState state) { + + public InstanceElementDto(UUID instanceId, UUID elementId, ToscaServiceTemplate toscaServiceTemplateFragment, + Map<String, Object> inProperties, Map<String, Object> outProperties) { + this(instanceId, elementId, toscaServiceTemplateFragment, inProperties, outProperties, ElementState.PRESENT); + } } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ParticipantIntermediaryApi.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ParticipantIntermediaryApi.java index 9b3279232..c06ffe62e 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ParticipantIntermediaryApi.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ParticipantIntermediaryApi.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,41 +38,52 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; public interface ParticipantIntermediaryApi { /** - * Update the state of a automation composition element. + * Update the state of a AutomationComposition Instance Element. * - * @param automationCompositionId the ID of the automation composition to update the state on - * @param elementId the ID of the automation composition element to update the state on - * @param deployState the Deploy State of the automation composition element - * @param lockState the Lock State of the automation composition element + * @param instance the ID of the AutomationComposition Instance to update the state on + * @param elementId the ID of the AutomationComposition Instance element to update the state on + * @param deployState the Deploy State of the AutomationComposition Instance element + * @param lockState the Lock State of the AutomationComposition Instance element * @param stateChangeResult the indicator if error occurs * @param message the message */ - void updateAutomationCompositionElementState(UUID automationCompositionId, UUID elementId, DeployState deployState, + void updateAutomationCompositionElementState(UUID instance, UUID elementId, DeployState deployState, LockState lockState, StateChangeResult stateChangeResult, String message); /** - * Get a copy of all AutomationCompositions. + * Update the stage of a AutomationComposition Instance Element. * - * @return get all AutomationCompositions + * @param instance the ID of the AutomationComposition Instance to update the state on + * @param elementId the ID of the AutomationComposition Instance Element to update the state on + * @param stateChangeResult the indicator if error occurs + * @param message the message + */ + void updateAutomationCompositionElementStage(UUID instance, UUID elementId, StateChangeResult stateChangeResult, + int stage, String message); + + /** + * Get a copy of all AutomationComposition Instances. + * + * @return get all AutomationComposition Instances */ Map<UUID, AutomationComposition> getAutomationCompositions(); /** - * Get a copy of the AutomationComposition by automationCompositionId. + * Get a copy of the AutomationComposition Instance by AutomationComposition Instance Id. * - * @param automationCompositionId the ID of the automation composition to update the state on - * @return get the AutomationComposition + * @param instanceId the ID of the AutomationComposition Instance to update the state on + * @return get the AutomationComposition Instance */ - AutomationComposition getAutomationComposition(UUID automationCompositionId); + AutomationComposition getAutomationComposition(UUID instanceId); /** - * Get a copy of the AutomationCompositionElement by automationCompositionId and elementId. + * Get a copy of the AutomationCompositionElement by AutomationComposition Instance Id and elementId. * - * @param automationCompositionId the ID of the automation composition to update the state on - * @param elementId the ID of the automation composition element to update the state on + * @param instanceId the ID of the AutomationComposition Instance to update the state on + * @param elementId the ID of the AutomationComposition Instance Element to update the state on * @return get the AutomationCompositionElement */ - AutomationCompositionElement getAutomationCompositionElement(UUID automationCompositionId, UUID elementId); + AutomationCompositionElement getAutomationCompositionElement(UUID instanceId, UUID elementId); /** * Get a copy of all AutomationCompositionElementDefinition from all primed compositions. @@ -99,15 +110,15 @@ public interface ParticipantIntermediaryApi { AutomationCompositionElementDefinition getAcElementDefinition(UUID compositionId, ToscaConceptIdentifier elementId); /** - * Send Automation Composition Element update Info to AC-runtime. + * Send AutomationComposition Instance Element update Info to AC-runtime. * - * @param automationCompositionId the ID of the automation composition to update the states - * @param elementId the ID of the automation composition element to update the states + * @param instanceId the ID of the AutomationComposition Instance to update the states + * @param elementId the ID of the AutomationComposition Instance Element to update the states * @param useState the use State * @param operationalState the operational State * @param outProperties the output Properties Map */ - void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState, String operationalState, + void sendAcElementInfo(UUID instanceId, UUID elementId, String useState, String operationalState, Map<String, Object> outProperties); /** diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV1.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV1.java index cf5ac419d..34bdc349b 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV1.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV1.java @@ -209,7 +209,8 @@ public abstract class AcElementListenerV1 @Override public void migrate(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget, - InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate) throws PfModelException { + InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate, + int stage) throws PfModelException { var element = new AcElementDeploy(); element.setId(instanceElementMigrate.elementId()); element.setDefinition(compositionElementTarget.elementDefinitionId()); @@ -224,4 +225,29 @@ public abstract class AcElementListenerV1 intermediaryApi.updateAutomationCompositionElementState(instanceId, element.getId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated"); } + + @Override + public void migratePrecheck(CompositionElementDto compositionElement, + CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement, + InstanceElementDto instanceElementMigrate) throws PfModelException { + intermediaryApi.updateAutomationCompositionElementState(instanceElementMigrate.instanceId(), + instanceElementMigrate.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Migration Precheck completed"); + } + + @Override + public void review(CompositionElementDto compositionElement, InstanceElementDto instanceElement) + throws PfModelException { + intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Review completed"); + } + + @Override + public void prepare(CompositionElementDto compositionElement, InstanceElementDto instanceElement) + throws PfModelException { + intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.UNDEPLOYED, null, + StateChangeResult.NO_ERROR, "Prepare completed"); + } } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV2.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV2.java index 3fe33191f..7db220095 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV2.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV2.java @@ -36,7 +36,8 @@ import org.onap.policy.models.base.PfModelException; * Wrapper of AutomationCompositionElementListener. * Valid since 7.1.1 release. */ -public abstract class AcElementListenerV2 implements AutomationCompositionElementListener { +public abstract class AcElementListenerV2 + implements AutomationCompositionElementListener, AutomationCompositionElementListenerV2 { protected final ParticipantIntermediaryApi intermediaryApi; private static final String NOT_SUPPORTED = "not supported!"; @@ -98,9 +99,41 @@ public abstract class AcElementListenerV2 implements AutomationCompositionElemen @Override public void migrate(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget, + InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate, int stage) + throws PfModelException { + migrate(compositionElement, compositionElementTarget, instanceElement, instanceElementMigrate); + } + + @Override + public void migrate(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate) throws PfModelException { intermediaryApi.updateAutomationCompositionElementState(instanceElementMigrate.instanceId(), instanceElementMigrate.elementId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated"); } + + @Override + public void migratePrecheck(CompositionElementDto compositionElement, + CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement, + InstanceElementDto instanceElementMigrate) throws PfModelException { + intermediaryApi.updateAutomationCompositionElementState(instanceElementMigrate.instanceId(), + instanceElementMigrate.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Migration Precheck completed"); + } + + @Override + public void review(CompositionElementDto compositionElement, InstanceElementDto instanceElement) + throws PfModelException { + intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Review completed"); + } + + @Override + public void prepare(CompositionElementDto compositionElement, InstanceElementDto instanceElement) + throws PfModelException { + intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.UNDEPLOYED, null, + StateChangeResult.NO_ERROR, "Prepare completed"); + } } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV3.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV3.java new file mode 100644 index 000000000..d63323d1a --- /dev/null +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV3.java @@ -0,0 +1,119 @@ +/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.acm.participant.intermediary.api.impl;
+
+import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener;
+import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionDto;
+import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
+import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
+import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
+import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
+import org.onap.policy.clamp.models.acm.concepts.DeployState;
+import org.onap.policy.clamp.models.acm.concepts.LockState;
+import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
+import org.onap.policy.models.base.PfModelException;
+
+/**
+ * Wrapper of AutomationCompositionElementListener.
+ * Valid since 8.0.1 release.
+ */
+public abstract class AcElementListenerV3 implements AutomationCompositionElementListener {
+ protected final ParticipantIntermediaryApi intermediaryApi;
+
+ protected AcElementListenerV3(ParticipantIntermediaryApi intermediaryApi) {
+ this.intermediaryApi = intermediaryApi;
+ }
+
+ @Override
+ public void lock(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
+ throws PfModelException {
+ intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
+ instanceElement.elementId(), null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked");
+ }
+
+ @Override
+ public void unlock(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
+ throws PfModelException {
+ intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
+ instanceElement.elementId(), null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked");
+ }
+
+ @Override
+ public void delete(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
+ throws PfModelException {
+ intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
+ instanceElement.elementId(), DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
+ }
+
+ @Override
+ public void update(CompositionElementDto compositionElement, InstanceElementDto instanceElement,
+ InstanceElementDto instanceElementUpdated) throws PfModelException {
+ intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
+ instanceElement.elementId(), DeployState.DEPLOYED, null,
+ StateChangeResult.NO_ERROR, "Update not supported");
+
+ }
+
+ @Override
+ public void prime(CompositionDto composition) throws PfModelException {
+ intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
+ StateChangeResult.NO_ERROR, "Primed");
+ }
+
+ @Override
+ public void deprime(CompositionDto composition) throws PfModelException {
+ intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
+ StateChangeResult.NO_ERROR, "Deprimed");
+ }
+
+ @Override
+ public void migrate(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget,
+ InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate, int stage)
+ throws PfModelException {
+ intermediaryApi.updateAutomationCompositionElementState(instanceElementMigrate.instanceId(),
+ instanceElementMigrate.elementId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
+ }
+
+ @Override
+ public void migratePrecheck(CompositionElementDto compositionElement,
+ CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
+ InstanceElementDto instanceElementMigrate) throws PfModelException {
+ intermediaryApi.updateAutomationCompositionElementState(instanceElementMigrate.instanceId(),
+ instanceElementMigrate.elementId(), DeployState.DEPLOYED, null,
+ StateChangeResult.NO_ERROR, "Migration Precheck completed");
+ }
+
+ @Override
+ public void review(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
+ throws PfModelException {
+ intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
+ instanceElement.elementId(), DeployState.DEPLOYED, null,
+ StateChangeResult.NO_ERROR, "Review completed");
+ }
+
+ @Override
+ public void prepare(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
+ throws PfModelException {
+ intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
+ instanceElement.elementId(), DeployState.UNDEPLOYED, null,
+ StateChangeResult.NO_ERROR, "Prepare completed");
+ }
+}
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AutomationCompositionElementListenerV2.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AutomationCompositionElementListenerV2.java new file mode 100644 index 000000000..721caa88e --- /dev/null +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AutomationCompositionElementListenerV2.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.acm.participant.intermediary.api.impl; + +import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionDto; +import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto; +import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto; +import org.onap.policy.models.base.PfModelException; + +public interface AutomationCompositionElementListenerV2 { + + void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException; + + void undeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException; + + void lock(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException; + + void unlock(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException; + + void delete(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException; + + void update(CompositionElementDto compositionElement, InstanceElementDto instanceElement, + InstanceElementDto instanceElementUpdated) throws PfModelException; + + void prime(CompositionDto composition) throws PfModelException; + + void deprime(CompositionDto composition) throws PfModelException; + + void migrate(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget, + InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate) throws PfModelException; + + void migratePrecheck(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget, + InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate) throws PfModelException; + + void review(CompositionElementDto compositionElement, InstanceElementDto instanceElement) + throws PfModelException; + + void prepare(CompositionElementDto compositionElement, InstanceElementDto instanceElement) + throws PfModelException; +} diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java index 5cdbacab6..233b55926 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -50,16 +50,23 @@ public class ParticipantIntermediaryApiImpl implements ParticipantIntermediaryAp private final CacheProvider cacheProvider; @Override - public void updateAutomationCompositionElementState(UUID automationCompositionId, UUID id, DeployState newState, + public void updateAutomationCompositionElementState(UUID instance, UUID elementId, DeployState deployState, LockState lockState, StateChangeResult stateChangeResult, String message) { - automationCompositionHandler.updateAutomationCompositionElementState(automationCompositionId, id, newState, - lockState, stateChangeResult, message); + automationCompositionHandler.updateAutomationCompositionElementState(instance, elementId, deployState, + lockState, stateChangeResult, message); } @Override - public void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState, + public void updateAutomationCompositionElementStage(UUID instance, UUID elementId, + StateChangeResult stateChangeResult, int stage, String message) { + automationCompositionHandler.updateAutomationCompositionElementStage(instance, elementId, stateChangeResult, + stage, message); + } + + @Override + public void sendAcElementInfo(UUID instance, UUID elementId, String useState, String operationalState, Map<String, Object> outProperties) { - automationCompositionHandler.sendAcElementInfo(automationCompositionId, elementId, useState, operationalState, + automationCompositionHandler.sendAcElementInfo(instance, elementId, useState, operationalState, outProperties); } @@ -75,8 +82,8 @@ public class ParticipantIntermediaryApiImpl implements ParticipantIntermediaryAp } @Override - public AutomationCompositionElement getAutomationCompositionElement(UUID automationCompositionId, UUID elementId) { - var automationComposition = cacheProvider.getAutomationCompositions().get(automationCompositionId); + public AutomationCompositionElement getAutomationCompositionElement(UUID instanceId, UUID elementId) { + var automationComposition = cacheProvider.getAutomationCompositions().get(instanceId); if (automationComposition == null) { return null; } @@ -91,8 +98,8 @@ public class ParticipantIntermediaryApiImpl implements ParticipantIntermediaryAp } @Override - public AutomationComposition getAutomationComposition(UUID automationCompositionId) { - var automationComposition = cacheProvider.getAutomationCompositions().get(automationCompositionId); + public AutomationComposition getAutomationComposition(UUID instanceId) { + var automationComposition = cacheProvider.getAutomationCompositions().get(instanceId); return automationComposition != null ? new AutomationComposition(automationComposition) : null; } @@ -107,7 +114,7 @@ public class ParticipantIntermediaryApiImpl implements ParticipantIntermediaryAp UUID compositionId) { var acElementDefinitions = cacheProvider.getAcElementsDefinitions().get(compositionId); if (acElementDefinitions == null) { - return null; + return Map.of(); } return PfUtils.mapMap(acElementDefinitions, AutomationCompositionElementDefinition::new); } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AcPrepareListener.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AcPrepareListener.java new file mode 100644 index 000000000..0f6d2c09f --- /dev/null +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AcPrepareListener.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.acm.participant.intermediary.comm; + +import org.onap.policy.clamp.acm.participant.intermediary.handler.ParticipantHandler; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionPrepare; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType; +import org.springframework.stereotype.Component; + +@Component +public class AcPrepareListener extends ParticipantListener<AutomationCompositionPrepare> { + + /** + * Constructs the object. + * + * @param participantHandler the handler for managing the state of the participant + */ + public AcPrepareListener(final ParticipantHandler participantHandler) { + super(AutomationCompositionPrepare.class, participantHandler, + participantHandler::handleAutomationCompositionPrepare); + } + + + @Override + public String getType() { + return ParticipantMessageType.AUTOMATION_COMPOSITION_PREPARE.name(); + } +} diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcDefinitionHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcDefinitionHandler.java index b38df515a..9e3efce57 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcDefinitionHandler.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcDefinitionHandler.java @@ -114,16 +114,15 @@ public class AcDefinitionHandler { public void handleParticipantSync(ParticipantSync participantSyncMsg) { if (participantSyncMsg.isDelete()) { - if (AcTypeState.COMMISSIONED.equals(participantSyncMsg.getState())) { - cacheProvider.removeElementDefinition(participantSyncMsg.getCompositionId()); - } - for (var automationcomposition : participantSyncMsg.getAutomationcompositionList()) { - cacheProvider.removeAutomationComposition(automationcomposition.getAutomationCompositionId()); - } + deleteScenario(participantSyncMsg); return; } if (!participantSyncMsg.getParticipantDefinitionUpdates().isEmpty()) { + if (StateChangeResult.TIMEOUT.equals(participantSyncMsg.getStateChangeResult())) { + listener.cleanExecution(participantSyncMsg.getCompositionId(), participantSyncMsg.getMessageId()); + } + List<AutomationCompositionElementDefinition> list = new ArrayList<>(); for (var participantDefinition : participantSyncMsg.getParticipantDefinitionUpdates()) { list.addAll(participantDefinition.getAutomationCompositionElementDefinitionList()); @@ -134,6 +133,20 @@ public class AcDefinitionHandler { for (var automationcomposition : participantSyncMsg.getAutomationcompositionList()) { cacheProvider .initializeAutomationComposition(participantSyncMsg.getCompositionId(), automationcomposition); + if (StateChangeResult.TIMEOUT.equals(automationcomposition.getStateChangeResult())) { + for (var element : automationcomposition.getAcElementList()) { + listener.cleanExecution(element.getId(), participantSyncMsg.getMessageId()); + } + } + } + } + + private void deleteScenario(ParticipantSync participantSyncMsg) { + if (AcTypeState.COMMISSIONED.equals(participantSyncMsg.getState())) { + cacheProvider.removeElementDefinition(participantSyncMsg.getCompositionId()); + } + for (var automationcomposition : participantSyncMsg.getAutomationcompositionList()) { + cacheProvider.removeAutomationComposition(automationcomposition.getAutomationCompositionId()); } } } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcLockHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcLockHandler.java index 89daa5fd2..95613cc9e 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcLockHandler.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcLockHandler.java @@ -27,6 +27,7 @@ import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; import org.onap.policy.clamp.models.acm.concepts.LockState; import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils; +import org.onap.policy.clamp.models.acm.concepts.SubState; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -79,6 +80,7 @@ public class AcLockHandler { int startPhase = ParticipantUtils.findStartPhase(compositionInProperties); if (startPhaseMsg.equals(startPhase)) { element.setLockState(LockState.LOCKING); + element.setSubState(SubState.NONE); var compositionElement = cacheProvider.createCompositionElementDto( automationComposition.getCompositionId(), element, compositionInProperties); var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(), @@ -99,6 +101,7 @@ public class AcLockHandler { int startPhase = ParticipantUtils.findStartPhase(compositionInProperties); if (startPhaseMsg.equals(startPhase)) { element.setLockState(LockState.UNLOCKING); + element.setSubState(SubState.NONE); var compositionElement = cacheProvider.createCompositionElementDto( automationComposition.getCompositionId(), element, compositionInProperties); var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(), diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcSubStateHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcSubStateHandler.java new file mode 100644 index 000000000..1dbf2c935 --- /dev/null +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcSubStateHandler.java @@ -0,0 +1,197 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.acm.participant.intermediary.handler; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto; +import org.onap.policy.clamp.acm.participant.intermediary.api.ElementState; +import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto; +import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy; +import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement; +import org.onap.policy.clamp.models.acm.concepts.DeployState; +import org.onap.policy.clamp.models.acm.concepts.SubState; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionPrepare; +import org.onap.policy.clamp.models.acm.utils.AcmUtils; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class AcSubStateHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(AcSubStateHandler.class); + + private final CacheProvider cacheProvider; + private final ThreadHandler listener; + + /** + * Handles AutomationComposition Migration Precheck. + * + * @param migrationMsg the AutomationCompositionMigration + */ + public void handleAcMigrationPrecheck(AutomationCompositionMigration migrationMsg) { + if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) { + return; + } + + var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId()); + if (automationComposition == null) { + LOGGER.debug("Automation composition {} does not use this participant", + migrationMsg.getAutomationCompositionId()); + return; + } + automationComposition.setSubState(SubState.MIGRATION_PRECHECKING); + for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) { + if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) { + + callParticipantMigratePrecheck(migrationMsg.getMessageId(), participantDeploy.getAcElementList(), + automationComposition, migrationMsg.getCompositionTargetId()); + } + } + } + + private void callParticipantMigratePrecheck(UUID messageId, List<AcElementDeploy> acElements, + AutomationComposition automationComposition, UUID compositionTargetId) { + var compositionElementMap = cacheProvider.getCompositionElementDtoMap(automationComposition); + var instanceElementMap = cacheProvider.getInstanceElementDtoMap(automationComposition); + var acElementList = automationComposition.getElements(); + for (var acElement : acElements) { + var element = acElementList.get(acElement.getId()); + if (element != null) { + element.setSubState(SubState.MIGRATION_PRECHECKING); + } + } + var acCopyMigrateTo = new AutomationComposition(automationComposition); + var acElementCopyList = acCopyMigrateTo.getElements(); + for (var acElement : acElements) { + var element = acElementCopyList.get(acElement.getId()); + if (element != null) { + AcmUtils.recursiveMerge(element.getProperties(), acElement.getProperties()); + element.setDefinition(acElement.getDefinition()); + } else { + element = CacheProvider.createAutomationCompositionElement(acElement); + element.setSubState(SubState.MIGRATION_PRECHECKING); + acElementCopyList.put(element.getId(), element); + } + } + var toDelete = acElementCopyList.values().stream() + .filter(el -> !SubState.MIGRATION_PRECHECKING.equals(el.getSubState())) + .map(AutomationCompositionElement::getId) + .toList(); + toDelete.forEach(acElementCopyList::remove); + + var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(acCopyMigrateTo, + compositionTargetId); + var instanceElementMigrateMap = cacheProvider.getInstanceElementDtoMap(acCopyMigrateTo); + + for (var acElement : acElements) { + var compositionElement = compositionElementMap.get(acElement.getId()); + var compositionElementTarget = compositionElementTargetMap.get(acElement.getId()); + var instanceElement = instanceElementMap.get(acElement.getId()); + var instanceElementMigrate = instanceElementMigrateMap.get(acElement.getId()); + + if (instanceElement == null) { + // new element scenario + compositionElement = new CompositionElementDto(automationComposition.getCompositionId(), + acElement.getDefinition(), Map.of(), Map.of(), ElementState.NOT_PRESENT); + instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), acElement.getId(), + new ToscaServiceTemplate(), Map.of(), Map.of(), ElementState.NOT_PRESENT); + compositionElementTarget = CacheProvider.changeStateToNew(compositionElementTarget); + instanceElementMigrate = CacheProvider.changeStateToNew(instanceElementMigrate); + } + + listener.migratePrecheck(messageId, compositionElement, compositionElementTarget, + instanceElement, instanceElementMigrate); + } + + for (var elementId : toDelete) { + var compositionDtoTarget = + new CompositionElementDto(compositionTargetId, + automationComposition.getElements().get(elementId).getDefinition(), + Map.of(), Map.of(), ElementState.REMOVED); + var instanceDtoTarget = + new InstanceElementDto(automationComposition.getInstanceId(), elementId, + null, Map.of(), Map.of(), ElementState.REMOVED); + + listener.migratePrecheck(messageId, compositionElementMap.get(elementId), compositionDtoTarget, + instanceElementMap.get(elementId), instanceDtoTarget); + } + } + + /** + * Handle AutomationComposition Prepare message. + * + * @param acPrepareMsg the AutomationCompositionPrepare message + */ + public void handleAcPrepare(AutomationCompositionPrepare acPrepareMsg) { + if (acPrepareMsg.isPreDeploy()) { + for (var participantPrepare : acPrepareMsg.getParticipantList()) { + if (cacheProvider.getParticipantId().equals(participantPrepare.getParticipantId())) { + cacheProvider.initializeAutomationComposition(acPrepareMsg.getCompositionId(), + acPrepareMsg.getAutomationCompositionId(), participantPrepare, DeployState.UNDEPLOYED, + SubState.PREPARING); + callParticipanPrepare(acPrepareMsg.getMessageId(), participantPrepare.getAcElementList(), + acPrepareMsg.getAutomationCompositionId()); + } + } + } else { + var automationComposition = + cacheProvider.getAutomationComposition(acPrepareMsg.getAutomationCompositionId()); + automationComposition.setSubState(SubState.REVIEWING); + callParticipanReview(acPrepareMsg.getMessageId(), automationComposition); + } + } + + private void callParticipanPrepare(UUID messageId, List<AcElementDeploy> acElementList, UUID instanceId) { + var automationComposition = cacheProvider.getAutomationComposition(instanceId); + for (var elementDeploy : acElementList) { + var element = automationComposition.getElements().get(elementDeploy.getId()); + var compositionInProperties = cacheProvider + .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition()); + var compositionElement = cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(), + element, compositionInProperties); + var instanceElement = new InstanceElementDto(instanceId, elementDeploy.getId(), + elementDeploy.getToscaServiceTemplateFragment(), + elementDeploy.getProperties(), element.getOutProperties()); + listener.prepare(messageId, compositionElement, instanceElement); + } + } + + private void callParticipanReview(UUID messageId, AutomationComposition automationComposition) { + for (var element : automationComposition.getElements().values()) { + var compositionInProperties = cacheProvider + .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition()); + element.setSubState(SubState.REVIEWING); + var compositionElement = cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(), + element, compositionInProperties); + var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(), + null, element.getProperties(), element.getOutProperties()); + listener.review(messageId, compositionElement, instanceElement); + } + } +} diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java index b60d6372c..6d94efb0f 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java @@ -21,20 +21,24 @@ package org.onap.policy.clamp.acm.participant.intermediary.handler; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto; +import org.onap.policy.clamp.acm.participant.intermediary.api.ElementState; import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto; import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher; import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy; import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement; import org.onap.policy.clamp.models.acm.concepts.DeployState; +import org.onap.policy.clamp.models.acm.concepts.LockState; import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy; import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; +import org.onap.policy.clamp.models.acm.concepts.SubState; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration; @@ -119,8 +123,7 @@ public class AutomationCompositionHandler { updateMsg.getAutomationCompositionId()); automationComposition.setDeployState(DeployState.UPDATING); var acCopy = new AutomationComposition(automationComposition); - updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy, - DeployState.UPDATING); + updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy); callParticipantUpdateProperty(updateMsg.getMessageId(), participantDeploy.getAcElementList(), acCopy); } @@ -171,57 +174,70 @@ public class AutomationCompositionHandler { } } - private Map<UUID, CompositionElementDto> getCompositionElementDtoMap(AutomationComposition automationComposition, - UUID compositionId) { - Map<UUID, CompositionElementDto> map = new HashMap<>(); - for (var element : automationComposition.getElements().values()) { - var compositionInProperties = cacheProvider.getCommonProperties(compositionId, element.getDefinition()); - var compositionElement = cacheProvider - .createCompositionElementDto(compositionId, element, compositionInProperties); - map.put(element.getId(), compositionElement); - } - return map; - } - - private Map<UUID, CompositionElementDto> getCompositionElementDtoMap(AutomationComposition automationComposition) { - return getCompositionElementDtoMap(automationComposition, automationComposition.getCompositionId()); - } - - private Map<UUID, InstanceElementDto> getInstanceElementDtoMap(AutomationComposition automationComposition) { - Map<UUID, InstanceElementDto> map = new HashMap<>(); - var serviceTemplateFragment = cacheProvider - .getServiceTemplateFragmentMap().get(automationComposition.getCompositionId()); - for (var element : automationComposition.getElements().values()) { - var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(), - serviceTemplateFragment, element.getProperties(), element.getOutProperties()); - map.put(element.getId(), instanceElement); - } - return map; - } - private void callParticipantUpdateProperty(UUID messageId, List<AcElementDeploy> acElements, AutomationComposition acCopy) { - var instanceElementDtoMap = getInstanceElementDtoMap(acCopy); - var instanceElementDtoMapUpdated = getInstanceElementDtoMap( + var instanceElementDtoMap = cacheProvider.getInstanceElementDtoMap(acCopy); + var instanceElementDtoMapUpdated = cacheProvider.getInstanceElementDtoMap( cacheProvider.getAutomationComposition(acCopy.getInstanceId())); - var compositionElementDtoMap = getCompositionElementDtoMap(acCopy); + var compositionElementDtoMap = cacheProvider.getCompositionElementDtoMap(acCopy); for (var acElement : acElements) { listener.update(messageId, compositionElementDtoMap.get(acElement.getId()), instanceElementDtoMap.get(acElement.getId()), instanceElementDtoMapUpdated.get(acElement.getId())); } } - private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy, - DeployState deployState) { + private void migrateExistingElementsOnThisParticipant(UUID instanceId, UUID compositionTargetId, + ParticipantDeploy participantDeploy, int stage) { + var automationComposition = cacheProvider.getAutomationComposition(instanceId); + var acElementList = automationComposition.getElements(); + for (var element : participantDeploy.getAcElementList()) { + var compositionInProperties = + cacheProvider.getCommonProperties(compositionTargetId, element.getDefinition()); + var stageSet = ParticipantUtils.findStageSet(compositionInProperties); + if (stageSet.contains(stage)) { + var acElement = acElementList.get(element.getId()); + if (acElement == null) { + var newElement = CacheProvider.createAutomationCompositionElement(element); + newElement.setParticipantId(participantDeploy.getParticipantId()); + newElement.setDeployState(DeployState.MIGRATING); + newElement.setLockState(LockState.LOCKED); + newElement.setStage(stage); + + acElementList.put(element.getId(), newElement); + LOGGER.info("New Ac Element with id {} is added in Migration", element.getId()); + } else { + AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties()); + acElement.setDeployState(DeployState.MIGRATING); + acElement.setStage(stage); + acElement.setDefinition(element.getDefinition()); + } + } + } + // Check for missing elements and remove them from cache + var elementsToRemove = findElementsToRemove(participantDeploy.getAcElementList(), acElementList); + for (var key : elementsToRemove) { + acElementList.remove(key); + LOGGER.info("Element with id {} is removed in Migration", key); + } + } + + private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy) { var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements(); for (var element : participantDeploy.getAcElementList()) { var acElement = acElementList.get(element.getId()); AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties()); - acElement.setDeployState(deployState); + acElement.setDeployState(DeployState.UPDATING); + acElement.setSubState(SubState.NONE); acElement.setDefinition(element.getDefinition()); } } + private List<UUID> findElementsToRemove(List<AcElementDeploy> acElementDeployList, Map<UUID, + AutomationCompositionElement> acElementList) { + var acElementDeploySet = acElementDeployList.stream().map(AcElementDeploy::getId).collect(Collectors.toSet()); + return acElementList.keySet().stream().filter(id -> !acElementDeploySet.contains(id)).toList(); + } + /** * Method to handle when the new state from participant is UNINITIALISED state. * @@ -261,6 +277,7 @@ public class AutomationCompositionHandler { int startPhase = ParticipantUtils.findStartPhase(compositionInProperties); if (startPhaseMsg.equals(startPhase)) { element.setDeployState(DeployState.DELETING); + element.setSubState(SubState.NONE); var compositionElement = cacheProvider.createCompositionElementDto( automationComposition.getCompositionId(), element, compositionInProperties); var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(), @@ -292,27 +309,66 @@ public class AutomationCompositionHandler { for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) { if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) { - updateExistingElementsOnThisParticipant(migrationMsg.getAutomationCompositionId(), participantDeploy, - DeployState.MIGRATING); + migrateExistingElementsOnThisParticipant(migrationMsg.getAutomationCompositionId(), + migrationMsg.getCompositionTargetId(), participantDeploy, migrationMsg.getStage()); callParticipantMigrate(migrationMsg.getMessageId(), participantDeploy.getAcElementList(), - acCopy, migrationMsg.getCompositionTargetId()); + acCopy, migrationMsg.getCompositionTargetId(), migrationMsg.getStage()); } } } private void callParticipantMigrate(UUID messageId, List<AcElementDeploy> acElements, - AutomationComposition acCopy, UUID compositionTargetId) { - var compositionElementMap = getCompositionElementDtoMap(acCopy); - var instanceElementMap = getInstanceElementDtoMap(acCopy); + AutomationComposition acCopy, UUID compositionTargetId, int stage) { + var compositionElementMap = cacheProvider.getCompositionElementDtoMap(acCopy); + var instanceElementMap = cacheProvider.getInstanceElementDtoMap(acCopy); var automationComposition = cacheProvider.getAutomationComposition(acCopy.getInstanceId()); - var compositionElementTargetMap = getCompositionElementDtoMap(automationComposition, compositionTargetId); - var instanceElementMigrateMap = getInstanceElementDtoMap(automationComposition); + var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(automationComposition, + compositionTargetId); + var instanceElementMigrateMap = cacheProvider.getInstanceElementDtoMap(automationComposition); + // Call migrate for newly added and updated elements for (var acElement : acElements) { - listener.migrate(messageId, compositionElementMap.get(acElement.getId()), - compositionElementTargetMap.get(acElement.getId()), - instanceElementMap.get(acElement.getId()), instanceElementMigrateMap.get(acElement.getId())); + var compositionInProperties = cacheProvider + .getCommonProperties(compositionTargetId, acElement.getDefinition()); + var stageSet = ParticipantUtils.findStageSet(compositionInProperties); + if (stageSet.contains(stage)) { + if (instanceElementMap.get(acElement.getId()) == null) { + var compositionElementDto = + new CompositionElementDto(acCopy.getCompositionId(), acElement.getDefinition(), + Map.of(), Map.of(), ElementState.NOT_PRESENT); + var instanceElementDto = new InstanceElementDto(acCopy.getInstanceId(), acElement.getId(), + null, Map.of(), Map.of(), ElementState.NOT_PRESENT); + var compositionElementTargetDto = CacheProvider.changeStateToNew( + compositionElementTargetMap.get(acElement.getId())); + var instanceElementMigrateDto = CacheProvider + .changeStateToNew(instanceElementMigrateMap.get(acElement.getId())); + + listener.migrate(messageId, compositionElementDto, compositionElementTargetDto, instanceElementDto, + instanceElementMigrateDto, stage); + } else { + listener.migrate(messageId, compositionElementMap.get(acElement.getId()), + compositionElementTargetMap.get(acElement.getId()), + instanceElementMap.get(acElement.getId()), instanceElementMigrateMap.get(acElement.getId()), + stage); + } + } + } + if (stage == 0) { + // Call migrate for removed elements + List<UUID> removedElements = findElementsToRemove(acElements, acCopy.getElements()); + for (var elementId : removedElements) { + var compositionDtoTarget = + new CompositionElementDto(compositionTargetId, + acCopy.getElements().get(elementId).getDefinition(), + Map.of(), Map.of(), ElementState.REMOVED); + var instanceDtoTarget = + new InstanceElementDto(acCopy.getInstanceId(), elementId, null, Map.of(), + Map.of(), ElementState.REMOVED); + + listener.migrate(messageId, compositionElementMap.get(elementId), compositionDtoTarget, + instanceElementMap.get(elementId), instanceDtoTarget, 0); + } } } } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandler.java index 1f4c036e7..7cf83db9d 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandler.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandler.java @@ -37,10 +37,12 @@ import org.onap.policy.clamp.models.acm.concepts.LockState; import org.onap.policy.clamp.models.acm.concepts.ParticipantDefinition; import org.onap.policy.clamp.models.acm.concepts.ParticipantState; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; +import org.onap.policy.clamp.models.acm.concepts.SubState; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantStatus; +import org.onap.policy.clamp.models.acm.utils.AcmUtils; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,27 +57,94 @@ public class AutomationCompositionOutHandler { private final CacheProvider cacheProvider; /** + * Handle a automation composition element stage change message. + * + * @param instance the automationComposition Id + * @param elementId the automationComposition Element Id + * @param stage the next stage + * @param message the message + * @param stateChangeResult the indicator if error occurs + */ + public void updateAutomationCompositionElementStage(UUID instance, UUID elementId, + StateChangeResult stateChangeResult, int stage, String message) { + if (!validateData(instance, elementId, stateChangeResult)) { + return; + } + + var automationComposition = cacheProvider.getAutomationComposition(instance); + if (automationComposition == null) { + LOGGER.error("Cannot update Automation composition element stage, Automation composition id {} not present", + instance); + return; + } + + var element = automationComposition.getElements().get(elementId); + if (element == null) { + var msg = "Cannot update Automation composition element stage, AC Element id {} not present"; + LOGGER.error(msg, elementId); + return; + } + + var automationCompositionStateChangeAck = + new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK); + automationCompositionStateChangeAck.setParticipantId(cacheProvider.getParticipantId()); + automationCompositionStateChangeAck.setMessage(AcmUtils.validatedMessage(message)); + automationCompositionStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(element.getId())); + automationCompositionStateChangeAck.setStateChangeResult(stateChangeResult); + automationCompositionStateChangeAck.setStage(stage); + automationCompositionStateChangeAck.setAutomationCompositionId(instance); + automationCompositionStateChangeAck.getAutomationCompositionResultMap().put(element.getId(), + new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(), + element.getUseState(), element.getOutProperties(), true, message)); + LOGGER.debug("Automation composition element {} stage changed to {}", elementId, stage); + automationCompositionStateChangeAck.setResult(true); + publisher.sendAutomationCompositionAck(automationCompositionStateChangeAck); + cacheProvider.getMsgIdentification().remove(element.getId()); + } + + private boolean validateData(UUID instance, UUID elementId, StateChangeResult stateChangeResult) { + if (instance == null || elementId == null) { + LOGGER.error("Not valid Ac instance, id is null"); + return false; + } + if (stateChangeResult == null) { + LOGGER.error("Not valid Ac instance, stateChangeResult is null"); + return false; + } + if (!StateChangeResult.NO_ERROR.equals(stateChangeResult) + && !StateChangeResult.FAILED.equals(stateChangeResult)) { + LOGGER.error("Not valid Ac instance, stateChangeResult is not valid"); + return false; + } + return true; + } + + /** * Handle a automation composition element state change message. * - * @param automationCompositionId the automationComposition Id + * @param instance the automationComposition Id * @param elementId the automationComposition Element Id * @param deployState the DeployState state * @param lockState the LockState state * @param message the message * @param stateChangeResult the indicator if error occurs */ - public void updateAutomationCompositionElementState(UUID automationCompositionId, UUID elementId, + public void updateAutomationCompositionElementState(UUID instance, UUID elementId, DeployState deployState, LockState lockState, StateChangeResult stateChangeResult, String message) { + if (!validateData(instance, elementId, stateChangeResult)) { + return; + } - if (automationCompositionId == null || elementId == null) { - LOGGER.error("Cannot update Automation composition element state, id is null"); + if ((deployState != null && lockState != null) || (deployState == null && lockState == null) + || AcmUtils.isInTransitionalState(deployState, lockState, SubState.NONE)) { + LOGGER.error("state error {} and {} cannot be handled", deployState, lockState); return; } - var automationComposition = cacheProvider.getAutomationComposition(automationCompositionId); + var automationComposition = cacheProvider.getAutomationComposition(instance); if (automationComposition == null) { LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present", - automationCompositionId); + instance); return; } @@ -86,14 +155,13 @@ public class AutomationCompositionOutHandler { return; } - if ((element.getRestarting() == null) - && ((deployState != null && lockState != null) || (deployState == null && lockState == null))) { - LOGGER.error("state error {} and {} cannot be handled", deployState, lockState); - return; - } - element.setRestarting(null); - - if (deployState != null) { + if (deployState != null && !SubState.NONE.equals(element.getSubState())) { + handleSubState(automationComposition, element); + if (!StateChangeResult.NO_ERROR.equals(stateChangeResult)) { + stateChangeResult = StateChangeResult.NO_ERROR; + LOGGER.warn("SubState has always NO_ERROR result!"); + } + } else if (deployState != null) { handleDeployState(automationComposition, element, deployState); } if (lockState != null) { @@ -104,10 +172,10 @@ public class AutomationCompositionOutHandler { new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK); automationCompositionStateChangeAck.setParticipantId(cacheProvider.getParticipantId()); automationCompositionStateChangeAck.setReplicaId(cacheProvider.getReplicaId()); - automationCompositionStateChangeAck.setMessage(message); + automationCompositionStateChangeAck.setMessage(AcmUtils.validatedMessage(message)); automationCompositionStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(element.getId())); automationCompositionStateChangeAck.setStateChangeResult(stateChangeResult); - automationCompositionStateChangeAck.setAutomationCompositionId(automationCompositionId); + automationCompositionStateChangeAck.setAutomationCompositionId(instance); automationCompositionStateChangeAck.getAutomationCompositionResultMap().put(element.getId(), new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(), element.getUseState(), element.getOutProperties(), true, message)); @@ -132,6 +200,7 @@ public class AutomationCompositionOutHandler { } automationComposition.setDeployState(deployState); automationComposition.setLockState(element.getLockState()); + automationComposition.setSubState(SubState.NONE); if (DeployState.DELETED.equals(deployState)) { cacheProvider.removeAutomationComposition(automationComposition.getInstanceId()); @@ -146,6 +215,16 @@ public class AutomationCompositionOutHandler { .filter(acElement -> !lockState.equals(acElement.getLockState())).findAny(); if (checkOpt.isEmpty()) { automationComposition.setLockState(lockState); + automationComposition.setSubState(SubState.NONE); + } + } + + private void handleSubState(AutomationComposition automationComposition, AutomationCompositionElement element) { + element.setSubState(SubState.NONE); + var checkOpt = automationComposition.getElements().values().stream() + .filter(acElement -> !SubState.NONE.equals(acElement.getSubState())).findAny(); + if (checkOpt.isEmpty()) { + automationComposition.setSubState(SubState.NONE); } } @@ -221,9 +300,29 @@ public class AutomationCompositionOutHandler { */ public void updateCompositionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult, String message) { + if (compositionId == null) { + LOGGER.error("Cannot update Automation composition definition state, id is null"); + return; + } + + if (stateChangeResult == null) { + LOGGER.error("Cannot update Automation composition definition state, stateChangeResult is null"); + return; + } + if (!StateChangeResult.NO_ERROR.equals(stateChangeResult) + && !StateChangeResult.FAILED.equals(stateChangeResult)) { + LOGGER.error("Cannot update Automation composition definition state, stateChangeResult is not valid"); + return; + } + + if ((state == null) || AcTypeState.PRIMING.equals(state) || AcTypeState.DEPRIMING.equals(state)) { + LOGGER.error("state invalid {} cannot be handled", state); + return; + } + var participantPrimeAck = new ParticipantPrimeAck(); participantPrimeAck.setCompositionId(compositionId); - participantPrimeAck.setMessage(message); + participantPrimeAck.setMessage(AcmUtils.validatedMessage(message)); participantPrimeAck.setResult(true); participantPrimeAck.setResponseTo(cacheProvider.getMsgIdentification().get(compositionId)); participantPrimeAck.setCompositionState(state); diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/CacheProvider.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/CacheProvider.java index 29b77fcb6..3837ec629 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/CacheProvider.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/CacheProvider.java @@ -30,7 +30,10 @@ import lombok.Getter; import lombok.NonNull; import lombok.Setter; import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto; +import org.onap.policy.clamp.acm.participant.intermediary.api.ElementState; +import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto; import org.onap.policy.clamp.acm.participant.intermediary.parameters.ParticipantParameters; +import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy; import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition; @@ -39,6 +42,7 @@ import org.onap.policy.clamp.models.acm.concepts.LockState; import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy; import org.onap.policy.clamp.models.acm.concepts.ParticipantRestartAc; import org.onap.policy.clamp.models.acm.concepts.ParticipantSupportedElementType; +import org.onap.policy.clamp.models.acm.concepts.SubState; import org.onap.policy.models.base.PfUtils; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; @@ -161,16 +165,28 @@ public class CacheProvider { */ public void initializeAutomationComposition(@NonNull UUID compositionId, @NonNull UUID instanceId, ParticipantDeploy participantDeploy) { + initializeAutomationComposition(compositionId, instanceId, participantDeploy, + DeployState.DEPLOYING, SubState.NONE); + } + + /** + * Initialize an AutomationComposition from a ParticipantDeploy. + * + * @param compositionId the composition Id + * @param instanceId the Automation Composition Id + * @param participantDeploy the ParticipantDeploy + * @param deployState the DeployState + * @param subState the SubState + */ + public void initializeAutomationComposition(@NonNull UUID compositionId, @NonNull UUID instanceId, + ParticipantDeploy participantDeploy, DeployState deployState, SubState subState) { var acLast = automationCompositions.get(instanceId); Map<UUID, AutomationCompositionElement> acElementMap = new LinkedHashMap<>(); for (var element : participantDeploy.getAcElementList()) { - var acElement = new AutomationCompositionElement(); - acElement.setId(element.getId()); + var acElement = createAutomationCompositionElement(element); acElement.setParticipantId(getParticipantId()); - acElement.setDefinition(element.getDefinition()); - acElement.setDeployState(DeployState.DEPLOYING); - acElement.setLockState(LockState.NONE); - acElement.setProperties(element.getProperties()); + acElement.setDeployState(deployState); + acElement.setSubState(subState); var acElementLast = acLast != null ? acLast.getElements().get(element.getId()) : null; if (acElementLast != null) { acElement.setOutProperties(acElementLast.getOutProperties()); @@ -186,6 +202,8 @@ public class CacheProvider { automationComposition.setCompositionId(compositionId); automationComposition.setInstanceId(instanceId); automationComposition.setElements(acElementMap); + automationComposition.setDeployState(deployState); + automationComposition.setSubState(subState); automationCompositions.put(instanceId, automationComposition); } @@ -208,6 +226,7 @@ public class CacheProvider { acElement.setDefinition(element.getDefinition()); acElement.setDeployState(element.getDeployState()); acElement.setLockState(element.getLockState()); + acElement.setSubState(SubState.NONE); acElement.setOperationalState(element.getOperationalState()); acElement.setUseState(element.getUseState()); acElement.setProperties(element.getProperties()); @@ -224,10 +243,27 @@ public class CacheProvider { automationComposition.setLockState(participantRestartAc.getLockState()); automationComposition.setInstanceId(participantRestartAc.getAutomationCompositionId()); automationComposition.setElements(acElementMap); + automationComposition.setStateChangeResult(participantRestartAc.getStateChangeResult()); automationCompositions.put(automationComposition.getInstanceId(), automationComposition); } /** + * Create AutomationCompositionElement to save in memory. + * + * @param element AcElementDeploy + * @return a new AutomationCompositionElement + */ + public static AutomationCompositionElement createAutomationCompositionElement(AcElementDeploy element) { + var acElement = new AutomationCompositionElement(); + acElement.setId(element.getId()); + acElement.setDefinition(element.getDefinition()); + acElement.setProperties(element.getProperties()); + acElement.setSubState(SubState.NONE); + acElement.setLockState(LockState.LOCKED); + return acElement; + } + + /** * Create CompositionElementDto. * * @param compositionId the composition Id @@ -236,10 +272,78 @@ public class CacheProvider { * @return the CompositionElementDto */ public CompositionElementDto createCompositionElementDto(UUID compositionId, AutomationCompositionElement element, - Map<String, Object> compositionInProperties) { + Map<String, Object> compositionInProperties) { var compositionOutProperties = getAcElementsDefinitions() .get(compositionId).get(element.getDefinition()).getOutProperties(); return new CompositionElementDto(compositionId, element.getDefinition(), compositionInProperties, compositionOutProperties); } + + /** + * Get a Map of CompositionElementDto by elementId from the elements of an AutomationComposition. + * + * @param automationComposition the AutomationComposition + * @param compositionId the compositionId + * @return the Map of CompositionElementDto + */ + public Map<UUID, CompositionElementDto> getCompositionElementDtoMap(AutomationComposition automationComposition, + UUID compositionId) { + var definitions = acElementsDefinitions.get(compositionId); + Map<UUID, CompositionElementDto> map = new HashMap<>(); + for (var element : automationComposition.getElements().values()) { + var definition = definitions.get(element.getDefinition()); + var compositionElement = (definition != null) + ? new CompositionElementDto(compositionId, element.getDefinition(), + definition.getAutomationCompositionElementToscaNodeTemplate().getProperties(), + definition.getOutProperties()) : + new CompositionElementDto(compositionId, element.getDefinition(), + Map.of(), Map.of(), ElementState.NOT_PRESENT); + map.put(element.getId(), compositionElement); + } + return map; + } + + public Map<UUID, CompositionElementDto> getCompositionElementDtoMap(AutomationComposition automationComposition) { + return getCompositionElementDtoMap(automationComposition, automationComposition.getCompositionId()); + } + + /** + * Get a Map of InstanceElementDto by elementId from the elements of an AutomationComposition. + * + * @param automationComposition the AutomationComposition + * @return the Map of InstanceElementDto + */ + public Map<UUID, InstanceElementDto> getInstanceElementDtoMap(AutomationComposition automationComposition) { + Map<UUID, InstanceElementDto> map = new HashMap<>(); + var serviceTemplateFragment = serviceTemplateFragmentMap.get(automationComposition.getCompositionId()); + for (var element : automationComposition.getElements().values()) { + var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(), + serviceTemplateFragment, element.getProperties(), element.getOutProperties()); + map.put(element.getId(), instanceElement); + } + return map; + } + + /** + * Create a new InstanceElementDto record with state New. + * + * @param instanceElement the InstanceElementDto + * @return a new InstanceElementDto + */ + public static InstanceElementDto changeStateToNew(InstanceElementDto instanceElement) { + return new InstanceElementDto(instanceElement.instanceId(), instanceElement.elementId(), + instanceElement.toscaServiceTemplateFragment(), + instanceElement.inProperties(), instanceElement.outProperties(), ElementState.NEW); + } + + /** + * Create a new CompositionElementDto record with state New. + * + * @param compositionElement the CompositionElementDto + * @return a new CompositionElementDto + */ + public static CompositionElementDto changeStateToNew(CompositionElementDto compositionElement) { + return new CompositionElementDto(compositionElement.compositionId(), compositionElement.elementDefinitionId(), + compositionElement.inProperties(), compositionElement.outProperties(), ElementState.NEW); + } } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java index 5ae8f0422..6615ae102 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java @@ -28,6 +28,7 @@ import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessag import org.onap.policy.clamp.models.acm.concepts.ParticipantState; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionPrepare; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantAckMessage; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantDeregister; @@ -55,6 +56,7 @@ public class ParticipantHandler { private final AutomationCompositionHandler automationCompositionHandler; private final AcLockHandler acLockHandler; + private final AcSubStateHandler acSubStateHandler; private final AcDefinitionHandler acDefinitionHandler; private final ParticipantMessagePublisher publisher; private final CacheProvider cacheProvider; @@ -106,7 +108,11 @@ public class ParticipantHandler { value = "listener.automation_composition_migration", description = "AUTOMATION_COMPOSITION_MIGRATION messages received") public void handleAutomationCompositionMigration(AutomationCompositionMigration migrationMsg) { - automationCompositionHandler.handleAutomationCompositionMigration(migrationMsg); + if (Boolean.TRUE.equals(migrationMsg.getPrecheck())) { + acSubStateHandler.handleAcMigrationPrecheck(migrationMsg); + } else { + automationCompositionHandler.handleAutomationCompositionMigration(migrationMsg); + } } /** @@ -119,6 +125,11 @@ public class ParticipantHandler { automationCompositionHandler.handleAcPropertyUpdate(propertyUpdateMsg); } + @Timed(value = "listener.prepare", description = "AUTOMATION_COMPOSITION_PREPARE message received") + public void handleAutomationCompositionPrepare(AutomationCompositionPrepare acPrepareMsg) { + acSubStateHandler.handleAcPrepare(acPrepareMsg); + } + /** * Check if a participant message applies to this participant handler. * diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java index 00e0044b4..c422b22b5 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java @@ -53,7 +53,7 @@ public class ThreadHandler implements Closeable { private final ParticipantIntermediaryApi intermediaryApi; private final CacheProvider cacheProvider; - private final Map<UUID, Future> executionMap = new ConcurrentHashMap<>(); + private final Map<UUID, Future<?>> executionMap = new ConcurrentHashMap<>(); private final ExecutorService executor = Context.taskWrapping(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())); @@ -218,7 +218,13 @@ public class ThreadHandler implements Closeable { executionMap.remove(instanceElement.elementId()); } - private void cleanExecution(UUID execIdentificationId, UUID messageId) { + /** + * Clean Execution. + * + * @param execIdentificationId the identification Id + * @param messageId the messageId + */ + public void cleanExecution(UUID execIdentificationId, UUID messageId) { var process = executionMap.get(execIdentificationId); if (process != null) { if (!process.isDone()) { @@ -295,21 +301,24 @@ public class ThreadHandler implements Closeable { * @param compositionElementTarget the information of the Automation Composition Definition Element Target * @param instanceElement the information of the Automation Composition Instance Element * @param instanceElementMigrate the information of the Automation Composition Instance Element updated + * @param stage the stage */ public void migrate(UUID messageId, CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement, - InstanceElementDto instanceElementMigrate) { + InstanceElementDto instanceElementMigrate, int stage) { cleanExecution(instanceElement.elementId(), messageId); var result = executor.submit(() -> - this.migrateProcess(compositionElement, compositionElementTarget, instanceElement, instanceElementMigrate)); + this.migrateProcess(compositionElement, compositionElementTarget, + instanceElement, instanceElementMigrate, stage)); executionMap.put(instanceElement.elementId(), result); } private void migrateProcess(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement, - InstanceElementDto instanceElementMigrate) { + InstanceElementDto instanceElementMigrate, int stage) { try { - listener.migrate(compositionElement, compositionElementTarget, instanceElement, instanceElementMigrate); + listener.migrate(compositionElement, compositionElementTarget, + instanceElement, instanceElementMigrate, stage); } catch (PfModelException e) { LOGGER.error("Automation composition element migrate failed {} {}", instanceElement.elementId(), e.getMessage()); @@ -319,4 +328,93 @@ public class ThreadHandler implements Closeable { } executionMap.remove(instanceElement.elementId()); } + + /** + * Handles AutomationComposition Migration Precheck. + * + * @param messageId the messageId + * @param compositionElement the information of the Automation Composition Definition Element + * @param compositionElementTarget the information of the Automation Composition Definition Element Target + * @param instanceElement the information of the Automation Composition Instance Element + * @param instanceElementMigrate the information of the Automation Composition Instance Element updated + */ + public void migratePrecheck(UUID messageId, CompositionElementDto compositionElement, + CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement, + InstanceElementDto instanceElementMigrate) { + cleanExecution(instanceElement.elementId(), messageId); + var result = executor.submit(() -> + this.migratePrecheckProcess(compositionElement, compositionElementTarget, instanceElement, + instanceElementMigrate)); + executionMap.put(instanceElement.elementId(), result); + } + + private void migratePrecheckProcess(CompositionElementDto compositionElement, + CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement, + InstanceElementDto instanceElementMigrate) { + try { + listener.migratePrecheck(compositionElement, compositionElementTarget, instanceElement, + instanceElementMigrate); + } catch (PfModelException e) { + LOGGER.error("Automation composition element migrate precheck failed {} {}", + instanceElement.elementId(), e.getMessage()); + intermediaryApi.updateAutomationCompositionElementState( + instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED, + null, StateChangeResult.FAILED, "Automation composition element migrate precheck failed"); + } + executionMap.remove(instanceElement.elementId()); + } + + /** + * Handles AutomationComposition Prepare Post Deploy. + * + * @param messageId the messageId + * @param compositionElement the information of the Automation Composition Definition Element + * @param instanceElement the information of the Automation Composition Instance Element + */ + public void review(UUID messageId, CompositionElementDto compositionElement, + InstanceElementDto instanceElement) { + cleanExecution(instanceElement.elementId(), messageId); + var result = executor.submit(() -> this.reviewProcess(compositionElement, instanceElement)); + executionMap.put(instanceElement.elementId(), result); + } + + private void reviewProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) { + try { + listener.review(compositionElement, instanceElement); + } catch (PfModelException e) { + LOGGER.error("Automation composition element Review failed {} {}", + instanceElement.elementId(), e.getMessage()); + intermediaryApi.updateAutomationCompositionElementState( + instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED, + null, StateChangeResult.FAILED, "Automation composition element Review failed"); + } + executionMap.remove(instanceElement.elementId()); + } + + /** + * Handles AutomationComposition Prepare Pre Deploy. + * + * @param messageId the messageId + * @param compositionElement the information of the Automation Composition Definition Element + * @param instanceElement the information of the Automation Composition Instance Element + */ + public void prepare(UUID messageId, CompositionElementDto compositionElement, + InstanceElementDto instanceElement) { + cleanExecution(instanceElement.elementId(), messageId); + var result = executor.submit(() -> this.prepareProcess(compositionElement, instanceElement)); + executionMap.put(instanceElement.elementId(), result); + } + + private void prepareProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) { + try { + listener.prepare(compositionElement, instanceElement); + } catch (PfModelException e) { + LOGGER.error("Automation composition element prepare Pre Deploy failed {} {}", + instanceElement.elementId(), e.getMessage()); + intermediaryApi.updateAutomationCompositionElementState( + instanceElement.instanceId(), instanceElement.elementId(), DeployState.UNDEPLOYED, + null, StateChangeResult.FAILED, "Automation composition element prepare Pre Deploy failed"); + } + executionMap.remove(instanceElement.elementId()); + } } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/parameters/ParticipantIntermediaryParameters.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/parameters/ParticipantIntermediaryParameters.java index 1c36ad17f..47fa7754e 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/parameters/ParticipantIntermediaryParameters.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/parameters/ParticipantIntermediaryParameters.java @@ -62,6 +62,6 @@ public class ParticipantIntermediaryParameters { @NotNull @Valid - private Topics topics; + private Topics topics = new Topics(); } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/parameters/Topics.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/parameters/Topics.java index ddf72052f..7a93255b0 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/parameters/Topics.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/parameters/Topics.java @@ -24,6 +24,7 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; /** @@ -32,6 +33,7 @@ import lombok.Setter; @Getter @Setter @AllArgsConstructor +@NoArgsConstructor public class Topics { @NotNull diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV1Test.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV1Test.java index 7355b03e9..12acdbbb6 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV1Test.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV1Test.java @@ -157,23 +157,61 @@ class AcElementListenerV1Test { var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), Map.of(), Map.of()); var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); - acElementListenerV1.migrate(compositionElement, compositionElement, instanceElement, instanceElement); + acElementListenerV1.migrate(compositionElement, compositionElement, instanceElement, instanceElement, 0); verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated"); } + @Test + void migratePrecheckTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV1 = createAcElementListenerV1(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV1.migratePrecheck(compositionElement, compositionElement, instanceElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Migration Precheck completed"); + } + + @Test + void reviewTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV1 = createAcElementListenerV1(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV1.review(compositionElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Review completed"); + } + + @Test + void prepareTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV1 = createAcElementListenerV1(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV1.prepare(compositionElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.UNDEPLOYED, null, + StateChangeResult.NO_ERROR, "Prepare completed"); + } + private AcElementListenerV1 createAcElementListenerV1(ParticipantIntermediaryApi intermediaryApi) { return new AcElementListenerV1(intermediaryApi) { @Override - public void deploy(UUID instanceId, AcElementDeploy element, Map<String, Object> properties) - throws PfModelException { - + public void deploy(UUID instanceId, AcElementDeploy element, Map<String, Object> properties) { + // dummy implementation } @Override - public void undeploy(UUID instanceId, UUID elementId) throws PfModelException { - + public void undeploy(UUID instanceId, UUID elementId) { + // dummy implementation } }; } diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV2Test.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV2Test.java index c8ab9e222..a6cb7b005 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV2Test.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV2Test.java @@ -134,22 +134,61 @@ class AcElementListenerV2Test { var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), Map.of(), Map.of()); var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); - acElementListenerV2.migrate(compositionElement, compositionElement, instanceElement, instanceElement); + acElementListenerV2.migrate(compositionElement, compositionElement, instanceElement, instanceElement, 0); verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated"); } + @Test + void migratePrecheckTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV1 = createAcElementListenerV2(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV1.migratePrecheck(compositionElement, compositionElement, instanceElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Migration Precheck completed"); + } + + @Test + void reviewTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV1 = createAcElementListenerV2(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV1.review(compositionElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Review completed"); + } + + @Test + void prepareTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV1 = createAcElementListenerV2(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV1.prepare(compositionElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.UNDEPLOYED, null, + StateChangeResult.NO_ERROR, "Prepare completed"); + } + private AcElementListenerV2 createAcElementListenerV2(ParticipantIntermediaryApi intermediaryApi) { return new AcElementListenerV2(intermediaryApi) { @Override - public void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) - throws PfModelException { + public void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) { + // dummy implementation } @Override - public void undeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) - throws PfModelException { + public void undeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) { + // dummy implementation } }; } diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV3Test.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV3Test.java new file mode 100644 index 000000000..1385f439a --- /dev/null +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV3Test.java @@ -0,0 +1,180 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.acm.participant.intermediary.api.impl; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.util.Map; +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionDto; +import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto; +import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto; +import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi; +import org.onap.policy.clamp.models.acm.concepts.AcTypeState; +import org.onap.policy.clamp.models.acm.concepts.DeployState; +import org.onap.policy.clamp.models.acm.concepts.LockState; +import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +class AcElementListenerV3Test { + + @Test + void lockTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV2 = createAcElementListenerV3(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV2.lock(compositionElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked"); + } + + @Test + void deleteTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV2 = createAcElementListenerV3(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV2.delete(compositionElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted"); + } + + @Test + void updateTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV2 = createAcElementListenerV3(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV2.update(compositionElement, instanceElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Update not supported"); + } + + @Test + void unlockTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV2 = createAcElementListenerV3(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV2.unlock(compositionElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked"); + } + + @Test + void primeTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV2 = createAcElementListenerV3(intermediaryApi); + var compositionId = UUID.randomUUID(); + var toscaConceptIdentifier = new ToscaConceptIdentifier(); + var composition = new CompositionDto(compositionId, Map.of(toscaConceptIdentifier, Map.of()), Map.of()); + acElementListenerV2.prime(composition); + verify(intermediaryApi) + .updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.NO_ERROR, "Primed"); + } + + @Test + void deprimeTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV2 = createAcElementListenerV3(intermediaryApi); + var compositionId = UUID.randomUUID(); + var toscaConceptIdentifier = new ToscaConceptIdentifier(); + var composition = new CompositionDto(compositionId, Map.of(toscaConceptIdentifier, Map.of()), Map.of()); + acElementListenerV2.deprime(composition); + verify(intermediaryApi) + .updateCompositionState(compositionId, AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR, "Deprimed"); + } + + @Test + void migrateTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV2 = createAcElementListenerV3(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV2.migrate(compositionElement, compositionElement, instanceElement, instanceElement, 0); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Migrated"); + } + + @Test + void migratePrecheckTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV1 = createAcElementListenerV3(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV1.migratePrecheck(compositionElement, compositionElement, instanceElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Migration Precheck completed"); + } + + @Test + void reviewTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV1 = createAcElementListenerV3(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV1.review(compositionElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.DEPLOYED, null, + StateChangeResult.NO_ERROR, "Review completed"); + } + + @Test + void prepareTest() throws PfModelException { + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + var acElementListenerV1 = createAcElementListenerV3(intermediaryApi); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + Map.of(), Map.of()); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, Map.of(), Map.of()); + acElementListenerV1.prepare(compositionElement, instanceElement); + verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(), + instanceElement.elementId(), DeployState.UNDEPLOYED, null, + StateChangeResult.NO_ERROR, "Prepare completed"); + } + + private AcElementListenerV3 createAcElementListenerV3(ParticipantIntermediaryApi intermediaryApi) { + return new AcElementListenerV3(intermediaryApi) { + @Override + public void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) { + // dummy implementation + } + + @Override + public void undeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) { + // dummy implementation + } + }; + } +} diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AutomationCompositionElementListenerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AutomationCompositionElementListenerTest.java deleted file mode 100644 index b01065d09..000000000 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AutomationCompositionElementListenerTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.clamp.acm.participant.intermediary.api.impl; - -import static org.assertj.core.api.Assertions.assertThatCode; - -import java.util.Map; -import java.util.UUID; -import org.junit.jupiter.api.Test; -import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto; -import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto; -import org.onap.policy.clamp.acm.participant.intermediary.handler.DummyAcElementListener; -import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; - -class AutomationCompositionElementListenerTest { - - @Test - void defaultTest() { - var listener = new DummyAcElementListener(); - var compositionElementDto = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), - Map.of(), Map.of()); - var instanceElementDto = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), null, - Map.of(), Map.of()); - assertThatCode(() -> listener.lock(compositionElementDto, instanceElementDto)).doesNotThrowAnyException(); - assertThatCode(() -> listener.unlock(compositionElementDto, instanceElementDto)).doesNotThrowAnyException(); - } -} diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/ParticipantIntermediaryApiImplTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/ParticipantIntermediaryApiImplTest.java index 22929a237..71af77fbf 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/ParticipantIntermediaryApiImplTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/ParticipantIntermediaryApiImplTest.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,7 +84,7 @@ class ParticipantIntermediaryApiImplTest { var automationComposiitonHandler = mock(AutomationCompositionOutHandler.class); var apiImpl = new ParticipantIntermediaryApiImpl(automationComposiitonHandler, mock(CacheProvider.class)); apiImpl.sendAcDefinitionInfo(COMPOSITION_ID, DEFINITION_ELEMENT_ID, MAP); - verify(automationComposiitonHandler).sendAcDefinitionInfo(COMPOSITION_ID, DEFINITION_ELEMENT_ID, MAP);; + verify(automationComposiitonHandler).sendAcDefinitionInfo(COMPOSITION_ID, DEFINITION_ELEMENT_ID, MAP); } @Test @@ -134,7 +134,7 @@ class ParticipantIntermediaryApiImplTest { assertEquals(map, mapResult); var result = apiImpl.getAcElementsDefinitions(UUID.randomUUID()); - assertThat(result).isNull(); + assertThat(result).isEmpty(); result = apiImpl.getAcElementsDefinitions(COMPOSITION_ID); assertEquals(elementsDefinitions, result); diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/comm/ParticipantCommTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/comm/ParticipantCommTest.java index eaf89ec51..39e51f576 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/comm/ParticipantCommTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/comm/ParticipantCommTest.java @@ -88,6 +88,9 @@ class ParticipantCommTest { var acMigrationListener = new AutomationCompositionMigrationListener(participantHandler); assertEquals(ParticipantMessageType.AUTOMATION_COMPOSITION_MIGRATION.name(), acMigrationListener.getType()); + + var acPrepareListener = new AcPrepareListener(participantHandler); + assertEquals(ParticipantMessageType.AUTOMATION_COMPOSITION_PREPARE.name(), acPrepareListener.getType()); } @Test diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcDefinitionHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcDefinitionHandlerTest.java index c6259a28f..d72f5deea 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcDefinitionHandlerTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcDefinitionHandlerTest.java @@ -35,6 +35,7 @@ import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessag import org.onap.policy.clamp.acm.participant.intermediary.main.parameters.CommonTestData; import org.onap.policy.clamp.models.acm.concepts.AcTypeState; import org.onap.policy.clamp.models.acm.concepts.ParticipantDefinition; +import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrime; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantSync; @@ -110,6 +111,28 @@ class AcDefinitionHandlerTest { } @Test + void syncCompositionDefinitionTimeout() { + var participantSyncMsg = new ParticipantSync(); + participantSyncMsg.setState(AcTypeState.PRIMED); + participantSyncMsg.setStateChangeResult(StateChangeResult.TIMEOUT); + participantSyncMsg.setCompositionId(UUID.randomUUID()); + participantSyncMsg.getParticipantDefinitionUpdates().add(createParticipantDefinition()); + var participantRestartAc = CommonTestData.createParticipantRestartAc(); + participantRestartAc.setStateChangeResult(StateChangeResult.TIMEOUT); + participantSyncMsg.setAutomationcompositionList(List.of(participantRestartAc)); + + var cacheProvider = mock(CacheProvider.class); + var listener = mock(ThreadHandler.class); + var ach = new AcDefinitionHandler(cacheProvider, mock(ParticipantMessagePublisher.class), listener); + ach.handleParticipantSync(participantSyncMsg); + verify(cacheProvider).initializeAutomationComposition(any(UUID.class), any()); + verify(cacheProvider).addElementDefinition(any(), any()); + verify(listener).cleanExecution(participantSyncMsg.getCompositionId(), participantSyncMsg.getMessageId()); + var elementId = participantRestartAc.getAcElementList().get(0).getId(); + verify(listener).cleanExecution(elementId, participantSyncMsg.getMessageId()); + } + + @Test void syncDeleteTest() { var participantSyncMsg = new ParticipantSync(); participantSyncMsg.setState(AcTypeState.COMMISSIONED); diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcSubStateHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcSubStateHandlerTest.java new file mode 100644 index 000000000..8fad1d22b --- /dev/null +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AcSubStateHandlerTest.java @@ -0,0 +1,199 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.acm.participant.intermediary.handler; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.onap.policy.clamp.acm.participant.intermediary.main.parameters.CommonTestData; +import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy; +import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; +import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition; +import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionPrepare; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +class AcSubStateHandlerTest { + + @Test + void handleAcStateChangeNullTest() { + var cacheProvider = mock(CacheProvider.class); + var ach = new AcSubStateHandler(cacheProvider, mock(ThreadHandler.class)); + + var acMigration = new AutomationCompositionMigration(); + acMigration.setPrecheck(true); + assertDoesNotThrow(() -> ach.handleAcMigrationPrecheck(acMigration)); + + var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); + acMigration.setAutomationCompositionId(automationComposition.getInstanceId()); + acMigration.setCompositionTargetId(UUID.randomUUID()); + assertDoesNotThrow(() -> ach.handleAcMigrationPrecheck(acMigration)); + + var acPrepare = new AutomationCompositionPrepare(); + assertDoesNotThrow(() -> ach.handleAcPrepare(acPrepare)); + + acPrepare.setAutomationCompositionId(automationComposition.getInstanceId()); + assertDoesNotThrow(() -> ach.handleAcPrepare(acPrepare)); + } + + @Test + void handleAcMigrationPrecheckTest() { + var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); + automationComposition.setCompositionId(UUID.randomUUID()); + automationComposition.setInstanceId(UUID.randomUUID()); + automationComposition.setCompositionTargetId(UUID.randomUUID()); + var cacheProvider = new CacheProvider(CommonTestData.getParticipantParameters()); + var definitions = + CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition); + cacheProvider.addElementDefinition(automationComposition.getCompositionId(), definitions); + cacheProvider.addElementDefinition(automationComposition.getCompositionTargetId(), definitions); + var participantDeploy = + CommonTestData.createparticipantDeploy(cacheProvider.getParticipantId(), automationComposition); + cacheProvider.initializeAutomationComposition(automationComposition.getCompositionId(), + automationComposition.getInstanceId(), participantDeploy); + var migrationMsg = new AutomationCompositionMigration(); + migrationMsg.setStage(0); + migrationMsg.setCompositionId(automationComposition.getCompositionId()); + migrationMsg.setAutomationCompositionId(automationComposition.getInstanceId()); + migrationMsg.setCompositionTargetId(automationComposition.getCompositionTargetId()); + migrationMsg.setParticipantUpdatesList(List.of(participantDeploy)); + migrationMsg.setPrecheck(true); + var listener = mock(ThreadHandler.class); + var ach = new AcSubStateHandler(cacheProvider, listener); + ach.handleAcMigrationPrecheck(migrationMsg); + verify(listener, times(automationComposition.getElements().size())) + .migratePrecheck(any(), any(), any(), any(), any()); + } + + @Test + void handleAcMigrationPrecheckAddRemoveTest() { + var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); + automationComposition.setCompositionId(UUID.randomUUID()); + automationComposition.setInstanceId(UUID.randomUUID()); + var cacheProvider = new CacheProvider(CommonTestData.getParticipantParameters()); + var definitions = + CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition); + cacheProvider.addElementDefinition(automationComposition.getCompositionId(), definitions); + var participantDeploy = + CommonTestData.createparticipantDeploy(cacheProvider.getParticipantId(), automationComposition); + cacheProvider.initializeAutomationComposition(automationComposition.getCompositionId(), + automationComposition.getInstanceId(), participantDeploy); + + var acMigrate = new AutomationComposition(automationComposition); + acMigrate.setCompositionTargetId(UUID.randomUUID()); + + // replacing first element with new one + var element = acMigrate.getElements().values().iterator().next(); + element.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.0.0")); + element.setId(UUID.randomUUID()); + + var migrateDefinitions = + CommonTestData.createAutomationCompositionElementDefinitionList(acMigrate); + cacheProvider.addElementDefinition(acMigrate.getCompositionTargetId(), migrateDefinitions); + + var migrationMsg = new AutomationCompositionMigration(); + migrationMsg.setStage(0); + migrationMsg.setCompositionId(acMigrate.getCompositionId()); + migrationMsg.setAutomationCompositionId(acMigrate.getInstanceId()); + migrationMsg.setCompositionTargetId(acMigrate.getCompositionTargetId()); + var participantMigrate = CommonTestData.createparticipantDeploy(cacheProvider.getParticipantId(), acMigrate); + migrationMsg.setParticipantUpdatesList(List.of(participantMigrate)); + var listener = mock(ThreadHandler.class); + var ach = new AcSubStateHandler(cacheProvider, listener); + ach.handleAcMigrationPrecheck(migrationMsg); + verify(listener, times(acMigrate.getElements().size() + 1)) + .migratePrecheck(any(), any(), any(), any(), any()); + } + + @Test + void handlePrepareTest() { + var listener = mock(ThreadHandler.class); + var cacheProvider = mock(CacheProvider.class); + var ach = new AcSubStateHandler(cacheProvider, listener); + + var acPrepareMsg = new AutomationCompositionPrepare(); + acPrepareMsg.setPreDeploy(true); + assertDoesNotThrow(() -> ach.handleAcPrepare(acPrepareMsg)); + + acPrepareMsg.setParticipantId(CommonTestData.getParticipantId()); + when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId()); + var participantDeploy = new ParticipantDeploy(); + participantDeploy.setParticipantId(CommonTestData.getParticipantId()); + acPrepareMsg.getParticipantList().add(participantDeploy); + + var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); + acPrepareMsg.setAutomationCompositionId(automationComposition.getInstanceId()); + when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId())) + .thenReturn(automationComposition); + Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> map = new HashMap<>(); + for (var element : automationComposition.getElements().values()) { + var acElementDeploy = new AcElementDeploy(); + acElementDeploy.setProperties(Map.of()); + acElementDeploy.setId(element.getId()); + participantDeploy.getAcElementList().add(acElementDeploy); + map.put(element.getDefinition(), new AutomationCompositionElementDefinition()); + } + when(cacheProvider.getAcElementsDefinitions()) + .thenReturn(Map.of(automationComposition.getCompositionId(), map)); + + ach.handleAcPrepare(acPrepareMsg); + verify(listener, times(automationComposition.getElements().size())).prepare(any(), any(), any()); + } + + @Test + void handleReviewTest() { + var cacheProvider = mock(CacheProvider.class); + when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId()); + + var acPrepareMsg = new AutomationCompositionPrepare(); + acPrepareMsg.setPreDeploy(false); + acPrepareMsg.setParticipantId(CommonTestData.getParticipantId()); + + var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); + acPrepareMsg.setAutomationCompositionId(automationComposition.getInstanceId()); + when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId())) + .thenReturn(automationComposition); + Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> map = new HashMap<>(); + for (var element : automationComposition.getElements().values()) { + var acElementDeploy = new AcElementDeploy(); + acElementDeploy.setProperties(Map.of()); + acElementDeploy.setId(element.getId()); + map.put(element.getDefinition(), new AutomationCompositionElementDefinition()); + } + when(cacheProvider.getAcElementsDefinitions()) + .thenReturn(Map.of(automationComposition.getCompositionId(), map)); + + var listener = mock(ThreadHandler.class); + var ach = new AcSubStateHandler(cacheProvider, listener); + ach.handleAcPrepare(acPrepareMsg); + verify(listener, times(automationComposition.getElements().size())).review(any(), any(), any()); + } +} diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java index 40e3b1eec..ec61f886e 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java @@ -23,18 +23,22 @@ package org.onap.policy.clamp.acm.participant.intermediary.handler; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; import org.junit.jupiter.api.Test; import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher; import org.onap.policy.clamp.acm.participant.intermediary.main.parameters.CommonTestData; import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy; +import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition; import org.onap.policy.clamp.models.acm.concepts.DeployState; import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy; @@ -196,36 +200,145 @@ class AutomationCompositionHandlerTest { } @Test - void handleAutomationCompositionMigrationTest() { - var listener = mock(ThreadHandler.class); - var cacheProvider = mock(CacheProvider.class); - var ach = new AutomationCompositionHandler(cacheProvider, mock(ParticipantMessagePublisher.class), listener); + void handleMigrationNullTest() { + var ach = new AutomationCompositionHandler( + mock(CacheProvider.class), mock(ParticipantMessagePublisher.class), mock(ThreadHandler.class)); var migrationMsg = new AutomationCompositionMigration(); + migrationMsg.setStage(0); assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(migrationMsg)); - var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); + migrationMsg.setAutomationCompositionId(UUID.randomUUID()); migrationMsg.setCompositionTargetId(UUID.randomUUID()); - migrationMsg.setAutomationCompositionId(automationComposition.getInstanceId()); assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(migrationMsg)); - when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId())) - .thenReturn(automationComposition); - var participantDeploy = new ParticipantDeploy(); - participantDeploy.setParticipantId(CommonTestData.getParticipantId()); - when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId()); - migrationMsg.getParticipantUpdatesList().add(participantDeploy); - Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> map = new HashMap<>(); - for (var element : automationComposition.getElements().values()) { - var acElementDeploy = new AcElementDeploy(); - acElementDeploy.setProperties(Map.of()); - acElementDeploy.setId(element.getId()); - acElementDeploy.setDefinition(element.getDefinition()); - participantDeploy.getAcElementList().add(acElementDeploy); - map.put(element.getDefinition(), new AutomationCompositionElementDefinition()); - } - when(cacheProvider.getAcElementsDefinitions()) - .thenReturn(Map.of(automationComposition.getCompositionId(), map, - migrationMsg.getCompositionTargetId(), map)); + } + + @Test + void handleAutomationCompositionMigrationTest() { + var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); + automationComposition.setCompositionId(UUID.randomUUID()); + automationComposition.setInstanceId(UUID.randomUUID()); + automationComposition.setCompositionTargetId(UUID.randomUUID()); + var definitions = + CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition); + var participantDeploy = + CommonTestData.createparticipantDeploy(CommonTestData.getParticipantId(), automationComposition); + + var cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), + automationComposition.getInstanceId(), definitions, + automationComposition.getCompositionTargetId(), definitions); + + testMigration(cacheProvider, automationComposition, 0, automationComposition.getElements().size()); + } + + @Test + void handleMigrationAddRemoveTest() { + var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); + automationComposition.setCompositionId(UUID.randomUUID()); + automationComposition.setInstanceId(UUID.randomUUID()); + var acMigrate = new AutomationComposition(automationComposition); + acMigrate.setCompositionTargetId(UUID.randomUUID()); + + // replacing first element with new one + var element = acMigrate.getElements().values().iterator().next(); + element.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.0.0")); + element.setId(UUID.randomUUID()); + + var migrateDefinitions = + CommonTestData.createAutomationCompositionElementDefinitionList(acMigrate); + + var participantDeploy = + CommonTestData.createparticipantDeploy(CommonTestData.getParticipantId(), automationComposition); + var definitions = + CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition); + var cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), + automationComposition.getInstanceId(), definitions, + acMigrate.getCompositionTargetId(), migrateDefinitions); + + testMigration(cacheProvider, acMigrate, 0, acMigrate.getElements().size() + 1); + } + + @Test + void handleAcMigrationStageTest() { + var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); + automationComposition.setCompositionId(UUID.randomUUID()); + automationComposition.setInstanceId(UUID.randomUUID()); + + var acMigrate = new AutomationComposition(automationComposition); + acMigrate.setCompositionTargetId(UUID.randomUUID()); + + // replacing first element with new one + var element = acMigrate.getElements().values().iterator().next(); + element.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.2.4")); + element.setId(UUID.randomUUID()); + + // replacing definition version + acMigrate.getElements().values().forEach(el -> el.setDefinition( + new ToscaConceptIdentifier(el.getDefinition().getName(), "1.2.4"))); + + var migrateDefinitions = + CommonTestData.createAutomationCompositionElementDefinitionList(acMigrate); + + migrateDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate() + .setProperties(Map.of("stage", List.of(0, 1)))); + + var participantDeploy = + CommonTestData.createparticipantDeploy(CommonTestData.getParticipantId(), automationComposition); + var definitions = + CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition); + var cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), + automationComposition.getInstanceId(), definitions, + acMigrate.getCompositionTargetId(), migrateDefinitions); + + // scenario 1,2 + migrateDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate() + .setProperties(Map.of("stage", List.of(1, 2)))); + + // expected the element deleted + testMigration(cacheProvider, acMigrate, 0, 1); + + // expected 4 elements from stage 1 + testMigration(cacheProvider, acMigrate, 1, 4); + + // scenario 0,2 + cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), + automationComposition.getInstanceId(), definitions, + acMigrate.getCompositionTargetId(), migrateDefinitions); + + migrateDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate() + .setProperties(Map.of("stage", List.of(0, 2)))); + + // expected the element deleted + 4 elements from stage 0 + testMigration(cacheProvider, acMigrate, 0, 5); + + // expected 0 elements + testMigration(cacheProvider, acMigrate, 1, 0); + } + + private CacheProvider createCacheProvider(ParticipantDeploy participantDeploy, + UUID compositionId, UUID instanceId, List<AutomationCompositionElementDefinition> definitions, + UUID compositionTargetId, List<AutomationCompositionElementDefinition> migrateDefinitions) { + var cacheProvider = new CacheProvider(CommonTestData.getParticipantParameters()); + cacheProvider.addElementDefinition(compositionId, definitions); + cacheProvider.initializeAutomationComposition(compositionId, instanceId, participantDeploy); + cacheProvider.addElementDefinition(compositionTargetId, migrateDefinitions); + return cacheProvider; + } + + private void testMigration(CacheProvider cacheProvider, AutomationComposition acMigrate, + int stage, int expectedMigrated) { + var migrationMsg = new AutomationCompositionMigration(); + migrationMsg.setStage(stage); + migrationMsg.setCompositionId(acMigrate.getCompositionId()); + migrationMsg.setAutomationCompositionId(acMigrate.getInstanceId()); + migrationMsg.setCompositionTargetId(acMigrate.getCompositionTargetId()); + var participantMigrate = CommonTestData.createparticipantDeploy(cacheProvider.getParticipantId(), acMigrate); + migrationMsg.setParticipantUpdatesList(List.of(participantMigrate)); + var listener = mock(ThreadHandler.class); + + clearInvocations(); + var ach = new AutomationCompositionHandler(cacheProvider, mock(ParticipantMessagePublisher.class), listener); ach.handleAutomationCompositionMigration(migrationMsg); - verify(listener, times(automationComposition.getElements().size())).migrate(any(), any(), any(), any(), any()); + verify(listener, times(expectedMigrated)).migrate(any(), any(), any(), any(), any(), anyInt()); } + } diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandlerTest.java index eed5319f8..202f25c6f 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandlerTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionOutHandlerTest.java @@ -20,7 +20,6 @@ package org.onap.policy.clamp.acm.participant.intermediary.handler; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; @@ -39,6 +38,7 @@ import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDef import org.onap.policy.clamp.models.acm.concepts.DeployState; import org.onap.policy.clamp.models.acm.concepts.LockState; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; +import org.onap.policy.clamp.models.acm.concepts.SubState; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantStatus; @@ -49,45 +49,77 @@ class AutomationCompositionOutHandlerTest { @Test void updateAutomationCompositionElementStateNullTest() { var cacheProvider = mock(CacheProvider.class); - var acOutHandler = new AutomationCompositionOutHandler(mock(ParticipantMessagePublisher.class), cacheProvider); + var publisher = mock(ParticipantMessagePublisher.class); + var acOutHandler = new AutomationCompositionOutHandler(publisher, cacheProvider); assertDoesNotThrow( () -> acOutHandler.updateAutomationCompositionElementState(null, null, null, null, null, null)); + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementState(null, + UUID.randomUUID(), null, null, null, null)); + + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementState(UUID.randomUUID(), + null, null, null, null, null)); + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementState(UUID.randomUUID(), UUID.randomUUID(), null, null, null, null)); assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementState(UUID.randomUUID(), + UUID.randomUUID(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, null)); + + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementState(UUID.randomUUID(), UUID.randomUUID(), DeployState.DEPLOYED, null, null, null)); var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId())) .thenReturn(automationComposition); assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementState( - automationComposition.getInstanceId(), UUID.randomUUID(), DeployState.DEPLOYED, null, null, null)); + automationComposition.getInstanceId(), UUID.randomUUID(), DeployState.DEPLOYED, + null, StateChangeResult.NO_ERROR, null)); var elementId = automationComposition.getElements().values().iterator().next().getId(); assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementState( - automationComposition.getInstanceId(), elementId, null, null, null, null)); + automationComposition.getInstanceId(), elementId, null, null, + StateChangeResult.NO_ERROR, null)); + + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementStage( + elementId, null, StateChangeResult.NO_ERROR, 0, null)); + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementStage( + null, elementId, StateChangeResult.NO_ERROR, 0, null)); + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementStage( + UUID.randomUUID(), elementId, StateChangeResult.NO_ERROR, 0, null)); + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementStage( + automationComposition.getInstanceId(), UUID.randomUUID(), + StateChangeResult.NO_ERROR, 0, null)); + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementState( + automationComposition.getInstanceId(), elementId, DeployState.DEPLOYED, LockState.LOCKED, + StateChangeResult.NO_ERROR, null)); + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementState( + automationComposition.getInstanceId(), elementId, DeployState.DEPLOYING, null, + StateChangeResult.NO_ERROR, "")); + assertDoesNotThrow(() -> acOutHandler.updateAutomationCompositionElementState( + automationComposition.getInstanceId(), elementId, DeployState.DEPLOYED, null, + StateChangeResult.TIMEOUT, "")); + + verify(publisher, times(0)).sendAutomationCompositionAck(any()); } @Test - void updateAutomationCompositionElementStateDeployedTest() { + void updateAutomationCompositionElementStageTest() { var publisher = mock(ParticipantMessagePublisher.class); var cacheProvider = mock(CacheProvider.class); var acOutHandler = new AutomationCompositionOutHandler(publisher, cacheProvider); - var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId())) .thenReturn(automationComposition); var elementId = automationComposition.getElements().values().iterator().next().getId(); - acOutHandler.updateAutomationCompositionElementState(automationComposition.getInstanceId(), elementId, - DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed"); + acOutHandler.updateAutomationCompositionElementStage( + automationComposition.getInstanceId(), elementId, StateChangeResult.NO_ERROR, 0, "OK"); verify(publisher).sendAutomationCompositionAck(any(AutomationCompositionDeployAck.class)); } @Test - void updateAutomationCompositionElementStateLockTest() { + void updateAutomationCompositionElementStateDeployedTest() { var publisher = mock(ParticipantMessagePublisher.class); var cacheProvider = mock(CacheProvider.class); var acOutHandler = new AutomationCompositionOutHandler(publisher, cacheProvider); @@ -96,13 +128,30 @@ class AutomationCompositionOutHandlerTest { when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId())) .thenReturn(automationComposition); var elementId = automationComposition.getElements().values().iterator().next().getId(); - acOutHandler.updateAutomationCompositionElementState(automationComposition.getInstanceId(), elementId, null, - LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked"); + acOutHandler.updateAutomationCompositionElementState(automationComposition.getInstanceId(), elementId, + DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed"); + verify(publisher).sendAutomationCompositionAck(any(AutomationCompositionDeployAck.class)); + } + + @Test + void updateAutomationCompositionElementStatePrepareTest() { + var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); + automationComposition.setSubState(SubState.PREPARING); + var cacheProvider = mock(CacheProvider.class); + when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId())) + .thenReturn(automationComposition); + var element = automationComposition.getElements().values().iterator().next(); + element.setSubState(SubState.PREPARING); + var elementId = element.getId(); + var publisher = mock(ParticipantMessagePublisher.class); + var acOutHandler = new AutomationCompositionOutHandler(publisher, cacheProvider); + acOutHandler.updateAutomationCompositionElementState(automationComposition.getInstanceId(), elementId, + DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Prepare completed"); verify(publisher).sendAutomationCompositionAck(any(AutomationCompositionDeployAck.class)); } @Test - void updateAutomationCompositionElementStateRestartedTest() { + void updateAutomationCompositionElementStateLockTest() { var publisher = mock(ParticipantMessagePublisher.class); var cacheProvider = mock(CacheProvider.class); var acOutHandler = new AutomationCompositionOutHandler(publisher, cacheProvider); @@ -110,12 +159,10 @@ class AutomationCompositionOutHandlerTest { var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next(); when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId())) .thenReturn(automationComposition); - var element = automationComposition.getElements().values().iterator().next(); - element.setRestarting(true); - acOutHandler.updateAutomationCompositionElementState(automationComposition.getInstanceId(), element.getId(), - DeployState.DEPLOYED, LockState.LOCKED, StateChangeResult.NO_ERROR, "Restarted"); + var elementId = automationComposition.getElements().values().iterator().next().getId(); + acOutHandler.updateAutomationCompositionElementState(automationComposition.getInstanceId(), elementId, null, + LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked"); verify(publisher).sendAutomationCompositionAck(any(AutomationCompositionDeployAck.class)); - assertThat(element.getRestarting()).isNull(); } @Test @@ -169,6 +216,28 @@ class AutomationCompositionOutHandlerTest { } @Test + void updateCompositionStateNullTest() { + var publisher = mock(ParticipantMessagePublisher.class); + var cacheProvider = mock(CacheProvider.class); + var acOutHandler = new AutomationCompositionOutHandler(publisher, cacheProvider); + + assertDoesNotThrow( + () -> acOutHandler.updateCompositionState(null, null, null, null)); + assertDoesNotThrow(() -> acOutHandler.updateCompositionState(UUID.randomUUID(), null, + StateChangeResult.NO_ERROR, null)); + assertDoesNotThrow( + () -> acOutHandler.updateCompositionState(UUID.randomUUID(), AcTypeState.PRIMED, null, null)); + assertDoesNotThrow(() -> acOutHandler.updateCompositionState(UUID.randomUUID(), AcTypeState.PRIMING, + StateChangeResult.NO_ERROR, null)); + assertDoesNotThrow(() -> acOutHandler.updateCompositionState(UUID.randomUUID(), AcTypeState.DEPRIMING, + StateChangeResult.NO_ERROR, null)); + assertDoesNotThrow(() -> acOutHandler.updateCompositionState(UUID.randomUUID(), AcTypeState.PRIMED, + StateChangeResult.TIMEOUT, null)); + + verify(publisher, times(0)).sendParticipantPrimeAck(any()); + } + + @Test void updateCompositionStatePrimedTest() { var cacheProvider = mock(CacheProvider.class); when(cacheProvider.getParticipantId()).thenReturn(UUID.randomUUID()); diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/CacheProviderTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/CacheProviderTest.java index 9451f0138..ced2d81e8 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/CacheProviderTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/CacheProviderTest.java @@ -186,4 +186,36 @@ class CacheProviderTest { assertEquals(element.getDefinition(), result.elementDefinitionId()); } } + + @Test + void testGetCompositionElementDtoMap() { + var parameter = CommonTestData.getParticipantParameters(); + var cacheProvider = new CacheProvider(parameter); + var compositionId = UUID.randomUUID(); + var automationComposition = + CommonTestData.getTestAutomationCompositions().getAutomationCompositionList().get(0); + automationComposition.setCompositionId(compositionId); + cacheProvider.addElementDefinition(compositionId, + CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition)); + var result = cacheProvider.getCompositionElementDtoMap(automationComposition); + for (var element : automationComposition.getElements().values()) { + var compositionElementDto = result.get(element.getId()); + assertEquals(element.getDefinition(), compositionElementDto.elementDefinitionId()); + } + } + + @Test + void testGetInstanceElementDtoMap() { + var parameter = CommonTestData.getParticipantParameters(); + var cacheProvider = new CacheProvider(parameter); + var compositionId = UUID.randomUUID(); + var automationComposition = + CommonTestData.getTestAutomationCompositions().getAutomationCompositionList().get(0); + automationComposition.setCompositionId(compositionId); + var result = cacheProvider.getInstanceElementDtoMap(automationComposition); + for (var element : automationComposition.getElements().values()) { + var compositionElementDto = result.get(element.getId()); + assertEquals(element.getId(), compositionElementDto.elementId()); + } + } } diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/DummyAcElementListener.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/DummyAcElementListener.java deleted file mode 100644 index 173ed031b..000000000 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/DummyAcElementListener.java +++ /dev/null @@ -1,78 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.clamp.acm.participant.intermediary.handler; - -import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener; -import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionDto; -import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto; -import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto; -import org.onap.policy.models.base.PfModelException; - -public class DummyAcElementListener implements AutomationCompositionElementListener { - @Override - public void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) - throws PfModelException { - - } - - @Override - public void undeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) - throws PfModelException { - - } - - @Override - public void lock(CompositionElementDto compositionElement, InstanceElementDto instanceElement) - throws PfModelException { - - } - - @Override - public void unlock(CompositionElementDto compositionElement, InstanceElementDto instanceElement) - throws PfModelException { - - } - - @Override - public void delete(CompositionElementDto compositionElement, InstanceElementDto instanceElement) - throws PfModelException { - } - - @Override - public void update(CompositionElementDto compositionElement, InstanceElementDto instanceElement, - InstanceElementDto instanceElementUpdated) - throws PfModelException { - } - - @Override - public void prime(CompositionDto composition) throws PfModelException { - } - - @Override - public void deprime(CompositionDto composition) throws PfModelException { - } - - @Override - public void migrate(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget, - InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate) - throws PfModelException { - } -} diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandlerTest.java index 8c2b2473c..1fb72812b 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandlerTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandlerTest.java @@ -62,7 +62,8 @@ class ParticipantHandlerTest { when(publisher.isActive()).thenReturn(true); var cacheProvider = mock(CacheProvider.class); var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class), - mock(AcLockHandler.class), mock(AcDefinitionHandler.class), publisher, cacheProvider); + mock(AcLockHandler.class), mock(AcSubStateHandler.class), mock(AcDefinitionHandler.class), + publisher, cacheProvider); participantHandler.handleParticipantStatusReq(new ParticipantStatusReq()); verify(publisher).sendParticipantRegister(any(ParticipantRegister.class)); @@ -76,7 +77,8 @@ class ParticipantHandlerTest { void handleAutomationCompositionDeployTest() { var acHandler = mock(AutomationCompositionHandler.class); var participantHandler = new ParticipantHandler(acHandler, mock(AcLockHandler.class), - mock(AcDefinitionHandler.class), mock(ParticipantMessagePublisher.class), mock(CacheProvider.class)); + mock(AcSubStateHandler.class), mock(AcDefinitionHandler.class), mock(ParticipantMessagePublisher.class), + mock(CacheProvider.class)); var automationCompositionDeploy = new AutomationCompositionDeploy(); participantHandler.handleAutomationCompositionDeploy(automationCompositionDeploy); verify(acHandler).handleAutomationCompositionDeploy(automationCompositionDeploy); @@ -86,8 +88,8 @@ class ParticipantHandlerTest { void handleAutomationCompositionStateChangeTest() { var acHandler = mock(AutomationCompositionHandler.class); var acLockHandler = mock(AcLockHandler.class); - var participantHandler = new ParticipantHandler(acHandler, acLockHandler, mock(AcDefinitionHandler.class), - mock(ParticipantMessagePublisher.class), mock(CacheProvider.class)); + var participantHandler = new ParticipantHandler(acHandler, acLockHandler, mock(AcSubStateHandler.class), + mock(AcDefinitionHandler.class), mock(ParticipantMessagePublisher.class), mock(CacheProvider.class)); var acStateChange = new AutomationCompositionStateChange(); acStateChange.setDeployOrderedState(DeployOrder.DEPLOY); @@ -104,18 +106,25 @@ class ParticipantHandlerTest { @Test void handleAutomationCompositionMigrationTest() { var acHandler = mock(AutomationCompositionHandler.class); + var acSubStateHandler = mock(AcSubStateHandler.class); var participantHandler = new ParticipantHandler(acHandler, mock(AcLockHandler.class), - mock(AcDefinitionHandler.class), mock(ParticipantMessagePublisher.class), mock(CacheProvider.class)); + acSubStateHandler, mock(AcDefinitionHandler.class), mock(ParticipantMessagePublisher.class), + mock(CacheProvider.class)); var migrationMsg = new AutomationCompositionMigration(); participantHandler.handleAutomationCompositionMigration(migrationMsg); verify(acHandler).handleAutomationCompositionMigration(migrationMsg); + + migrationMsg.setPrecheck(true); + participantHandler.handleAutomationCompositionMigration(migrationMsg); + verify(acSubStateHandler).handleAcMigrationPrecheck(migrationMsg); } @Test void handleAcPropertyUpdateTest() { var acHandler = mock(AutomationCompositionHandler.class); var participantHandler = new ParticipantHandler(acHandler, mock(AcLockHandler.class), - mock(AcDefinitionHandler.class), mock(ParticipantMessagePublisher.class), mock(CacheProvider.class)); + mock(AcSubStateHandler.class), mock(AcDefinitionHandler.class), mock(ParticipantMessagePublisher.class), + mock(CacheProvider.class)); var propertyUpdateMsg = new PropertiesUpdate(); participantHandler.handleAcPropertyUpdate(propertyUpdateMsg); verify(acHandler).handleAcPropertyUpdate(propertyUpdateMsg); @@ -127,8 +136,8 @@ class ParticipantHandlerTest { when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId()); when(cacheProvider.getReplicaId()).thenReturn(CommonTestData.getReplicaId()); var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class), - mock(AcLockHandler.class), mock(AcDefinitionHandler.class), mock(ParticipantMessagePublisher.class), - cacheProvider); + mock(AcLockHandler.class), mock(AcSubStateHandler.class), mock(AcDefinitionHandler.class), + mock(ParticipantMessagePublisher.class), cacheProvider); var participantAckMsg = new ParticipantAckMessage(ParticipantMessageType.AUTOMATION_COMPOSITION_DEPLOY); assertTrue(participantHandler.appliesTo(participantAckMsg)); @@ -147,7 +156,8 @@ class ParticipantHandlerTest { when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId()); when(cacheProvider.getSupportedAcElementTypes()).thenReturn(List.of(new ParticipantSupportedElementType())); var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class), - mock(AcLockHandler.class), mock(AcDefinitionHandler.class), publisher, cacheProvider); + mock(AcLockHandler.class), mock(AcSubStateHandler.class), mock(AcDefinitionHandler.class), publisher, + cacheProvider); participantHandler.sendParticipantRegister(); verify(publisher).sendParticipantRegister(any(ParticipantRegister.class)); @@ -159,7 +169,8 @@ class ParticipantHandlerTest { var cacheProvider = mock(CacheProvider.class); when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId()); var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class), - mock(AcLockHandler.class), mock(AcDefinitionHandler.class), publisher, cacheProvider); + mock(AcLockHandler.class), mock(AcSubStateHandler.class), mock(AcDefinitionHandler.class), publisher, + cacheProvider); participantHandler.handleParticipantRegisterAck(new ParticipantRegisterAck()); verify(publisher).sendParticipantStatus(any(ParticipantStatus.class)); @@ -171,7 +182,8 @@ class ParticipantHandlerTest { var cacheProvider = mock(CacheProvider.class); when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId()); var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class), - mock(AcLockHandler.class), mock(AcDefinitionHandler.class), publisher, cacheProvider); + mock(AcLockHandler.class), mock(AcSubStateHandler.class), mock(AcDefinitionHandler.class), publisher, + cacheProvider); participantHandler.sendParticipantDeregister(); verify(publisher).sendParticipantDeregister(any(ParticipantDeregister.class)); @@ -180,8 +192,8 @@ class ParticipantHandlerTest { @Test void handleParticipantDeregisterAckTest() { var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class), - mock(AcLockHandler.class), mock(AcDefinitionHandler.class), mock(ParticipantMessagePublisher.class), - mock(CacheProvider.class)); + mock(AcLockHandler.class), mock(AcSubStateHandler.class), mock(AcDefinitionHandler.class), + mock(ParticipantMessagePublisher.class), mock(CacheProvider.class)); var participantDeregisterAck = new ParticipantDeregisterAck(); assertDoesNotThrow(() -> participantHandler.handleParticipantDeregisterAck(participantDeregisterAck)); } @@ -194,8 +206,8 @@ class ParticipantHandlerTest { var acHandler = mock(AcDefinitionHandler.class); var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class), - mock(AcLockHandler.class), acHandler, mock(ParticipantMessagePublisher.class), - mock(CacheProvider.class)); + mock(AcLockHandler.class), mock(AcSubStateHandler.class), acHandler, + mock(ParticipantMessagePublisher.class), mock(CacheProvider.class)); participantHandler.handleParticipantPrime(participantPrime); verify(acHandler).handlePrime(participantPrime); @@ -213,7 +225,7 @@ class ParticipantHandlerTest { var publisher = mock(ParticipantMessagePublisher.class); var acHandler = mock(AcDefinitionHandler.class); var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class), - mock(AcLockHandler.class), acHandler, publisher, cacheProvider); + mock(AcLockHandler.class), mock(AcSubStateHandler.class), acHandler, publisher, cacheProvider); participantHandler.handleParticipantSync(participantSyncMsg); verify(acHandler).handleParticipantSync(participantSyncMsg); @@ -229,7 +241,7 @@ class ParticipantHandlerTest { when(publisher.isActive()).thenReturn(true); var acHandler = mock(AcDefinitionHandler.class); var participantHandler = new ParticipantHandler(mock(AutomationCompositionHandler.class), - mock(AcLockHandler.class), acHandler, publisher, cacheProvider); + mock(AcLockHandler.class), mock(AcSubStateHandler.class), acHandler, publisher, cacheProvider); participantHandler.sendHeartbeat(); verify(publisher).sendParticipantRegister(any(ParticipantRegister.class)); diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java index f3471e6ee..d05471901 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java @@ -49,7 +49,7 @@ class ThreadHandlerTest { private static final int TIMEOUT = 400; @Test - void test() throws PfModelException, IOException { + void testPrime() throws PfModelException, IOException { var listener = mock(AutomationCompositionElementListener.class); var intermediaryApi = mock(ParticipantIntermediaryApi.class); try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) { @@ -61,11 +61,45 @@ class ThreadHandlerTest { verify(listener, timeout(TIMEOUT)).prime(composition); clearInvocations(listener); + threadHandler.deprime(messageId, composition); + verify(listener, timeout(TIMEOUT)).deprime(composition); + } + } + + @Test + void testPrimeException() throws PfModelException, IOException { + var listener = mock(AutomationCompositionElementListener.class); + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) { + + var compositionId = UUID.randomUUID(); + var composition = new CompositionDto(compositionId, Map.of(), Map.of()); + doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener).prime(composition); + var messageId = UUID.randomUUID(); + threadHandler.prime(messageId, composition); + verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.COMMISSIONED, + StateChangeResult.FAILED, "Composition Defintion prime failed"); + + clearInvocations(listener); + doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener).deprime(composition); + threadHandler.deprime(messageId, composition); + verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.PRIMED, + StateChangeResult.FAILED, "Composition Defintion deprime failed"); + } + } + + @Test + void testDeploy() throws PfModelException, IOException { + var listener = mock(AutomationCompositionElementListener.class); + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) { + Map<String, Object> properties = Map.of("key", "value"); var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), properties, properties); var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), - null, properties, properties); + null, properties, properties); + var messageId = UUID.randomUUID(); threadHandler.deploy(messageId, compositionElement, instanceElement); verify(listener, timeout(TIMEOUT)).deploy(compositionElement, instanceElement); @@ -83,17 +117,9 @@ class ThreadHandlerTest { var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(), properties, properties); threadHandler.migrate(messageId, compositionElement, compositionElementTarget, - instanceElement, instanceElementUpdated); + instanceElement, instanceElementUpdated, 0); verify(listener, timeout(TIMEOUT)).migrate(compositionElement, compositionElementTarget, - instanceElement, instanceElementUpdated); - - clearInvocations(listener); - threadHandler.lock(messageId, compositionElement, instanceElement); - verify(listener, timeout(TIMEOUT)).lock(compositionElement, instanceElement); - - clearInvocations(listener); - threadHandler.unlock(messageId, compositionElement, instanceElement); - verify(listener, timeout(TIMEOUT)).unlock(compositionElement, instanceElement); + instanceElement, instanceElementUpdated, 0); clearInvocations(listener); threadHandler.undeploy(messageId, compositionElement, instanceElement); @@ -102,29 +128,15 @@ class ThreadHandlerTest { clearInvocations(listener); threadHandler.delete(messageId, compositionElement, instanceElement); verify(listener, timeout(TIMEOUT)).delete(compositionElement, instanceElement); - - clearInvocations(listener); - threadHandler.deprime(messageId, composition); - verify(listener, timeout(TIMEOUT)).deprime(composition); } } @Test - void testException() throws PfModelException, IOException { + void testDeployException() throws PfModelException, IOException { var listener = mock(AutomationCompositionElementListener.class); var intermediaryApi = mock(ParticipantIntermediaryApi.class); try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) { - var compositionId = UUID.randomUUID(); - var composition = new CompositionDto(compositionId, Map.of(), Map.of()); - doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) - .prime(composition); - var messageId = UUID.randomUUID(); - threadHandler.prime(messageId, composition); - verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.COMMISSIONED, - StateChangeResult.FAILED, "Composition Defintion prime failed"); - - clearInvocations(intermediaryApi); Map<String, Object> properties = Map.of("key", "value"); var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), properties, properties); @@ -135,9 +147,10 @@ class ThreadHandlerTest { element.setId(elementId); doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) .deploy(compositionElement, instanceElement); + var messageId = UUID.randomUUID(); threadHandler.deploy(messageId, compositionElement, instanceElement); verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, - DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, + DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Automation composition element deploy failed"); clearInvocations(listener); @@ -147,44 +160,169 @@ class ThreadHandlerTest { .update(compositionElement, instanceElement, instanceElementUpdated); threadHandler.update(messageId, compositionElement, instanceElement, instanceElementUpdated); verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, - DeployState.DEPLOYED, null, StateChangeResult.FAILED, - "Automation composition element update failed"); + DeployState.DEPLOYED, null, StateChangeResult.FAILED, + "Automation composition element update failed"); + + clearInvocations(listener); + var compositionTargetId = UUID.randomUUID(); + var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(), + properties, properties); + doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) + .migrate(compositionElement, compositionElementTarget, instanceElement, instanceElementUpdated, 0); + threadHandler.migrate(messageId, compositionElement, compositionElementTarget, + instanceElement, instanceElementUpdated, 0); + verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, + DeployState.DEPLOYED, null, StateChangeResult.FAILED, + "Automation composition element migrate failed"); + + clearInvocations(listener); + doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) + .undeploy(compositionElement, instanceElement); + threadHandler.undeploy(messageId, compositionElement, instanceElement); + verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, + DeployState.DEPLOYED, null, StateChangeResult.FAILED, + "Automation composition element undeploy failed"); + + clearInvocations(listener); + doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) + .delete(compositionElement, instanceElement); + threadHandler.delete(messageId, compositionElement, instanceElement); + verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, + DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, + "Automation composition element delete failed"); + } + } + + @Test + void testLock() throws PfModelException, IOException { + var listener = mock(AutomationCompositionElementListener.class); + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) { + + Map<String, Object> properties = Map.of("key", "value"); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + properties, properties); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), + null, properties, properties); + var messageId = UUID.randomUUID(); + threadHandler.lock(messageId, compositionElement, instanceElement); + verify(listener, timeout(TIMEOUT)).lock(compositionElement, instanceElement); + + clearInvocations(listener); + threadHandler.unlock(messageId, compositionElement, instanceElement); + verify(listener, timeout(TIMEOUT)).unlock(compositionElement, instanceElement); clearInvocations(listener); + threadHandler.undeploy(messageId, compositionElement, instanceElement); + verify(listener, timeout(TIMEOUT)).undeploy(compositionElement, instanceElement); + } + } + + @Test + void testLockException() throws PfModelException, IOException { + var listener = mock(AutomationCompositionElementListener.class); + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) { + + Map<String, Object> properties = Map.of("key", "value"); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + properties, properties); + var instanceId = UUID.randomUUID(); + var elementId = UUID.randomUUID(); + var instanceElement = new InstanceElementDto(instanceId, elementId, null, properties, properties); + var element = new AcElementDeploy(); + element.setId(elementId); + var messageId = UUID.randomUUID(); doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) .lock(compositionElement, instanceElement); threadHandler.lock(messageId, compositionElement, instanceElement); verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, - null, LockState.UNLOCKED, StateChangeResult.FAILED, "Automation composition element lock failed"); + null, LockState.UNLOCKED, StateChangeResult.FAILED, "Automation composition element lock failed"); clearInvocations(listener); doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) .unlock(compositionElement, instanceElement); threadHandler.unlock(messageId, compositionElement, instanceElement); verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, - null, LockState.LOCKED, StateChangeResult.FAILED, "Automation composition element unlock failed"); + null, LockState.LOCKED, StateChangeResult.FAILED, "Automation composition element unlock failed"); + } + } + + @Test + void testSubState() throws PfModelException, IOException { + var listener = mock(AutomationCompositionElementListener.class); + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) { + + Map<String, Object> properties = Map.of("key", "value"); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + properties, properties); + var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), + null, properties, properties); + var messageId = UUID.randomUUID(); + threadHandler.prepare(messageId, compositionElement, instanceElement); + verify(listener, timeout(TIMEOUT)).prepare(compositionElement, instanceElement); clearInvocations(listener); + threadHandler.review(messageId, compositionElement, instanceElement); + verify(listener, timeout(TIMEOUT)).review(compositionElement, instanceElement); + + clearInvocations(listener); + var instanceElementMigrate = new InstanceElementDto(instanceElement.instanceId(), + instanceElement.elementId(), null, properties, properties); + var compositionTargetId = UUID.randomUUID(); + var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(), + properties, properties); + threadHandler.migratePrecheck(messageId, compositionElement, compositionElementTarget, + instanceElement, instanceElementMigrate); + verify(listener, timeout(TIMEOUT)).migratePrecheck(compositionElement, compositionElementTarget, + instanceElement, instanceElementMigrate); + } + } + + @Test + void testSubStateException() throws PfModelException, IOException { + var listener = mock(AutomationCompositionElementListener.class); + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) { + + Map<String, Object> properties = Map.of("key", "value"); + var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(), + properties, properties); + var instanceId = UUID.randomUUID(); + var elementId = UUID.randomUUID(); + var instanceElement = new InstanceElementDto(instanceId, elementId, null, properties, properties); + var element = new AcElementDeploy(); + element.setId(elementId); doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) - .undeploy(compositionElement, instanceElement); - threadHandler.undeploy(messageId, compositionElement, instanceElement); + .prepare(compositionElement, instanceElement); + var messageId = UUID.randomUUID(); + threadHandler.prepare(messageId, compositionElement, instanceElement); verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, - DeployState.DEPLOYED, null, StateChangeResult.FAILED, - "Automation composition element undeploy failed"); + DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, + "Automation composition element prepare Pre Deploy failed"); clearInvocations(listener); doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) - .delete(compositionElement, instanceElement); - threadHandler.delete(messageId, compositionElement, instanceElement); + .review(compositionElement, instanceElement); + threadHandler.review(messageId, compositionElement, instanceElement); verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, - DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, - "Automation composition element delete failed"); + DeployState.DEPLOYED, null, StateChangeResult.FAILED, + "Automation composition element Review failed"); clearInvocations(listener); - doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener).deprime(composition); - threadHandler.deprime(messageId, composition); - verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.PRIMED, - StateChangeResult.FAILED, "Composition Defintion deprime failed"); + var compositionTargetId = UUID.randomUUID(); + var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(), + properties, properties); + var instanceElementMigrate = new InstanceElementDto(instanceElement.instanceId(), + instanceElement.elementId(), null, properties, properties); + doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) + .migratePrecheck(compositionElement, compositionElementTarget, instanceElement, instanceElementMigrate); + threadHandler.migratePrecheck(messageId, compositionElement, compositionElementTarget, + instanceElement, instanceElementMigrate); + verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, + DeployState.DEPLOYED, null, StateChangeResult.FAILED, + "Automation composition element migrate precheck failed"); } } } |