Add rollback signatures for participant intermediary 54/140854/2
authoradheli.tavares <adheli.tavares@est.tech>
Thu, 8 May 2025 09:44:41 +0000 (10:44 +0100)
committeradheli.tavares <adheli.tavares@est.tech>
Thu, 8 May 2025 13:11:34 +0000 (14:11 +0100)
Issue-ID: POLICY-5334
Change-Id: I9728f9285d2cbb85069f1db010d70e76c8e86937
Signed-off-by: adheli.tavares <adheli.tavares@est.tech>
participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/acm/participant/sim/main/handler/AutomationCompositionElementHandler.java
participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/acm/participant/sim/main/handler/SimulatorService.java
participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/acm/participant/sim/model/SimConfig.java
participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/acm/participant/sim/main/handler/AutomationCompositionElementHandlerTest.java
participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/acm/participant/sim/main/handler/SimulatorServiceTest.java
participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java
participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/ParticipantIntermediaryApi.java
participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV4.java
participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/api/impl/AcElementListenerV3Test.java

index 5107082..270aa03 100644 (file)
@@ -51,7 +51,7 @@ public class AutomationCompositionElementHandler extends AcElementListenerV4 {
     }
 
     /**
-     * Handle a deploy on a automation composition element.
+     * Handle deploying an automation composition element.
      *
      * @param compositionElement the information of the Automation Composition Definition Element
      * @param instanceElement the information of the Automation Composition Instance Element
@@ -64,7 +64,7 @@ public class AutomationCompositionElementHandler extends AcElementListenerV4 {
     }
 
     /**
-     * Handle a automation composition element state change.
+     * Handle an automation composition element state change.
      *
      * @param compositionElement the information of the Automation Composition Definition Element
      * @param instanceElement the information of the Automation Composition Instance Element
@@ -156,4 +156,11 @@ public class AutomationCompositionElementHandler extends AcElementListenerV4 {
         LOGGER.debug("review call compositionElement: {}, instanceElement: {}", compositionElement, instanceElement);
         simulatorService.review(instanceElement.instanceId(), instanceElement.elementId());
     }
+
+    @Override
+    public void rollbackMigration(CompositionElementDto compositionElement,
+                                  InstanceElementDto instanceElement, int nextStage) {
+        LOGGER.debug("rollback call compositionElement: {}, instanceElement: {}", compositionElement, instanceElement);
+        simulatorService.rollback(instanceElement.instanceId(), instanceElement.elementId());
+    }
 }
index 93a9ee7..dfced7c 100644 (file)
@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.locks.LockSupport;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.Setter;
@@ -80,16 +81,16 @@ public class SimulatorService {
     /**
      * Set OutProperties.
      *
-     * @param instanceId the automationComposition Id
-     * @param elementId the automationComposition Element Id
-     * @param useState the useState
+     * @param instanceId       the automationComposition Id
+     * @param elementId        the automationComposition Element Id
+     * @param useState         the useState
      * @param operationalState the operationalState
-     * @param outProperties the outProperties
+     * @param outProperties    the outProperties
      */
     public void setOutProperties(UUID instanceId, UUID elementId, String useState, String operationalState,
                                  Map<String, Object> outProperties) {
         intermediaryApi.sendAcElementInfo(instanceId, elementId, useState, operationalState,
-                outProperties);
+            outProperties);
     }
 
     /**
@@ -130,7 +131,7 @@ public class SimulatorService {
                 internalData.setCompositionId(entry.getKey());
                 internalData.setCompositionDefinitionElementId(acElementsDefinition.getAcElementDefinitionId());
                 internalData.setIntProperties(
-                        acElementsDefinition.getAutomationCompositionElementToscaNodeTemplate().getProperties());
+                    acElementsDefinition.getAutomationCompositionElementToscaNodeTemplate().getProperties());
                 internalData.setOutProperties(acElementsDefinition.getOutProperties());
                 internalDatas.getList().add(internalData);
             }
@@ -144,34 +145,28 @@ public class SimulatorService {
 
     }
 
-    protected boolean execution(int timeMs, String msg, UUID elementId) {
-        long endTime = System.currentTimeMillis() + timeMs;
-        while (System.currentTimeMillis() < endTime) {
-            try {
-                if (Thread.currentThread().isInterrupted()) {
-                    LOGGER.debug(msg, elementId);
-                    return false;
-                }
-                Thread.sleep(10L);
-            } catch (InterruptedException e) {
+    protected boolean isInterrupted(int timeMs, String msg, UUID elementId) {
+        long endTime = System.nanoTime() + (timeMs * 1_000_000L);
+        while (System.nanoTime() < endTime) {
+            if (Thread.interrupted()) {
                 LOGGER.debug(msg, elementId);
-                Thread.currentThread().interrupt();
-                return false;
+                return true;
             }
+            LockSupport.parkNanos(10_000_000L);
         }
-        return true;
+        return false;
     }
 
     /**
-     * Handle a deploy on a automation composition element.
+     * Handle deploying an automation composition element.
      *
-     * @param instanceId the instanceId
-     * @param elementId the elementId
+     * @param instanceId    the instanceId
+     * @param elementId     the elementId
      * @param outProperties the outProperties
      */
     public void deploy(UUID instanceId, UUID elementId, Map<String, Object> outProperties) {
-        if (!execution(getConfig().getDeployTimerMs(),
-                "Current Thread deploy is Interrupted during execution {}", elementId)) {
+        if (isInterrupted(getConfig().getDeployTimerMs(),
+            "Current Thread deploy is Interrupted during execution {}", elementId)) {
             return;
         }
 
@@ -180,26 +175,26 @@ public class SimulatorService {
             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, outProperties);
 
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
+                DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
         } else {
             outProperties.put(INTERNAL_STATE, DeployState.UNDEPLOYED.name());
             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, outProperties);
 
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Deploy failed!");
+                DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Deploy failed!");
         }
     }
 
     /**
-     * Handle an udeploy on a automation composition element.
+     * Handle undeploying an automation composition element.
      *
-     * @param instanceId the instanceId
-     * @param elementId the elementId
+     * @param instanceId    the instanceId
+     * @param elementId     the elementId
      * @param outProperties the outProperties
      */
     public void undeploy(UUID instanceId, UUID elementId, Map<String, Object> outProperties) {
-        if (!execution(getConfig().getUndeployTimerMs(),
-                "Current Thread undeploy is Interrupted during execution {}", elementId)) {
+        if (isInterrupted(getConfig().getUndeployTimerMs(),
+            "Current Thread undeploy is Interrupted during execution {}", elementId)) {
             return;
         }
 
@@ -208,119 +203,119 @@ public class SimulatorService {
             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, outProperties);
 
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Undeployed");
+                DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Undeployed");
         } else {
             outProperties.put(INTERNAL_STATE, DeployState.DEPLOYED.name());
             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, outProperties);
 
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Undeploy failed!");
+                DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Undeploy failed!");
         }
     }
 
     /**
-     * Handle a lock on a automation composition element.
+     * Handle locking an automation composition element.
      *
      * @param instanceId the instanceId
-     * @param elementId the elementId
+     * @param elementId  the elementId
      */
     public void lock(UUID instanceId, UUID elementId) {
-        if (!execution(getConfig().getLockTimerMs(),
-                "Current Thread lock is Interrupted during execution {}", elementId)) {
+        if (isInterrupted(getConfig().getLockTimerMs(),
+            "Current Thread lock is Interrupted during execution {}", elementId)) {
             return;
         }
 
         if (getConfig().isLockSuccess()) {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked");
+                null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked");
         } else {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    null, LockState.UNLOCKED, StateChangeResult.FAILED, "Lock failed!");
+                null, LockState.UNLOCKED, StateChangeResult.FAILED, "Lock failed!");
         }
     }
 
     /**
-     * Handle an unlock on a automation composition element.
+     * Handle unlocking an automation composition element.
      *
      * @param instanceId the instanceId
-     * @param elementId the elementId
+     * @param elementId  the elementId
      */
     public void unlock(UUID instanceId, UUID elementId) {
-        if (!execution(getConfig().getUnlockTimerMs(),
-                "Current Thread unlock is Interrupted during execution {}", elementId)) {
+        if (isInterrupted(getConfig().getUnlockTimerMs(),
+            "Current Thread unlock is Interrupted during execution {}", elementId)) {
             return;
         }
 
         if (getConfig().isUnlockSuccess()) {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked");
+                null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked");
         } else {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    null, LockState.LOCKED, StateChangeResult.FAILED, "Unlock failed!");
+                null, LockState.LOCKED, StateChangeResult.FAILED, "Unlock failed!");
         }
     }
 
     /**
-     * Handle a delete on a automation composition element.
+     * Handle deleting an automation composition element.
      *
      * @param instanceId the instanceId
-     * @param elementId the elementId
+     * @param elementId  the elementId
      */
     public void delete(UUID instanceId, UUID elementId) {
-        if (!execution(getConfig().getDeleteTimerMs(),
-                "Current Thread delete is Interrupted during execution {}", elementId)) {
+        if (isInterrupted(getConfig().getDeleteTimerMs(),
+            "Current Thread delete is Interrupted during execution {}", elementId)) {
             return;
         }
 
         if (getConfig().isDeleteSuccess()) {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
+                DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
         } else {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Delete failed!");
+                DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Delete failed!");
         }
     }
 
     /**
-     * Handle an update on a automation composition element.
+     * Handle an update on an automation composition element.
      *
      * @param instanceId the instanceId
-     * @param elementId the elementId
+     * @param elementId  the elementId
      */
     public void update(UUID instanceId, UUID elementId) {
-        if (!execution(getConfig().getUpdateTimerMs(),
-                "Current Thread update is Interrupted during execution {}", elementId)) {
+        if (isInterrupted(getConfig().getUpdateTimerMs(),
+            "Current Thread update is Interrupted during execution {}", elementId)) {
             return;
         }
 
         if (getConfig().isUpdateSuccess()) {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Updated");
+                DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Updated");
         } else {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Update failed!");
+                DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Update failed!");
         }
     }
 
     /**
-     * Handle a prime on a automation composition definition.
+     * Handle a prime on an automation composition definition.
      *
      * @param composition the information of the Automation Composition Definition
      */
     public void prime(CompositionDto composition) {
-        if (!execution(getConfig().getPrimeTimerMs(),
-                "Current Thread prime is Interrupted during execution {}", composition.compositionId())) {
+        if (isInterrupted(getConfig().getPrimeTimerMs(),
+            "Current Thread prime is Interrupted during execution {}", composition.compositionId())) {
             return;
         }
 
         if (getConfig().isPrimeSuccess()) {
             sendOutProperties(composition, AcTypeState.PRIMED.name());
             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
-                    StateChangeResult.NO_ERROR, "Primed");
+                StateChangeResult.NO_ERROR, "Primed");
         } else {
             sendOutProperties(composition, AcTypeState.COMMISSIONED.name());
             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
-                    StateChangeResult.FAILED, "Prime failed!");
+                StateChangeResult.FAILED, "Prime failed!");
         }
     }
 
