2  * ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2023-2024 Nordix Foundation.
 
   4  * ================================================================================
 
   5  * Licensed under the Apache License, Version 2.0 (the "License");
 
   6  * you may not use this file except in compliance with the License.
 
   7  * You may obtain a copy of the License at
 
   9  *      http://www.apache.org/licenses/LICENSE-2.0
 
  11  * Unless required by applicable law or agreed to in writing, software
 
  12  * distributed under the License is distributed on an "AS IS" BASIS,
 
  13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  14  * See the License for the specific language governing permissions and
 
  15  * limitations under the License.
 
  17  * SPDX-License-Identifier: Apache-2.0
 
  18  * ============LICENSE_END=========================================================
 
  21 package org.onap.policy.clamp.acm.participant.intermediary.handler;
 
  23 import static org.mockito.Mockito.clearInvocations;
 
  24 import static org.mockito.Mockito.doThrow;
 
  25 import static org.mockito.Mockito.mock;
 
  26 import static org.mockito.Mockito.timeout;
 
  27 import static org.mockito.Mockito.verify;
 
  29 import jakarta.ws.rs.core.Response.Status;
 
  30 import java.io.IOException;
 
  32 import java.util.UUID;
 
  33 import org.junit.jupiter.api.Test;
 
  34 import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener;
 
  35 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionDto;
 
  36 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
 
  37 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
 
  38 import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
 
  39 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
 
  40 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
 
  41 import org.onap.policy.clamp.models.acm.concepts.DeployState;
 
  42 import org.onap.policy.clamp.models.acm.concepts.LockState;
 
  43 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 
  44 import org.onap.policy.models.base.PfModelException;
 
  45 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
 
  47 class ThreadHandlerTest {
 
  49     private static final int TIMEOUT = 400;
 
  52     void testPrime() throws PfModelException, IOException {
 
  53         var listener = mock(AutomationCompositionElementListener.class);
 
  54         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
 
  55         try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
 
  57             var compositionId = UUID.randomUUID();
 
  58             var messageId = UUID.randomUUID();
 
  59             var composition = new CompositionDto(compositionId, Map.of(), Map.of());
 
  60             threadHandler.prime(messageId, composition);
 
  61             verify(listener, timeout(TIMEOUT)).prime(composition);
 
  63             clearInvocations(listener);
 
  64             threadHandler.deprime(messageId, composition);
 
  65             verify(listener, timeout(TIMEOUT)).deprime(composition);
 
  70     void testPrimeException() throws PfModelException, IOException {
 
  71         var listener = mock(AutomationCompositionElementListener.class);
 
  72         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
 
  73         try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
 
  75             var compositionId = UUID.randomUUID();
 
  76             var composition = new CompositionDto(compositionId, Map.of(), Map.of());
 
  77             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener).prime(composition);
 
  78             var messageId = UUID.randomUUID();
 
  79             threadHandler.prime(messageId, composition);
 
  80             verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.COMMISSIONED,
 
  81                 StateChangeResult.FAILED, "Composition Defintion prime failed");
 
  83             clearInvocations(listener);
 
  84             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener).deprime(composition);
 
  85             threadHandler.deprime(messageId, composition);
 
  86             verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.PRIMED,
 
  87                 StateChangeResult.FAILED, "Composition Defintion deprime failed");
 
  92     void testDeploy() throws PfModelException, IOException {
 
  93         var listener = mock(AutomationCompositionElementListener.class);
 
  94         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
 
  95         try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
 
  97             Map<String, Object> properties = Map.of("key", "value");
 
  98             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
 
  99                 properties, properties);
 
 100             var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
 
 101                     null, properties, properties);
 
 102             var messageId = UUID.randomUUID();
 
 103             threadHandler.deploy(messageId, compositionElement, instanceElement);
 
 104             verify(listener, timeout(TIMEOUT)).deploy(compositionElement, instanceElement);
 
 106             clearInvocations(listener);
 
 107             var element = new AcElementDeploy();
 
 108             var elementId = UUID.randomUUID();
 
 109             element.setId(elementId);
 
 110             var instanceElementUpdated = new InstanceElementDto(instanceElement.instanceId(),
 
 111                 instanceElement.elementId(), null, properties, properties);
 
 112             threadHandler.update(messageId, compositionElement, instanceElement, instanceElementUpdated);
 
 113             verify(listener, timeout(TIMEOUT)).update(compositionElement, instanceElement, instanceElementUpdated);
 
 115             clearInvocations(listener);
 
 116             var compositionTargetId = UUID.randomUUID();
 
 117             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
 
 118                 properties, properties);
 
 119             threadHandler.migrate(messageId, compositionElement, compositionElementTarget,
 
 120                 instanceElement, instanceElementUpdated);
 
 121             verify(listener, timeout(TIMEOUT)).migrate(compositionElement, compositionElementTarget,
 
 122                 instanceElement, instanceElementUpdated);
 
 124             clearInvocations(listener);
 
 125             threadHandler.undeploy(messageId, compositionElement, instanceElement);
 
 126             verify(listener, timeout(TIMEOUT)).undeploy(compositionElement, instanceElement);
 
 128             clearInvocations(listener);
 
 129             threadHandler.delete(messageId, compositionElement, instanceElement);
 
 130             verify(listener, timeout(TIMEOUT)).delete(compositionElement, instanceElement);
 
 135     void testDeployException() throws PfModelException, IOException {
 
 136         var listener = mock(AutomationCompositionElementListener.class);
 
 137         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
 
 138         try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
 
 140             Map<String, Object> properties = Map.of("key", "value");
 
 141             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
 
 142                 properties, properties);
 
 143             var instanceId = UUID.randomUUID();
 
 144             var elementId = UUID.randomUUID();
 
 145             var instanceElement = new InstanceElementDto(instanceId, elementId, null, properties, properties);
 
 146             var element = new AcElementDeploy();
 
 147             element.setId(elementId);
 
 148             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
 
 149                 .deploy(compositionElement, instanceElement);
 
 150             var messageId = UUID.randomUUID();
 
 151             threadHandler.deploy(messageId, compositionElement, instanceElement);
 
 152             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
 
 153                 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
 
 154                     "Automation composition element deploy failed");
 
 156             clearInvocations(listener);
 
 157             var instanceElementUpdated = new InstanceElementDto(instanceElement.instanceId(),
 
 158                 instanceElement.elementId(), null, properties, properties);
 
 159             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
 
 160                 .update(compositionElement, instanceElement, instanceElementUpdated);
 
 161             threadHandler.update(messageId, compositionElement, instanceElement, instanceElementUpdated);
 
 162             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
 
 163                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
 
 164                 "Automation composition element update failed");
 
 166             clearInvocations(listener);
 
 167             var compositionTargetId = UUID.randomUUID();
 
 168             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
 
 169                 properties, properties);
 
 170             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
 
 171                 .migrate(compositionElement, compositionElementTarget, instanceElement, instanceElementUpdated);
 
 172             threadHandler.migrate(messageId, compositionElement, compositionElementTarget,
 
 173                 instanceElement, instanceElementUpdated);
 
 174             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
 
 175                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
 
 176                 "Automation composition element migrate failed");
 
 178             clearInvocations(listener);
 
 179             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
 
 180                 .undeploy(compositionElement, instanceElement);
 
 181             threadHandler.undeploy(messageId, compositionElement, instanceElement);
 
 182             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
 
 183                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
 
 184                 "Automation composition element undeploy failed");
 
 186             clearInvocations(listener);
 
 187             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
 
 188                 .delete(compositionElement, instanceElement);
 
 189             threadHandler.delete(messageId, compositionElement, instanceElement);
 
 190             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
 
 191                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
 
 192                     "Automation composition element delete failed");
 
 197     void testLock() throws PfModelException, IOException {
 
 198         var listener = mock(AutomationCompositionElementListener.class);
 
 199         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
 
 200         try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
 
 202             Map<String, Object> properties = Map.of("key", "value");
 
 203             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
 
 204                 properties, properties);
 
 205             var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
 
 206                 null, properties, properties);
 
 207             var messageId = UUID.randomUUID();
 
 208             threadHandler.lock(messageId, compositionElement, instanceElement);
 
 209             verify(listener, timeout(TIMEOUT)).lock(compositionElement, instanceElement);
 
 211             clearInvocations(listener);
 
 212             threadHandler.unlock(messageId, compositionElement, instanceElement);
 
 213             verify(listener, timeout(TIMEOUT)).unlock(compositionElement, instanceElement);
 
 215             clearInvocations(listener);
 
 216             threadHandler.undeploy(messageId, compositionElement, instanceElement);
 
 217             verify(listener, timeout(TIMEOUT)).undeploy(compositionElement, instanceElement);
 
 222     void testLockException() throws PfModelException, IOException {
 
 223         var listener = mock(AutomationCompositionElementListener.class);
 
 224         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
 
 225         try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
 
 227             Map<String, Object> properties = Map.of("key", "value");
 
 228             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
 
 229                 properties, properties);
 
 230             var instanceId = UUID.randomUUID();
 
 231             var elementId = UUID.randomUUID();
 
 232             var instanceElement = new InstanceElementDto(instanceId, elementId, null, properties, properties);
 
 233             var element = new AcElementDeploy();
 
 234             element.setId(elementId);
 
 235             var messageId = UUID.randomUUID();
 
 236             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
 
 237                 .lock(compositionElement, instanceElement);
 
 238             threadHandler.lock(messageId, compositionElement, instanceElement);
 
 239             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
 
 240                 null, LockState.UNLOCKED, StateChangeResult.FAILED, "Automation composition element lock failed");
 
 242             clearInvocations(listener);
 
 243             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
 
 244                 .unlock(compositionElement, instanceElement);
 
 245             threadHandler.unlock(messageId, compositionElement, instanceElement);
 
 246             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
 
 247                 null, LockState.LOCKED, StateChangeResult.FAILED, "Automation composition element unlock failed");
 
 252     void testSubState() throws PfModelException, IOException {
 
 253         var listener = mock(AutomationCompositionElementListener.class);
 
 254         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
 
 255         try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
 
 257             Map<String, Object> properties = Map.of("key", "value");
 
 258             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
 
 259                 properties, properties);
 
 260             var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
 
 261                 null, properties, properties);
 
 262             var messageId = UUID.randomUUID();
 
 263             threadHandler.prepare(messageId, compositionElement, instanceElement);
 
 264             verify(listener, timeout(TIMEOUT)).prepare(compositionElement, instanceElement);
 
 266             clearInvocations(listener);
 
 267             threadHandler.review(messageId, compositionElement, instanceElement);
 
 268             verify(listener, timeout(TIMEOUT)).review(compositionElement, instanceElement);
 
 270             clearInvocations(listener);
 
 271             var instanceElementMigrate = new InstanceElementDto(instanceElement.instanceId(),
 
 272                 instanceElement.elementId(), null, properties, properties);
 
 273             var compositionTargetId = UUID.randomUUID();
 
 274             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
 
 275                 properties, properties);
 
 276             threadHandler.migratePrecheck(messageId, compositionElement, compositionElementTarget,
 
 277                 instanceElement, instanceElementMigrate);
 
 278             verify(listener, timeout(TIMEOUT)).migratePrecheck(compositionElement, compositionElementTarget,
 
 279                 instanceElement, instanceElementMigrate);
 
 284     void testSubStateException() throws PfModelException, IOException {
 
 285         var listener = mock(AutomationCompositionElementListener.class);
 
 286         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
 
 287         try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
 
 289             Map<String, Object> properties = Map.of("key", "value");
 
 290             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
 
 291                 properties, properties);
 
 292             var instanceId = UUID.randomUUID();
 
 293             var elementId = UUID.randomUUID();
 
 294             var instanceElement = new InstanceElementDto(instanceId, elementId, null, properties, properties);
 
 295             var element = new AcElementDeploy();
 
 296             element.setId(elementId);
 
 297             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
 
 298                 .prepare(compositionElement, instanceElement);
 
 299             var messageId = UUID.randomUUID();
 
 300             threadHandler.prepare(messageId, compositionElement, instanceElement);
 
 301             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
 
 302                 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
 
 303                 "Automation composition element prepare Pre Deploy failed");
 
 305             clearInvocations(listener);
 
 306             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
 
 307                 .review(compositionElement, instanceElement);
 
 308             threadHandler.review(messageId, compositionElement, instanceElement);
 
 309             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
 
 310                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
 
 311                 "Automation composition element Review failed");
 
 313             clearInvocations(listener);
 
 314             var compositionTargetId = UUID.randomUUID();
 
 315             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
 
 316                 properties, properties);
 
 317             var instanceElementMigrate = new InstanceElementDto(instanceElement.instanceId(),
 
 318                 instanceElement.elementId(), null, properties, properties);
 
 319             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
 
 320                 .migratePrecheck(compositionElement, compositionElementTarget, instanceElement, instanceElementMigrate);
 
 321             threadHandler.migratePrecheck(messageId, compositionElement, compositionElementTarget,
 
 322                 instanceElement, instanceElementMigrate);
 
 323             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
 
 324                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
 
 325                 "Automation composition element migrate precheck failed");