Add support for Prepare, Review and Migrate pre-check in ACM runtime 52/138552/1
authorFrancescoFioraEst <francesco.fiora@est.tech>
Tue, 23 Jul 2024 09:22:27 +0000 (10:22 +0100)
committerFrancesco Fiora <francesco.fiora@est.tech>
Tue, 23 Jul 2024 09:27:30 +0000 (09:27 +0000)
Issue-ID: POLICY-5079
Change-Id: I6e54d2bce31f906efcc4d5bf3b930d34e7913fd2
Signed-off-by: FrancescoFioraEst <francesco.fiora@est.tech>
12 files changed:
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolver.java
models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java
models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolverTest.java
models/src/test/java/org/onap/policy/clamp/models/acm/utils/AcmUtilsTest.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcPreparePublisher.java [new file with mode: 0644]
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionMigrationPublisher.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProviderTest.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/comm/SupervisionMessagesTest.java

index ace246c..fd8b635 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2023 Nordix Foundation.
+ *  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.
@@ -23,8 +23,10 @@ package org.onap.policy.clamp.models.acm.persistence.provider;
 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.rest.instantiation.DeployOrder;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.SubOrder;
 import org.onap.policy.clamp.models.acm.utils.StateDefinition;
 import org.springframework.stereotype.Component;
 
@@ -39,6 +41,10 @@ public class AcInstanceStateResolver {
     private static final String UPDATING = DeployState.UPDATING.name();
     private static final String DELETING = DeployState.DELETING.name();
     private static final String MIGRATING = DeployState.MIGRATING.name();
+    private static final String MIGRATION_PRECHECKING = SubState.MIGRATION_PRECHECKING.name();
+    private static final String PREPARING = SubState.PREPARING.name();
+    private static final String REVIEWING = SubState.REVIEWING.name();
+    private static final String SUB_STATE_NONE = SubState.NONE.name();
 
     private static final String LOCKED = LockState.LOCKED.name();
     private static final String LOCKING = LockState.LOCKING.name();
@@ -48,6 +54,7 @@ public class AcInstanceStateResolver {
 
     private static final String DEPLOY_NONE = DeployOrder.NONE.name();
     private static final String LOCK_NONE = LockOrder.NONE.name();
+    private static final String SUB_NONE = SubOrder.NONE.name();
 
     private static final String NO_ERROR = StateChangeResult.NO_ERROR.name();
     private static final String FAILED = StateChangeResult.FAILED.name();
@@ -60,55 +67,105 @@ public class AcInstanceStateResolver {
     public static final String LOCK = LockOrder.LOCK.name();
     public static final String UNLOCK = LockOrder.UNLOCK.name();
     public static final String MIGRATE = DeployOrder.MIGRATE.name();
+    public static final String MIGRATE_PRECHECK = SubOrder.MIGRATE_PRECHECK.name();
+    public static final String PREPARE = SubOrder.PREPARE.name();
+    public static final String REVIEW = SubOrder.REVIEW.name();
+    public static final String UPDATE = DeployOrder.UPDATE.name();
     public static final String NONE = "NONE";
 
     /**
      * Construct.
      */
     public AcInstanceStateResolver() {
-        this.graph = new StateDefinition<>(5, NONE);
-
-        // no error
-        this.graph.put(new String[] {DEPLOY, LOCK_NONE, UNDEPLOYED, STATE_LOCKED_NONE, NO_ERROR}, DEPLOY);
-        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, DEPLOYED, LOCKED, NO_ERROR}, UNDEPLOY);
-        this.graph.put(new String[] {DELETE, LOCK_NONE, UNDEPLOYED, LOCK_NONE, NO_ERROR}, DELETE);
-        this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, DEPLOYED, LOCKED, NO_ERROR}, UNLOCK);
-        this.graph.put(new String[] {DEPLOY_NONE, LOCK, DEPLOYED, UNLOCKED, NO_ERROR}, LOCK);
-        this.graph.put(new String[] {MIGRATE, LOCK_NONE, DEPLOYED, LOCKED, NO_ERROR}, MIGRATE);
-
-        // failed
-        this.graph.put(new String[] {DEPLOY, LOCK_NONE, UNDEPLOYING, STATE_LOCKED_NONE, FAILED}, DEPLOY);
-        this.graph.put(new String[] {DEPLOY, LOCK_NONE, DEPLOYING, STATE_LOCKED_NONE, FAILED}, DEPLOY);
-
-        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, UNDEPLOYING, STATE_LOCKED_NONE, FAILED}, UNDEPLOY);
-        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, UPDATING, LOCKED, FAILED}, UNDEPLOY);
-        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, MIGRATING, LOCKED, FAILED}, UNDEPLOY);
-        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, DEPLOYING, STATE_LOCKED_NONE, FAILED}, UNDEPLOY);
-
-        this.graph.put(new String[] {DELETE, LOCK_NONE, DELETING, LOCK_NONE, FAILED}, DELETE);
-
-        this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, DEPLOYED, LOCKING, FAILED}, UNLOCK);
-        this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, DEPLOYED, UNLOCKING, FAILED}, UNLOCK);
-
-        this.graph.put(new String[] {DEPLOY_NONE, LOCK, DEPLOYED, LOCKING, FAILED}, LOCK);
-        this.graph.put(new String[] {DEPLOY_NONE, LOCK, DEPLOYED, UNLOCKING, FAILED}, LOCK);
+        this.graph = new StateDefinition<>(7, NONE);
+
+        // make an order when there are no fails
+        this.graph.put(new String[] {DEPLOY, LOCK_NONE, SUB_NONE,
+            UNDEPLOYED, STATE_LOCKED_NONE, SUB_STATE_NONE, NO_ERROR}, DEPLOY);
+        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, SUB_NONE,
+            DEPLOYED, LOCKED, SUB_STATE_NONE, NO_ERROR}, UNDEPLOY);
+        this.graph.put(new String[] {DELETE, LOCK_NONE, SUB_NONE,
+            UNDEPLOYED, LOCK_NONE, SUB_STATE_NONE, NO_ERROR}, DELETE);
+        this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, SUB_NONE,
+            DEPLOYED, LOCKED, SUB_STATE_NONE, NO_ERROR}, UNLOCK);
+        this.graph.put(new String[] {DEPLOY_NONE, LOCK, SUB_NONE,
+            DEPLOYED, UNLOCKED, SUB_STATE_NONE, NO_ERROR}, LOCK);
+        this.graph.put(new String[] {MIGRATE, LOCK_NONE, SUB_NONE,
+            DEPLOYED, LOCKED, SUB_STATE_NONE, NO_ERROR}, MIGRATE);
+        this.graph.put(new String[] {UPDATE, LOCK_NONE, SUB_NONE,
+            DEPLOYED, LOCKED, SUB_STATE_NONE, NO_ERROR}, UPDATE);
+        this.graph.put(new String[] {DEPLOY_NONE, LOCK_NONE, REVIEW,
+            DEPLOYED, LOCKED, SUB_STATE_NONE, NO_ERROR}, REVIEW);
+        this.graph.put(new String[] {DEPLOY_NONE, LOCK_NONE, PREPARE,
+            UNDEPLOYED, STATE_LOCKED_NONE, SUB_STATE_NONE, NO_ERROR}, PREPARE);
+        this.graph.put(new String[] {DEPLOY_NONE, LOCK_NONE, MIGRATE_PRECHECK,
+            DEPLOYED, LOCKED, SUB_STATE_NONE, NO_ERROR}, MIGRATE_PRECHECK);
+
+        // make an order in a failed scenario
+        this.graph.put(new String[] {DEPLOY, LOCK_NONE, SUB_NONE,
+            UNDEPLOYING, STATE_LOCKED_NONE, SUB_STATE_NONE, FAILED}, DEPLOY);
+        this.graph.put(new String[] {DEPLOY, LOCK_NONE, SUB_NONE,
+            DEPLOYING, STATE_LOCKED_NONE, SUB_STATE_NONE, FAILED}, DEPLOY);
+
+        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, SUB_NONE,
+            UNDEPLOYING, STATE_LOCKED_NONE, SUB_STATE_NONE, FAILED}, UNDEPLOY);
+        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, SUB_NONE,
+            UPDATING, LOCKED, SUB_STATE_NONE, FAILED}, UNDEPLOY);
+        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, SUB_NONE,
+            MIGRATING, LOCKED, SUB_STATE_NONE, FAILED}, UNDEPLOY);
+        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, SUB_NONE,
+            DEPLOYING, STATE_LOCKED_NONE, SUB_STATE_NONE, FAILED}, UNDEPLOY);
+
+        this.graph.put(new String[] {DELETE, LOCK_NONE, SUB_NONE,
+            DELETING, LOCK_NONE, SUB_STATE_NONE, FAILED}, DELETE);
+
+        this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, SUB_NONE,
+            DEPLOYED, LOCKING, SUB_STATE_NONE, FAILED}, UNLOCK);
+        this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, SUB_NONE,
+            DEPLOYED, UNLOCKING, SUB_STATE_NONE, FAILED}, UNLOCK);
+
+        this.graph.put(new String[] {DEPLOY_NONE, LOCK, SUB_NONE, DEPLOYED, LOCKING, SUB_STATE_NONE, FAILED}, LOCK);
+        this.graph.put(new String[] {DEPLOY_NONE, LOCK, SUB_NONE, DEPLOYED, UNLOCKING, SUB_STATE_NONE, FAILED}, LOCK);
+
+        this.graph.put(new String[] {UPDATE, LOCK_NONE, SUB_NONE, UPDATING, LOCKED, SUB_STATE_NONE, FAILED}, UPDATE);
+
+        this.graph.put(new String[] {DEPLOY_NONE, LOCK_NONE, MIGRATE_PRECHECK,
+            DEPLOYED, LOCKED, MIGRATION_PRECHECKING, FAILED}, MIGRATE_PRECHECK);
 
         // timeout