@@ -328,45 +323,45 @@ public class SimulatorService {
         for (var elementEntry : composition.outPropertiesMap().entrySet()) {
             elementEntry.getValue().put(INTERNAL_STATE, data);
             intermediaryApi.sendAcDefinitionInfo(
-                    composition.compositionId(), elementEntry.getKey(), elementEntry.getValue());
+                composition.compositionId(), elementEntry.getKey(), elementEntry.getValue());
         }
     }
 
     /**
-     * Handle a deprime on a automation composition definition.
+     * Handle a deprime on an automation composition definition.
      *
      * @param composition the information of the Automation Composition Definition
      */
     public void deprime(CompositionDto composition) {
-        if (!execution(getConfig().getDeprimeTimerMs(),
-                "Current Thread deprime is Interrupted during execution {}", composition.compositionId())) {
+        if (isInterrupted(getConfig().getDeprimeTimerMs(),
+            "Current Thread deprime is Interrupted during execution {}", composition.compositionId())) {
             return;
         }
 
         if (getConfig().isDeprimeSuccess()) {
             sendOutProperties(composition, AcTypeState.COMMISSIONED.name());
             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
-                    StateChangeResult.NO_ERROR, "Deprimed");
+                StateChangeResult.NO_ERROR, "Deprimed");
         } else {
             sendOutProperties(composition, AcTypeState.PRIMED.name());
             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
-                    StateChangeResult.FAILED, "Deprime failed!");
+                StateChangeResult.FAILED, "Deprime failed!");
         }
     }
 
     /**
-     * Handle a migrate on a automation composition element.
+     * Handle a migration on an automation composition element.
      *
-     * @param instanceId the instanceId
-     * @param elementId the elementId
-     * @param stage the stage
+     * @param instanceId              the instanceId
+     * @param elementId               the elementId
+     * @param stage                   the stage
      * @param compositionInProperties in Properties from composition definition element
-     * @param instanceOutProperties in Properties from instance element
+     * @param instanceOutProperties   in Properties from instance element
      */
     public void migrate(UUID instanceId, UUID elementId, int stage, Map<String, Object> compositionInProperties,
-            Map<String, Object> instanceOutProperties) {
-        if (!execution(getConfig().getMigrateTimerMs(),
-                "Current Thread migrate is Interrupted during execution {}", elementId)) {
+                        Map<String, Object> instanceOutProperties) {
+        if (isInterrupted(getConfig().getMigrateTimerMs(),
+            "Current Thread migrate is Interrupted during execution {}", elementId)) {
             return;
         }
 
@@ -385,54 +380,54 @@ public class SimulatorService {
             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, instanceOutProperties);
             if (nextStage == 1000) {
                 intermediaryApi.updateAutomationCompositionElementState(
-                        instanceId, elementId,
-                        DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
+                    instanceId, elementId,
+                    DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
             } else {
                 intermediaryApi.updateAutomationCompositionElementStage(
-                        instanceId, elementId,
-                        StateChangeResult.NO_ERROR, nextStage, "stage " + stage + " Migrated");
+                    instanceId, elementId,
+                    StateChangeResult.NO_ERROR, nextStage, "stage " + stage + " Migrated");
             }
         } else {
             intermediaryApi.updateAutomationCompositionElementState(
-                    instanceId, elementId,
-                    DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migrate failed!");
+                instanceId, elementId,
+                DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migrate failed!");
         }
     }
 
     /**
-     * Handle a Migrate Precheck on a automation composition element.
+     * Handle a Migrate Precheck on an automation composition element.
      *
      * @param instanceId the instanceId
-     * @param elementId the elementId
+     * @param elementId  the elementId
      */
     public void migratePrecheck(UUID instanceId, UUID elementId) {
-        if (!execution(config.getMigratePrecheckTimerMs(),
-                "Current Thread migrate precheck is Interrupted during execution {}", elementId)) {
+        if (isInterrupted(config.getMigratePrecheckTimerMs(),
+            "Current Thread migrate precheck is Interrupted during execution {}", elementId)) {
             return;
         }
 
         if (config.isMigratePrecheck()) {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migration precheck completed");
+                DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migration precheck completed");
         } else {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migration precheck failed");
+                DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migration precheck failed");
         }
     }
 
     /**
-     * Handle a Prepare on a automation composition element.
+     * Handle a Prepare on an automation composition element.
      *
-     * @param instanceId the instanceId
-     * @param elementId the elementId
-     * @param stage the stage
+     * @param instanceId              the instanceId
+     * @param elementId               the elementId
+     * @param stage                   the stage
      * @param compositionInProperties in Properties from composition definition element
-     * @param instanceOutProperties in Properties from instance element
+     * @param instanceOutProperties   in Properties from instance element
      */
     public void prepare(UUID instanceId, UUID elementId, int stage, Map<String, Object> compositionInProperties,
-            Map<String, Object> instanceOutProperties) {
-        if (!execution(config.getPrepareTimerMs(),
-                "Current Thread prepare is Interrupted during execution {}", elementId)) {
+                        Map<String, Object> instanceOutProperties) {
+        if (isInterrupted(config.getPrepareTimerMs(),
+            "Current Thread prepare is Interrupted during execution {}", elementId)) {
             return;
         }
 
@@ -451,36 +446,58 @@ public class SimulatorService {
             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, instanceOutProperties);
             if (nextStage == 1000) {
                 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                        DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Prepare completed");
+                    DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Prepare completed");
             } else {
                 intermediaryApi.updateAutomationCompositionElementStage(
-                        instanceId, elementId,
-                        StateChangeResult.NO_ERROR, nextStage, "stage " + stage + " Prepared");
+                    instanceId, elementId,
+                    StateChangeResult.NO_ERROR, nextStage, "stage " + stage + " Prepared");
             }
         } else {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Prepare failed");
+                DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Prepare failed");
         }
     }
 
     /**
-     * Handle a Review on a automation composition element.
+     * Handle a Review on an automation composition element.
      *
      * @param instanceId the instanceId
-     * @param elementId the elementId
+     * @param elementId  the elementId
      */
     public void review(UUID instanceId, UUID elementId) {
-        if (!execution(config.getReviewTimerMs(),
-                "Current Thread review is Interrupted during execution {}", elementId)) {
+        if (isInterrupted(config.getReviewTimerMs(),
+            "Current Thread review is Interrupted during execution {}", elementId)) {
             return;
         }
 
         if (config.isReview()) {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Review completed");
+                DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Review completed");
         } else {
             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
-                    DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Review failed");
+                DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Review failed");
+        }
+    }
+
+    /**
+     * Handle rollback of an automation composition.
+     *
+     * @param instanceId AC instance ID
+     * @param elementId  AC element ID
+     */
+    public void rollback(UUID instanceId, UUID elementId) {
+        if (isInterrupted(getConfig().getRollbackTimerMs(),
+            "Current Thread for rollback was Interrupted during execution {}", instanceId)) {
+            LOGGER.debug("Rollback interrupted");
+            return;
+        }
+
+        if (config.isRollback()) {
+            intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, DeployState.DEPLOYED, null,
+                StateChangeResult.NO_ERROR, "Migration rollback done");
+        } else {
+            intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, DeployState.DEPLOYED, null,
+                StateChangeResult.FAILED, "Migration rollback failed");
         }
     }
 }
