Merge "Add Timeuot support in prime/deprime"
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantAckMessage.java b/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantAckMessage.java
index 3182332..56e5064 100644
--- a/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantAckMessage.java
+++ b/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantAckMessage.java
@@ -79,6 +79,7 @@
     public ParticipantAckMessage(ParticipantAckMessage source) {
         this.responseTo = source.responseTo;
         this.result = source.result;
+        this.stateChangeResult = source.stateChangeResult;
         this.message = source.message;
         this.messageType = source.messageType;
         this.participantId = source.participantId;
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantResponseStatus.java b/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantResponseStatus.java
deleted file mode 100644
index cb03077..0000000
--- a/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantResponseStatus.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021 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.models.acm.messages.dmaap.participant;
-
-/**
- * Class to hold the possible values for participant response status.
- */
-public enum ParticipantResponseStatus {
-
-    /**
-     * participant operation was successful.
-     */
-    SUCCESS,
-
-    /**
-     * participant operation failed.
-     */
-    FAIL,
-
-    /**
-     * periodic response.
-     */
-    PERIODIC
-}
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 f1c9309..d806156 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
@@ -39,6 +39,7 @@
     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();
+    private static final String TIMEOUT = StateChangeResult.TIMEOUT.name();
 
     /**
      * Construct.
@@ -57,6 +58,12 @@
         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);
+
+        // timeout
+        this.graph.put(new String[] {PRIME, PRIMING, TIMEOUT}, PrimeOrder.PRIME);
+        this.graph.put(new String[] {DEPRIME, PRIMING, TIMEOUT}, PrimeOrder.DEPRIME);
+        this.graph.put(new String[] {DEPRIME, DEPRIMING, TIMEOUT}, PrimeOrder.DEPRIME);
+        this.graph.put(new String[] {PRIME, DEPRIMING, TIMEOUT}, PrimeOrder.PRIME);
     }
 
     /**
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 862672f..a18ea19 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
@@ -89,6 +89,10 @@
 
         if (inProgress && !msgInErrors && completed) {
             acDefinition.setState(finalState);
+            if (StateChangeResult.TIMEOUT.equals(acDefinition.getStateChangeResult())) {
+                acDefinition.setStateChangeResult(StateChangeResult.NO_ERROR);
+            }
+
         }
         acDefinitionProvider.updateAcDefinition(acDefinition);
     }
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java
index b1bd292..0ccdaed 100644
--- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java
@@ -28,7 +28,9 @@
 import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher;
+import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+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;
@@ -85,15 +87,41 @@
 
         var list = acDefinitionProvider.getAllAcDefinitions();
         for (var acDefinition : list) {
-            var acList = automationCompositionProvider.getAcInstancesByCompositionId(acDefinition.getCompositionId());
-            for (var automationComposition : acList) {
-                scanAutomationComposition(automationComposition, acDefinition.getServiceTemplate());
+            if (AcTypeState.PRIMING.equals(acDefinition.getState())
+                    || AcTypeState.DEPRIMING.equals(acDefinition.getState())) {
+                scanAutomationCompositionDefinition(acDefinition);
+            } else {
+                acTimeout.clear(acDefinition.getCompositionId());
+                var acList =
+                        automationCompositionProvider.getAcInstancesByCompositionId(acDefinition.getCompositionId());
+                for (var automationComposition : acList) {
+                    scanAutomationComposition(automationComposition, acDefinition.getServiceTemplate());
+                }
             }
         }
 
         LOGGER.debug("Automation composition scan complete . . .");
     }
 
+    private void scanAutomationCompositionDefinition(AutomationCompositionDefinition acDefinition) {
+        if (StateChangeResult.FAILED.equals(acDefinition.getStateChangeResult())) {
+            LOGGER.debug("automation definition {} scanned, OK", acDefinition.getCompositionId());
+
+            // Clear Timeout on ac Definition
+            acTimeout.clear(acDefinition.getCompositionId());
+            return;
+        }
+
+        if (acTimeout.isTimeout(acDefinition.getCompositionId())
+                && StateChangeResult.NO_ERROR.equals(acDefinition.getStateChangeResult())) {
+            // retry by the user
+            LOGGER.debug("clearing Timeout for the ac definition");
+            acTimeout.clear(acDefinition.getCompositionId());
+        }
+
+        handleTimeout(acDefinition);
+    }
+
     private void scanAutomationComposition(final AutomationComposition automationComposition,
             ToscaServiceTemplate serviceTemplate) {
         LOGGER.debug("scanning automation composition {} . . .", automationComposition.getInstanceId());
@@ -188,6 +216,21 @@
         }
     }
 
+    private void handleTimeout(AutomationCompositionDefinition acDefinition) {
+        var compositionId = acDefinition.getCompositionId();
+        if (acTimeout.isTimeout(compositionId)) {
+            LOGGER.debug("The ac definition is in timeout {}", acDefinition.getCompositionId());
+            return;
+        }
+
+        if (acTimeout.getDuration(compositionId) > acTimeout.getMaxWaitMs()) {
+            LOGGER.debug("Report timeout for the ac definition {}", acDefinition.getCompositionId());
+            acTimeout.setTimeout(compositionId);
+            acDefinition.setStateChangeResult(StateChangeResult.TIMEOUT);
+            acDefinitionProvider.updateAcDefinition(acDefinition);
+        }
+    }
+
     private void handleTimeout(AutomationComposition automationComposition) {
         var instanceId = automationComposition.getInstanceId();
         if (acTimeout.isTimeout(instanceId)) {
diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java
index 99af728..9b596c8 100644
--- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java
+++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java
@@ -33,17 +33,18 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.UUID;
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.onap.policy.clamp.acm.runtime.instantiation.InstantiationUtils;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher;
 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.AutomationComposition;
 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.StateChangeResult;
 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
@@ -52,18 +53,52 @@
 
     private static final String AC_JSON = "src/test/resources/rest/acm/AutomationCompositionSmoke.json";
 
-    private static final AcDefinitionProvider acDefinitionProvider = mock(AcDefinitionProvider.class);
+    private static final UUID compositionId = UUID.randomUUID();
 
-    private static UUID compositionId;
-
-    @BeforeAll
-    public static void setUpBeforeAll() {
+    private AcDefinitionProvider createAcDefinitionProvider(AcTypeState acTypeState,
+            StateChangeResult stateChangeResult) {
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = new AutomationCompositionDefinition();
-        compositionId = UUID.randomUUID();
+        acDefinition.setState(acTypeState);
+        acDefinition.setStateChangeResult(stateChangeResult);
         acDefinition.setCompositionId(compositionId);
         acDefinition.setServiceTemplate(serviceTemplate);
+        var acDefinitionProvider = mock(AcDefinitionProvider.class);
         when(acDefinitionProvider.getAllAcDefinitions()).thenReturn(List.of(Objects.requireNonNull(acDefinition)));
+        return acDefinitionProvider;
+    }
+
+    private AcDefinitionProvider createAcDefinitionProvider() {
+        return createAcDefinitionProvider(AcTypeState.PRIMED, StateChangeResult.NO_ERROR);
+    }
+
+    @Test
+    void testScannerOrderedFailed() {
+        var acDefinitionProvider = createAcDefinitionProvider(AcTypeState.PRIMING, StateChangeResult.FAILED);
+        var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner");
+        var supervisionScanner = new SupervisionScanner(mock(AutomationCompositionProvider.class), acDefinitionProvider,
+                mock(AutomationCompositionStateChangePublisher.class), mock(AutomationCompositionDeployPublisher.class),
+                acRuntimeParameterGroup);
+        supervisionScanner.run();
+        verify(acDefinitionProvider, times(0)).updateAcDefinition(any(AutomationCompositionDefinition.class));
+    }
+
+    @Test
+    void testScannerOrderedPriming() {
+        var acDefinitionProvider = createAcDefinitionProvider(AcTypeState.PRIMING, StateChangeResult.NO_ERROR);
+        var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner");
+        var supervisionScanner = new SupervisionScanner(mock(AutomationCompositionProvider.class), acDefinitionProvider,
+                mock(AutomationCompositionStateChangePublisher.class), mock(AutomationCompositionDeployPublisher.class),
+                acRuntimeParameterGroup);
+        supervisionScanner.run();
+        verify(acDefinitionProvider, times(0)).updateAcDefinition(any(AutomationCompositionDefinition.class));
+
+        acRuntimeParameterGroup.getParticipantParameters().setMaxStatusWaitMs(-1);
+        supervisionScanner = new SupervisionScanner(mock(AutomationCompositionProvider.class), acDefinitionProvider,
+                mock(AutomationCompositionStateChangePublisher.class), mock(AutomationCompositionDeployPublisher.class),
+                acRuntimeParameterGroup);
+        supervisionScanner.run();
+        verify(acDefinitionProvider).updateAcDefinition(any(AutomationCompositionDefinition.class));
     }
 
     @Test
@@ -77,7 +112,7 @@
         when(automationCompositionProvider.getAcInstancesByCompositionId(compositionId))
                 .thenReturn(List.of(automationComposition));
 
-        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, acDefinitionProvider,
+        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, createAcDefinitionProvider(),
                 automationCompositionStateChangePublisher, automationCompositionDeployPublisher,
                 acRuntimeParameterGroup);
         supervisionScanner.run();
@@ -98,7 +133,7 @@
         var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class);
         var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner");
 
-        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, acDefinitionProvider,
+        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, createAcDefinitionProvider(),
                 automationCompositionStateChangePublisher, automationCompositionDeployPublisher,
                 acRuntimeParameterGroup);
         supervisionScanner.run();
@@ -106,7 +141,6 @@
         verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class));
     }
 
-
     @Test
     void testScannerDelete() {
         var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud");
@@ -120,7 +154,7 @@
         var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class);
         var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner");
 
-        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, acDefinitionProvider,
+        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, createAcDefinitionProvider(),
                 automationCompositionStateChangePublisher, automationCompositionDeployPublisher,
                 acRuntimeParameterGroup);
         supervisionScanner.run();
@@ -139,7 +173,7 @@
         var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class);
         var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner");
 
-        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, acDefinitionProvider,
+        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, createAcDefinitionProvider(),
                 automationCompositionStateChangePublisher, automationCompositionDeployPublisher,
                 acRuntimeParameterGroup);
 
@@ -164,8 +198,8 @@
         var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner");
         acRuntimeParameterGroup.getParticipantParameters().setMaxStatusWaitMs(-1);
 
-        //verify timeout scenario
-        var scannerObj2 = new SupervisionScanner(automationCompositionProvider, acDefinitionProvider,
+        // verify timeout scenario
+        var scannerObj2 = new SupervisionScanner(automationCompositionProvider, createAcDefinitionProvider(),
                 automationCompositionStateChangePublisher, automationCompositionDeployPublisher,
                 acRuntimeParameterGroup);
 
@@ -198,7 +232,7 @@
         var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class);
         var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner");
 
-        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, acDefinitionProvider,
+        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, createAcDefinitionProvider(),
                 automationCompositionStateChangePublisher, automationCompositionDeployPublisher,
                 acRuntimeParameterGroup);
 
@@ -232,7 +266,7 @@
         var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class);
         var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner");
 
-        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, acDefinitionProvider,
+        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, createAcDefinitionProvider(),
                 automationCompositionStateChangePublisher, automationCompositionDeployPublisher,
                 acRuntimeParameterGroup);
 
diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/comm/SupervisionMessagesTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/comm/SupervisionMessagesTest.java
index e0accc4..4ff759c 100644
--- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/comm/SupervisionMessagesTest.java
+++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/comm/SupervisionMessagesTest.java
@@ -60,6 +60,8 @@
 
 class SupervisionMessagesTest {
 
+    private static final String AC_INSTANTIATION_UPDATE_JSON =
+            "src/test/resources/rest/acm/AutomationCompositionUpdate.json";
     private static final String NOT_ACTIVE = "Not Active!";
     private static final CommInfrastructure INFRA = CommInfrastructure.NOOP;
     private static final String TOPIC = "my-topic";
@@ -207,6 +209,17 @@
     }
 
     @Test
+    void testAcElementPropertiesPublisher() {
+        var publisher = new AcElementPropertiesPublisher();
+        var topicSink = mock(TopicSink.class);
+        publisher.active(List.of(topicSink));
+        var automationComposition =
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
+        publisher.send(automationComposition);
+        verify(topicSink).send(anyString());
+    }
+
+    @Test
     void testParticipantRegisterListener() {
         final var participantRegister = new ParticipantRegister();
         var supervisionHandler = mock(SupervisionParticipantHandler.class);