-        this.graph.put(new String[] {DEPLOY, LOCK_NONE, UNDEPLOYING, STATE_LOCKED_NONE, TIMEOUT}, DEPLOY);
-        this.graph.put(new String[] {DEPLOY, LOCK_NONE, DEPLOYING, STATE_LOCKED_NONE, TIMEOUT}, DEPLOY);
-
-        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, UNDEPLOYING, STATE_LOCKED_NONE, TIMEOUT}, UNDEPLOY);
-        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, UPDATING, LOCKED, TIMEOUT}, UNDEPLOY);
-        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, MIGRATING, LOCKED, TIMEOUT}, UNDEPLOY);
-        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, DEPLOYING, STATE_LOCKED_NONE, TIMEOUT}, UNDEPLOY);
-
-        this.graph.put(new String[] {DELETE, LOCK_NONE, DELETING, LOCK_NONE, TIMEOUT}, DELETE);
-
-        this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, DEPLOYED, LOCKING, TIMEOUT}, UNLOCK);
-        this.graph.put(new String[] {DEPLOY_NONE, LOCK, DEPLOYED, LOCKING, TIMEOUT}, LOCK);
-
-        this.graph.put(new String[] {DEPLOY_NONE, LOCK, DEPLOYED, UNLOCKING, TIMEOUT}, LOCK);
-        this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, DEPLOYED, UNLOCKING, TIMEOUT}, UNLOCK);
+        this.graph.put(new String[] {DEPLOY, LOCK_NONE, SUB_NONE,
+            UNDEPLOYING, STATE_LOCKED_NONE, SUB_STATE_NONE, TIMEOUT}, DEPLOY);
+        this.graph.put(new String[] {DEPLOY, LOCK_NONE, SUB_NONE,
+            DEPLOYING, STATE_LOCKED_NONE, SUB_STATE_NONE, TIMEOUT}, DEPLOY);
+
+        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, SUB_NONE,
+            UNDEPLOYING, STATE_LOCKED_NONE, SUB_STATE_NONE, TIMEOUT}, UNDEPLOY);
+        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, SUB_NONE,
+            UPDATING, LOCKED, SUB_STATE_NONE, TIMEOUT}, UNDEPLOY);
+        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, SUB_NONE,
+            MIGRATING, LOCKED, SUB_STATE_NONE, TIMEOUT}, UNDEPLOY);
+        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, SUB_NONE,
+            MIGRATION_PRECHECKING, LOCKED, SUB_STATE_NONE, TIMEOUT}, UNDEPLOY);
+        this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, SUB_NONE,
+            DEPLOYING, STATE_LOCKED_NONE, SUB_STATE_NONE, TIMEOUT}, UNDEPLOY);
+
+        this.graph.put(new String[] {DELETE, LOCK_NONE, SUB_NONE,
+            DELETING, LOCK_NONE, SUB_STATE_NONE, TIMEOUT}, DELETE);
+
+        this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, SUB_NONE,
+            DEPLOYED, LOCKING, SUB_STATE_NONE, TIMEOUT}, UNLOCK);
+        this.graph.put(new String[] {DEPLOY_NONE, LOCK, SUB_NONE,
+            DEPLOYED, LOCKING, SUB_STATE_NONE, TIMEOUT}, LOCK);
+
+        this.graph.put(new String[] {DEPLOY_NONE, LOCK, SUB_NONE,
+            DEPLOYED, UNLOCKING, SUB_STATE_NONE, TIMEOUT}, LOCK);
+        this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, SUB_NONE,
+            DEPLOYED, UNLOCKING, SUB_STATE_NONE, TIMEOUT}, UNLOCK);
+
+        this.graph.put(new String[] {UPDATE, LOCK_NONE, SUB_NONE, UPDATING, LOCKED, SUB_STATE_NONE, TIMEOUT}, UPDATE);
+
+        this.graph.put(new String[] {DEPLOY_NONE, LOCK_NONE, MIGRATE_PRECHECK,
+            DEPLOYED, LOCKED, MIGRATION_PRECHECKING, TIMEOUT}, MIGRATE_PRECHECK);
     }
 
     /**
@@ -116,20 +173,24 @@ public class AcInstanceStateResolver {
      *
      * @param acDeployOrder the Deploy Ordered
      * @param acLockOrder the Lock Ordered
+     * @param acSubOrder the Sub Ordered
      * @param acDeployState then current Deploy State
      * @param acLockState the current Lock State
+     * @param acSubState the current Sub State
      * @param acStateChangeResult the current Result of the State Change
      * @return the order (DEPLOY/UNDEPLOY/LOCK/UNLOCK) to send to participant or NONE if order is not consistent
      */
-    public String resolve(DeployOrder acDeployOrder, LockOrder acLockOrder, DeployState acDeployState,
-            LockState acLockState, StateChangeResult acStateChangeResult) {
+    public String resolve(DeployOrder acDeployOrder, LockOrder acLockOrder, SubOrder acSubOrder,
+        DeployState acDeployState, LockState acLockState, SubState acSubState, StateChangeResult acStateChangeResult) {
         var deployOrder = acDeployOrder != null ? acDeployOrder : DeployOrder.NONE;
         var lockOrder = acLockOrder != null ? acLockOrder : LockOrder.NONE;
+        var subOrder = acSubOrder != null ? acSubOrder : SubOrder.NONE;
         var stateChangeResult = acStateChangeResult != null ? acStateChangeResult : StateChangeResult.NO_ERROR;
 
         var deployState = acDeployState != null ? acDeployState : DeployState.UNDEPLOYED;
         var lockState = acLockState != null ? acLockState : LockState.NONE;
-        return this.graph.get(new String[] {deployOrder.name(), lockOrder.name(), deployState.name(), lockState.name(),
-                stateChangeResult.name()});
+        var subState = acSubState != null ? acSubState : SubState.NONE;
+        return this.graph.get(new String[] {deployOrder.name(), lockOrder.name(), subOrder.name(),
+                deployState.name(), lockState.name(), subState.name(), stateChangeResult.name()});
     }
 }
index f90e5a8..50b8d14 100644 (file)
@@ -51,6 +51,7 @@ import org.onap.policy.clamp.models.acm.concepts.NodeTemplateState;
 import org.onap.policy.clamp.models.acm.concepts.ParticipantDefinition;
 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.SubState;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
 import org.onap.policy.clamp.models.acm.persistence.concepts.StringToMapConverter;
@@ -288,16 +289,20 @@ public final class AcmUtils {
         // @formatter:on
     }
 
+
     /**
-     * Return true if DeployState and LockState are in a Transitional State.
+     * Return true if DeployState, LockState and SubState are in a Transitional State.
      *
-     * @return true if DeployState and LockState are in a Transitional State
+     * @param deployState the DeployState
+     * @param lockState the LockState
+     * @param subState the SubState
+     * @return true if there is a state in a Transitional State
      */