index f38f307..546ee4d 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2023-2024 Nordix Foundation.
+ *  Copyright (C) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -48,6 +48,8 @@ public class SimConfig {
 
     private boolean deprimeSuccess = true;
 
+    private boolean rollback = true;
+
     private int deployTimerMs = 1000;
 
     private int undeployTimerMs = 1000;
@@ -71,4 +73,6 @@ public class SimConfig {
     private int primeTimerMs = 100;
 
     private int deprimeTimerMs = 100;
+
+    private int rollbackTimerMs = 100;
 }
index 57c13ce..baf1b2a 100644 (file)
 
 package org.onap.policy.clamp.acm.participant.sim.main.handler;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
 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 static org.mockito.Mockito.withSettings;
 
 import java.util.HashMap;
 import java.util.List;
@@ -44,11 +51,11 @@ class AutomationCompositionElementHandlerTest {
 
     private static final ToscaConceptIdentifier ELEMENT_DEFINITION_ID = new ToscaConceptIdentifier("name", "1.0.0");
     private static final CompositionElementDto COMPOSITION_ELEMENT =
-            new CompositionElementDto(UUID.randomUUID(), ELEMENT_DEFINITION_ID, Map.of(), Map.of());
+        new CompositionElementDto(UUID.randomUUID(), ELEMENT_DEFINITION_ID, Map.of(), Map.of());
     private static final InstanceElementDto INSTANCE_ELEMENT =
-            new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), Map.of(), new HashMap<>());
+        new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), Map.of(), new HashMap<>());
     private static final CompositionDto COMPOSITION = new CompositionDto(UUID.randomUUID(),
-            Map.of(ELEMENT_DEFINITION_ID, Map.of()), Map.of(ELEMENT_DEFINITION_ID, new HashMap<>()));
+        Map.of(ELEMENT_DEFINITION_ID, Map.of()), Map.of(ELEMENT_DEFINITION_ID, new HashMap<>()));
 
     @Test
     void testDeploy() {
@@ -59,14 +66,14 @@ class AutomationCompositionElementHandlerTest {
         simulatorService.setConfig(config);
         acElementHandler.deploy(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
-                null, StateChangeResult.NO_ERROR, "Deployed");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
+            null, StateChangeResult.NO_ERROR, "Deployed");
 
         config.setDeploySuccess(false);
         acElementHandler.deploy(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.UNDEPLOYED,
-                null, StateChangeResult.FAILED, "Deploy failed!");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.UNDEPLOYED,
+            null, StateChangeResult.FAILED, "Deploy failed!");
     }
 
     @Test
