2  * ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
 
   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.junit.jupiter.api.Assertions.assertDoesNotThrow;
 
  24 import static org.junit.jupiter.api.Assertions.assertEquals;
 
  25 import static org.mockito.ArgumentMatchers.any;
 
  26 import static org.mockito.ArgumentMatchers.anyInt;
 
  27 import static org.mockito.Mockito.clearInvocations;
 
  28 import static org.mockito.Mockito.mock;
 
  29 import static org.mockito.Mockito.times;
 
  30 import static org.mockito.Mockito.verify;
 
  31 import static org.mockito.Mockito.when;
 
  33 import java.util.HashMap;
 
  34 import java.util.List;
 
  36 import java.util.UUID;
 
  37 import org.junit.jupiter.api.Test;
 
  38 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
 
  39 import org.onap.policy.clamp.acm.participant.intermediary.main.parameters.CommonTestData;
 
  40 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
 
  41 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
 
  42 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
 
  43 import org.onap.policy.clamp.models.acm.concepts.DeployState;
 
  44 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
 
  45 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy;
 
  46 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
 
  47 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
 
  48 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange;
 
  49 import org.onap.policy.clamp.models.acm.messages.kafka.participant.PropertiesUpdate;
 
  50 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
 
  51 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
 
  52 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
 
  54 class AutomationCompositionHandlerTest {
 
  57     void handleAutomationCompositionStateChangeNullTest() {
 
  58         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
 
  59         var cacheProvider = mock(CacheProvider.class);
 
  61                 new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, mock(ThreadHandler.class));
 
  63         var automationCompositionStateChange = new AutomationCompositionStateChange();
 
  64         assertDoesNotThrow(() -> ach.handleAutomationCompositionStateChange(automationCompositionStateChange));
 
  66         automationCompositionStateChange.setAutomationCompositionId(UUID.randomUUID());
 
  67         automationCompositionStateChange.setDeployOrderedState(DeployOrder.DELETE);
 
  68         assertDoesNotThrow(() -> ach.handleAutomationCompositionStateChange(automationCompositionStateChange));
 
  69         verify(participantMessagePublisher).sendAutomationCompositionAck(any(AutomationCompositionDeployAck.class));
 
  71         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
 
  72         automationCompositionStateChange.setAutomationCompositionId(automationComposition.getInstanceId());
 
  73         when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
 
  74                 .thenReturn(automationComposition);
 
  75         automationCompositionStateChange.setDeployOrderedState(DeployOrder.UPDATE);
 
  76         assertDoesNotThrow(() -> ach.handleAutomationCompositionStateChange(automationCompositionStateChange));
 
  80     void handleAutomationCompositionStateChangeUndeployTest() {
 
  81         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
 
  82         var cacheProvider = mock(CacheProvider.class);
 
  83         when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
 
  84                 .thenReturn(automationComposition);
 
  85         when(cacheProvider.getCommonProperties(any(UUID.class), any(UUID.class))).thenReturn(Map.of());
 
  87         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
 
  88         var listener = mock(ThreadHandler.class);
 
  89         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
 
  90         Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> map = new HashMap<>();
 
  91         for (var element : automationComposition.getElements().values()) {
 
  92             map.put(element.getDefinition(), new AutomationCompositionElementDefinition());
 
  94         when(cacheProvider.getAcElementsDefinitions())
 
  95             .thenReturn(Map.of(automationComposition.getCompositionId(), map));
 
  96         var automationCompositionStateChange = CommonTestData.getStateChange(CommonTestData.getParticipantId(),
 
  97             automationComposition.getInstanceId(), DeployOrder.UNDEPLOY, LockOrder.NONE);
 
  99         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
 
 100         verify(listener, times(automationComposition.getElements().size())).undeploy(any(), any(), any());
 
 101         for (var element : automationComposition.getElements().values()) {
 
 102             assertEquals(DeployState.UNDEPLOYING, element.getDeployState());
 
 105         clearInvocations(listener);
 
 106         automationCompositionStateChange.setStartPhase(2);
 
 107         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
 
 108         verify(listener, times(0)).undeploy(any(), any(), any());
 
 112     void handleAutomationCompositionStateChangeDeleteTest() {
 
 113         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
 
 114         var cacheProvider = mock(CacheProvider.class);
 
 115         when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
 
 116                 .thenReturn(automationComposition);
 
 117         when(cacheProvider.getCommonProperties(any(UUID.class), any(UUID.class))).thenReturn(Map.of());
 
 119         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
 
 120         var listener = mock(ThreadHandler.class);
 
 121         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
 
 122         Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> map = new HashMap<>();
 
 123         for (var element : automationComposition.getElements().values()) {
 
 124             map.put(element.getDefinition(), new AutomationCompositionElementDefinition());
 
 126         when(cacheProvider.getAcElementsDefinitions())
 
 127             .thenReturn(Map.of(automationComposition.getCompositionId(), map));
 
 128         var automationCompositionStateChange = CommonTestData.getStateChange(CommonTestData.getParticipantId(),
 
 129             automationComposition.getInstanceId(), DeployOrder.DELETE, LockOrder.NONE);
 
 130         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
 
 131         verify(listener, times(automationComposition.getElements().size())).delete(any(), any(), any());
 
 132         for (var element : automationComposition.getElements().values()) {
 
 133             assertEquals(DeployState.DELETING, element.getDeployState());
 
 136         clearInvocations(listener);
 
 137         automationCompositionStateChange.setStartPhase(2);
 
 138         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
 
 139         verify(listener, times(0)).delete(any(), any(), any());
 
 143     void handleAcPropertyUpdateTest() {
 
 144         var cacheProvider = mock(CacheProvider.class);
 
 145         var listener = mock(ThreadHandler.class);
 
 146         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
 
 147         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
 
 149         var updateMsg = new PropertiesUpdate();
 
 150         assertDoesNotThrow(() -> ach.handleAcPropertyUpdate(updateMsg));
 
 152         updateMsg.setParticipantId(CommonTestData.getParticipantId());
 
 153         when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId());
 
 154         var participantDeploy = new ParticipantDeploy();
 
 155         participantDeploy.setParticipantId(CommonTestData.getParticipantId());
 
 156         updateMsg.getParticipantUpdatesList().add(participantDeploy);
 
 158         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
 
 159         updateMsg.setAutomationCompositionId(automationComposition.getInstanceId());
 
 160         when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
 
 161                 .thenReturn(automationComposition);
 
 162         var acElementDeploy = new AcElementDeploy();
 
 163         acElementDeploy.setProperties(Map.of());
 
 164         acElementDeploy.setId(automationComposition.getElements().values().iterator().next().getId());
 
 165         participantDeploy.getAcElementList().add(acElementDeploy);
 
 167         Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> map = new HashMap<>();
 
 168         for (var element : automationComposition.getElements().values()) {
 
 169             map.put(element.getDefinition(), new AutomationCompositionElementDefinition());
 
 171         when(cacheProvider.getAcElementsDefinitions())
 
 172             .thenReturn(Map.of(automationComposition.getCompositionId(), map));
 
 173         ach.handleAcPropertyUpdate(updateMsg);
 
 174         verify(listener).update(any(), any(), any(), any());
 
 178     void handleAutomationCompositionDeployTest() {
 
 179         var cacheProvider = mock(CacheProvider.class);
 
 180         var listener = mock(ThreadHandler.class);
 
 181         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
 
 182         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
 
 184         var deployMsg = new AutomationCompositionDeploy();
 
 185         assertDoesNotThrow(() -> ach.handleAutomationCompositionDeploy(deployMsg));
 
 187         deployMsg.setParticipantId(CommonTestData.getParticipantId());
 
 188         when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId());
 
 189         var participantDeploy = new ParticipantDeploy();
 
 190         participantDeploy.setParticipantId(CommonTestData.getParticipantId());
 
 191         deployMsg.getParticipantUpdatesList().add(participantDeploy);
 
 193         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
 
 194         deployMsg.setAutomationCompositionId(automationComposition.getInstanceId());
 
 195         when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
 
 196                 .thenReturn(automationComposition);
 
 197         Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> map = new HashMap<>();
 
 198         for (var element : automationComposition.getElements().values()) {
 
 199             var acElementDeploy = new AcElementDeploy();
 
 200             acElementDeploy.setProperties(Map.of());
 
 201             acElementDeploy.setId(element.getId());
 
 202             participantDeploy.getAcElementList().add(acElementDeploy);
 
 203             map.put(element.getDefinition(), new AutomationCompositionElementDefinition());
 
 205         when(cacheProvider.getAcElementsDefinitions())
 
 206             .thenReturn(Map.of(automationComposition.getCompositionId(), map));
 
 208         ach.handleAutomationCompositionDeploy(deployMsg);
 
 209         verify(listener, times(automationComposition.getElements().size())).deploy(any(), any(), any());
 
 211         clearInvocations(listener);
 
 212         deployMsg.setStartPhase(2);
 
 213         deployMsg.setFirstStartPhase(false);
 
 214         ach.handleAutomationCompositionDeploy(deployMsg);
 
 215         verify(listener, times(0)).deploy(any(), any(), any());
 
 219     void handleMigrationNullTest() {
 
 220         var ach = new AutomationCompositionHandler(
 
 221                 mock(CacheProvider.class), mock(ParticipantMessagePublisher.class), mock(ThreadHandler.class));
 
 222         var migrationMsg = new AutomationCompositionMigration();
 
 223         var rollbackMsg = new AutomationCompositionMigration();
 
 224         rollbackMsg.setRollback(true);
 
 226         migrationMsg.setStage(0);
 
 227         assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(migrationMsg));
 
 228         migrationMsg.setAutomationCompositionId(UUID.randomUUID());
 
 229         migrationMsg.setCompositionTargetId(UUID.randomUUID());
 
 230         assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(migrationMsg));
 
 232         rollbackMsg.setStage(0);
 
 233         assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(rollbackMsg));
 
 234         rollbackMsg.setAutomationCompositionId(UUID.randomUUID());
 
 235         rollbackMsg.setCompositionTargetId(UUID.randomUUID());
 
 236         assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(rollbackMsg));
 
 240     void handleAutomationCompositionMigrationTest() {
 
 241         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
 
 242         automationComposition.setCompositionId(UUID.randomUUID());
 
 243         automationComposition.setInstanceId(UUID.randomUUID());
 
 244         automationComposition.setCompositionTargetId(UUID.randomUUID());
 
 246                 CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition);
 
 247         var participantDeploy =
 
 248                 CommonTestData.createparticipantDeploy(CommonTestData.getParticipantId(), automationComposition);
 
 250         var cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
 
 251                 automationComposition.getInstanceId(), definitions,
 
 252                 automationComposition.getCompositionTargetId(), definitions);
 
 254         var cacheProviderRollback = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
 
 255                 automationComposition.getInstanceId(), definitions,
 
 256                 automationComposition.getCompositionTargetId(), definitions);
 
 258         testMigration(cacheProvider, automationComposition, 0,
 
 259                 automationComposition.getElements().size(), false);
 
 260         testMigration(cacheProviderRollback, automationComposition, 0,
 
 261                 automationComposition.getElements().size(), true);
 
 265     void handleMigrationAddRemoveTest() {
 
 266         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
 
 267         automationComposition.setCompositionId(UUID.randomUUID());
 
 268         automationComposition.setInstanceId(UUID.randomUUID());
 
 270         var acMigrate = new AutomationComposition(automationComposition);
 
 271         acMigrate.setCompositionTargetId(UUID.randomUUID());
 
 273         // replacing first element with new one
 
 274         var element = acMigrate.getElements().values().iterator().next();
 
 275         element.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.0.0"));
 
 276         element.setId(UUID.randomUUID());
 
 278         var migrateDefinitions =
 
 279                 CommonTestData.createAutomationCompositionElementDefinitionList(acMigrate);
 
 281         var participantDeploy =
 
 282                 CommonTestData.createparticipantDeploy(CommonTestData.getParticipantId(), automationComposition);
 
 284                 CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition);
 
 285         var cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
 
 286                 automationComposition.getInstanceId(), definitions,
 
 287                 acMigrate.getCompositionTargetId(), migrateDefinitions);
 
 288         var cacheProviderRollback = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
 
 289                 automationComposition.getInstanceId(), definitions,
 
 290                 acMigrate.getCompositionTargetId(), migrateDefinitions);
 
 292         testMigration(cacheProvider, acMigrate, 0, acMigrate.getElements().size() + 1, false);
 
 293         testMigration(cacheProviderRollback, acMigrate, 0, acMigrate.getElements().size() + 1, true);
 
 297     void handleAcMigrationStageTest() {
 
 298         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
 
 299         automationComposition.setCompositionId(UUID.randomUUID());
 
 300         automationComposition.setInstanceId(UUID.randomUUID());
 
 302         var acMigrate = new AutomationComposition(automationComposition);
 
 303         acMigrate.setCompositionTargetId(UUID.randomUUID());
 
 305         // replacing first element with new one
 
 306         var element = acMigrate.getElements().values().iterator().next();
 
 307         element.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.2.4"));
 
 308         element.setId(UUID.randomUUID());
 
 310         // replacing definition version
 
 311         acMigrate.getElements().values().forEach(el -> el.setDefinition(
 
 312                 new ToscaConceptIdentifier(el.getDefinition().getName(), "1.2.4")));
 
 314         var migrateDefinitions =
 
 315                 CommonTestData.createAutomationCompositionElementDefinitionList(acMigrate);
 
 317         migrateDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate()
 
 318                 .setProperties(Map.of("stage", List.of(0, 1))));
 
 320         var participantDeploy =
 
 321                 CommonTestData.createparticipantDeploy(CommonTestData.getParticipantId(), automationComposition);
 
 323                 CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition);
 
 324         var cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
 
 325                 automationComposition.getInstanceId(), definitions,
 
 326                 acMigrate.getCompositionTargetId(), migrateDefinitions);
 
 327         var cacheProviderRollback = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
 
 328                 automationComposition.getInstanceId(), definitions,
 
 329                 acMigrate.getCompositionTargetId(), migrateDefinitions);
 
 333         migrateDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate()
 
 334                 .setProperties(Map.of("stage", List.of(1, 2))));
 
 336         // expected the element deleted
 
 337         testMigration(cacheProvider, acMigrate, 0, 1, false);
 
 338         testMigration(cacheProviderRollback, acMigrate, 0, 1, true);
 
 340         // expected 4 elements from stage 1
 
 341         testMigration(cacheProvider, acMigrate, 1, 4, false);
 
 342         testMigration(cacheProviderRollback, acMigrate, 1, 4, true);
 
 345         cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
 
 346                 automationComposition.getInstanceId(), definitions,
 
 347                 acMigrate.getCompositionTargetId(), migrateDefinitions);
 
 348         cacheProviderRollback = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
 
 349                 automationComposition.getInstanceId(), definitions,
 
 350                 acMigrate.getCompositionTargetId(), migrateDefinitions);
 
 352         migrateDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate()
 
 353                 .setProperties(Map.of("stage", List.of(0, 2))));
 
 355         // expected the element deleted + 4 elements from stage 0
 
 356         testMigration(cacheProvider, acMigrate, 0, 5, false);
 
 357         testMigration(cacheProviderRollback, acMigrate, 0, 5, true);
 
 359         // expected 0 elements
 
 360         testMigration(cacheProvider, acMigrate, 1, 0, false);
 
 361         testMigration(cacheProviderRollback, acMigrate, 1, 0, true);
 
 364     private CacheProvider createCacheProvider(ParticipantDeploy participantDeploy,
 
 365             UUID compositionId, UUID instanceId, List<AutomationCompositionElementDefinition> definitions,
 
 366             UUID compositionTargetId, List<AutomationCompositionElementDefinition> migrateDefinitions) {
 
 367         var cacheProvider = new CacheProvider(CommonTestData.getParticipantParameters());
 
 368         cacheProvider.addElementDefinition(compositionId, definitions);
 
 369         cacheProvider.initializeAutomationComposition(compositionId, instanceId, participantDeploy);
 
 370         cacheProvider.addElementDefinition(compositionTargetId, migrateDefinitions);
 
 371         return cacheProvider;
 
 374     private void testMigration(CacheProvider cacheProvider, AutomationComposition acMigrate,
 
 375             int stage, int expectedMigrated, boolean rollback) {
 
 376         var migrationMsg = new AutomationCompositionMigration();
 
 377         migrationMsg.setStage(stage);
 
 378         migrationMsg.setCompositionId(acMigrate.getCompositionId());
 
 379         migrationMsg.setAutomationCompositionId(acMigrate.getInstanceId());
 
 380         migrationMsg.setCompositionTargetId(acMigrate.getCompositionTargetId());
 
 381         var participantMigrate = CommonTestData.createparticipantDeploy(cacheProvider.getParticipantId(), acMigrate);
 
 382         migrationMsg.setParticipantUpdatesList(List.of(participantMigrate));
 
 383         var listener = mock(ThreadHandler.class);
 
 386         var ach = new AutomationCompositionHandler(cacheProvider,
 
 387                 mock(ParticipantMessagePublisher.class), listener);
 
 390         migrationMsg.setRollback(rollback);
 
 391         ach.handleAutomationCompositionMigration(migrationMsg);
 
 394             verify(listener, times(expectedMigrated)).migrate(any(), any(), any(), any(), any(), anyInt());
 
 396             verify(listener, times(expectedMigrated)).rollback(any(), any(), any(), anyInt());