-    public static boolean isInTransitionalState(DeployState deployState, LockState lockState) {
+    public static boolean isInTransitionalState(DeployState deployState, LockState lockState, SubState subState) {
         return DeployState.DEPLOYING.equals(deployState) || DeployState.UNDEPLOYING.equals(deployState)
                 || LockState.LOCKING.equals(lockState) || LockState.UNLOCKING.equals(lockState)
                 || DeployState.DELETING.equals(deployState) || DeployState.UPDATING.equals(deployState)
-                || DeployState.MIGRATING.equals(deployState);
+                || DeployState.MIGRATING.equals(deployState) || !SubState.NONE.equals(subState);
     }
 
     /**
@@ -381,9 +386,23 @@ public final class AcmUtils {
      */
     public static void setCascadedState(final AutomationComposition automationComposition,
             final DeployState deployState, final LockState lockState) {
+        setCascadedState(automationComposition, deployState, lockState, SubState.NONE);
+    }
+
+    /**
+     /**
+     * Set the states on the automation composition and on all its automation composition elements.
+     *
+     * @param deployState the DeployState we want the automation composition to transition to
+     * @param lockState the LockState we want the automation composition to transition to
+     * @param subState the SubState we want the automation composition to transition to
+     */
+    public static void setCascadedState(final AutomationComposition automationComposition,
+        final DeployState deployState, final LockState lockState, final SubState subState) {
         automationComposition.setDeployState(deployState);
         automationComposition.setLockState(lockState);
         automationComposition.setLastMsg(TimestampHelper.now());
+        automationComposition.setSubState(subState);
 
         if (MapUtils.isEmpty(automationComposition.getElements())) {
             return;
@@ -392,6 +411,7 @@ public final class AcmUtils {
         for (var element : automationComposition.getElements().values()) {
             element.setDeployState(deployState);
             element.setLockState(lockState);
+            element.setSubState(subState);
             element.setMessage(null);
         }
     }
index 7f6cb2f..a807a11 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2023 Nordix Foundation.
+ *  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.
@@ -26,42 +26,78 @@ import org.junit.jupiter.api.Test;
 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.rest.instantiation.DeployOrder;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.SubOrder;
 
 class AcInstanceStateResolverTest {
 
     @Test
     void testResolve() {
         var acTypeStateResolver = new AcInstanceStateResolver();
-        var result = acTypeStateResolver.resolve(DeployOrder.DEPLOY, LockOrder.NONE, DeployState.UNDEPLOYED,
-                LockState.NONE, StateChangeResult.NO_ERROR);
+        // deploy
+        var result = acTypeStateResolver.resolve(DeployOrder.DEPLOY, LockOrder.NONE, SubOrder.NONE,
+            DeployState.UNDEPLOYED, LockState.NONE, SubState.NONE, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(AcInstanceStateResolver.DEPLOY);
-        result = acTypeStateResolver.resolve(DeployOrder.UNDEPLOY, LockOrder.NONE, DeployState.DEPLOYED,
-                LockState.LOCKED, StateChangeResult.NO_ERROR);
+
+        // undeploy
+        result = acTypeStateResolver.resolve(DeployOrder.UNDEPLOY, LockOrder.NONE, SubOrder.NONE,
+            DeployState.DEPLOYED, LockState.LOCKED, SubState.NONE, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(AcInstanceStateResolver.UNDEPLOY);
-        result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.UNLOCK, DeployState.DEPLOYED, LockState.LOCKED,
-                StateChangeResult.NO_ERROR);
+
+        // unlock
+        result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.UNLOCK, SubOrder.NONE,
+            DeployState.DEPLOYED, LockState.LOCKED, SubState.NONE, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(AcInstanceStateResolver.UNLOCK);
-        result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.LOCK, DeployState.DEPLOYED, LockState.UNLOCKED,
-                StateChangeResult.NO_ERROR);
+
+        // lock
+        result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.LOCK, SubOrder.NONE,
+            DeployState.DEPLOYED, LockState.UNLOCKED, SubState.NONE, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(AcInstanceStateResolver.LOCK);
 
-        result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.NONE, DeployState.UNDEPLOYED, LockState.NONE,
-                StateChangeResult.NO_ERROR);
+        // migrate
+        result = acTypeStateResolver.resolve(DeployOrder.MIGRATE, LockOrder.NONE, SubOrder.NONE,
+            DeployState.DEPLOYED, LockState.LOCKED, SubState.NONE, StateChangeResult.NO_ERROR);
+        assertThat(result).isEqualTo(AcInstanceStateResolver.MIGRATE);
+
+        // migrate-precheck
+        result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.NONE, SubOrder.MIGRATE_PRECHECK,
+            DeployState.DEPLOYED, LockState.LOCKED, SubState.NONE, StateChangeResult.NO_ERROR);
+        assertThat(result).isEqualTo(AcInstanceStateResolver.MIGRATE_PRECHECK);
+
+        // prepare
+        result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.NONE, SubOrder.PREPARE,
+            DeployState.UNDEPLOYED, LockState.NONE, SubState.NONE, StateChangeResult.NO_ERROR);
+        assertThat(result).isEqualTo(AcInstanceStateResolver.PREPARE);
+
+        // review
+        result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.NONE, SubOrder.REVIEW,
+            DeployState.DEPLOYED, LockState.LOCKED, SubState.NONE, StateChangeResult.NO_ERROR);
+        assertThat(result).isEqualTo(AcInstanceStateResolver.REVIEW);
+    }
+
+    @Test
+    void testResolveWrongOrder() {
+        var acTypeStateResolver = new AcInstanceStateResolver();
+
+        var result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.NONE, SubOrder.NONE,
+            DeployState.UNDEPLOYED, LockState.NONE, SubState.NONE, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(AcInstanceStateResolver.NONE);
-        result = acTypeStateResolver.resolve(DeployOrder.UNDEPLOY, LockOrder.UNLOCK, DeployState.DEPLOYED,
-                LockState.LOCKED, StateChangeResult.NO_ERROR);
+
+        result = acTypeStateResolver.resolve(DeployOrder.UNDEPLOY, LockOrder.UNLOCK, SubOrder.NONE,
+            DeployState.DEPLOYED, LockState.LOCKED, SubState.NONE, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(AcInstanceStateResolver.NONE);
-        result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.UNLOCK, DeployState.UNDEPLOYED, LockState.NONE,
-                StateChangeResult.NO_ERROR);
+
+        result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.UNLOCK, SubOrder.NONE,
+            DeployState.UNDEPLOYED, LockState.NONE, SubState.NONE, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(AcInstanceStateResolver.NONE);
-        result = acTypeStateResolver.resolve(DeployOrder.UNDEPLOY, LockOrder.NONE, DeployState.DEPLOYING,
-                LockState.NONE, StateChangeResult.NO_ERROR);
+
+        result = acTypeStateResolver.resolve(DeployOrder.UNDEPLOY, LockOrder.NONE, SubOrder.NONE,
+            DeployState.DEPLOYING, LockState.NONE, SubState.NONE, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(AcInstanceStateResolver.NONE);
 
-        result = acTypeStateResolver.resolve(null, null, null, null, null);
+        result = acTypeStateResolver.resolve(null, null, null, null, null, null, null);
         assertThat(result).isEqualTo(AcInstanceStateResolver.NONE);
     }
-
 }
index f17eff3..5d0a7d9 100644 (file)
@@ -43,6 +43,7 @@ import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition
 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.SubState;
 import org.onap.policy.clamp.models.acm.document.concepts.DocToscaServiceTemplate;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