@@ -78,14 +85,14 @@ class AutomationCompositionElementHandlerTest {
         simulatorService.setConfig(config);
         acElementHandler.undeploy(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.UNDEPLOYED,
-                null, StateChangeResult.NO_ERROR, "Undeployed");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.UNDEPLOYED,
+            null, StateChangeResult.NO_ERROR, "Undeployed");
 
         config.setUndeploySuccess(false);
         acElementHandler.undeploy(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
-                null, StateChangeResult.FAILED, "Undeploy failed!");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
+            null, StateChangeResult.FAILED, "Undeploy failed!");
     }
 
     @Test
@@ -97,14 +104,14 @@ class AutomationCompositionElementHandlerTest {
         simulatorService.setConfig(config);
         acElementHandler.lock(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), null, LockState.LOCKED,
-                StateChangeResult.NO_ERROR, "Locked");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), null, LockState.LOCKED,
+            StateChangeResult.NO_ERROR, "Locked");
 
         config.setLockSuccess(false);
         acElementHandler.lock(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), null, LockState.UNLOCKED,
-                StateChangeResult.FAILED, "Lock failed!");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), null, LockState.UNLOCKED,
+            StateChangeResult.FAILED, "Lock failed!");
     }
 
     @Test
@@ -116,14 +123,14 @@ class AutomationCompositionElementHandlerTest {
         simulatorService.setConfig(config);
         acElementHandler.unlock(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), null, LockState.UNLOCKED,
-                StateChangeResult.NO_ERROR, "Unlocked");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), null, LockState.UNLOCKED,
+            StateChangeResult.NO_ERROR, "Unlocked");
 
         config.setUnlockSuccess(false);
         acElementHandler.unlock(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), null, LockState.LOCKED,
-                StateChangeResult.FAILED, "Unlock failed!");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), null, LockState.LOCKED,
+            StateChangeResult.FAILED, "Unlock failed!");
     }
 
     @Test
@@ -134,18 +141,18 @@ class AutomationCompositionElementHandlerTest {
         var acElementHandler = new AutomationCompositionElementHandler(intermediaryApi, simulatorService);
         simulatorService.setConfig(config);
         var instanceElementUpdated = new InstanceElementDto(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                Map.of("key", "value"), Map.of());
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            Map.of("key", "value"), Map.of());
         acElementHandler.update(COMPOSITION_ELEMENT, INSTANCE_ELEMENT, instanceElementUpdated);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Updated");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Updated");
 
         config.setUpdateSuccess(false);
         acElementHandler.update(COMPOSITION_ELEMENT, INSTANCE_ELEMENT, instanceElementUpdated);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Update failed!");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Update failed!");
     }
 
     @Test
@@ -157,14 +164,14 @@ class AutomationCompositionElementHandlerTest {
         simulatorService.setConfig(config);
         acElementHandler.delete(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DELETED,
-                null, StateChangeResult.NO_ERROR, "Deleted");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DELETED,
+            null, StateChangeResult.NO_ERROR, "Deleted");
 
         config.setDeleteSuccess(false);
         acElementHandler.delete(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.UNDEPLOYED,
-                null, StateChangeResult.FAILED, "Delete failed!");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.UNDEPLOYED,
+            null, StateChangeResult.FAILED, "Delete failed!");
     }
 
     @Test
