Merge "Add support for Prime Deprime Failure Handling in ACM-Runtime"
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationCompositionDefinition.java b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationCompositionDefinition.java
index a8c0697..eb8a919 100644
--- a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationCompositionDefinition.java
+++ b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationCompositionDefinition.java
@@ -44,6 +44,8 @@
     @NonNull
     private AcTypeState state;
 
+    private StateChangeResult stateChangeResult;
+
     @NonNull
     // Map used to store prime state with key as NodeTemplate Name and value as NodeTemplateState
     private Map<String, NodeTemplateState> elementStateMap = new HashMap<>();
@@ -58,5 +60,6 @@
         this.serviceTemplate = new ToscaServiceTemplate(otherAcmDefinition.serviceTemplate);
         this.state = otherAcmDefinition.state;
         this.elementStateMap = PfUtils.mapMap(otherAcmDefinition.elementStateMap, NodeTemplateState::new);
+        this.stateChangeResult = otherAcmDefinition.stateChangeResult;
     }
 }
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/NodeTemplateState.java b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/NodeTemplateState.java
index 5d28cd7..62e9208 100644
--- a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/NodeTemplateState.java
+++ b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/NodeTemplateState.java
@@ -40,6 +40,8 @@
 
     private AcTypeState state;
 
+    private String message;
+
     /**
      * Copy constructor, does a deep copy but as all fields here are immutable, it's just a regular copy.
      *
@@ -50,5 +52,6 @@
         this.participantId = copyConstructor.participantId;
         this.nodeTemplateId = new ToscaConceptIdentifier(copyConstructor.nodeTemplateId);
         this.state = copyConstructor.state;
+        this.message = copyConstructor.message;
     }
 }
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionDefinition.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionDefinition.java
index 11e3f58..50949d7 100644
--- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionDefinition.java
+++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionDefinition.java
@@ -41,6 +41,7 @@
 import lombok.NonNull;
 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition;
+import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 import org.onap.policy.clamp.models.acm.document.base.ToscaServiceTemplateValidation;
 import org.onap.policy.clamp.models.acm.document.concepts.DocToscaServiceTemplate;
 import org.onap.policy.common.parameters.BeanValidationResult;
@@ -76,6 +77,9 @@
     @NotNull
     private AcTypeState state;
 
+    @Column
+    private StateChangeResult stateChangeResult;
+
     @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
     @JoinColumn(name = "compositionId", foreignKey = @ForeignKey(name = "dt_element_fk"))
     private Set<JpaNodeTemplateState> elements = new HashSet<>();
@@ -91,6 +95,7 @@
         var acmDefinition = new AutomationCompositionDefinition();
         acmDefinition.setCompositionId(UUID.fromString(this.compositionId));
         acmDefinition.setState(this.state);
+        acmDefinition.setStateChangeResult(this.stateChangeResult);
         acmDefinition.setServiceTemplate(this.serviceTemplate.toAuthorative());
         for (var element : this.elements) {
             var key = element.getNodeTemplateId().getName();
@@ -103,6 +108,7 @@
     public void fromAuthorative(final AutomationCompositionDefinition copyConcept) {
         this.compositionId = copyConcept.getCompositionId().toString();
         this.state = copyConcept.getState();
+        this.stateChangeResult = copyConcept.getStateChangeResult();
         this.serviceTemplate = new DocToscaServiceTemplate(copyConcept.getServiceTemplate());
         setName(this.serviceTemplate.getName());
         setVersion(this.serviceTemplate.getVersion());
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaNodeTemplateState.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaNodeTemplateState.java
index 19d25e1..8ee1075 100644
--- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaNodeTemplateState.java
+++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaNodeTemplateState.java
@@ -70,6 +70,9 @@
     @NotNull
     private AcTypeState state;
 
+    @Column
+    private String message;
+
     /**
      * The Default Constructor.
      */
@@ -96,6 +99,7 @@
         }
         this.nodeTemplateId = copyConcept.getNodeTemplateId().asConceptKey();
         this.state = copyConcept.getState();
+        this.message = copyConcept.getMessage();
     }
 
     @Override
@@ -107,6 +111,7 @@
         }
         nodeTemplateState.setNodeTemplateId(new ToscaConceptIdentifier(this.nodeTemplateId));
         nodeTemplateState.setState(this.state);
