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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.clamp.acm.participant.intermediary.handler;
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;
29 import jakarta.ws.rs.core.Response.Status;
30 import java.io.IOException;
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.models.acm.concepts.AcElementDeploy;
40 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
41 import org.onap.policy.clamp.models.acm.concepts.DeployState;
42 import org.onap.policy.clamp.models.acm.concepts.LockState;
43 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
44 import org.onap.policy.models.base.PfModelException;
45 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
47 class ThreadHandlerTest {
49 private static final int TIMEOUT = 400;
52 void testPrime() throws PfModelException, IOException {
53 var listener = mock(AutomationCompositionElementListener.class);
54 var intermediaryApi = mock(ParticipantIntermediaryApi.class);
55 try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
57 var compositionId = UUID.randomUUID();
58 var messageId = UUID.randomUUID();
59 var composition = new CompositionDto(compositionId, Map.of(), Map.of());
60 threadHandler.prime(messageId, composition);
61 verify(listener, timeout(TIMEOUT)).prime(composition);
63 clearInvocations(listener);
64 threadHandler.deprime(messageId, composition);
65 verify(listener, timeout(TIMEOUT)).deprime(composition);
70 void testPrimeException() throws PfModelException, IOException {
71 var listener = mock(AutomationCompositionElementListener.class);
72 var intermediaryApi = mock(ParticipantIntermediaryApi.class);
73 try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
75 var compositionId = UUID.randomUUID();
76 var composition = new CompositionDto(compositionId, Map.of(), Map.of());
77 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener).prime(composition);
78 var messageId = UUID.randomUUID();
79 threadHandler.prime(messageId, composition);
80 verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.COMMISSIONED,
81 StateChangeResult.FAILED, "Composition Defintion prime failed");
83 clearInvocations(listener);
84 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener).deprime(composition);
85 threadHandler.deprime(messageId, composition);
86 verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.PRIMED,
87 StateChangeResult.FAILED, "Composition Defintion deprime failed");
92 void testDeploy() throws PfModelException, IOException {
93 var listener = mock(AutomationCompositionElementListener.class);
94 var intermediaryApi = mock(ParticipantIntermediaryApi.class);
95 try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
97 Map<String, Object> properties = Map.of("key", "value");
98 var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
99 properties, properties);
100 var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
101 properties, properties);
102 var messageId = UUID.randomUUID();
103 threadHandler.deploy(messageId, compositionElement, instanceElement);
104 verify(listener, timeout(TIMEOUT)).deploy(compositionElement, instanceElement);
106 clearInvocations(listener);
107 var element = new AcElementDeploy();
108 var elementId = UUID.randomUUID();
109 element.setId(elementId);
110 var instanceElementUpdated = new InstanceElementDto(instanceElement.instanceId(),
111 instanceElement.elementId(), properties, properties);
112 threadHandler.update(messageId, compositionElement, instanceElement, instanceElementUpdated);
113 verify(listener, timeout(TIMEOUT)).update(compositionElement, instanceElement, instanceElementUpdated);
115 clearInvocations(listener);
116 var compositionTargetId = UUID.randomUUID();
117 var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
118 properties, properties);
119 threadHandler.migrate(messageId, compositionElement, compositionElementTarget,
120 instanceElement, instanceElementUpdated, 0);
121 verify(listener, timeout(TIMEOUT)).migrate(compositionElement, compositionElementTarget,
122 instanceElement, instanceElementUpdated, 0);
124 clearInvocations(listener);
125 threadHandler.undeploy(messageId, compositionElement, instanceElement);
126 verify(listener, timeout(TIMEOUT)).undeploy(compositionElement, instanceElement);
128 clearInvocations(listener);
129 threadHandler.delete(messageId, compositionElement, instanceElement);
130 verify(listener, timeout(TIMEOUT)).delete(compositionElement, instanceElement);
135 void testDeployException() throws PfModelException, IOException {
136 var listener = mock(AutomationCompositionElementListener.class);
137 var intermediaryApi = mock(ParticipantIntermediaryApi.class);
138 try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
140 Map<String, Object> properties = Map.of("key", "value");
141 var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
142 properties, properties);
143 var instanceId = UUID.randomUUID();
144 var elementId = UUID.randomUUID();
145 var instanceElement = new InstanceElementDto(instanceId, elementId, properties, properties);
146 var element = new AcElementDeploy();
147 element.setId(elementId);
148 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
149 .deploy(compositionElement, instanceElement);
150 var messageId = UUID.randomUUID();
151 threadHandler.deploy(messageId, compositionElement, instanceElement);
152 verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
153 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
154 "Automation composition element deploy failed");
156 clearInvocations(listener);
157 var instanceElementUpdated = new InstanceElementDto(instanceElement.instanceId(),
158 instanceElement.elementId(), properties, properties);
159 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
160 .update(compositionElement, instanceElement, instanceElementUpdated);
161 threadHandler.update(messageId, compositionElement, instanceElement, instanceElementUpdated);
162 verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
163 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
164 "Automation composition element update failed");
166 clearInvocations(listener);
167 var compositionTargetId = UUID.randomUUID();
168 var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
169 properties, properties);
170 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
171 .migrate(compositionElement, compositionElementTarget, instanceElement, instanceElementUpdated, 0);
172 threadHandler.migrate(messageId, compositionElement, compositionElementTarget,
173 instanceElement, instanceElementUpdated, 0);
174 verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
175 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
176 "Automation composition element migrate failed");
178 clearInvocations(listener);
179 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
180 .undeploy(compositionElement, instanceElement);
181 threadHandler.undeploy(messageId, compositionElement, instanceElement);
182 verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
183 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
184 "Automation composition element undeploy failed");
186 clearInvocations(listener);
187 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
188 .delete(compositionElement, instanceElement);
189 threadHandler.delete(messageId, compositionElement, instanceElement);
190 verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
191 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
192 "Automation composition element delete failed");
197 void testLock() throws PfModelException, IOException {
198 var listener = mock(AutomationCompositionElementListener.class);
199 var intermediaryApi = mock(ParticipantIntermediaryApi.class);
200 try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
202 Map<String, Object> properties = Map.of("key", "value");
203 var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
204 properties, properties);
205 var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
206 properties, properties);
207 var messageId = UUID.randomUUID();
208 threadHandler.lock(messageId, compositionElement, instanceElement);
209 verify(listener, timeout(TIMEOUT)).lock(compositionElement, instanceElement);
211 clearInvocations(listener);
212 threadHandler.unlock(messageId, compositionElement, instanceElement);
213 verify(listener, timeout(TIMEOUT)).unlock(compositionElement, instanceElement);
215 clearInvocations(listener);
216 threadHandler.undeploy(messageId, compositionElement, instanceElement);
217 verify(listener, timeout(TIMEOUT)).undeploy(compositionElement, instanceElement);
222 void testLockException() throws PfModelException, IOException {
223 var listener = mock(AutomationCompositionElementListener.class);
224 var intermediaryApi = mock(ParticipantIntermediaryApi.class);
225 try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
227 Map<String, Object> properties = Map.of("key", "value");
228 var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
229 properties, properties);
230 var instanceId = UUID.randomUUID();
231 var elementId = UUID.randomUUID();
232 var instanceElement = new InstanceElementDto(instanceId, elementId, properties, properties);
233 var element = new AcElementDeploy();
234 element.setId(elementId);
235 var messageId = UUID.randomUUID();
236 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
237 .lock(compositionElement, instanceElement);
238 threadHandler.lock(messageId, compositionElement, instanceElement);
239 verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
240 null, LockState.UNLOCKED, StateChangeResult.FAILED, "Automation composition element lock failed");
242 clearInvocations(listener);
243 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
244 .unlock(compositionElement, instanceElement);
245 threadHandler.unlock(messageId, compositionElement, instanceElement);
246 verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
247 null, LockState.LOCKED, StateChangeResult.FAILED, "Automation composition element unlock failed");
252 void testSubState() throws PfModelException, IOException {
253 var listener = mock(AutomationCompositionElementListener.class);
254 var intermediaryApi = mock(ParticipantIntermediaryApi.class);
255 try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
257 Map<String, Object> properties = Map.of("key", "value");
258 var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
259 properties, properties);
260 var instanceElement = new InstanceElementDto(UUID.randomUUID(), UUID.randomUUID(),
261 properties, properties);
262 var messageId = UUID.randomUUID();
263 threadHandler.prepare(messageId, compositionElement, instanceElement, 0);
264 verify(listener, timeout(TIMEOUT)).prepare(compositionElement, instanceElement, 0);
266 clearInvocations(listener);
267 threadHandler.review(messageId, compositionElement, instanceElement);
268 verify(listener, timeout(TIMEOUT)).review(compositionElement, instanceElement);
270 clearInvocations(listener);
271 var instanceElementMigrate = new InstanceElementDto(instanceElement.instanceId(),
272 instanceElement.elementId(), properties, properties);
273 var compositionTargetId = UUID.randomUUID();
274 var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
275 properties, properties);
276 threadHandler.migratePrecheck(messageId, compositionElement, compositionElementTarget,
277 instanceElement, instanceElementMigrate);
278 verify(listener, timeout(TIMEOUT)).migratePrecheck(compositionElement, compositionElementTarget,
279 instanceElement, instanceElementMigrate);
284 void testSubStateException() throws PfModelException, IOException {
285 var listener = mock(AutomationCompositionElementListener.class);
286 var intermediaryApi = mock(ParticipantIntermediaryApi.class);
287 try (var threadHandler = new ThreadHandler(listener, intermediaryApi, mock(CacheProvider.class))) {
289 Map<String, Object> properties = Map.of("key", "value");
290 var compositionElement = new CompositionElementDto(UUID.randomUUID(), new ToscaConceptIdentifier(),
291 properties, properties);
292 var instanceId = UUID.randomUUID();
293 var elementId = UUID.randomUUID();
294 var instanceElement = new InstanceElementDto(instanceId, elementId, properties, properties);
295 var element = new AcElementDeploy();
296 element.setId(elementId);
297 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
298 .prepare(compositionElement, instanceElement, 0);
299 var messageId = UUID.randomUUID();
300 threadHandler.prepare(messageId, compositionElement, instanceElement, 0);
301 verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
302 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
303 "Automation composition element prepare Pre Deploy failed");
305 clearInvocations(listener);
306 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
307 .review(compositionElement, instanceElement);
308 threadHandler.review(messageId, compositionElement, instanceElement);
309 verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
310 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
311 "Automation composition element Review failed");
313 clearInvocations(listener);
314 var compositionTargetId = UUID.randomUUID();
315 var compositionElementTarget = new CompositionElementDto(compositionTargetId, new ToscaConceptIdentifier(),
316 properties, properties);
317 var instanceElementMigrate = new InstanceElementDto(instanceElement.instanceId(),
318 instanceElement.elementId(), properties, properties);
319 doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener)
320 .migratePrecheck(compositionElement, compositionElementTarget, instanceElement, instanceElementMigrate);
321 threadHandler.migratePrecheck(messageId, compositionElement, compositionElementTarget,
322 instanceElement, instanceElementMigrate);
323 verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId,
324 DeployState.DEPLOYED, null, StateChangeResult.FAILED,
325 "Automation composition element migrate precheck failed");