@@ -176,12 +183,12 @@ class AutomationCompositionElementHandlerTest {
         simulatorService.setConfig(config);
         acElementHandler.prime(COMPOSITION);
         verify(intermediaryApi).updateCompositionState(
-                COMPOSITION.compositionId(), AcTypeState.PRIMED, StateChangeResult.NO_ERROR, "Primed");
+            COMPOSITION.compositionId(), AcTypeState.PRIMED, StateChangeResult.NO_ERROR, "Primed");
 
         config.setPrimeSuccess(false);
         acElementHandler.prime(COMPOSITION);
         verify(intermediaryApi).updateCompositionState(
-                COMPOSITION.compositionId(), AcTypeState.COMMISSIONED, StateChangeResult.FAILED, "Prime failed!");
+            COMPOSITION.compositionId(), AcTypeState.COMMISSIONED, StateChangeResult.FAILED, "Prime failed!");
     }
 
     @Test
@@ -193,12 +200,12 @@ class AutomationCompositionElementHandlerTest {
         simulatorService.setConfig(config);
         acElementHandler.deprime(COMPOSITION);
         verify(intermediaryApi).updateCompositionState(
-                COMPOSITION.compositionId(), AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR, "Deprimed");
+            COMPOSITION.compositionId(), AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR, "Deprimed");
 
         config.setDeprimeSuccess(false);
         acElementHandler.deprime(COMPOSITION);
         verify(intermediaryApi).updateCompositionState(
-                COMPOSITION.compositionId(), AcTypeState.PRIMED, StateChangeResult.FAILED, "Deprime failed!");
+            COMPOSITION.compositionId(), AcTypeState.PRIMED, StateChangeResult.FAILED, "Deprime failed!");
     }
 
     @Test
@@ -209,22 +216,22 @@ class AutomationCompositionElementHandlerTest {
         var acElementHandler = new AutomationCompositionElementHandler(intermediaryApi, simulatorService);
         simulatorService.setConfig(config);
         var compositionElementTarget = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
-                Map.of(), Map.of());
+            Map.of(), Map.of());
         var instanceElementMigrated = new InstanceElementDto(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                Map.of("key", "value"), new HashMap<>());
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            Map.of("key", "value"), new HashMap<>());
         acElementHandler
-                .migrate(COMPOSITION_ELEMENT, compositionElementTarget, INSTANCE_ELEMENT, instanceElementMigrated, 0);
+            .migrate(COMPOSITION_ELEMENT, compositionElementTarget, INSTANCE_ELEMENT, instanceElementMigrated, 0);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
 
         config.setMigrateSuccess(false);
         acElementHandler
-                .migrate(COMPOSITION_ELEMENT, compositionElementTarget, INSTANCE_ELEMENT, instanceElementMigrated, 0);
+            .migrate(COMPOSITION_ELEMENT, compositionElementTarget, INSTANCE_ELEMENT, instanceElementMigrated, 0);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migrate failed!");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migrate failed!");
     }
 
     @Test
@@ -235,14 +242,14 @@ class AutomationCompositionElementHandlerTest {
         var acElementHandler = new AutomationCompositionElementHandler(intermediaryApi, simulatorService);
         simulatorService.setConfig(config);
         var compositionElementTarget = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
-                Map.of("stage", List.of(1, 2)), Map.of());
+            Map.of("stage", List.of(1, 2)), Map.of());
         var instanceElementMigrated = new InstanceElementDto(INSTANCE_ELEMENT.instanceId(),
-                INSTANCE_ELEMENT.elementId(), Map.of(), new HashMap<>());
+            INSTANCE_ELEMENT.elementId(), Map.of(), new HashMap<>());
         acElementHandler
-                .migrate(COMPOSITION_ELEMENT, compositionElementTarget, INSTANCE_ELEMENT, instanceElementMigrated, 1);
+            .migrate(COMPOSITION_ELEMENT, compositionElementTarget, INSTANCE_ELEMENT, instanceElementMigrated, 1);
         verify(intermediaryApi).updateAutomationCompositionElementStage(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                StateChangeResult.NO_ERROR, 2, "stage 1 Migrated");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            StateChangeResult.NO_ERROR, 2, "stage 1 Migrated");
     }
 
     @Test
@@ -253,20 +260,20 @@ class AutomationCompositionElementHandlerTest {
         var acElementHandler = new AutomationCompositionElementHandler(intermediaryApi, simulatorService);
         simulatorService.setConfig(config);
         var compositionElement = new CompositionElementDto(
-                UUID.randomUUID(), new ToscaConceptIdentifier(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
+            UUID.randomUUID(), new ToscaConceptIdentifier(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
 
         var instanceElement = new InstanceElementDto(
-                UUID.randomUUID(), UUID.randomUUID(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
+            UUID.randomUUID(), UUID.randomUUID(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
 
         var compoElTargetAdd = new CompositionElementDto(
-                UUID.randomUUID(), new ToscaConceptIdentifier(), Map.of(), Map.of(), ElementState.NEW);
+            UUID.randomUUID(), new ToscaConceptIdentifier(), Map.of(), Map.of(), ElementState.NEW);
         var inElMigratedAdd = new InstanceElementDto(instanceElement.instanceId(), instanceElement.elementId(),
-                Map.of(), new HashMap<>(), ElementState.NEW);
+            Map.of(), new HashMap<>(), ElementState.NEW);
         acElementHandler
-                .migrate(compositionElement, compoElTargetAdd, instanceElement, inElMigratedAdd, 0);
+            .migrate(compositionElement, compoElTargetAdd, instanceElement, inElMigratedAdd, 0);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                instanceElement.instanceId(), instanceElement.elementId(),
-                DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
+            instanceElement.instanceId(), instanceElement.elementId(),
+            DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
     }
 
     @Test
@@ -278,18 +285,18 @@ class AutomationCompositionElementHandlerTest {
         simulatorService.setConfig(config);
 
         var compoElTargetRemove = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
-                Map.of(), Map.of(), ElementState.REMOVED);
+            Map.of(), Map.of(), ElementState.REMOVED);
         var inElMigratedRemove = new InstanceElementDto(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                Map.of("key", "value"), Map.of(), ElementState.REMOVED);
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            Map.of("key", "value"), Map.of(), ElementState.REMOVED);
         acElementHandler
-                .migrate(COMPOSITION_ELEMENT, compoElTargetRemove, INSTANCE_ELEMENT, inElMigratedRemove, 0);
+            .migrate(COMPOSITION_ELEMENT, compoElTargetRemove, INSTANCE_ELEMENT, inElMigratedRemove, 0);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Undeployed");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Undeployed");
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
     }
 
     @Test