+        nodeTemplateState.setMessage(this.message);
         return nodeTemplateState;
     }
 }
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcTypeStateResolver.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcTypeStateResolver.java
index 7070a31..f1c9309 100644
--- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcTypeStateResolver.java
+++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcTypeStateResolver.java
@@ -21,6 +21,7 @@
 package org.onap.policy.clamp.models.acm.persistence.provider;
 
 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
+import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.PrimeOrder;
 import org.onap.policy.clamp.models.acm.utils.StateDefinition;
 import org.springframework.stereotype.Component;
@@ -33,17 +34,29 @@
     private static final String PRIME = PrimeOrder.PRIME.toString();
     private static final String DEPRIME = PrimeOrder.DEPRIME.toString();
     private static final String PRIMED = AcTypeState.PRIMED.toString();
+    private static final String PRIMING = AcTypeState.PRIMING.toString();
     private static final String COMMISSIONED = AcTypeState.COMMISSIONED.toString();
+    private static final String DEPRIMING = AcTypeState.DEPRIMING.toString();
+    private static final String NO_ERROR = StateChangeResult.NO_ERROR.name();
+    private static final String FAILED = StateChangeResult.FAILED.name();
 
     /**
      * Construct.
      */
     public AcTypeStateResolver() {
-        this.graph = new StateDefinition<>(2, PrimeOrder.NONE);
-        this.graph.put(new String[] {PRIME, PRIMED}, PrimeOrder.PRIME);
-        this.graph.put(new String[] {PRIME, COMMISSIONED}, PrimeOrder.PRIME);
-        this.graph.put(new String[] {DEPRIME, PRIMED}, PrimeOrder.DEPRIME);
-        this.graph.put(new String[] {DEPRIME, COMMISSIONED}, PrimeOrder.DEPRIME);
+        this.graph = new StateDefinition<>(3, PrimeOrder.NONE);
+
+        // no error
+        this.graph.put(new String[] {PRIME, PRIMED, NO_ERROR}, PrimeOrder.PRIME);
+        this.graph.put(new String[] {PRIME, COMMISSIONED, NO_ERROR}, PrimeOrder.PRIME);
+        this.graph.put(new String[] {DEPRIME, PRIMED, NO_ERROR}, PrimeOrder.DEPRIME);
+        this.graph.put(new String[] {DEPRIME, COMMISSIONED, NO_ERROR}, PrimeOrder.DEPRIME);
+
+        // failed
+        this.graph.put(new String[] {PRIME, PRIMING, FAILED}, PrimeOrder.PRIME);
+        this.graph.put(new String[] {DEPRIME, PRIMING, FAILED}, PrimeOrder.DEPRIME);
+        this.graph.put(new String[] {DEPRIME, DEPRIMING, FAILED}, PrimeOrder.DEPRIME);
+        this.graph.put(new String[] {PRIME, DEPRIMING, FAILED}, PrimeOrder.PRIME);
     }
 
     /**
@@ -51,11 +64,13 @@
      *
      * @param primeOrder the PrimeOrder
      * @param acTypeState then current AcTypeState
+     * @param acStateChangeResult the current Result of the State Change
      * @return primeOrder or NONE if the primeOrder is not consistent
      */
-    public PrimeOrder resolve(PrimeOrder primeOrder, AcTypeState acTypeState) {
+    public PrimeOrder resolve(PrimeOrder primeOrder, AcTypeState acTypeState, StateChangeResult acStateChangeResult) {
         var po = primeOrder != null ? primeOrder : PrimeOrder.NONE;
         var state = acTypeState != null ? acTypeState : AcTypeState.COMMISSIONED;
-        return this.graph.get(new String[] {po.toString(), state.toString()});
+        var stateChangeResult = acStateChangeResult != null ? acStateChangeResult : StateChangeResult.NO_ERROR;
+        return this.graph.get(new String[] {po.name(), state.name(), stateChangeResult.name()});
     }
 }
diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcTypeStateResolverTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcTypeStateResolverTest.java
index bf27c3e..5ea13c9 100644
--- a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcTypeStateResolverTest.java
+++ b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcTypeStateResolverTest.java
@@ -24,6 +24,7 @@
 
 import org.junit.jupiter.api.Test;
 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