@@ -68,14 +69,16 @@ class AcmUtilsTest {
 
     @Test
     void testIsInTransitionalState() {
-        assertThat(AcmUtils.isInTransitionalState(DeployState.DEPLOYED, LockState.LOCKED)).isFalse();
-        assertThat(AcmUtils.isInTransitionalState(DeployState.DEPLOYING, LockState.NONE)).isTrue();
-        assertThat(AcmUtils.isInTransitionalState(DeployState.UNDEPLOYING, LockState.NONE)).isTrue();
-        assertThat(AcmUtils.isInTransitionalState(DeployState.DEPLOYED, LockState.LOCKING)).isTrue();
-        assertThat(AcmUtils.isInTransitionalState(DeployState.DEPLOYED, LockState.UNLOCKING)).isTrue();
-        assertThat(AcmUtils.isInTransitionalState(DeployState.DELETING, LockState.NONE)).isTrue();
-        assertThat(AcmUtils.isInTransitionalState(DeployState.UPDATING, LockState.LOCKED)).isTrue();
-        assertThat(AcmUtils.isInTransitionalState(DeployState.MIGRATING, LockState.LOCKED)).isTrue();
+        assertThat(AcmUtils.isInTransitionalState(DeployState.DEPLOYED, LockState.LOCKED, SubState.NONE)).isFalse();
+        assertThat(AcmUtils.isInTransitionalState(DeployState.DEPLOYING, LockState.NONE, SubState.NONE)).isTrue();
+        assertThat(AcmUtils.isInTransitionalState(DeployState.UNDEPLOYING, LockState.NONE, SubState.NONE)).isTrue();
+        assertThat(AcmUtils.isInTransitionalState(DeployState.DEPLOYED, LockState.LOCKING, SubState.NONE)).isTrue();
+        assertThat(AcmUtils.isInTransitionalState(DeployState.DEPLOYED, LockState.UNLOCKING, SubState.NONE)).isTrue();
+        assertThat(AcmUtils.isInTransitionalState(DeployState.DELETING, LockState.NONE, SubState.NONE)).isTrue();
+        assertThat(AcmUtils.isInTransitionalState(DeployState.UPDATING, LockState.LOCKED, SubState.NONE)).isTrue();
+        assertThat(AcmUtils.isInTransitionalState(DeployState.MIGRATING, LockState.LOCKED, SubState.NONE)).isTrue();
+        assertThat(AcmUtils.isInTransitionalState(DeployState.DEPLOYED, LockState.LOCKED,
+                SubState.MIGRATION_PRECHECKING)).isTrue();
     }
 
     @Test
index 2bf0822..c732654 100644 (file)
@@ -22,7 +22,6 @@
 package org.onap.policy.clamp.acm.runtime.instantiation;
 
 import jakarta.validation.Valid;
-import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.Response.Status;
 import java.util.UUID;
 import java.util.stream.Collectors;
@@ -37,8 +36,12 @@ 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.NodeTemplateState;
 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.rest.instantiation.AcInstanceStateUpdate;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.SubOrder;
 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
@@ -82,19 +85,19 @@ public class AutomationCompositionInstantiationProvider {
     public InstantiationResponse createAutomationComposition(UUID compositionId,
             AutomationComposition automationComposition) {
         if (!compositionId.equals(automationComposition.getCompositionId())) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+            throw new PfModelRuntimeException(Status.BAD_REQUEST,
                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
         }
         var checkAutomationCompositionOpt =
                 automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
         if (checkAutomationCompositionOpt.isPresent()) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+            throw new PfModelRuntimeException(Status.BAD_REQUEST,
                     automationComposition.getKey().asIdentifier() + " already defined");
         }
 
         var validationResult = validateAutomationComposition(automationComposition);
         if (!validationResult.isValid()) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
+            throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
         }
         automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
 
@@ -120,7 +123,7 @@ public class AutomationCompositionInstantiationProvider {
         var instanceId = automationComposition.getInstanceId();
         var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
         if (!compositionId.equals(acToUpdate.getCompositionId())) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+            throw new PfModelRuntimeException(Status.BAD_REQUEST,
                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
         }
         if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
@@ -131,22 +134,42 @@ public class AutomationCompositionInstantiationProvider {
             acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
             var validationResult = validateAutomationComposition(acToUpdate);
             if (!validationResult.isValid()) {
-                throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
+                throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
             }
             automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
             return createInstantiationResponse(automationComposition);
 
-        } else if ((DeployState.DEPLOYED.equals(acToUpdate.getDeployState())
-                || DeployState.UPDATING.equals(acToUpdate.getDeployState()))
-                && LockState.LOCKED.equals(acToUpdate.getLockState())) {
-            if (automationComposition.getCompositionTargetId() != null) {
-                return  migrateAutomationComposition(automationComposition, acToUpdate);
+        }
+
+        if (automationComposition.getRestarting() != null) {
+            throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Update not allowed");
+        }
+
+        var deployOrder = DeployOrder.UPDATE;
+        var subOrder = SubOrder.NONE;
+
+        if (automationComposition.getCompositionTargetId() != null) {
+
+            if (Boolean.TRUE.equals(automationComposition.getPrecheck())) {
+                subOrder = SubOrder.MIGRATE_PRECHECK;
+                deployOrder = DeployOrder.NONE;
             } else {
-                return updateDeployedAutomationComposition(automationComposition, acToUpdate);
+                deployOrder = DeployOrder.MIGRATE;
             }
         }
-        throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
-                "Not allowed to update in the state " + acToUpdate.getDeployState());
+        var result = acInstanceStateResolver.resolve(deployOrder, LockOrder.NONE, subOrder,
+                acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
+                acToUpdate.getStateChangeResult());
+        return switch (result) {
+            case "UPDATE" -> updateDeployedAutomationComposition(automationComposition, acToUpdate);
+
+            case "MIGRATE" -> migrateAutomationComposition(automationComposition, acToUpdate);
+
+            case "MIGRATE_PRECHECK" -> migratePrecheckAc(automationComposition, acToUpdate);
+
+            default -> throw new PfModelRuntimeException(Status.BAD_REQUEST,
+                    "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
+        };
     }
 
     /**
@@ -164,17 +187,14 @@ public class AutomationCompositionInstantiationProvider {
             var elementId = element.getKey();
             var dbAcElement = acToBeUpdated.getElements().get(elementId);
             if (dbAcElement == null) {
-                throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, "Element id not present " + elementId);
+                throw new PfModelRuntimeException(Status.BAD_REQUEST, "Element id not present " + elementId);
             }
             AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
         }
-        if (automationComposition.getRestarting() != null) {
-            throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Update not allowed");
-        }
 
         var validationResult = validateAutomationComposition(acToBeUpdated);
         if (!validationResult.isValid()) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
+            throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
         }
         // Publish property update event to the participants
         supervisionAcHandler.update(acToBeUpdated);
@@ -187,26 +207,23 @@ public class AutomationCompositionInstantiationProvider {
         AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
 
         if (!DeployState.DEPLOYED.equals(acToBeUpdated.getDeployState())) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+            throw new PfModelRuntimeException(Status.BAD_REQUEST,
                 "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
         }
-        if (automationComposition.getRestarting() != null) {
-            throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Migrate not allowed");
-        }
 
         // Iterate and update the element property values
         for (var element : automationComposition.getElements().entrySet()) {
             var elementId = element.getKey();
             var dbAcElement = acToBeUpdated.getElements().get(elementId);
             if (dbAcElement == null) {
-                throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, "Element id not present " + elementId);
+                throw new PfModelRuntimeException(Status.BAD_REQUEST, "Element id not present " + elementId);
             }
             AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
             var newDefinition = element.getValue().getDefinition();
             var compatibility =
                 newDefinition.asConceptKey().getCompatibility(dbAcElement.getDefinition().asConceptKey());
             if (PfKey.Compatibility.DIFFERENT.equals(compatibility)) {
-                throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+                throw new PfModelRuntimeException(Status.BAD_REQUEST,
                     dbAcElement.getDefinition() + " is not compatible with " + newDefinition);
             }
             if (PfKey.Compatibility.MAJOR.equals(compatibility) || PfKey.Compatibility.MINOR.equals(compatibility)) {
@@ -219,17 +236,57 @@ public class AutomationCompositionInstantiationProvider {
         var validationResult =
             validateAutomationComposition(acToBeUpdated, automationComposition.getCompositionTargetId());
         if (!validationResult.isValid()) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
+            throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
         }
         acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
 
         // Publish migrate event to the participants
-        supervisionAcHandler.migrate(acToBeUpdated, automationComposition.getCompositionTargetId());
+        supervisionAcHandler.migrate(acToBeUpdated);
 
         automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
         return createInstantiationResponse(automationComposition);
     }
 
+    private InstantiationResponse migratePrecheckAc(
+            AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
+
+        acToBeUpdated.setPrecheck(true);
+        var copyAc = new AutomationComposition(acToBeUpdated);
+        // Iterate and update the element property values
+        for (var element : automationComposition.getElements().entrySet()) {
+            var elementId = element.getKey();
+            var copyElement = copyAc.getElements().get(elementId);
+            if (copyElement == null) {
+                throw new PfModelRuntimeException(Status.BAD_REQUEST, "Element id not present " + elementId);
+            }
+            AcmUtils.recursiveMerge(copyElement.getProperties(), element.getValue().getProperties());
+            var newDefinition = element.getValue().getDefinition();
+            var compatibility =
+                    newDefinition.asConceptKey().getCompatibility(copyElement.getDefinition().asConceptKey());
+            if (PfKey.Compatibility.DIFFERENT.equals(compatibility)) {
+                throw new PfModelRuntimeException(Status.BAD_REQUEST,
+                        copyElement.getDefinition() + " is not compatible with " + newDefinition);
+            }
+            copyElement.setDefinition(element.getValue().getDefinition());
+        }
+
+        var validationResult =
+                validateAutomationComposition(copyAc, automationComposition.getCompositionTargetId());
+        if (!validationResult.isValid()) {
+            throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
+        }
+        copyAc.setCompositionTargetId(automationComposition.getCompositionTargetId());
+
+        // Publish migrate event to the participants
+        supervisionAcHandler.migratePrecheck(copyAc);
+
+        AcmUtils.setCascadedState(acToBeUpdated, DeployState.DEPLOYED, LockState.LOCKED,
+            SubState.MIGRATION_PRECHECKING);
+        acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
+
+        return createInstantiationResponse(automationCompositionProvider.updateAutomationComposition(acToBeUpdated));
+    }
+
     private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition) {
         return validateAutomationComposition(automationComposition, automationComposition.getCompositionId());
     }
@@ -296,7 +353,7 @@ public class AutomationCompositionInstantiationProvider {
         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
         if (!compositionId.equals(automationComposition.getCompositionId())
                         && !compositionId.equals(automationComposition.getCompositionTargetId())) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+            throw new PfModelRuntimeException(Status.BAD_REQUEST,
                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
         }
         return automationComposition;
@@ -312,17 +369,17 @@ public class AutomationCompositionInstantiationProvider {
     public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
         if (!compositionId.equals(automationComposition.getCompositionId())) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+            throw new PfModelRuntimeException(Status.BAD_REQUEST,
                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
         }
         if (!DeployState.UNDEPLOYED.equals(automationComposition.getDeployState())
                 && !DeployState.DELETING.equals(automationComposition.getDeployState())) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+            throw new PfModelRuntimeException(Status.BAD_REQUEST,
                     "Automation composition state is still " + automationComposition.getDeployState());
         }
         if (DeployState.DELETING.equals(automationComposition.getDeployState())
                 && StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult())) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+            throw new PfModelRuntimeException(Status.BAD_REQUEST,
                     "Automation composition state is still " + automationComposition.getDeployState());
         }
         if (automationComposition.getRestarting() != null) {
@@ -366,7 +423,7 @@ public class AutomationCompositionInstantiationProvider {
             @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
         if (!compositionId.equals(automationComposition.getCompositionId())) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+            throw new PfModelRuntimeException(Status.BAD_REQUEST,
                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
         }
         var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
@@ -376,8 +433,9 @@ public class AutomationCompositionInstantiationProvider {
 
         participantProvider.verifyParticipantState(participantIds);
         var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
-                acInstanceStateUpdate.getLockOrder(), automationComposition.getDeployState(),
-                automationComposition.getLockState(), automationComposition.getStateChangeResult());
+                acInstanceStateUpdate.getLockOrder(), acInstanceStateUpdate.getSubOrder(),
+                automationComposition.getDeployState(), automationComposition.getLockState(),
+                automationComposition.getSubState(), automationComposition.getStateChangeResult());
         switch (result) {
             case "DEPLOY":
                 supervisionAcHandler.deploy(automationComposition, acDefinition);
@@ -395,6 +453,14 @@ public class AutomationCompositionInstantiationProvider {
                 supervisionAcHandler.unlock(automationComposition, acDefinition);
                 break;
 
+            case "PREPARE":
+                supervisionAcHandler.prepare(automationComposition);
+                break;
+
+            case "REVIEW":
+                supervisionAcHandler.review(automationComposition);
+                break;
+
             default:
                 throw new PfModelRuntimeException(Status.BAD_REQUEST, "Not valid " + acInstanceStateUpdate);
         }
index 7547786..a8d2687 100644 (file)
@@ -30,6 +30,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import lombok.AllArgsConstructor;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AcElementPropertiesPublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.AcPreparePublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionMigrationPublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher;
@@ -42,6 +43,7 @@ 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.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.AutomationCompositionDeployAck;
 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
@@ -68,6 +70,7 @@ public class SupervisionAcHandler {
     private final AcElementPropertiesPublisher acElementPropertiesPublisher;
     private final AutomationCompositionMigrationPublisher acCompositionMigrationPublisher;
     private final ParticipantSyncPublisher participantSyncPublisher;
+    private final AcPreparePublisher acPreparePublisher;
 
     private final ExecutorService executor = Context.taskWrapping(Executors.newFixedThreadPool(1));
 
@@ -149,6 +152,30 @@ public class SupervisionAcHandler {
             () -> automationCompositionStateChangePublisher.send(automationComposition, startPhase, true));
     }
 
+    /**
+     * Handle prepare Pre Deploy an AutomationComposition instance.
+     *
+     * @param automationComposition the AutomationComposition
+     */
+    public void prepare(AutomationComposition automationComposition) {
+        AcmUtils.setCascadedState(automationComposition, DeployState.UNDEPLOYED, LockState.NONE, SubState.PREPARING);
+        automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
+        automationCompositionProvider.updateAutomationComposition(automationComposition);
+        executor.execute(() -> acPreparePublisher.sendPrepare(automationComposition));
+    }
+
+    /**
+     * Handle prepare Post Deploy an AutomationComposition instance.
+     *
+     * @param automationComposition the AutomationComposition
+     */
+    public void review(AutomationComposition automationComposition) {
+        AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYED, LockState.LOCKED, SubState.REVIEWING);
+        automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
+        automationCompositionProvider.updateAutomationComposition(automationComposition);
+        executor.execute(() -> acPreparePublisher.sendRevew(automationComposition));
+    }
+
     /**
      * Handle Lock an AutomationComposition instance.
      *
@@ -285,6 +312,7 @@ public class SupervisionAcHandler {
                 element.setOutProperties(acElementAck.getValue().getOutProperties());
                 element.setOperationalState(acElementAck.getValue().getOperationalState());
                 element.setUseState(acElementAck.getValue().getUseState());
+                element.setSubState(SubState.NONE);
                 element.setDeployState(acElementAck.getValue().getDeployState());
                 element.setLockState(acElementAck.getValue().getLockState());
                 element.setRestarting(null);
@@ -308,12 +336,19 @@ public class SupervisionAcHandler {
      * Handle Migration of an AutomationComposition instance to other ACM Definition.
      *
      * @param automationComposition the AutomationComposition
-     * @param compositionTargetId the ACM Definition Id
      */
-    public void migrate(AutomationComposition automationComposition, UUID compositionTargetId) {
+    public void migrate(AutomationComposition automationComposition) {
         AcmUtils.setCascadedState(automationComposition, DeployState.MIGRATING, LockState.LOCKED);
         automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
-        executor.execute(
-            () -> acCompositionMigrationPublisher.send(automationComposition, compositionTargetId));
+        executor.execute(() -> acCompositionMigrationPublisher.send(automationComposition));
+    }
+
+    /**
+     * Handle Migration precheck of an AutomationComposition instance to other ACM Definition.
+     *
+     * @param automationComposition the AutomationComposition
+     */
+    public void migratePrecheck(AutomationComposition automationComposition) {
+        executor.execute(() -> acCompositionMigrationPublisher.send(automationComposition));
     }
 }
index d1aa6c2..e723d2c 100644 (file)
@@ -34,6 +34,7 @@ import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition
 import org.onap.policy.clamp.models.acm.concepts.DeployState;
 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.persistence.provider.AcDefinitionProvider;
 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
@@ -133,7 +134,7 @@ public class SupervisionScanner {
         LOGGER.debug("scanning automation composition {} . . .", automationComposition.getInstanceId());
 
         if (!AcmUtils.isInTransitionalState(automationComposition.getDeployState(),
-                automationComposition.getLockState())
+                automationComposition.getLockState(), automationComposition.getSubState())
                 || StateChangeResult.FAILED.equals(automationComposition.getStateChangeResult())) {
             LOGGER.debug("automation composition {} scanned, OK", automationComposition.getInstanceId());
 
@@ -151,7 +152,8 @@ public class SupervisionScanner {
             int startPhase = ParticipantUtils.findStartPhase(toscaNodeTemplate.getProperties());
             defaultMin = Math.min(defaultMin, startPhase);
             defaultMax = Math.max(defaultMax, startPhase);
-            if (AcmUtils.isInTransitionalState(element.getDeployState(), element.getLockState())) {
+            if (AcmUtils.isInTransitionalState(element.getDeployState(), element.getLockState(),
+                    element.getSubState())) {
                 completed = false;
                 minSpNotCompleted = Math.min(minSpNotCompleted, startPhase);
                 maxSpNotCompleted = Math.max(maxSpNotCompleted, startPhase);
@@ -168,7 +170,8 @@ public class SupervisionScanner {
                     automationComposition.getDeployState(), automationComposition.getLockState());
 
             if (DeployState.UPDATING.equals(automationComposition.getDeployState())
-                    || DeployState.MIGRATING.equals(automationComposition.getDeployState())) {
+                    || DeployState.MIGRATING.equals(automationComposition.getDeployState())
+                    || !SubState.NONE.equals(automationComposition.getSubState())) {
                 // UPDATING do not need phases
                 handleTimeoutUpdate(automationComposition);
                 return;
@@ -198,6 +201,8 @@ public class SupervisionScanner {
         automationComposition.setDeployState(AcmUtils.deployCompleted(deployState));
         automationComposition.setLockState(AcmUtils.lockCompleted(deployState, automationComposition.getLockState()));
         automationComposition.setPhase(null);
+        automationComposition.setSubState(SubState.NONE);
+        automationComposition.setPrecheck(null);
         if (StateChangeResult.TIMEOUT.equals(automationComposition.getStateChangeResult())) {
             automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
         }
@@ -233,7 +238,8 @@ public class SupervisionScanner {
         var now = TimestampHelper.nowEpochMilli();
         var lastMsg = TimestampHelper.toEpochMilli(automationComposition.getLastMsg());
         for (var element : automationComposition.getElements().values()) {
-            if (!AcmUtils.isInTransitionalState(element.getDeployState(), element.getLockState())) {
+            if (!AcmUtils.isInTransitionalState(
+                    element.getDeployState(), element.getLockState(), element.getSubState())) {
                 continue;
             }
             if ((now - lastMsg) > maxStatusWaitMs) {
@@ -255,7 +261,8 @@ public class SupervisionScanner {
         var now = TimestampHelper.nowEpochMilli();
         var lastMsg = TimestampHelper.toEpochMilli(automationComposition.getLastMsg());
         for (var element : automationComposition.getElements().values()) {
-            if (!AcmUtils.isInTransitionalState(element.getDeployState(), element.getLockState())) {
+            if (!AcmUtils.isInTransitionalState(
+                    element.getDeployState(), element.getLockState(), element.getSubState())) {
                 continue;
             }
             var toscaNodeTemplate = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcPreparePublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcPreparePublisher.java
new file mode 100644 (file)
index 0000000..acf4035
--- /dev/null
@@ -0,0 +1,78 @@
+/*-
+ * ============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.runtime.supervision.comm;
+
+import io.micrometer.core.annotation.Timed;
+import java.time.Instant;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionPrepare;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
+import org.onap.policy.clamp.models.acm.utils.AcmUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+@AllArgsConstructor
+public class AcPreparePublisher extends AbstractParticipantPublisher<AutomationCompositionPrepare> {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(AcPreparePublisher.class);
+
+    /**
+     * Send AutomationCompositionPrepare Prepare message to Participant.
+     *
+     * @param automationComposition the AutomationComposition
+     */
+    @Timed(value = "publisher.prepare", description = "AC Prepare Pre Deploy published")
+    public void sendPrepare(AutomationComposition automationComposition) {
+        var acPrepare = createAutomationCompositionPrepare(automationComposition.getCompositionId(),
+            automationComposition.getInstanceId());
+        acPrepare.setParticipantList(
+            AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.NONE));
+        LOGGER.debug("AC Prepare sent {}", acPrepare);
+        super.send(acPrepare);
+    }
+
+    /**
+     * Send AutomationCompositionPrepare Review message to Participant.
+     *
+     * @param automationComposition the AutomationComposition
+     */
+    @Timed(value = "publisher.review", description = "AC Review Post Deploy published")
+    public void sendRevew(AutomationComposition automationComposition) {
+        var acPrepare = createAutomationCompositionPrepare(automationComposition.getCompositionId(),
+            automationComposition.getInstanceId());
+        acPrepare.setPreDeploy(false);
+        LOGGER.debug("AC Review sent {}", acPrepare);
+        super.send(acPrepare);
+    }
+
+    private AutomationCompositionPrepare createAutomationCompositionPrepare(UUID compositionId, UUID instanceId) {
+        var acPrepare = new AutomationCompositionPrepare();
+        acPrepare.setCompositionId(compositionId);
+        acPrepare.setAutomationCompositionId(instanceId);
+        acPrepare.setMessageId(UUID.randomUUID());
+        acPrepare.setTimestamp(Instant.now());
+        return acPrepare;
+    }
+}
index e26a540..b961eab 100644 (file)
@@ -36,17 +36,17 @@ public class AutomationCompositionMigrationPublisher
      * Send AutomationCompositionMigration message to Participant.
      *
      * @param automationComposition the AutomationComposition
-     * @param compositionTargetId the Composition Definition Target
      */
     @Timed(
             value = "publisher.automation_composition_migration",
             description = "AUTOMATION_COMPOSITION_MIGRATION messages published")
-    public void send(AutomationComposition automationComposition, UUID compositionTargetId) {
+    public void send(AutomationComposition automationComposition) {
         var acsc = new AutomationCompositionMigration();
+        acsc.setPrecheck(Boolean.TRUE.equals(automationComposition.getPrecheck()));
         acsc.setCompositionId(automationComposition.getCompositionId());
         acsc.setAutomationCompositionId(automationComposition.getInstanceId());
         acsc.setMessageId(UUID.randomUUID());
-        acsc.setCompositionTargetId(compositionTargetId);
+        acsc.setCompositionTargetId(automationComposition.getCompositionTargetId());
         acsc.setParticipantUpdatesList(
                 AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.MIGRATE));
 
index 2ee6a15..0591ab0 100644 (file)
@@ -48,6 +48,7 @@ import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.SubOrder;
 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
@@ -169,7 +170,7 @@ class AutomationCompositionInstantiationProviderTest {
         var supervisionAcHandler = mock(SupervisionAcHandler.class);
         var participantProvider = mock(ParticipantProvider.class);
         var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
-                null, supervisionAcHandler, participantProvider,
+                new AcInstanceStateResolver(), supervisionAcHandler, participantProvider,
                 CommonTestData.getTestParamaterGroup());
         var instantiationResponse = instantiationProvider.updateAutomationComposition(
                 automationCompositionUpdate.getCompositionId(), automationCompositionUpdate);
@@ -200,15 +201,15 @@ class AutomationCompositionInstantiationProviderTest {
                 .thenReturn(automationCompositionUpdate);
 
         var instantiationProvider =
-                new AutomationCompositionInstantiationProvider(acProvider, mock(AcDefinitionProvider.class), null,
-                        mock(SupervisionAcHandler.class), mock(ParticipantProvider.class),
-                        mock(AcRuntimeParameterGroup.class));
+            new AutomationCompositionInstantiationProvider(acProvider, mock(AcDefinitionProvider.class),
+                new AcInstanceStateResolver(), mock(SupervisionAcHandler.class), mock(ParticipantProvider.class),
+                mock(AcRuntimeParameterGroup.class));
 
         var compositionId = automationCompositionUpdate.getCompositionId();
         assertThatThrownBy(
                 () -> instantiationProvider.updateAutomationComposition(compositionId, automationCompositionUpdate))
                         .hasMessageMatching(
-                                "Not allowed to update in the state " + automationCompositionUpdate.getDeployState());
+                                "Not allowed to UPDATE in the state " + automationCompositionUpdate.getDeployState());
 
         automationCompositionUpdate.setDeployState(DeployState.UPDATING);
         automationCompositionUpdate.setLockState(LockState.LOCKED);
@@ -216,7 +217,7 @@ class AutomationCompositionInstantiationProviderTest {
         assertThatThrownBy(
                 () -> instantiationProvider.updateAutomationComposition(compositionId, automationCompositionUpdate))
                         .hasMessageMatching(
-                                "Not allowed to migrate in the state " + automationCompositionUpdate.getDeployState());
+                                "Not allowed to MIGRATE in the state " + automationCompositionUpdate.getDeployState());
     }
 
     @Test
@@ -243,7 +244,7 @@ class AutomationCompositionInstantiationProviderTest {
         automationCompositionUpdate.setCompositionTargetId(UUID.randomUUID());
         assertThatThrownBy(
                 () -> instantiationProvider.updateAutomationComposition(compositionId, automationCompositionUpdate))
-                .hasMessageMatching("There is a restarting process, Migrate not allowed");
+                .hasMessageMatching("There is a restarting process, Update not allowed");
 
         automationCompositionUpdate.setDeployState(DeployState.UNDEPLOYED);
         automationCompositionUpdate.setLockState(LockState.NONE);
@@ -275,7 +276,7 @@ class AutomationCompositionInstantiationProviderTest {
         var supervisionAcHandler = mock(SupervisionAcHandler.class);
         var participantProvider = mock(ParticipantProvider.class);
         var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
-                null, supervisionAcHandler, participantProvider,
+                new AcInstanceStateResolver(), supervisionAcHandler, participantProvider,
                 mock(AcRuntimeParameterGroup.class));
         assertThatThrownBy(
                 () -> instantiationProvider.updateAutomationComposition(compositionId, automationCompositionUpdate))
@@ -305,7 +306,7 @@ class AutomationCompositionInstantiationProviderTest {
         var supervisionAcHandler = mock(SupervisionAcHandler.class);
         var participantProvider = mock(ParticipantProvider.class);
         var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
-                null, supervisionAcHandler, participantProvider, new AcRuntimeParameterGroup());
+            new AcInstanceStateResolver(), supervisionAcHandler, participantProvider, new AcRuntimeParameterGroup());
 
         assertThatThrownBy(() -> instantiationProvider
                 .updateAutomationComposition(automationComposition.getCompositionId(), automationComposition))
@@ -321,7 +322,51 @@ class AutomationCompositionInstantiationProviderTest {
         var instantiationResponse = instantiationProvider
                 .updateAutomationComposition(automationComposition.getCompositionId(), automationComposition);
 
-        verify(supervisionAcHandler).migrate(any(), any());
+        verify(supervisionAcHandler).migrate(any());
+        verify(acProvider).updateAutomationComposition(automationComposition);
+        InstantiationUtils.assertInstantiationResponse(instantiationResponse, automationComposition);
+    }
+
+
+    @Test
+    void testInstantiationMigrationPrecheck() {
+        var acDefinitionProvider = mock(AcDefinitionProvider.class);
+        var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
+        var compositionId = acDefinition.getCompositionId();
+        when(acDefinitionProvider.findAcDefinition(compositionId)).thenReturn(Optional.of(acDefinition));
+
+        var automationComposition =
+            InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
+        automationComposition.setCompositionId(compositionId);
+        automationComposition.setDeployState(DeployState.DEPLOYED);
+        automationComposition.setLockState(LockState.LOCKED);
+        automationComposition.setCompositionTargetId(UUID.randomUUID());
+        automationComposition.setPrecheck(true);
+        var acProvider = mock(AutomationCompositionProvider.class);
+        when(acProvider.getAutomationComposition(automationComposition.getInstanceId()))
+            .thenReturn(automationComposition);
+        when(acProvider.updateAutomationComposition(automationComposition)).thenReturn(automationComposition);
+
+        var supervisionAcHandler = mock(SupervisionAcHandler.class);
+        var acmParticipantProvider = mock(ParticipantProvider.class);
+        var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
+            new AcInstanceStateResolver(), supervisionAcHandler, acmParticipantProvider, new AcRuntimeParameterGroup());
+
+        assertThatThrownBy(() -> instantiationProvider
+            .updateAutomationComposition(automationComposition.getCompositionId(), automationComposition))
+            .hasMessageMatching(
+                String.format(AC_DEFINITION_NOT_FOUND, automationComposition.getCompositionTargetId()));
+
+        var acDefinitionTarget = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
+        var compositionTargetId = acDefinitionTarget.getCompositionId();
+        when(acDefinitionProvider.findAcDefinition(compositionTargetId)).thenReturn(Optional.of(acDefinitionTarget));
+
+        automationComposition.setCompositionTargetId(compositionTargetId);
+
+        var instantiationResponse = instantiationProvider
+            .updateAutomationComposition(automationComposition.getCompositionId(), automationComposition);
+
+        verify(supervisionAcHandler).migratePrecheck(any());
         verify(acProvider).updateAutomationComposition(automationComposition);
         InstantiationUtils.assertInstantiationResponse(instantiationResponse, automationComposition);
     }
@@ -354,7 +399,45 @@ class AutomationCompositionInstantiationProviderTest {
         var supervisionAcHandler = mock(SupervisionAcHandler.class);
         var participantProvider = mock(ParticipantProvider.class);
         var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
-                null, supervisionAcHandler, participantProvider, new AcRuntimeParameterGroup());
+                new AcInstanceStateResolver(), supervisionAcHandler, participantProvider,
+                new AcRuntimeParameterGroup());
+
+        assertThatThrownBy(() -> instantiationProvider
+                .updateAutomationComposition(automationComposition.getCompositionId(), acMigrate))
+                .hasMessageStartingWith("Element id not present");
+    }
+
+    @Test
+    void testMigratePrecheckBadRequest() {
+        var acDefinitionProvider = mock(AcDefinitionProvider.class);
+        var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
+        var compositionId = acDefinition.getCompositionId();
+        when(acDefinitionProvider.findAcDefinition(compositionId)).thenReturn(Optional.of(acDefinition));
+
+        var automationComposition =
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
+        automationComposition.setCompositionId(compositionId);
+        automationComposition.setDeployState(DeployState.DEPLOYED);
+        automationComposition.setLockState(LockState.LOCKED);
+        automationComposition.setPrecheck(true);
+        var acProvider = mock(AutomationCompositionProvider.class);
+        when(acProvider.getAutomationComposition(automationComposition.getInstanceId()))
+                .thenReturn(automationComposition);
+        when(acProvider.updateAutomationComposition(automationComposition)).thenReturn(automationComposition);
+
+        var acDefinitionTarget = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
+        var compositionTargetId = acDefinitionTarget.getCompositionId();
+        when(acDefinitionProvider.findAcDefinition(compositionTargetId)).thenReturn(Optional.of(acDefinitionTarget));
+
+        var acMigrate = new AutomationComposition(automationComposition);
+        acMigrate.setCompositionTargetId(compositionTargetId);
+        automationComposition.getElements().clear();
+
+        var supervisionAcHandler = mock(SupervisionAcHandler.class);
+        var participantProvider = mock(ParticipantProvider.class);
+        var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
+                new AcInstanceStateResolver(), supervisionAcHandler, participantProvider,
+                new AcRuntimeParameterGroup());
 
         assertThatThrownBy(() -> instantiationProvider
                 .updateAutomationComposition(automationComposition.getCompositionId(), acMigrate))
@@ -605,5 +688,21 @@ class AutomationCompositionInstantiationProviderTest {
         acInstanceStateUpdate.setLockOrder(LockOrder.LOCK);
         provider.compositionInstanceState(compositionId, instanceId, acInstanceStateUpdate);
         verify(supervisionAcHandler).lock(any(AutomationComposition.class), any(AutomationCompositionDefinition.class));
+
+        automationComposition.setDeployState(DeployState.UNDEPLOYED);
+        automationComposition.setLockState(LockState.NONE);
+        acInstanceStateUpdate.setDeployOrder(DeployOrder.NONE);
+        acInstanceStateUpdate.setLockOrder(LockOrder.NONE);
+        acInstanceStateUpdate.setSubOrder(SubOrder.PREPARE);
+        provider.compositionInstanceState(compositionId, instanceId, acInstanceStateUpdate);
+        verify(supervisionAcHandler).prepare(any(AutomationComposition.class));
+
+        automationComposition.setDeployState(DeployState.DEPLOYED);
+        automationComposition.setLockState(LockState.LOCKED);
+        acInstanceStateUpdate.setDeployOrder(DeployOrder.NONE);
+        acInstanceStateUpdate.setLockOrder(LockOrder.NONE);
+        acInstanceStateUpdate.setSubOrder(SubOrder.REVIEW);
+        provider.compositionInstanceState(compositionId, instanceId, acInstanceStateUpdate);
+        verify(supervisionAcHandler).review(any(AutomationComposition.class));
     }
 }
index e895401..2d9c128 100644 (file)
@@ -36,6 +36,7 @@ import java.util.UUID;
 import org.junit.jupiter.api.Test;
 import org.onap.policy.clamp.acm.runtime.instantiation.InstantiationUtils;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AcElementPropertiesPublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.AcPreparePublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionMigrationPublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher;
@@ -76,7 +77,7 @@ class SupervisionAcHandlerTest {
         var handler = new SupervisionAcHandler(automationCompositionProvider, acDefinitionProvider,
                 mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class),
                 mock(AcElementPropertiesPublisher.class), null,
-                mock(ParticipantSyncPublisher.class));
+                mock(ParticipantSyncPublisher.class), null);
 
         var automationCompositionAckMessage =
                 getAutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK,
@@ -124,7 +125,7 @@ class SupervisionAcHandlerTest {
         var handler = new SupervisionAcHandler(automationCompositionProvider, acDefinitionProvider,
                 mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class),
                 mock(AcElementPropertiesPublisher.class), null,
-                mock(ParticipantSyncPublisher.class));
+                mock(ParticipantSyncPublisher.class), null);
 
         handler.handleAutomationCompositionUpdateAckMessage(automationCompositionAckMessage);
 
@@ -161,7 +162,7 @@ class SupervisionAcHandlerTest {
 
         var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class),
                 mock(AutomationCompositionDeployPublisher.class), automationCompositionStateChangePublisher, null,
-                null, mock(ParticipantSyncPublisher.class));
+                null, mock(ParticipantSyncPublisher.class), null);
 
         handler.handleAutomationCompositionUpdateAckMessage(automationCompositionAckMessage);
 
@@ -175,7 +176,8 @@ class SupervisionAcHandlerTest {
         var automationCompositionProvider = mock(AutomationCompositionProvider.class);
         var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class),
                 automationCompositionDeployPublisher, mock(AutomationCompositionStateChangePublisher.class),
-                mock(AcElementPropertiesPublisher.class), null, mock(ParticipantSyncPublisher.class));
+                mock(AcElementPropertiesPublisher.class), null,
+                mock(ParticipantSyncPublisher.class), null);
 
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
@@ -195,7 +197,7 @@ class SupervisionAcHandlerTest {
         var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class),
                 mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher,
                 mock(AcElementPropertiesPublisher.class), null,
-                mock(ParticipantSyncPublisher.class));
+                mock(ParticipantSyncPublisher.class), null);
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var automationComposition =
@@ -213,7 +215,7 @@ class SupervisionAcHandlerTest {
         var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class),
                 mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher,
                 mock(AcElementPropertiesPublisher.class), null,
