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