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