-                mock(ParticipantSyncPublisher.class));
+                mock(ParticipantSyncPublisher.class), null);
 
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
@@ -234,7 +236,7 @@ class SupervisionAcHandlerTest {
         var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class),
                 mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher,
                 mock(AcElementPropertiesPublisher.class), null,
-                mock(ParticipantSyncPublisher.class));
+                mock(ParticipantSyncPublisher.class), null);
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var automationComposition =
@@ -252,7 +254,7 @@ class SupervisionAcHandlerTest {
         var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class),
                 mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher,
                 mock(AcElementPropertiesPublisher.class), null,
-                mock(ParticipantSyncPublisher.class));
+                mock(ParticipantSyncPublisher.class), null);
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var automationComposition =
@@ -272,7 +274,7 @@ class SupervisionAcHandlerTest {
         var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class),
                 mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher,
                 mock(AcElementPropertiesPublisher.class), null,
-                mock(ParticipantSyncPublisher.class));
+                mock(ParticipantSyncPublisher.class), null);
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var automationComposition =
@@ -290,7 +292,7 @@ class SupervisionAcHandlerTest {
         var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class),
                 mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher,
                 mock(AcElementPropertiesPublisher.class), null,
-                mock(ParticipantSyncPublisher.class));
+                mock(ParticipantSyncPublisher.class), null);
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var automationComposition =
@@ -321,7 +323,7 @@ class SupervisionAcHandlerTest {
         var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class),
                 mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class),
                 mock(AcElementPropertiesPublisher.class), null,
