8846442e26a97da8ff480e12e8912ec794d296df
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2023-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.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;
28
29 import jakarta.ws.rs.core.Response.Status;
30 import java.io.IOException;
31 import java.util.Map;
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.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.AcTypeState;
42 import org.onap.policy.clamp.models.acm.concepts.DeployState;
43 import org.onap.policy.clamp.models.acm.concepts.LockState;
44 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
45 import org.onap.policy.models.base.PfModelException;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
47
48 class ThreadHandlerTest {
49
50     private static final int TIMEOUT = 400;
51
52     private ThreadHandler createThreadHandler(AutomationCompositionElementListener listener,
53             ParticipantIntermediaryApi intermediaryApi) {
54         return new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class),
55                 CommonTestData.getParticipantParameters());
56     }
57
58     @Test
59     void testPrime() throws PfModelException, IOException {
60         var listener = mock(AutomationCompositionElementListener.class);
61         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
62         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
63
64             var compositionId = UUID.randomUUID();
65             var messageId = UUID.randomUUID();
66             var composition = new CompositionDto(compositionId, Map.of(), Map.of());
67             threadHandler.prime(messageId, composition);
68             verify(listener, timeout(TIMEOUT)).prime(composition);
69
70             clearInvocations(listener);
71             threadHandler.deprime(messageId, composition);
72             verify(listener, timeout(TIMEOUT)).deprime(composition);
73         }
74     }
75
76     @Test
77     void testPrimeException() throws PfModelException, IOException {
78         var listener = mock(AutomationCompositionElementListener.class);
79         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
80         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
81
82             var compositionId = UUID.randomUUID();
83             var composition = new CompositionDto(compositionId, Map.of(), Map.of());
84             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener).prime(composition);
85             var messageId = UUID.randomUUID();
86             threadHandler.prime(messageId, composition);
87             verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.COMMISSIONED,
88                 StateChangeResult.FAILED, "Composition Defintion prime failed");
89
90             clearInvocations(listener);
91             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener).deprime(composition);
92             threadHandler.deprime(messageId, composition);
93             verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.PRIMED,
94                 StateChangeResult.FAILED, "Composition Defintion deprime failed");
95         }
96     }
97
98     @Test
99     void testDeploy() throws PfModelException, IOException {
100         var listener = mock(AutomationCompositionElementListener.class);
101         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
102         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
103
104             Map<String, Object> properties = Map.of("key", "value");
105             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
106                 properties, properties);
107             var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
108                 properties, properties);
109             var messageId = UUID.randomUUID();
110             threadHandler.deploy(messageId, compositionElement, instanceElement);
111             verify(listener, timeout(TIMEOUT)).deploy(compositionElement, instanceElement);
112
113             clearInvocations(listener);
114             var element = new AcElementDeploy();
115             var elementId = UUID.randomUUID();
116             element.setId(elementId);
117             var instanceElementUpdated = new InstanceElementDto(instanceElement.instanceId(),
118                 instanceElement.elementId(), properties, properties);
119             threadHandler.update(messageId, compositionElement, instanceElement, instanceElementUpdated);
120             verify(listener, timeout(TIMEOUT)).update(compositionElement, instanceElement, instanceElementUpdated);
121
122             clearInvocations(listener);
123             var compositionTargetId = UUID.randomUUID();
124             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
125                 properties, properties);
126             threadHandler.migrate(messageId, compositionElement, compositionElementTarget,
127                 instanceElement, instanceElementUpdated, 0);
128             verify(listener, timeout(TIMEOUT)).migrate(compositionElement, compositionElementTarget,
129                 instanceElement, instanceElementUpdated, 0);
130
131             clearInvocations(listener);
132             threadHandler.rollback(messageId, compositionElement, compositionElementTarget,
133                     instanceElement, instanceElementUpdated, 0);
134             verify(listener, timeout(TIMEOUT)).rollbackMigration(compositionElement, compositionElementTarget,
135                     instanceElement, instanceElementUpdated, 0);
136
137             clearInvocations(listener);
138             threadHandler.undeploy(messageId, compositionElement, instanceElement);
139             verify(listener, timeout(TIMEOUT)).undeploy(compositionElement, instanceElement);
140
141             clearInvocations(listener);
142             threadHandler.delete(messageId, compositionElement, instanceElement);
143             verify(listener, timeout(TIMEOUT)).delete(compositionElement, instanceElement);
144         }
145     }
146
147     @Test
148     void testDeployException() throws PfModelException, IOException {
149         var listener = mock(AutomationCompositionElementListener.class);
150         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
151         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
152
153             Map<String, Object> properties = Map.of("key", "value");
154             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
155                 properties, properties);
156             var instanceId = UUID.randomUUID();
157             var elementId = UUID.randomUUID();
158             var instanceElement = new InstanceElementDto(instanceId, elementId, properties, properties);
159             var element = new AcElementDeploy();
160             element.setId(elementId);
161             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
162                 .deploy(compositionElement, instanceElement);
163             var messageId = UUID.randomUUID();
164             threadHandler.deploy(messageId, compositionElement, instanceElement);
165             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
166                 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
167                     "Automation composition element deploy failed");
168
169             clearInvocations(listener);
170             var instanceElementUpdated = new InstanceElementDto(instanceElement.instanceId(),
171                 instanceElement.elementId(), properties, properties);
172             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
173                 .update(compositionElement, instanceElement, instanceElementUpdated);
174             threadHandler.update(messageId, compositionElement, instanceElement, instanceElementUpdated);
175             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
176                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
177                 "Automation composition element update failed");
178
179             clearInvocations(listener);
180             var compositionTargetId = UUID.randomUUID();
181             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
182                 properties, properties);
183             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
184                 .migrate(compositionElement, compositionElementTarget, instanceElement, instanceElementUpdated, 0);
185             threadHandler.migrate(messageId, compositionElement, compositionElementTarget,
186                 instanceElement, instanceElementUpdated, 0);
187             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
188                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
189                 "Automation composition element migrate failed");
190
191             clearInvocations(listener);
192             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
193                 .undeploy(compositionElement, instanceElement);
194             threadHandler.undeploy(messageId, compositionElement, instanceElement);
195             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
196                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
197                 "Automation composition element undeploy failed");
198
199             clearInvocations(listener);
200             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
201                 .delete(compositionElement, instanceElement);
202             threadHandler.delete(messageId, compositionElement, instanceElement);
203             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
204                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
205                     "Automation composition element delete failed");
206         }
207     }
208
209     @Test
210     void testLock() throws PfModelException, IOException {
211         var listener = mock(AutomationCompositionElementListener.class);
212         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
213         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
214
215             Map<String, Object> properties = Map.of("key", "value");
216             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
217                 properties, properties);
218             var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
219                 properties, properties);
220             var messageId = UUID.randomUUID();
221             threadHandler.lock(messageId, compositionElement, instanceElement);
222             verify(listener, timeout(TIMEOUT)).lock(compositionElement, instanceElement);
223
224             clearInvocations(listener);
225             threadHandler.unlock(messageId, compositionElement, instanceElement);
226             verify(listener, timeout(TIMEOUT)).unlock(compositionElement, instanceElement);
227
228             clearInvocations(listener);
229             threadHandler.undeploy(messageId, compositionElement, instanceElement);
230             verify(listener, timeout(TIMEOUT)).undeploy(compositionElement, instanceElement);
231         }
232     }
233
234     @Test
235     void testLockException() throws PfModelException, IOException {
236         var listener = mock(AutomationCompositionElementListener.class);
237         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
238         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
239
240             Map<String, Object> properties = Map.of("key", "value");
241             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
242                 properties, properties);
243             var instanceId = UUID.randomUUID();
244             var elementId = UUID.randomUUID();
245             var instanceElement = new InstanceElementDto(instanceId, elementId, properties, properties);
246             var element = new AcElementDeploy();
247             element.setId(elementId);
248             var messageId = UUID.randomUUID();
249             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
250                 .lock(compositionElement, instanceElement);
251             threadHandler.lock(messageId, compositionElement, instanceElement);
252             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
253                 null, LockState.UNLOCKED, StateChangeResult.FAILED, "Automation composition element lock failed");
254
255             clearInvocations(listener);
256             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
257                 .unlock(compositionElement, instanceElement);
258             threadHandler.unlock(messageId, compositionElement, instanceElement);
259             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
260                 null, LockState.LOCKED, StateChangeResult.FAILED, "Automation composition element unlock failed");
261         }
262     }
263
264     @Test
265     void testSubState() throws PfModelException, IOException {
266         var listener = mock(AutomationCompositionElementListener.class);
267         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
268         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
269
270             Map<String, Object> properties = Map.of("key", "value");
271             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
272                 properties, properties);
273             var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
274                 properties, properties);
275             var messageId = UUID.randomUUID();
276             threadHandler.prepare(messageId, compositionElement, instanceElement, 0);
277             verify(listener, timeout(TIMEOUT)).prepare(compositionElement, instanceElement, 0);
278
279             clearInvocations(listener);
280             threadHandler.review(messageId, compositionElement, instanceElement);
281             verify(listener, timeout(TIMEOUT)).review(compositionElement, instanceElement);
282
283             clearInvocations(listener);
284             var instanceElementMigrate = new InstanceElementDto(instanceElement.instanceId(),
285                 instanceElement.elementId(), properties, properties);
286             var compositionTargetId = UUID.randomUUID();
287             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
288                 properties, properties);
289             threadHandler.migratePrecheck(messageId, compositionElement, compositionElementTarget,
290                 instanceElement, instanceElementMigrate);
291             verify(listener, timeout(TIMEOUT)).migratePrecheck(compositionElement, compositionElementTarget,
292                 instanceElement, instanceElementMigrate);
293         }
294     }
295
296     @Test
297     void testSubStateException() throws PfModelException, IOException {
298         var listener = mock(AutomationCompositionElementListener.class);
299         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
300         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
301
302             Map<String, Object> properties = Map.of("key", "value");
303             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
304                 properties, properties);
305             var instanceId = UUID.randomUUID();
306             var elementId = UUID.randomUUID();
307             var instanceElement = new InstanceElementDto(instanceId, elementId, properties, properties);
308             var element = new AcElementDeploy();
309             element.setId(elementId);
310             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
311                 .prepare(compositionElement, instanceElement, 0);
312             var messageId = UUID.randomUUID();
313             threadHandler.prepare(messageId, compositionElement, instanceElement, 0);
314             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
315                 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
316                 "Automation composition element prepare Pre Deploy failed");
317
318             clearInvocations(listener);
319             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
320                 .review(compositionElement, instanceElement);
321             threadHandler.review(messageId, compositionElement, instanceElement);
322             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
323                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
324                 "Automation composition element Review failed");
325
326             clearInvocations(listener);
327             var compositionTargetId = UUID.randomUUID();
328             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
329                 properties, properties);
330             var instanceElementMigrate = new InstanceElementDto(instanceElement.instanceId(),
331                 instanceElement.elementId(), properties, properties);
332             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
333                 .migratePrecheck(compositionElement, compositionElementTarget, instanceElement, instanceElementMigrate);
334             threadHandler.migratePrecheck(messageId, compositionElement, compositionElementTarget,
335                 instanceElement, instanceElementMigrate);
336             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
337                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
338                 "Automation composition element migrate precheck failed");
339         }
340     }
341 }