+import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.PrimeOrder;
 
 class AcTypeStateResolverTest {
@@ -31,25 +32,26 @@
     @Test
     void testAcTypeState() {
         var acTypeStateResolver = new AcTypeStateResolver();
-        var result = acTypeStateResolver.resolve(PrimeOrder.PRIME, AcTypeState.COMMISSIONED);
+        var result =
+                acTypeStateResolver.resolve(PrimeOrder.PRIME, AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(PrimeOrder.PRIME);
-        result = acTypeStateResolver.resolve(PrimeOrder.PRIME, AcTypeState.PRIMED);
+        result = acTypeStateResolver.resolve(PrimeOrder.PRIME, AcTypeState.PRIMED, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(PrimeOrder.PRIME);
-        result = acTypeStateResolver.resolve(PrimeOrder.PRIME, AcTypeState.PRIMING);
+        result = acTypeStateResolver.resolve(PrimeOrder.PRIME, AcTypeState.PRIMING, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(PrimeOrder.NONE);
-        result = acTypeStateResolver.resolve(PrimeOrder.PRIME, AcTypeState.DEPRIMING);
+        result = acTypeStateResolver.resolve(PrimeOrder.PRIME, AcTypeState.DEPRIMING, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(PrimeOrder.NONE);
 
-        result = acTypeStateResolver.resolve(PrimeOrder.DEPRIME, AcTypeState.COMMISSIONED);
+        result = acTypeStateResolver.resolve(PrimeOrder.DEPRIME, AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(PrimeOrder.DEPRIME);
-        result = acTypeStateResolver.resolve(PrimeOrder.DEPRIME, AcTypeState.PRIMED);
+        result = acTypeStateResolver.resolve(PrimeOrder.DEPRIME, AcTypeState.PRIMED, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(PrimeOrder.DEPRIME);
-        result = acTypeStateResolver.resolve(PrimeOrder.DEPRIME, AcTypeState.PRIMING);
+        result = acTypeStateResolver.resolve(PrimeOrder.DEPRIME, AcTypeState.PRIMING, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(PrimeOrder.NONE);
-        result = acTypeStateResolver.resolve(PrimeOrder.DEPRIME, AcTypeState.DEPRIMING);
+        result = acTypeStateResolver.resolve(PrimeOrder.DEPRIME, AcTypeState.DEPRIMING, StateChangeResult.NO_ERROR);
         assertThat(result).isEqualTo(PrimeOrder.NONE);
 
-        result = acTypeStateResolver.resolve(null, null);
+        result = acTypeStateResolver.resolve(null, null, null);
         assertThat(result).isEqualTo(PrimeOrder.NONE);
     }
 }
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProvider.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProvider.java
index d8eddf5..1412076 100644
--- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProvider.java
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProvider.java
@@ -30,6 +30,7 @@
 import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantPrimePublisher;
 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition;
+import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.AcTypeStateUpdate;
 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
@@ -180,7 +181,8 @@
             throw new PfModelRuntimeException(Status.BAD_REQUEST, "There are instances, Priming/Depriming not allowed");
         }
         var acmDefinition = acDefinitionProvider.getAcDefinition(compositionId);
-        var stateOrdered = acTypeStateResolver.resolve(acTypeStateUpdate.getPrimeOrder(), acmDefinition.getState());
+        var stateOrdered = acTypeStateResolver.resolve(acTypeStateUpdate.getPrimeOrder(), acmDefinition.getState(),
+                acmDefinition.getStateChangeResult());
         switch (stateOrdered) {
             case PRIME:
                 prime(acmDefinition);
@@ -197,21 +199,24 @@
     }
 
     private void prime(AutomationCompositionDefinition acmDefinition) {
-        var prearation = participantPrimePublisher.prepareParticipantPriming(acmDefinition);
+        acmDefinition.setStateChangeResult(StateChangeResult.NO_ERROR);
+        var preparation = participantPrimePublisher.prepareParticipantPriming(acmDefinition);
         acDefinitionProvider.updateAcDefinition(acmDefinition);
 
         executor.execute(
-                () -> participantPrimePublisher.sendPriming(prearation, acmDefinition.getCompositionId(), null));
+                () -> participantPrimePublisher.sendPriming(preparation, acmDefinition.getCompositionId(), null));
     }
 
     private void deprime(AutomationCompositionDefinition acmDefinition) {
-        if (!AcTypeState.COMMISSIONED.equals(acmDefinition.getState())) {
-            for (var elementState : acmDefinition.getElementStateMap().values()) {
+        acmDefinition.setStateChangeResult(StateChangeResult.NO_ERROR);
+        for (var elementState : acmDefinition.getElementStateMap().values()) {
+            if (elementState.getParticipantId() != null) {
                 elementState.setState(AcTypeState.DEPRIMING);
             }
-            acmDefinition.setState(AcTypeState.DEPRIMING);
-            acDefinitionProvider.updateAcDefinition(acmDefinition);
         }
+        acmDefinition.setState(AcTypeState.DEPRIMING);
+        acDefinitionProvider.updateAcDefinition(acmDefinition);
+
         executor.execute(() -> participantPrimePublisher.sendDepriming(acmDefinition.getCompositionId()));
     }
 
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java
index e9f8d6c..536e3e2 100644
--- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java
@@ -78,8 +78,8 @@
         automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
         automationCompositionProvider.updateAutomationComposition(automationComposition);
         var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate());
-        automationCompositionDeployPublisher.send(automationComposition, acDefinition.getServiceTemplate(), startPhase,
-                true);
+        automationCompositionDeployPublisher.send(automationComposition, acDefinition.getServiceTemplate(),
+                startPhase, true);
     }
 
     /**
@@ -207,24 +207,25 @@
     }
 
     private void setAcElementStateInDb(AutomationCompositionDeployAck automationCompositionAckMessage) {
-        var automationComposition = automationCompositionProvider
+        var automationCompositionOpt = automationCompositionProvider
                 .findAutomationComposition(automationCompositionAckMessage.getAutomationCompositionId());
-        if (automationComposition.isEmpty()) {
+        if (automationCompositionOpt.isEmpty()) {
             LOGGER.warn("AutomationComposition not found in database {}",
                     automationCompositionAckMessage.getAutomationCompositionId());
             return;
         }
+        var automationComposition = automationCompositionOpt.get();
 
         if (automationCompositionAckMessage.getAutomationCompositionResultMap() == null
                 || automationCompositionAckMessage.getAutomationCompositionResultMap().isEmpty()) {
-            if (DeployState.DELETING.equals(automationComposition.get().getDeployState())) {
+            if (DeployState.DELETING.equals(automationComposition.getDeployState())) {
                 // scenario when Automation Composition instance has never been deployed
-                for (var element : automationComposition.get().getElements().values()) {
+                for (var element : automationComposition.getElements().values()) {
                     if (element.getParticipantId().equals(automationCompositionAckMessage.getParticipantId())) {
                         element.setDeployState(DeployState.DELETED);
                     }
                 }
-                automationCompositionProvider.updateAutomationComposition(automationComposition.get());
+                automationCompositionProvider.updateAutomationComposition(automationComposition);
             } else {
                 LOGGER.warn("Empty AutomationCompositionResultMap  {} {}",
                         automationCompositionAckMessage.getAutomationCompositionId(),
@@ -233,11 +234,11 @@
             return;
         }
 
-        var updated = updateState(automationComposition.get(),
+        var updated = updateState(automationComposition,
                 automationCompositionAckMessage.getAutomationCompositionResultMap().entrySet(),
                 automationCompositionAckMessage.getStateChangeResult());
         if (updated) {
-            automationCompositionProvider.updateAutomationComposition(automationComposition.get());
+            automationCompositionProvider.updateAutomationComposition(automationComposition);
         }
     }
 
@@ -246,7 +247,10 @@
             StateChangeResult stateChangeResult) {
         var updated = false;
         var elementInErrors = StateChangeResult.FAILED.equals(stateChangeResult);
-        boolean inProgress = StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult());
+        boolean inProgress = !StateChangeResult.FAILED.equals(automationComposition.getStateChangeResult());
+        if (elementInErrors && inProgress) {
+            automationComposition.setStateChangeResult(StateChangeResult.FAILED);
+        }
 
         for (var acElementAck : automationCompositionResultSet) {
             var element = automationComposition.getElements().get(acElementAck.getKey());
@@ -255,16 +259,11 @@
                 element.setOutProperties(acElementAck.getValue().getOutProperties());
                 element.setOperationalState(acElementAck.getValue().getOperationalState());
                 element.setUseState(acElementAck.getValue().getUseState());
+                element.setDeployState(acElementAck.getValue().getDeployState());
+                element.setLockState(acElementAck.getValue().getLockState());
                 updated = true;
-                if (!elementInErrors || inProgress) {
-                    element.setDeployState(acElementAck.getValue().getDeployState());
-                    element.setLockState(acElementAck.getValue().getLockState());
-                }
             }
         }
-        if (elementInErrors && inProgress) {
-            automationComposition.setStateChangeResult(stateChangeResult.FAILED);
-        }
         return updated;
     }
 }
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java
index 6a1e12f..862672f 100644
--- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java
@@ -24,6 +24,8 @@
 import io.micrometer.core.annotation.Timed;
 import lombok.AllArgsConstructor;
 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition;
+import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantPrimeAck;
 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
 import org.slf4j.Logger;
@@ -61,18 +63,34 @@
                     participantPrimeAckMessage.getCompositionId(), participantPrimeAckMessage.getParticipantId());
             return;
         }
-        var state = AcTypeState.PRIMING.equals(acDefinition.getState()) ? AcTypeState.PRIMED : AcTypeState.COMMISSIONED;
+        handleParticipantPrimeAck(participantPrimeAckMessage, acDefinition);
+    }
+
+    private void handleParticipantPrimeAck(ParticipantPrimeAck participantPrimeAckMessage,
+            AutomationCompositionDefinition acDefinition) {
+        var finalState =
+                AcTypeState.PRIMING.equals(acDefinition.getState()) ? AcTypeState.PRIMED : AcTypeState.COMMISSIONED;
+        var msgInErrors = StateChangeResult.FAILED.equals(participantPrimeAckMessage.getStateChangeResult());
+        boolean inProgress = !StateChangeResult.FAILED.equals(acDefinition.getStateChangeResult());
+        if (inProgress && msgInErrors) {
+            acDefinition.setStateChangeResult(StateChangeResult.FAILED);
+        }
+
         boolean completed = true;
         for (var element : acDefinition.getElementStateMap().values()) {
             if (participantPrimeAckMessage.getParticipantId().equals(element.getParticipantId())) {
-                element.setState(state);
-            } else if (!state.equals(element.getState())) {
+                element.setMessage(participantPrimeAckMessage.getMessage());
+                element.setState(participantPrimeAckMessage.getCompositionState());
+            }
+            if (!finalState.equals(element.getState())) {
                 completed = false;
             }
         }
-        if (completed) {
-            acDefinition.setState(state);
+
+        if (inProgress && !msgInErrors && completed) {
+            acDefinition.setState(finalState);
         }
         acDefinitionProvider.updateAcDefinition(acDefinition);
     }
+
 }
diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java
index 6988cd3..1f63c3d 100644
--- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java
+++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java
@@ -53,9 +53,10 @@
 
     @Test
     void testHandleAutomationCompositionStateChangeAckMessage() {
-        var automationCompositionProvider = mock(AutomationCompositionProvider.class);
         var automationComposition =
                 InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Crud");
+        automationComposition.setInstanceId(IDENTIFIER);
+        var automationCompositionProvider = mock(AutomationCompositionProvider.class);
         when(automationCompositionProvider.findAutomationComposition(IDENTIFIER))
                 .thenReturn(Optional.of(automationComposition));
 
@@ -64,38 +65,39 @@
                 mock(AcElementPropertiesPublisher.class));
 
         var automationCompositionAckMessage =
-                new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
-        for (var elementEntry : automationComposition.getElements().entrySet()) {
-            var acElementDeployAck =
-                    new AcElementDeployAck(DeployState.DEPLOYED, LockState.UNLOCKED, "", "", Map.of(), true, "");
-            automationCompositionAckMessage.getAutomationCompositionResultMap().put(elementEntry.getKey(),
-                    acElementDeployAck);
-        }
-        automationCompositionAckMessage.setAutomationCompositionId(IDENTIFIER);
-
+                getAutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK,
+                        automationComposition, DeployState.DEPLOYED, LockState.UNLOCKED);
         handler.handleAutomationCompositionStateChangeAckMessage(automationCompositionAckMessage);
 
         verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class));
     }
 
+    private AutomationCompositionDeployAck getAutomationCompositionDeployAck(ParticipantMessageType messageType,
+            AutomationComposition automationComposition, DeployState deployState, LockState lockState) {
+        var automationCompositionAckMessage = new AutomationCompositionDeployAck(messageType);
+        for (var elementEntry : automationComposition.getElements().entrySet()) {
+            var acElementDeployAck = new AcElementDeployAck(deployState, lockState, "", "", Map.of(), true, "");
+            automationCompositionAckMessage.getAutomationCompositionResultMap().put(elementEntry.getKey(),
+                    acElementDeployAck);
+        }
+        automationCompositionAckMessage.setAutomationCompositionId(automationComposition.getInstanceId());
+        automationCompositionAckMessage.setParticipantId(CommonTestData.getParticipantId());
+        return automationCompositionAckMessage;
+    }
+
     @Test
     void testHandleAutomationCompositionUpdateAckMessage() {
-        var automationCompositionProvider = mock(AutomationCompositionProvider.class);
         var automationComposition =
                 InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Crud");
+        automationComposition.setInstanceId(IDENTIFIER);
+        var automationCompositionProvider = mock(AutomationCompositionProvider.class);
         when(automationCompositionProvider.findAutomationComposition(IDENTIFIER))
                 .thenReturn(Optional.of(automationComposition));
 
         var automationCompositionAckMessage =
-                new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_DEPLOY_ACK);
-        for (var elementEntry : automationComposition.getElements().entrySet()) {
-            var acElementDeployAck =
-                    new AcElementDeployAck(DeployState.DEPLOYED, LockState.LOCKED, "", "", Map.of(), true, "");
-            automationCompositionAckMessage
-                    .setAutomationCompositionResultMap(Map.of(elementEntry.getKey(), acElementDeployAck));
-        }
+                getAutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_DEPLOY_ACK,
+                        automationComposition, DeployState.DEPLOYED, LockState.LOCKED);
         automationCompositionAckMessage.setParticipantId(CommonTestData.getParticipantId());
-        automationCompositionAckMessage.setAutomationCompositionId(IDENTIFIER);
 
         var handler = new SupervisionAcHandler(automationCompositionProvider,
                 mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class),
@@ -108,11 +110,11 @@
 
     @Test
     void testHandleAcUpdateAckFailedMessage() {
-        var automationCompositionProvider = mock(AutomationCompositionProvider.class);
         var automationComposition =
                 InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Crud");
         automationComposition.setDeployState(DeployState.DEPLOYING);
         automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
+        var automationCompositionProvider = mock(AutomationCompositionProvider.class);
         when(automationCompositionProvider.findAutomationComposition(IDENTIFIER))
                 .thenReturn(Optional.of(automationComposition));
 
diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java
index d4cc5e3..9ce63b0 100644
--- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java
+++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java
@@ -32,6 +32,7 @@
 import org.onap.policy.clamp.acm.runtime.util.CommonTestData;
 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
+import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantPrimeAck;
 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
 
@@ -78,6 +79,32 @@
         var acDefinition = CommonTestData.createAcDefinition(
                 InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML), AcTypeState.PRIMING);
         participantPrimeAckMessage.setCompositionId(acDefinition.getCompositionId());
+        acDefinition.getElementStateMap().values().iterator().next()
+                .setParticipantId(CommonTestData.getParticipantId());
+
+        var acDefinitionProvider = mock(AcDefinitionProvider.class);
+        when(acDefinitionProvider.findAcDefinition(acDefinition.getCompositionId()))
+                .thenReturn(Optional.of(acDefinition));
+
+        var handler = new SupervisionHandler(acDefinitionProvider);
+
+        handler.handleParticipantMessage(participantPrimeAckMessage);
+        verify(acDefinitionProvider).findAcDefinition(any());
+        verify(acDefinitionProvider).updateAcDefinition(any());
+    }
+
+    @Test
+    void testParticipantPrimeAckFailed() {
+        var participantPrimeAckMessage = new ParticipantPrimeAck();
+        participantPrimeAckMessage.setParticipantId(CommonTestData.getParticipantId());
+        participantPrimeAckMessage.setState(ParticipantState.ON_LINE);
+        participantPrimeAckMessage.setStateChangeResult(StateChangeResult.FAILED);
+
+        var acDefinition = CommonTestData.createAcDefinition(
+                InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML), AcTypeState.PRIMING);
+        participantPrimeAckMessage.setCompositionId(acDefinition.getCompositionId());
+        acDefinition.getElementStateMap().values().iterator().next()
+                .setParticipantId(CommonTestData.getParticipantId());
 
         var acDefinitionProvider = mock(AcDefinitionProvider.class);
         when(acDefinitionProvider.findAcDefinition(acDefinition.getCompositionId()))