@@ -300,24 +307,24 @@ class AutomationCompositionElementHandlerTest {
         var acElementHandler = new AutomationCompositionElementHandler(intermediaryApi, simulatorService);
         simulatorService.setConfig(config);
         var compositionElementTarget = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
-                Map.of(), Map.of());
+            Map.of(), Map.of());
         var instanceElementMigrated = new InstanceElementDto(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                Map.of("key", "value"), Map.of());
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            Map.of("key", "value"), Map.of());
         acElementHandler.migratePrecheck(COMPOSITION_ELEMENT, compositionElementTarget,
-                INSTANCE_ELEMENT, instanceElementMigrated);
+            INSTANCE_ELEMENT, instanceElementMigrated);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                DeployState.DEPLOYED, null,
-                StateChangeResult.NO_ERROR, "Migration precheck completed");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            DeployState.DEPLOYED, null,
+            StateChangeResult.NO_ERROR, "Migration precheck completed");
 
         config.setMigratePrecheck(false);
         acElementHandler.migratePrecheck(COMPOSITION_ELEMENT, compositionElementTarget,
-                INSTANCE_ELEMENT, instanceElementMigrated);
+            INSTANCE_ELEMENT, instanceElementMigrated);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
-                DeployState.DEPLOYED, null,
-                StateChangeResult.FAILED, "Migration precheck failed");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(),
+            DeployState.DEPLOYED, null,
+            StateChangeResult.FAILED, "Migration precheck failed");
     }
 
     @Test
@@ -329,14 +336,14 @@ class AutomationCompositionElementHandlerTest {
         simulatorService.setConfig(config);
         acElementHandler.prepare(COMPOSITION_ELEMENT, INSTANCE_ELEMENT, 0);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.UNDEPLOYED,
-                null, StateChangeResult.NO_ERROR, "Prepare completed");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.UNDEPLOYED,
+            null, StateChangeResult.NO_ERROR, "Prepare completed");
 
         config.setPrepare(false);
         acElementHandler.prepare(COMPOSITION_ELEMENT, INSTANCE_ELEMENT, 0);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.UNDEPLOYED,
-                null, StateChangeResult.FAILED, "Prepare failed");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.UNDEPLOYED,
+            null, StateChangeResult.FAILED, "Prepare failed");
     }
 
     @Test
@@ -348,13 +355,52 @@ class AutomationCompositionElementHandlerTest {
         simulatorService.setConfig(config);
         acElementHandler.review(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
-                null, StateChangeResult.NO_ERROR, "Review completed");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
+            null, StateChangeResult.NO_ERROR, "Review completed");
 
         config.setReview(false);
         acElementHandler.review(COMPOSITION_ELEMENT, INSTANCE_ELEMENT);
         verify(intermediaryApi).updateAutomationCompositionElementState(
-                INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
-                null, StateChangeResult.FAILED, "Review failed");
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
+            null, StateChangeResult.FAILED, "Review failed");
+    }
+
+    @Test
+    void testRollback() {
+        var config = CommonTestData.createSimConfig();
+        var intermediaryApi = mock(ParticipantIntermediaryApi.class);
+        var simulatorService = new SimulatorService(intermediaryApi);
+        var acElementHandler = new AutomationCompositionElementHandler(intermediaryApi, simulatorService);
+        simulatorService.setConfig(config);
+
+        acElementHandler.rollbackMigration(COMPOSITION_ELEMENT, INSTANCE_ELEMENT, DeployState.DEPLOYED.ordinal());
+        verify(intermediaryApi).updateAutomationCompositionElementState(
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
+            null, StateChangeResult.NO_ERROR, "Migration rollback done");
+
+        config.setRollback(false);
+        acElementHandler.rollbackMigration(COMPOSITION_ELEMENT, INSTANCE_ELEMENT, DeployState.DEPLOYED.ordinal());
+        verify(intermediaryApi).updateAutomationCompositionElementState(
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
+            null, StateChangeResult.FAILED, "Migration rollback failed");
+    }
+
+    @Test
+    void testRollbackTimeout() {
+        var config = CommonTestData.createSimConfig();
+        var intermediaryApi = mock(ParticipantIntermediaryApi.class);
+        var simulatorService = mock(SimulatorService.class, withSettings().useConstructor(intermediaryApi));
+
+        when(simulatorService.getConfig()).thenReturn(config);
+        when(simulatorService.isInterrupted(anyInt(), anyString(), any())).thenReturn(true);
+        doCallRealMethod().when(simulatorService).rollback(INSTANCE_ELEMENT.instanceId(),
+            INSTANCE_ELEMENT.elementId());
+
+        var acElementHandler = new AutomationCompositionElementHandler(intermediaryApi, simulatorService);
+        acElementHandler.rollbackMigration(COMPOSITION_ELEMENT, INSTANCE_ELEMENT, DeployState.DEPLOYED.ordinal());
+        verify(simulatorService).rollback(INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId());
+        verify(intermediaryApi, times(0)).updateAutomationCompositionElementState(
+            INSTANCE_ELEMENT.instanceId(), INSTANCE_ELEMENT.elementId(), DeployState.DEPLOYED,
+            null, StateChangeResult.NO_ERROR, "Migration rollback done");
     }
 }
index 3087183..ca92ad1 100644 (file)
@@ -22,6 +22,7 @@ package org.onap.policy.clamp.acm.participant.sim.main.handler;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -32,6 +33,7 @@ import java.util.HashMap;
 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.ParticipantIntermediaryApi;
 import org.onap.policy.clamp.acm.participant.sim.comm.CommonTestData;
 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
