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