c9df95dedea189bb4007ac9566e3127cac6b95a0
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2021-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.models.acm.persistence.provider;
22
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.assertj.core.api.Assertions.assertThatThrownBy;
25 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertNotNull;
28 import static org.junit.jupiter.api.Assertions.assertThrows;
29 import static org.mockito.ArgumentMatchers.any;
30 import static org.mockito.ArgumentMatchers.anyCollection;
31 import static org.mockito.ArgumentMatchers.anyIterable;
32 import static org.mockito.ArgumentMatchers.anyString;
33 import static org.mockito.Mockito.mock;
34 import static org.mockito.Mockito.verify;
35 import static org.mockito.Mockito.when;
36
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Optional;
40 import java.util.UUID;
41 import org.junit.jupiter.api.BeforeEach;
42 import org.junit.jupiter.api.Test;
43 import org.mockito.Mockito;
44 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
45 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
46 import org.onap.policy.clamp.models.acm.concepts.DeployState;
47 import org.onap.policy.clamp.models.acm.concepts.LockState;
48 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
49 import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationComposition;
50 import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionElement;
51 import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionRollback;
52 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionElementRepository;
53 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRepository;
54 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRollbackRepository;
55 import org.onap.policy.common.utils.coder.Coder;
56 import org.onap.policy.common.utils.coder.StandardCoder;
57 import org.onap.policy.common.utils.resources.ResourceUtils;
58 import org.onap.policy.models.base.PfConceptKey;
59 import org.onap.policy.models.base.PfModelRuntimeException;
60 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
61 import org.springframework.data.domain.Page;
62 import org.springframework.data.domain.PageImpl;
63 import org.springframework.data.domain.PageRequest;
64 import org.springframework.data.domain.Pageable;
65
66 class AutomationCompositionProviderTest {
67
68     private static final String AC_IS_NULL = "automationComposition is marked non-null but is null";
69     private static final String ACELEMENT_ID_IS_NULL = "elementId is marked non-null but is null";
70
71     private static final Coder CODER = new StandardCoder();
72     private static final String AUTOMATION_COMPOSITION_JSON =
73         "src/test/resources/providers/TestAutomationCompositions.json";
74
75     private AutomationCompositions inputAutomationCompositions;
76     private List<JpaAutomationComposition> inputAutomationCompositionsJpa;
77     private final String originalJson = ResourceUtils.getResourceAsString(AUTOMATION_COMPOSITION_JSON);
78
79     @BeforeEach
80     void beforeSetupDao() throws Exception {
81         inputAutomationCompositions = CODER.decode(originalJson, AutomationCompositions.class);
82         inputAutomationCompositionsJpa =
83             ProviderUtils.getJpaAndValidateList(inputAutomationCompositions.getAutomationCompositionList(),
84                 JpaAutomationComposition::new, "automation compositions");
85     }
86
87     @Test
88     void testAutomationCompositionCreate() {
89         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
90         when(automationCompositionRepository.save(any(JpaAutomationComposition.class)))
91             .thenReturn(inputAutomationCompositionsJpa.get(0));
92         var inputAc = inputAutomationCompositions.getAutomationCompositionList().get(0);
93
94         var automationCompositionProvider = new AutomationCompositionProvider(
95                 automationCompositionRepository, mock(AutomationCompositionElementRepository.class),
96                 mock(AutomationCompositionRollbackRepository.class));
97         var createdAutomationComposition = automationCompositionProvider.createAutomationComposition(inputAc);
98         inputAc.setInstanceId(createdAutomationComposition.getInstanceId());
99         inputAc.setLastMsg(createdAutomationComposition.getLastMsg());
100         assertEquals(inputAc, createdAutomationComposition);
101     }
102
103     @Test
104     void testAutomationCompositionUpdate() {
105         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
106         var automationCompositionProvider = new AutomationCompositionProvider(
107                 automationCompositionRepository, mock(AutomationCompositionElementRepository.class),
108                 mock(AutomationCompositionRollbackRepository.class));
109         assertThatThrownBy(() -> automationCompositionProvider.updateAutomationComposition(null))
110             .hasMessageMatching(AC_IS_NULL);
111
112         when(automationCompositionRepository.save(inputAutomationCompositionsJpa.get(0)))
113             .thenReturn(inputAutomationCompositionsJpa.get(0));
114
115         var createdAutomationComposition = automationCompositionProvider
116             .updateAutomationComposition(inputAutomationCompositions.getAutomationCompositionList().get(0));
117
118         assertEquals(inputAutomationCompositions.getAutomationCompositionList().get(0), createdAutomationComposition);
119     }
120
121     @Test
122     void testGetAutomationCompositionsWithNull() {
123         var automationCompositionProvider = new AutomationCompositionProvider(
124                 mock(AutomationCompositionRepository.class), mock(AutomationCompositionElementRepository.class),
125                 mock(AutomationCompositionRollbackRepository.class));
126         assertThatThrownBy(() -> automationCompositionProvider
127             .getAutomationCompositions(UUID.randomUUID(), null, null, null))
128             .hasMessage("pageable is marked non-null but is null");
129
130         assertThatThrownBy(() -> automationCompositionProvider
131             .getAutomationCompositions(null, null, null, Pageable.unpaged()))
132             .hasMessage("compositionId is marked non-null but is null");
133     }
134
135     @Test
136     void testGetAutomationCompositions() {
137         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
138         var automationCompositionProvider = new AutomationCompositionProvider(
139                 automationCompositionRepository, mock(AutomationCompositionElementRepository.class),
140                 mock(AutomationCompositionRollbackRepository.class));
141         var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
142         when(automationCompositionRepository
143             .findAll(Mockito.any(), any(Pageable.class)))
144             .thenReturn(new PageImpl<>(inputAutomationCompositionsJpa));
145         var acList = automationCompositionProvider.getAutomationCompositions(UUID.randomUUID(),
146             automationComposition.getName(), automationComposition.getVersion(), Pageable.unpaged());
147         assertThat(acList).hasSize(2);
148
149         acList = automationCompositionProvider.getAutomationCompositions(automationComposition.getCompositionId(), null,
150             null, Pageable.unpaged());
151         assertThat(acList).hasSize(2);
152
153         when(automationCompositionRepository
154             .findAll(Mockito.any(), Mockito.any(Pageable.class)))
155             .thenReturn(new PageImpl<>(inputAutomationCompositionsJpa));
156         acList = automationCompositionProvider.getAutomationCompositions(automationComposition.getCompositionId(), null,
157             null, PageRequest.of(0, 10));
158         assertThat(acList).hasSize(2);
159     }
160
161     @Test
162     void testGetAutomationComposition() {
163         var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
164         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
165         var automationCompositionProvider = new AutomationCompositionProvider(
166                 automationCompositionRepository, mock(AutomationCompositionElementRepository.class),
167                 mock(AutomationCompositionRollbackRepository.class));
168         assertThatThrownBy(
169             () -> automationCompositionProvider.getAutomationComposition(automationComposition.getInstanceId()))
170             .hasMessageMatching("AutomationComposition not found");
171
172         when(automationCompositionRepository.findById(automationComposition.getInstanceId().toString()))
173             .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
174         var ac = automationCompositionProvider.getAutomationComposition(automationComposition.getInstanceId());
175         assertEquals(automationComposition, ac);
176     }
177
178     @Test
179     void testFindAutomationComposition() {
180         var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
181         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
182         var automationCompositionProvider = new AutomationCompositionProvider(
183                 automationCompositionRepository, mock(AutomationCompositionElementRepository.class),
184                 mock(AutomationCompositionRollbackRepository.class));
185         var acOpt = automationCompositionProvider.findAutomationComposition(automationComposition.getInstanceId());
186         assertThat(acOpt).isEmpty();
187
188         when(automationCompositionRepository.findById(automationComposition.getInstanceId().toString()))
189                 .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
190         acOpt = automationCompositionProvider.findAutomationComposition(automationComposition.getInstanceId());
191         assertEquals(automationComposition, acOpt.get());
192     }
193
194     @Test
195     void testGetAcInstancesByCompositionId() {
196         var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
197         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
198         when(automationCompositionRepository.findByCompositionId(automationComposition.getCompositionId().toString()))
199             .thenReturn(inputAutomationCompositionsJpa);
200         var automationCompositionProvider = new AutomationCompositionProvider(
201                 automationCompositionRepository, mock(AutomationCompositionElementRepository.class),
202                 mock(AutomationCompositionRollbackRepository.class));
203         var acList =
204             automationCompositionProvider.getAcInstancesByCompositionId(automationComposition.getCompositionId());
205         assertEquals(inputAutomationCompositions.getAutomationCompositionList(), acList);
206     }
207
208     @Test
209     void testGetAcInstancesInTransition() {
210         inputAutomationCompositions.getAutomationCompositionList().get(0).setDeployState(DeployState.DEPLOYING);
211         inputAutomationCompositions.getAutomationCompositionList().get(1).setLockState(LockState.LOCKING);
212         inputAutomationCompositionsJpa.get(0).setDeployState(DeployState.DEPLOYING);
213         inputAutomationCompositionsJpa.get(1).setLockState(LockState.LOCKING);
214
215         List<JpaAutomationComposition> res1 = new ArrayList<>();
216         res1.add(inputAutomationCompositionsJpa.get(0));
217
218         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
219         when(automationCompositionRepository.findByDeployStateIn(List.of(DeployState.DEPLOYING,
220             DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING,
221                 DeployState.MIGRATION_REVERTING)))
222             .thenReturn(res1);
223         when(automationCompositionRepository.findByLockStateIn(List.of(LockState.LOCKING, LockState.UNLOCKING)))
224             .thenReturn(List.of(inputAutomationCompositionsJpa.get(1)));
225         var automationCompositionProvider = new AutomationCompositionProvider(
226                 automationCompositionRepository, mock(AutomationCompositionElementRepository.class),
227                 mock(AutomationCompositionRollbackRepository.class));
228         var acList = automationCompositionProvider.getAcInstancesInTransition();
229         assertThat(acList).hasSize(2)
230             .contains(inputAutomationCompositions.getAutomationCompositionList().get(0).getInstanceId())
231             .contains(inputAutomationCompositions.getAutomationCompositionList().get(1).getInstanceId());
232     }
233
234     @Test
235     void testDeleteAutomationComposition() {
236         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
237         var acRollbackRepository = mock(AutomationCompositionRollbackRepository.class);
238         var automationCompositionProvider = new AutomationCompositionProvider(
239                 automationCompositionRepository, mock(AutomationCompositionElementRepository.class),
240                 acRollbackRepository);
241         assertThatThrownBy(() -> automationCompositionProvider.deleteAutomationComposition(UUID.randomUUID()))
242             .hasMessageMatching(".*.failed, automation composition does not exist");
243
244         assertThatThrownBy(() -> automationCompositionProvider.deleteAutomationComposition(null))
245                 .hasMessageMatching("instanceId is marked non-null but is null");
246
247         var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
248         when(automationCompositionRepository.findById(automationComposition.getInstanceId().toString()))
249             .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
250
251         var deletedAc =
252             automationCompositionProvider.deleteAutomationComposition(automationComposition.getInstanceId());
253         assertEquals(automationComposition, deletedAc);
254
255         when(acRollbackRepository.existsById(automationComposition.getInstanceId().toString())).thenReturn(true);
256
257         deletedAc =
258                 automationCompositionProvider.deleteAutomationComposition(automationComposition.getInstanceId());
259         assertEquals(automationComposition, deletedAc);
260         verify(acRollbackRepository).deleteById(automationComposition.getInstanceId().toString());
261     }
262
263     @Test
264     void testDeleteElementById() {
265         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
266         var acElementRepository = mock(AutomationCompositionElementRepository.class);
267         var automationCompositionProvider = new AutomationCompositionProvider(
268                 automationCompositionRepository, acElementRepository,
269                 mock(AutomationCompositionRollbackRepository.class));
270         assertThatThrownBy(() -> automationCompositionProvider.deleteAutomationCompositionElement(null))
271             .hasMessageMatching(ACELEMENT_ID_IS_NULL);
272         var elementId = UUID.randomUUID();
273         automationCompositionProvider.deleteAutomationCompositionElement(elementId);
274         verify(acElementRepository).deleteById(elementId.toString());
275     }
276
277     @Test
278     void testValidateElementIds() {
279         var ac = inputAutomationCompositions.getAutomationCompositionList().get(0);
280
281         var acElementRepository = mock(AutomationCompositionElementRepository.class);
282         var automationCompositionProvider = new AutomationCompositionProvider(
283                 mock(AutomationCompositionRepository.class), acElementRepository,
284                 mock(AutomationCompositionRollbackRepository.class));
285         var result = automationCompositionProvider.validateElementIds(ac);
286         assertThat(result.isValid()).isTrue();
287
288         var jpaElement = new JpaAutomationCompositionElement(ac.getElements().values().iterator().next());
289         when(acElementRepository.findAllById(anyIterable()))
290             .thenReturn(List.of(jpaElement));
291
292         ac.setInstanceId(null);
293         result = automationCompositionProvider.validateElementIds(ac);
294         assertThat(result.isValid()).isFalse();
295
296         ac.setInstanceId(UUID.randomUUID());
297         jpaElement.setInstanceId(UUID.randomUUID().toString());
298         result = automationCompositionProvider.validateElementIds(ac);
299         assertThat(result.isValid()).isFalse();
300
301         ac.setInstanceId(UUID.randomUUID());
302         jpaElement.setInstanceId(ac.getInstanceId().toString());
303         result = automationCompositionProvider.validateElementIds(ac);
304         assertThat(result.isValid()).isTrue();
305     }
306
307     @Test
308     void testCopyAcElements() {
309         var ac = inputAutomationCompositions.getAutomationCompositionList().get(0);
310         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
311         var acRollbackRepository = mock(AutomationCompositionRollbackRepository.class);
312         var automationCompositionProvider = new AutomationCompositionProvider(
313                 automationCompositionRepository, mock(AutomationCompositionElementRepository.class),
314                 acRollbackRepository);
315         automationCompositionProvider.copyAcElementsBeforeUpdate(ac);
316
317         verify(acRollbackRepository).save(any(JpaAutomationCompositionRollback.class));
318         var instanceId = ac.getInstanceId();
319         assertThrows(PfModelRuntimeException.class, () -> automationCompositionProvider
320             .getAutomationCompositionRollback(instanceId));
321     }
322
323     @Test
324     void testGetRollbackSuccess() {
325         var ac = inputAutomationCompositions.getAutomationCompositionList().get(0);
326         var rollback = new JpaAutomationCompositionRollback();
327         rollback.setInstanceId(ac.getInstanceId().toString());
328         rollback.setCompositionId(ac.getCompositionId().toString());
329
330         var acRollbackRepository = mock(AutomationCompositionRollbackRepository.class);
331         when(acRollbackRepository.findById(anyString())).thenReturn(Optional.of(rollback));
332
333         var automationCompositionProvider = new AutomationCompositionProvider(
334                 mock(AutomationCompositionRepository.class), mock(AutomationCompositionElementRepository.class),
335                 acRollbackRepository);
336         var rbFromDb = automationCompositionProvider.getAutomationCompositionRollback(ac.getInstanceId());
337         assertNotNull(rbFromDb);
338     }
339
340     @Test
341     void testGetRollbackEmpty() {
342         var acRollbackRepository = mock(AutomationCompositionRollbackRepository.class);
343         var automationCompositionProvider = new AutomationCompositionProvider(
344                 mock(AutomationCompositionRepository.class), mock(AutomationCompositionElementRepository.class),
345                 acRollbackRepository);
346         when(acRollbackRepository.findById(anyString())).thenReturn(Optional.empty());
347         var compositionId = UUID.randomUUID();
348         assertThrows(PfModelRuntimeException.class, () -> automationCompositionProvider
349             .getAutomationCompositionRollback(compositionId));
350     }
351
352     @Test
353     void testVersionCompatibility() {
354         // Identical
355         var newDefinition = new PfConceptKey("policy.clamp.element", "1.2.3");
356         var oldDefinition = new PfConceptKey("policy.clamp.element", "1.2.3");
357
358         var instanceId = UUID.randomUUID();
359         assertDoesNotThrow(() ->
360                 AutomationCompositionProvider.checkCompatibility(newDefinition, oldDefinition, instanceId));
361
362         // Patch
363         newDefinition.setVersion("1.2.4");
364         assertDoesNotThrow(() ->
365                 AutomationCompositionProvider.checkCompatibility(newDefinition, oldDefinition, instanceId));
366
367         // Minor
368         newDefinition.setVersion("1.3.1");
369         assertDoesNotThrow(() ->
370                 AutomationCompositionProvider.checkCompatibility(newDefinition, oldDefinition, instanceId));
371
372         // Major
373         newDefinition.setVersion("2.1.1");
374         assertDoesNotThrow(() ->
375                 AutomationCompositionProvider.checkCompatibility(newDefinition, oldDefinition, instanceId));
376
377         // Not compatible
378         newDefinition.setName("policy.clamp.newElement");
379         newDefinition.setVersion("2.2.4");
380         assertThatThrownBy(() -> AutomationCompositionProvider
381                 .checkCompatibility(newDefinition, oldDefinition, instanceId))
382                 .hasMessageContaining("is not compatible");
383     }
384
385     @Test
386     void testValidateNameVersion() {
387         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
388         var automationCompositionProvider = new AutomationCompositionProvider(
389                 automationCompositionRepository, mock(AutomationCompositionElementRepository.class),
390                 mock(AutomationCompositionRollbackRepository.class));
391
392         var acIdentifier = new ToscaConceptIdentifier();
393         assertDoesNotThrow(() -> {
394             automationCompositionProvider.validateNameVersion(acIdentifier);
395         });
396
397         when(automationCompositionRepository.findOne(Mockito.any()))
398                 .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
399         assertThatThrownBy(() -> {
400             automationCompositionProvider.validateNameVersion(acIdentifier);
401         }).hasMessageContaining("already defined");
402     }
403
404     @Test
405     void testValidateInstanceEndpoint() {
406         var automationComposition = new AutomationComposition();
407         automationComposition.setCompositionId(UUID.randomUUID());
408
409         var compositionId = automationComposition.getCompositionId();
410         assertDoesNotThrow(() -> AutomationCompositionProvider
411                 .validateInstanceEndpoint(compositionId, automationComposition));
412
413         var wrongCompositionId = UUID.randomUUID();
414         assertThatThrownBy(() -> AutomationCompositionProvider
415                 .validateInstanceEndpoint(wrongCompositionId, automationComposition))
416                 .hasMessageContaining("do not match with");
417     }
418
419     @Test
420     void testGetAcInstancesByFilter() {
421         Page<JpaAutomationComposition> mockPage = new PageImpl<>(inputAutomationCompositionsJpa);
422         var acRepository = mock(AutomationCompositionRepository.class);
423         when(acRepository.findByStateChangeResultIn(anyCollection(), any(Pageable.class)))
424             .thenReturn(mockPage);
425         when(acRepository.findByDeployStateIn(anyCollection(), any(Pageable.class)))
426             .thenReturn(mockPage);
427
428         var stateChangeResults = new ArrayList<StateChangeResult>();
429         var deployStates = new ArrayList<DeployState>();
430         var pageable = Pageable.unpaged();
431         when(acRepository.findByStateChangeResultInAndDeployStateIn(
432             stateChangeResults, deployStates, pageable)).thenReturn(mockPage);
433         when(acRepository.findAll(any(Pageable.class))).thenReturn(mockPage);
434         var acProvider = new AutomationCompositionProvider(acRepository,
435             mock(AutomationCompositionElementRepository.class), mock(AutomationCompositionRollbackRepository.class));
436
437         var acInstances = acProvider.getAcInstancesByStateResultDeployState(stateChangeResults, deployStates, pageable);
438         assertNotNull(acInstances);
439         assertEquals(2, acInstances.size());
440
441         stateChangeResults.add(StateChangeResult.NO_ERROR);
442         acInstances = acProvider.getAcInstancesByStateResultDeployState(stateChangeResults, deployStates, pageable);
443         assertNotNull(acInstances);
444
445         deployStates.add(DeployState.DEPLOYED);
446         acInstances = acProvider.getAcInstancesByStateResultDeployState(stateChangeResults, deployStates, pageable);
447         assertNotNull(acInstances);
448
449         stateChangeResults.clear();
450         acInstances = acProvider.getAcInstancesByStateResultDeployState(stateChangeResults, deployStates, pageable);
451         assertNotNull(acInstances);
452     }
453
454     @Test
455     void testGetAcInstancesByFilterWithNull() {
456         var provider = new AutomationCompositionProvider(mock(AutomationCompositionRepository.class),
457             mock(AutomationCompositionElementRepository.class), mock(AutomationCompositionRollbackRepository.class));
458         var stateChangeResults = new ArrayList<StateChangeResult>();
459         var deployStates = new ArrayList<DeployState>();
460         var pageable = Pageable.unpaged();
461         assertThrows(NullPointerException.class, () ->
462             provider.getAcInstancesByStateResultDeployState(null, deployStates, pageable));
463         assertThrows(NullPointerException.class, () ->
464             provider.getAcInstancesByStateResultDeployState(stateChangeResults, null, pageable));
465         assertThrows(NullPointerException.class, () ->
466             provider.getAcInstancesByStateResultDeployState(stateChangeResults, deployStates, null));
467     }
468 }