@@ -132,8 +134,8 @@ class SimulatorServiceTest {
         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
         var simulatorService = new SimulatorService(intermediaryApi) {
             @Override
-            protected boolean execution(int timeMs, String msg, UUID elementId) {
-                return false;
+            protected boolean isInterrupted(int timeMs, String msg, UUID elementId) {
+                return true;
             }
         };
 
@@ -143,9 +145,27 @@ class SimulatorServiceTest {
         simulatorService.unlock(UUID.randomUUID(), UUID.randomUUID());
         simulatorService.delete(UUID.randomUUID(), UUID.randomUUID());
         simulatorService.update(UUID.randomUUID(), UUID.randomUUID());
+        simulatorService.prime(mock(CompositionDto.class));
+        simulatorService.deprime(mock(CompositionDto.class));
+        simulatorService.migrate(UUID.randomUUID(), UUID.randomUUID(), 0, new HashMap<>(), new HashMap<>());
         simulatorService.review(UUID.randomUUID(), UUID.randomUUID());
         simulatorService.prepare(UUID.randomUUID(), UUID.randomUUID(), 0, new HashMap<>(), new HashMap<>());
         simulatorService.migratePrecheck(UUID.randomUUID(), UUID.randomUUID());
         verify(intermediaryApi, times(0)).sendAcDefinitionInfo(any(), any(), any());
     }
+
+    @Test
+    void testImmediateInterruption() throws InterruptedException {
+        var intermediaryApi = mock(ParticipantIntermediaryApi.class);
+        var simulatorService = new SimulatorService(intermediaryApi);
+
+        Thread testThread = new Thread(() -> {
+            boolean result = simulatorService.isInterrupted(5000, "test", UUID.randomUUID());
+            assertTrue(result, "Thread was supposed to be interrupted");
+        });
+
+        testThread.start();
+        testThread.interrupt();
+        testThread.join();
+    }
 }
index c4edf6e..63db854 100644 (file)
@@ -27,85 +27,98 @@ import org.onap.policy.models.base.PfModelException;
  */
 public interface AutomationCompositionElementListener {
     /**
-     * Handle a deploy on a automation composition element.
+     * Handle a deployment on an automation composition element.
      *
      * @param compositionElement the information of the Automation Composition Definition Element
-     * @param instanceElement the information of the Automation Composition Instance Element
+     * @param instanceElement    the information of the Automation Composition Instance Element
      * @throws PfModelException from Policy framework
      */
     void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException;
 
     /**
-     * Handle an udeploy on a automation composition element.
+     * Handle an udeploy on an automation composition element.
      *
      * @param compositionElement the information of the Automation Composition Definition Element
-     * @param instanceElement the information of the Automation Composition Instance Element
+     * @param instanceElement    the information of the Automation Composition Instance Element
      * @throws PfModelException in case of a model exception
      */
     void undeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException;
 
     /**
-     * Handle a lock on a automation composition element.
+     * Handle a lock on an automation composition element.
      *
      * @param compositionElement the information of the Automation Composition Definition Element
-     * @param instanceElement the information of the Automation Composition Instance Element
+     * @param instanceElement    the information of the Automation Composition Instance Element
      * @throws PfModelException in case of a model exception
      */
     void lock(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException;
 
     /**
-     * Handle an unlock on a automation composition element.
+     * Handle an unlock on an automation composition element.
      *
      * @param compositionElement the information of the Automation Composition Definition Element
-     * @param instanceElement the information of the Automation Composition Instance Element
+     * @param instanceElement    the information of the Automation Composition Instance Element
      * @throws PfModelException in case of a model exception
      */
     void unlock(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException;
 
     /**
-     * Handle a delete on a automation composition element.
+     * Handle delete on an automation composition element.
      *
      * @param compositionElement the information of the Automation Composition Definition Element
-     * @param instanceElement the information of the Automation Composition Instance Element
+     * @param instanceElement    the information of the Automation Composition Instance Element
      * @throws PfModelException in case of a model exception
      */
     void delete(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException;
 
     /**
-     * Handle an update on a automation composition element.
+     * Handle an update on an automation composition element.
      *
-     * @param compositionElement the information of the Automation Composition Definition Element
-     * @param instanceElement the information of the Automation Composition Instance Element
+     * @param compositionElement     the information of the Automation Composition Definition Element
+     * @param instanceElement        the information of the Automation Composition Instance Element
      * @param instanceElementUpdated the information of the Automation Composition Instance Element updated
      * @throws PfModelException from Policy framework
      */
     void update(CompositionElementDto compositionElement, InstanceElementDto instanceElement,
-            InstanceElementDto instanceElementUpdated) throws PfModelException;
+                InstanceElementDto instanceElementUpdated) throws PfModelException;
 
     void prime(CompositionDto composition) throws PfModelException;
 
     void deprime(CompositionDto composition) throws PfModelException;
 
     /**
-     * Handle an update on a automation composition element.
+     * Handle an update on an automation composition 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 nextStage                    the next stage
+     * @param nextStage                the next stage
      * @throws PfModelException from Policy framework
      */
     void migrate(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget,
-            InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate,
-            int nextStage) throws PfModelException;
+                 InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate,
+                 int nextStage) throws PfModelException;
 
     void migratePrecheck(CompositionElementDto compositionElement, CompositionElementDto compositionElementTarget,
-            InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate) throws PfModelException;
+                         InstanceElementDto instanceElement, InstanceElementDto instanceElementMigrate)
+        throws PfModelException;
 
     void review(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
         throws PfModelException;
 
     void prepare(CompositionElementDto compositionElement, InstanceElementDto instanceElement, int nextStage)
         throws PfModelException;
+
+    /**
+     * Rollback migration changes done to a composition.
+     *
+     * @param compositionElement the composition to roll back the changes
+     * @param instanceElement    instance to roll back the changes
+     * @param nextStage         in which stage should the instance be after the rollback
+     * @throws PfModelException if anything goes wrong
+     */
+    void rollbackMigration(CompositionElementDto compositionElement,
+                           InstanceElementDto instanceElement, int nextStage)
+        throws PfModelException;
 }
index c06ffe6..e74b460 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2021-2024 Nordix Foundation.
+ *  Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -38,7 +38,7 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
 public interface ParticipantIntermediaryApi {
 
     /**
-     * Update the state of a AutomationComposition Instance Element.
+     * Update the state of an AutomationComposition Instance 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
@@ -51,7 +51,7 @@ public interface ParticipantIntermediaryApi {
             LockState lockState, StateChangeResult stateChangeResult, String message);
 
     /**
-     * Update the stage of a AutomationComposition Instance Element.
+     * Update the stage of an AutomationComposition Instance 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
@@ -69,7 +69,7 @@ public interface ParticipantIntermediaryApi {
     Map<UUID, AutomationComposition> getAutomationCompositions();
 
     /**
-     * Get a copy of the AutomationComposition Instance by AutomationComposition Instance Id.
+     * Get a copy of the AutomationComposition Instance by AutomationComposition instanceId.
      *
      * @param instanceId the ID of the AutomationComposition Instance to update the state on
      * @return get the AutomationComposition Instance
@@ -77,7 +77,7 @@ public interface ParticipantIntermediaryApi {
     AutomationComposition getAutomationComposition(UUID instanceId);
 
     /**
-     * Get a copy of the AutomationCompositionElement by AutomationComposition Instance Id and elementId.
+     * Get a copy of the AutomationCompositionElement by AutomationComposition instanceId and elementId.
      *
      * @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
@@ -96,15 +96,15 @@ public interface ParticipantIntermediaryApi {
      * Get a copy of AutomationCompositionElementDefinitions of a composition.
      *
      * @param compositionId the composition id
-     * @return a Map by element definition Id of AutomationCompositionElementDefinitions
+     * @return a Map by element definition id of AutomationCompositionElementDefinitions
      */
     Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> getAcElementsDefinitions(UUID compositionId);
 
     /**
-     * Get a copy of the AutomationCompositionElementDefinition by compositionId and element definition Id.
+     * Get a copy of the AutomationCompositionElementDefinition by compositionId and element definition id.
      *
      * @param compositionId the composition id
-     * @param elementId the element definition Id
+     * @param elementId the element definition id
      * @return the AutomationCompositionElementDefinition
      */
     AutomationCompositionElementDefinition getAcElementDefinition(UUID compositionId, ToscaConceptIdentifier elementId);
@@ -125,13 +125,13 @@ public interface ParticipantIntermediaryApi {
      * Send Automation Composition Definition update Info to AC-runtime.
      *
      * @param compositionId the composition id
-     * @param elementId the element definition Id
+     * @param elementId the element definition id
      * @param outProperties the output Properties Map
      */
     void sendAcDefinitionInfo(UUID compositionId, ToscaConceptIdentifier elementId, Map<String, Object> outProperties);
 
     /**
-     * Update the state of a Automation Composition Definition.
+     * Update the state of an Automation Composition Definition.
      *
      * @param compositionId the composition id
      * @param state the state of Automation Composition Definition
index 002b67d..a167085 100644 (file)
@@ -94,26 +94,34 @@ public abstract class AcElementListenerV4 implements AutomationCompositionElemen
 
     @Override
     public void migratePrecheck(CompositionElementDto compositionElement,
-            CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
-            InstanceElementDto instanceElementMigrate) throws PfModelException {
+                                CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
+                                InstanceElementDto instanceElementMigrate) throws PfModelException {
         intermediaryApi.updateAutomationCompositionElementState(instanceElementMigrate.instanceId(),
-                instanceElementMigrate.elementId(), DeployState.DEPLOYED, null,
-                StateChangeResult.NO_ERROR, "Migration Precheck completed");
+            instanceElementMigrate.elementId(), DeployState.DEPLOYED, null,
+            StateChangeResult.NO_ERROR, "Migration Precheck completed");
     }
 
     @Override
     public void review(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
-            throws PfModelException {
+        throws PfModelException {
         intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
-                instanceElement.elementId(), DeployState.DEPLOYED, null,
-                StateChangeResult.NO_ERROR, "Review completed");
+            instanceElement.elementId(), DeployState.DEPLOYED, null,
+            StateChangeResult.NO_ERROR, "Review completed");
     }
 
     @Override
     public void prepare(CompositionElementDto compositionElement, InstanceElementDto instanceElement, int nextStage)
-            throws PfModelException {
+        throws PfModelException {
+        intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
+            instanceElement.elementId(), DeployState.UNDEPLOYED, null,
+            StateChangeResult.NO_ERROR, "Prepare completed");
+    }
+
+    @Override
+    public void rollbackMigration(CompositionElementDto compositionElement,
+                                  InstanceElementDto instanceElement, int nextStage) {
         intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
-                instanceElement.elementId(), DeployState.UNDEPLOYED, null,
-                StateChangeResult.NO_ERROR, "Prepare completed");
+            instanceElement.elementId(), DeployState.DEPLOYED, null,
+            StateChangeResult.NO_ERROR, "Migration rollback done");
     }
 }
index 8dbefe2..a2b6521 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2024 Nordix Foundation.
+ *  Copyright (C) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
   * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -164,6 +164,19 @@ class AcElementListenerV3Test {
                 StateChangeResult.NO_ERROR, "Prepare completed");
     }
 
+    @Test
+    void testRollbackMigration() {
+        var intermediaryApi = mock(ParticipantIntermediaryApi.class);
+        var acElementListenerV3 = createAcElementListenerV3(intermediaryApi);
+        var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
+            Map.of(), Map.of());
+        var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(), Map.of(), Map.of());
+        acElementListenerV3.rollbackMigration(compositionElement, instanceElement, 1);
+        verify(intermediaryApi).updateAutomationCompositionElementState(instanceElement.instanceId(),
+            instanceElement.elementId(), DeployState.DEPLOYED, null,
+            StateChangeResult.NO_ERROR, "Migration rollback done");
+    }
+
     private AcElementListenerV3 createAcElementListenerV3(ParticipantIntermediaryApi intermediaryApi) {
         return new AcElementListenerV3(intermediaryApi) {
             @Override