46002cb61ab19b062f16d059e7efbc8ad4fd8701
[policy/clamp.git] /
1 /*-
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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.clamp.acm.participant.intermediary.handler;
22
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;
32
33 import java.util.List;
34 import java.util.Map;
35 import java.util.UUID;
36 import org.junit.jupiter.api.Test;
37 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
38 import org.onap.policy.clamp.acm.participant.intermediary.handler.cache.AcDefinition;
39 import org.onap.policy.clamp.acm.participant.intermediary.handler.cache.CacheProvider;
40 import org.onap.policy.clamp.acm.participant.intermediary.main.parameters.CommonTestData;
41 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
42 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
43 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
44 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
45 import org.onap.policy.clamp.models.acm.concepts.DeployState;
46 import org.onap.policy.clamp.models.acm.concepts.LockState;
47 import org.onap.policy.clamp.models.acm.concepts.MigrationState;
48 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
49 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy;
50 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
51 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
52 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange;
53 import org.onap.policy.clamp.models.acm.messages.kafka.participant.PropertiesUpdate;
54 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
55 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
56 import org.onap.policy.clamp.models.acm.utils.AcmStateUtils;
57 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
58
59 class AutomationCompositionHandlerTest {
60
61     @Test
62     void handleAutomationCompositionStateChangeNullTest() {
63         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
64         var cacheProvider = mock(CacheProvider.class);
65         var ach =
66                 new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, mock(ThreadHandler.class));
67
68         var automationCompositionStateChange = new AutomationCompositionStateChange();
69         assertDoesNotThrow(() -> ach.handleAutomationCompositionStateChange(automationCompositionStateChange));
70
71         automationCompositionStateChange.setAutomationCompositionId(UUID.randomUUID());
72         automationCompositionStateChange.setDeployOrderedState(DeployOrder.DELETE);
73         assertDoesNotThrow(() -> ach.handleAutomationCompositionStateChange(automationCompositionStateChange));
74         verify(participantMessagePublisher).sendAutomationCompositionAck(any(AutomationCompositionDeployAck.class));
75
76         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
77         automationCompositionStateChange.setAutomationCompositionId(automationComposition.getInstanceId());
78         when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
79                 .thenReturn(automationComposition);
80         automationCompositionStateChange.setDeployOrderedState(DeployOrder.UPDATE);
81         assertDoesNotThrow(() -> ach.handleAutomationCompositionStateChange(automationCompositionStateChange));
82     }
83
84     @Test
85     void handleAcStateChangeUndeployTest() {
86         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
87         automationComposition.setCompositionId(UUID.randomUUID());
88         automationComposition.setInstanceId(UUID.randomUUID());
89         automationComposition.setCompositionTargetId(UUID.randomUUID());
90         var participantDeploy =
91                 CommonTestData.createparticipantDeploy(CommonTestData.getParticipantId(), automationComposition);
92
93         var cacheProvider = new CacheProvider(CommonTestData.getParticipantParameters());
94         cacheProvider.initializeAutomationComposition(automationComposition.getCompositionId(),
95                 automationComposition.getInstanceId(), participantDeploy, UUID.randomUUID());
96
97         var automationCompositionStateChange = CommonTestData.getStateChange(CommonTestData.getParticipantId(),
98                 automationComposition.getInstanceId(), DeployOrder.UNDEPLOY, LockOrder.NONE);
99
100         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
101         var listener = mock(ThreadHandler.class);
102         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
103         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
104         automationComposition = cacheProvider.getAutomationComposition(automationComposition.getInstanceId());
105         verify(listener, times(automationComposition.getElements().size())).undeploy(any(), any(), any());
106         for (var element : automationComposition.getElements().values()) {
107             assertEquals(DeployState.UNDEPLOYING, element.getDeployState());
108         }
109     }
110
111     @Test
112     void handleAutomationCompositionStateChangeUndeployTest() {
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());
118
119         var acDefinition = new AcDefinition();
120         acDefinition.setCompositionId(automationComposition.getCompositionId());
121         for (var element : automationComposition.getElements().values()) {
122             acDefinition.getElements().put(element.getDefinition(), new AutomationCompositionElementDefinition());
123         }
124         when(cacheProvider.getAcElementsDefinitions())
125             .thenReturn(Map.of(automationComposition.getCompositionId(), acDefinition));
126         var automationCompositionStateChange = CommonTestData.getStateChange(CommonTestData.getParticipantId(),
127             automationComposition.getInstanceId(), DeployOrder.UNDEPLOY, LockOrder.NONE);
128
129         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
130         var listener = mock(ThreadHandler.class);
131         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
132         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
133         verify(listener, times(automationComposition.getElements().size())).undeploy(any(), any(), any());
134         for (var element : automationComposition.getElements().values()) {
135             assertEquals(DeployState.UNDEPLOYING, element.getDeployState());
136         }
137
138         clearInvocations(listener);
139         automationCompositionStateChange.setStartPhase(2);
140         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
141         verify(listener, times(0)).undeploy(any(), any(), any());
142     }
143
144     @Test
145     void handleAutomationCompositionStateChangeDeleteTest() {
146         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
147         var cacheProvider = mock(CacheProvider.class);
148         when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
149                 .thenReturn(automationComposition);
150         when(cacheProvider.getCommonProperties(any(UUID.class), any(UUID.class))).thenReturn(Map.of());
151
152         var acDefinition = new AcDefinition();
153         acDefinition.setCompositionId(automationComposition.getCompositionId());
154         for (var element : automationComposition.getElements().values()) {
155             acDefinition.getElements().put(element.getDefinition(), new AutomationCompositionElementDefinition());
156         }
157         when(cacheProvider.getAcElementsDefinitions())
158             .thenReturn(Map.of(automationComposition.getCompositionId(), acDefinition));
159         var automationCompositionStateChange = CommonTestData.getStateChange(CommonTestData.getParticipantId(),
160             automationComposition.getInstanceId(), DeployOrder.DELETE, LockOrder.NONE);
161         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
162         var listener = mock(ThreadHandler.class);
163         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
164         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
165         verify(listener, times(automationComposition.getElements().size())).delete(any(), any(), any());
166         for (var element : automationComposition.getElements().values()) {
167             assertEquals(DeployState.DELETING, element.getDeployState());
168         }
169
170         clearInvocations(listener);
171         automationCompositionStateChange.setStartPhase(2);
172         ach.handleAutomationCompositionStateChange(automationCompositionStateChange);
173         verify(listener, times(0)).delete(any(), any(), any());
174     }
175
176     @Test
177     void handleAcPropertyUpdateTest() {
178         var cacheProvider = mock(CacheProvider.class);
179         var listener = mock(ThreadHandler.class);
180         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
181         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
182
183         var updateMsg = new PropertiesUpdate();
184         assertDoesNotThrow(() -> ach.handleAcPropertyUpdate(updateMsg));
185
186         updateMsg.setParticipantId(CommonTestData.getParticipantId());
187         when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId());
188         var participantDeploy = new ParticipantDeploy();
189         participantDeploy.setParticipantId(CommonTestData.getParticipantId());
190         updateMsg.getParticipantUpdatesList().add(participantDeploy);
191
192         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
193         updateMsg.setAutomationCompositionId(automationComposition.getInstanceId());
194         when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
195                 .thenReturn(automationComposition);
196         var acElementDeploy = new AcElementDeploy();
197         acElementDeploy.setProperties(Map.of());
198         acElementDeploy.setId(automationComposition.getElements().values().iterator().next().getId());
199         participantDeploy.getAcElementList().add(acElementDeploy);
200
201         var acDefinition = new AcDefinition();
202         acDefinition.setCompositionId(automationComposition.getCompositionId());
203         for (var element : automationComposition.getElements().values()) {
204             acDefinition.getElements().put(element.getDefinition(), new AutomationCompositionElementDefinition());
205         }
206         when(cacheProvider.getAcElementsDefinitions())
207             .thenReturn(Map.of(automationComposition.getCompositionId(), acDefinition));
208         ach.handleAcPropertyUpdate(updateMsg);
209         verify(listener).update(any(), any(), any(), any());
210     }
211
212     @Test
213     void handleAutomationCompositionDeployTest() {
214         var cacheProvider = mock(CacheProvider.class);
215         var listener = mock(ThreadHandler.class);
216         var participantMessagePublisher = mock(ParticipantMessagePublisher.class);
217         var ach = new AutomationCompositionHandler(cacheProvider, participantMessagePublisher, listener);
218
219         var deployMsg = new AutomationCompositionDeploy();
220         assertDoesNotThrow(() -> ach.handleAutomationCompositionDeploy(deployMsg));
221
222         deployMsg.setParticipantId(CommonTestData.getParticipantId());
223         when(cacheProvider.getParticipantId()).thenReturn(CommonTestData.getParticipantId());
224         var participantDeploy = new ParticipantDeploy();
225         participantDeploy.setParticipantId(CommonTestData.getParticipantId());
226         deployMsg.getParticipantUpdatesList().add(participantDeploy);
227
228         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
229         deployMsg.setAutomationCompositionId(automationComposition.getInstanceId());
230         when(cacheProvider.getAutomationComposition(automationComposition.getInstanceId()))
231                 .thenReturn(automationComposition);
232         var acDefinition = new AcDefinition();
233         acDefinition.setCompositionId(automationComposition.getCompositionId());
234         for (var element : automationComposition.getElements().values()) {
235             var acElementDeploy = new AcElementDeploy();
236             acElementDeploy.setProperties(Map.of());
237             acElementDeploy.setId(element.getId());
238             participantDeploy.getAcElementList().add(acElementDeploy);
239             acDefinition.getElements().put(element.getDefinition(), new AutomationCompositionElementDefinition());
240         }
241         when(cacheProvider.getAcElementsDefinitions())
242             .thenReturn(Map.of(automationComposition.getCompositionId(), acDefinition));
243
244         ach.handleAutomationCompositionDeploy(deployMsg);
245         verify(listener, times(automationComposition.getElements().size())).deploy(any(), any(), any());
246
247         clearInvocations(listener);
248         deployMsg.setStartPhase(2);
249         deployMsg.setFirstStartPhase(false);
250         ach.handleAutomationCompositionDeploy(deployMsg);
251         verify(listener, times(0)).deploy(any(), any(), any());
252     }
253
254     @Test
255     void handleAutomationCompositionMigrationTest() {
256         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
257         automationComposition.setCompositionId(UUID.randomUUID());
258         automationComposition.setInstanceId(UUID.randomUUID());
259         automationComposition.setCompositionTargetId(UUID.randomUUID());
260         var definitions =
261                 CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition);
262         var participantDeploy =
263                 CommonTestData.createparticipantDeploy(CommonTestData.getParticipantId(), automationComposition);
264
265         var cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
266                 automationComposition.getInstanceId(), definitions,
267                 automationComposition.getCompositionTargetId(), definitions);
268
269         var cacheProviderRollback = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
270                 automationComposition.getInstanceId(), definitions,
271                 automationComposition.getCompositionTargetId(), definitions);
272
273         testMigration(cacheProvider, automationComposition, 0,
274                 automationComposition.getElements().size(), false);
275         testMigration(cacheProviderRollback, automationComposition, 0,
276                 automationComposition.getElements().size(), true);
277     }
278
279     @Test
280     void handleAcMigrationStageTest() {
281         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
282         AcmStateUtils.setCascadedState(automationComposition, DeployState.DEPLOYED, LockState.LOCKED);
283         automationComposition.setCompositionId(UUID.randomUUID());
284         automationComposition.setInstanceId(UUID.randomUUID());
285
286         var acMigrate = new AutomationComposition(automationComposition);
287         AcmStateUtils.setCascadedState(acMigrate, DeployState.MIGRATING, LockState.LOCKED);
288         acMigrate.setCompositionTargetId(UUID.randomUUID());
289
290         // remove first element
291         var elementRemoved = acMigrate.getElements().values().iterator().next();
292         elementRemoved.setMigrationState(MigrationState.REMOVED);
293
294         // add new element
295         var element = new AutomationCompositionElement(elementRemoved);
296         element.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.2.4"));
297         element.setId(UUID.randomUUID());
298         element.setMigrationState(MigrationState.NEW);
299         acMigrate.getElements().put(element.getId(), element);
300
301         // replacing definition version excluding the removed element
302         acMigrate.getElements().values().stream()
303                 .filter(el -> !el.getId().equals(elementRemoved.getId()))
304                 .forEach(el -> el.setDefinition(
305                         new ToscaConceptIdentifier(el.getDefinition().getName(), "1.2.4")));
306
307         var migrateDefinitions =
308                 CommonTestData.createAutomationCompositionElementDefinitionList(acMigrate);
309
310         // scenario 1,2
311         migrateDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate()
312                 .setProperties(Map.of("stage", List.of(1, 2))));
313
314         var participantDeploy =
315                 CommonTestData.createparticipantDeploy(CommonTestData.getParticipantId(), automationComposition);
316         var definitions =
317                 CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition);
318         var cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
319                 automationComposition.getInstanceId(), definitions,
320                 acMigrate.getCompositionTargetId(), migrateDefinitions);
321
322         definitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate()
323                 .setProperties(Map.of("stage", List.of(1, 2))));
324         automationComposition.getElements().put(element.getId(), element);
325
326         // expected the element deleted
327         testMigration(cacheProvider, acMigrate, 0, 1, false);
328
329         // expected 4 elements from stage 1
330         testMigration(cacheProvider, acMigrate, 1, 4, false);
331
332         // scenario 0,2
333         cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(),
334                 automationComposition.getInstanceId(), definitions,
335                 acMigrate.getCompositionTargetId(), migrateDefinitions);
336
337         migrateDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate()
338                 .setProperties(Map.of("stage", List.of(0, 2))));
339
340         // expected the element deleted + 4 elements from stage 0
341         testMigration(cacheProvider, acMigrate, 0, 5, false);
342
343         // expected 0 elements
344         testMigration(cacheProvider, acMigrate, 1, 0, false);
345     }
346
347     private CacheProvider createCacheProvider(ParticipantDeploy participantDeploy,
348             UUID compositionId, UUID instanceId, List<AutomationCompositionElementDefinition> definitions,
349             UUID compositionTargetId, List<AutomationCompositionElementDefinition> migrateDefinitions) {
350         var cacheProvider = new CacheProvider(CommonTestData.getParticipantParameters());
351         cacheProvider.addElementDefinition(compositionId, definitions, UUID.randomUUID());
352         cacheProvider.initializeAutomationComposition(compositionId, instanceId, participantDeploy, UUID.randomUUID());
353         cacheProvider.addElementDefinition(compositionTargetId, migrateDefinitions, UUID.randomUUID());
354         return cacheProvider;
355     }
356
357     private void testMigration(CacheProvider cacheProvider, AutomationComposition acMigrate,
358             int stage, int expectedMigrated, boolean rollback) {
359         var migrationMsg = new AutomationCompositionMigration();
360         migrationMsg.setStage(stage);
361         migrationMsg.setCompositionId(acMigrate.getCompositionId());
362         migrationMsg.setAutomationCompositionId(acMigrate.getInstanceId());
363         migrationMsg.setCompositionTargetId(acMigrate.getCompositionTargetId());
364         var participantMigrate = CommonTestData.createparticipantDeploy(cacheProvider.getParticipantId(), acMigrate);
365         migrationMsg.setParticipantUpdatesList(List.of(participantMigrate));
366         var listener = mock(ThreadHandler.class);
367
368         clearInvocations();
369         var ach = new AutomationCompositionHandler(cacheProvider,
370                 mock(ParticipantMessagePublisher.class), listener);
371
372         clearInvocations();
373         migrationMsg.setRollback(rollback);
374         ach.handleAutomationCompositionMigration(migrationMsg);
375
376         if (!rollback) {
377             verify(listener, times(expectedMigrated)).migrate(any(), any(), any(), any(), any(), anyInt());
378         } else {
379             verify(listener, times(expectedMigrated)).rollback(any(), any(), any(), any(), any(), anyInt());
380         }
381     }
382
383     @Test
384     void handleAcRollbackStageTest() {
385         var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
386         AcmStateUtils.setCascadedState(automationComposition, DeployState.MIGRATING, LockState.LOCKED);
387         automationComposition.setCompositionId(UUID.randomUUID());
388         automationComposition.setInstanceId(UUID.randomUUID());
389         automationComposition.setCompositionTargetId(UUID.randomUUID());
390
391         var acRollback = new AutomationComposition(automationComposition);
392         AcmStateUtils.setCascadedState(acRollback, DeployState.MIGRATION_REVERTING, LockState.LOCKED);
393
394         var acRollbackDefinitions =
395                 CommonTestData.createAutomationCompositionElementDefinitionList(acRollback);
396         acRollbackDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate()
397                 .setProperties(Map.of("stage", List.of(1, 2))));
398
399         // remove first element
400         var elementRemoved = automationComposition.getElements().values().iterator().next();
401         elementRemoved.setMigrationState(MigrationState.REMOVED);
402         acRollback.getElements().get(elementRemoved.getId()).setMigrationState(MigrationState.REMOVED);
403
404         // add new element
405         var element = new AutomationCompositionElement(elementRemoved);
406         element.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.2.4"));
407         element.setId(UUID.randomUUID());
408         element.setMigrationState(MigrationState.NEW);
409         automationComposition.getElements().put(element.getId(), element);
410         acRollback.getElements().put(element.getId(), element);
411
412         // replacing definition version excluding the removed element
413         automationComposition.getElements().values().stream()
414                 .filter(el -> !el.getId().equals(elementRemoved.getId()))
415                 .forEach(el -> el.setDefinition(
416                         new ToscaConceptIdentifier(el.getDefinition().getName(), "1.2.4")));
417
418         var acDefinitions =
419                 CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition);
420         acDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate()
421                 .setProperties(Map.of("stage", List.of(1, 2))));
422
423         var participantDeploy =
424                 CommonTestData.createparticipantDeploy(CommonTestData.getParticipantId(), automationComposition);
425         var cacheProvider = new CacheProvider(CommonTestData.getParticipantParameters());
426         cacheProvider.addElementDefinition(
427                 automationComposition.getCompositionTargetId(), acDefinitions, UUID.randomUUID());
428         cacheProvider.initializeAutomationComposition(automationComposition.getCompositionId(),
429                 automationComposition.getInstanceId(), participantDeploy, UUID.randomUUID());
430         cacheProvider.addElementDefinition(
431                 automationComposition.getCompositionId(), acRollbackDefinitions, UUID.randomUUID());
432
433         // expected the new element deleted
434         testMigration(cacheProvider, acRollback, 0, 1, true);
435
436         // expected default elements
437         testMigration(cacheProvider, acRollback, 1, 4, true);
438
439         // expected default elements
440         testMigration(cacheProvider, acRollback, 2, 4, true);
441     }
442
443 }