f03990a635ca4ede13e88fa69e422b949e0f4aa2
[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, instanceElement, 0);
133             verify(listener, timeout(TIMEOUT)).rollbackMigration(compositionElement, instanceElement, 0);
134
135
136             clearInvocations(listener);
137             threadHandler.undeploy(messageId, compositionElement, instanceElement);
138             verify(listener, timeout(TIMEOUT)).undeploy(compositionElement, instanceElement);
139
140             clearInvocations(listener);
141             threadHandler.delete(messageId, compositionElement, instanceElement);
142             verify(listener, timeout(TIMEOUT)).delete(compositionElement, instanceElement);
143         }
144     }
145
146     @Test
147     void testDeployException() throws PfModelException, IOException {
148         var listener = mock(AutomationCompositionElementListener.class);
149         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
150         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
151
152             Map<String, Object> properties = Map.of("key", "value");
153             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
154                 properties, properties);
155             var instanceId = UUID.randomUUID();
156             var elementId = UUID.randomUUID();
157             var instanceElement = new InstanceElementDto(instanceId, elementId, properties, properties);
158             var element = new AcElementDeploy();
159             element.setId(elementId);
160             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
161                 .deploy(compositionElement, instanceElement);
162             var messageId = UUID.randomUUID();
163             threadHandler.deploy(messageId, compositionElement, instanceElement);
164             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
165                 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
166                     "Automation composition element deploy failed");
167
168             clearInvocations(listener);
169             var instanceElementUpdated = new InstanceElementDto(instanceElement.instanceId(),
170                 instanceElement.elementId(), properties, properties);
171             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
172                 .update(compositionElement, instanceElement, instanceElementUpdated);
173             threadHandler.update(messageId, compositionElement, instanceElement, instanceElementUpdated);
174             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
175                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
176                 "Automation composition element update failed");
177
178             clearInvocations(listener);
179             var compositionTargetId = UUID.randomUUID();
180             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
181                 properties, properties);
182             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
183                 .migrate(compositionElement, compositionElementTarget, instanceElement, instanceElementUpdated, 0);
184             threadHandler.migrate(messageId, compositionElement, compositionElementTarget,
185                 instanceElement, instanceElementUpdated, 0);
186             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
187                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
188                 "Automation composition element migrate failed");
189
190             clearInvocations(listener);
191             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
192                 .undeploy(compositionElement, instanceElement);
193             threadHandler.undeploy(messageId, compositionElement, instanceElement);
194             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
195                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
196                 "Automation composition element undeploy failed");
197
198             clearInvocations(listener);
199             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
200                 .delete(compositionElement, instanceElement);
201             threadHandler.delete(messageId, compositionElement, instanceElement);
202             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
203                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
204                     "Automation composition element delete failed");
205         }
206     }
207
208     @Test
209     void testLock() throws PfModelException, IOException {
210         var listener = mock(AutomationCompositionElementListener.class);
211         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
212         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
213
214             Map<String, Object> properties = Map.of("key", "value");
215             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
216                 properties, properties);
217             var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
218                 properties, properties);
219             var messageId = UUID.randomUUID();
220             threadHandler.lock(messageId, compositionElement, instanceElement);
221             verify(listener, timeout(TIMEOUT)).lock(compositionElement, instanceElement);
222
223             clearInvocations(listener);
224             threadHandler.unlock(messageId, compositionElement, instanceElement);
225             verify(listener, timeout(TIMEOUT)).unlock(compositionElement, instanceElement);
226
227             clearInvocations(listener);
228             threadHandler.undeploy(messageId, compositionElement, instanceElement);
229             verify(listener, timeout(TIMEOUT)).undeploy(compositionElement, instanceElement);
230         }
231     }
232
233     @Test
234     void testLockException() throws PfModelException, IOException {
235         var listener = mock(AutomationCompositionElementListener.class);
236         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
237         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
238
239             Map<String, Object> properties = Map.of("key", "value");
240             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
241                 properties, properties);
242             var instanceId = UUID.randomUUID();
243             var elementId = UUID.randomUUID();
244             var instanceElement = new InstanceElementDto(instanceId, elementId, properties, properties);
245             var element = new AcElementDeploy();
246             element.setId(elementId);
247             var messageId = UUID.randomUUID();
248             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
249                 .lock(compositionElement, instanceElement);
250             threadHandler.lock(messageId, compositionElement, instanceElement);
251             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
252                 null, LockState.UNLOCKED, StateChangeResult.FAILED, "Automation composition element lock failed");
253
254             clearInvocations(listener);
255             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
256                 .unlock(compositionElement, instanceElement);
257             threadHandler.unlock(messageId, compositionElement, instanceElement);
258             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
259                 null, LockState.LOCKED, StateChangeResult.FAILED, "Automation composition element unlock failed");
260         }
261     }
262
263     @Test
264     void testSubState() throws PfModelException, IOException {
265         var listener = mock(AutomationCompositionElementListener.class);
266         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
267         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
268
269             Map<String, Object> properties = Map.of("key", "value");
270             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
271                 properties, properties);
272             var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
273                 properties, properties);
274             var messageId = UUID.randomUUID();
275             threadHandler.prepare(messageId, compositionElement, instanceElement, 0);
276             verify(listener, timeout(TIMEOUT)).prepare(compositionElement, instanceElement, 0);
277
278             clearInvocations(listener);
279             threadHandler.review(messageId, compositionElement, instanceElement);
280             verify(listener, timeout(TIMEOUT)).review(compositionElement, instanceElement);
281
282             clearInvocations(listener);
283             var instanceElementMigrate = new InstanceElementDto(instanceElement.instanceId(),
284                 instanceElement.elementId(), properties, properties);
285             var compositionTargetId = UUID.randomUUID();
286             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
287                 properties, properties);
288             threadHandler.migratePrecheck(messageId, compositionElement, compositionElementTarget,
289                 instanceElement, instanceElementMigrate);
290             verify(listener, timeout(TIMEOUT)).migratePrecheck(compositionElement, compositionElementTarget,
291                 instanceElement, instanceElementMigrate);
292         }
293     }
294
295     @Test
296     void testSubStateException() throws PfModelException, IOException {
297         var listener = mock(AutomationCompositionElementListener.class);
298         var intermediaryApi = mock(ParticipantIntermediaryApi.class);
299         try (var threadHandler = createThreadHandler(listener, intermediaryApi)) {
300
301             Map<String, Object> properties = Map.of("key", "value");
302             var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
303                 properties, properties);
304             var instanceId = UUID.randomUUID();
305             var elementId = UUID.randomUUID();
306             var instanceElement = new InstanceElementDto(instanceId, elementId, properties, properties);
307             var element = new AcElementDeploy();
308             element.setId(elementId);
309             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
310                 .prepare(compositionElement, instanceElement, 0);
311             var messageId = UUID.randomUUID();
312             threadHandler.prepare(messageId, compositionElement, instanceElement, 0);
313             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
314                 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
315                 "Automation composition element prepare Pre Deploy failed");
316
317             clearInvocations(listener);
318             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
319                 .review(compositionElement, instanceElement);
320             threadHandler.review(messageId, compositionElement, instanceElement);
321             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
322                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
323                 "Automation composition element Review failed");
324
325             clearInvocations(listener);
326             var compositionTargetId = UUID.randomUUID();
327             var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
328                 properties, properties);
329             var instanceElementMigrate = new InstanceElementDto(instanceElement.instanceId(),
330                 instanceElement.elementId(), properties, properties);
331             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
332                 .migratePrecheck(compositionElement, compositionElementTarget, instanceElement, instanceElementMigrate);
333             threadHandler.migratePrecheck(messageId, compositionElement, compositionElementTarget,
334                 instanceElement, instanceElementMigrate);
335             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
336                 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
337                 "Automation composition element migrate precheck failed");
338
339             clearInvocations(listener);
340             doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
341                     .rollbackMigration(compositionElement, instanceElement, 0);
342             threadHandler.rollback(compositionElement.compositionId(), compositionElement, instanceElement, 0);
343             verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
344                     DeployState.DEPLOYED, null, StateChangeResult.FAILED,
345                     "Automation composition element migrate precheck failed");
346         }
347     }
348 }