-                mock(ParticipantSyncPublisher.class));
+                mock(ParticipantSyncPublisher.class), null);
 
         handler.handleAutomationCompositionUpdateAckMessage(automationCompositionAckMessage);
 
@@ -335,7 +337,7 @@ class SupervisionAcHandlerTest {
         var handler = new SupervisionAcHandler(mock(AutomationCompositionProvider.class),
                 mock(AcDefinitionProvider.class), mock(AutomationCompositionDeployPublisher.class),
                 mock(AutomationCompositionStateChangePublisher.class), acElementPropertiesPublisher, null,
-                mock(ParticipantSyncPublisher.class));
+                mock(ParticipantSyncPublisher.class), null);
         var automationComposition =
                 InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Lock");
         handler.update(automationComposition);
@@ -348,10 +350,46 @@ class SupervisionAcHandlerTest {
         var acCompositionMigrationPublisher = mock(AutomationCompositionMigrationPublisher.class);
         var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class),
                 null, null, null,
-                acCompositionMigrationPublisher, mock(ParticipantSyncPublisher.class));
+                acCompositionMigrationPublisher, mock(ParticipantSyncPublisher.class), null);
+        var automationComposition =
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Migrate");
+        handler.migrate(automationComposition);
+        verify(acCompositionMigrationPublisher, timeout(1000)).send(any(AutomationComposition.class));
+    }
+
+    @Test
+    void testMigratePrecheck() {
+        var automationCompositionProvider = mock(AutomationCompositionProvider.class);
+        var acCompositionMigrationPublisher = mock(AutomationCompositionMigrationPublisher.class);
+        var handler = new SupervisionAcHandler(automationCompositionProvider, null, null, null,
+                null, acCompositionMigrationPublisher, null, null);
+        var automationComposition =
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Migrate");
+        handler.migratePrecheck(automationComposition);
+        verify(acCompositionMigrationPublisher, timeout(1000)).send(any(AutomationComposition.class));
+    }
+
+    @Test
+    void testPrepare() {
+        var automationCompositionProvider = mock(AutomationCompositionProvider.class);
+        var acPreparePublisher = mock(AcPreparePublisher.class);
+        var handler = new SupervisionAcHandler(automationCompositionProvider, null, null, null,
+                null, null, null, acPreparePublisher);
+        var automationComposition =
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Migrate");
+        handler.prepare(automationComposition);
+        verify(acPreparePublisher, timeout(1000)).sendPrepare(any(AutomationComposition.class));
+    }
+
+    @Test
+    void testReview() {
+        var automationCompositionProvider = mock(AutomationCompositionProvider.class);
+        var acPreparePublisher = mock(AcPreparePublisher.class);
+        var handler = new SupervisionAcHandler(automationCompositionProvider, null, null, null,
+                null, null, null, acPreparePublisher);
         var automationComposition =
                 InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Migrate");
-        handler.migrate(automationComposition, UUID.randomUUID());
-        verify(acCompositionMigrationPublisher, timeout(1000)).send(any(AutomationComposition.class), any());
+        handler.review(automationComposition);
+        verify(acPreparePublisher, timeout(1000)).sendRevew(any(AutomationComposition.class));
     }
 }
index 7cf0bf8..77b47f4 100644 (file)
@@ -231,7 +231,29 @@ class SupervisionMessagesTest {
         publisher.active(topicSink);
         var automationComposition =
                 InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
-        publisher.send(automationComposition, UUID.randomUUID());
+        publisher.send(automationComposition);
+        verify(topicSink).send(anyString());
+    }
+
+    @Test
+    void testAcPreparePublisher() {
+        var publisher = new AcPreparePublisher();
+        var topicSink = mock(TopicSink.class);
+        publisher.active(topicSink);
+        var automationComposition =
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
+        publisher.sendPrepare(automationComposition);
+        verify(topicSink).send(anyString());
+    }
+
+    @Test
+    void testAcReviewPublisher() {
+        var publisher = new AcPreparePublisher();
+        var topicSink = mock(TopicSink.class);
+        publisher.active(topicSink);
+        var automationComposition =
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
+        publisher.sendRevew(automationComposition);
         verify(topicSink).send(anyString());
     }