Fix incorrect deployments counter on parallel execution
[policy/pap.git] / main / src / test / java / org / onap / policy / pap / main / notification / DeploymentStatusTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2022 Bell Canada. All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.pap.main.notification;
23
24 import static org.assertj.core.api.Assertions.assertThat;
25 import static org.mockito.ArgumentMatchers.anyString;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.when;
28
29 import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 import lombok.NonNull;
36 import org.apache.commons.lang3.builder.CompareToBuilder;
37 import org.junit.AfterClass;
38 import org.junit.Before;
39 import org.junit.BeforeClass;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 import org.mockito.ArgumentCaptor;
43 import org.mockito.Captor;
44 import org.mockito.Mock;
45 import org.mockito.junit.MockitoJUnitRunner;
46 import org.onap.policy.common.utils.services.Registry;
47 import org.onap.policy.models.base.PfModelException;
48 import org.onap.policy.models.pap.concepts.PolicyNotification;
49 import org.onap.policy.models.pap.concepts.PolicyStatus;
50 import org.onap.policy.models.pdp.concepts.PdpPolicyStatus;
51 import org.onap.policy.models.pdp.concepts.PdpPolicyStatus.PdpPolicyStatusBuilder;
52 import org.onap.policy.models.pdp.concepts.PdpPolicyStatus.State;
53 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
54 import org.onap.policy.pap.main.PapConstants;
55 import org.onap.policy.pap.main.notification.StatusAction.Action;
56 import org.onap.policy.pap.main.service.PolicyStatusService;
57
58 @RunWith(MockitoJUnitRunner.class)
59 public class DeploymentStatusTest {
60
61     private static final String VERSION = "1.2.3";
62     private static final @NonNull String GROUP_A = "groupA";
63     private static final String PDP_A = "pdpA";
64     private static final String PDP_B = "pdpB";
65     private static final String PDP_C = "pdpC";
66     private static final String PDP_D = "pdpD";
67     private static final String PDP_TYPE = "MyPdpType";
68     private static final ToscaConceptIdentifier POLICY_A = new ToscaConceptIdentifier("MyPolicyA", VERSION);
69     private static final ToscaConceptIdentifier POLICY_B = new ToscaConceptIdentifier("MyPolicyB", VERSION);
70     private static final ToscaConceptIdentifier POLICY_C = new ToscaConceptIdentifier("MyPolicyC", VERSION);
71     private static final ToscaConceptIdentifier POLICY_D = new ToscaConceptIdentifier("MyPolicyD", VERSION);
72     private static final ToscaConceptIdentifier POLICY_TYPE = new ToscaConceptIdentifier("MyPolicyType", VERSION);
73
74     private PdpPolicyStatusBuilder builder;
75
76     @Captor
77     private ArgumentCaptor<List<PdpPolicyStatus>> created;
78     @Captor
79     private ArgumentCaptor<List<PdpPolicyStatus>> updated;
80     @Captor
81     private ArgumentCaptor<List<PdpPolicyStatus>> deleted;
82
83     @Mock
84     private PolicyStatusService policyStatusService;
85
86     private DeploymentStatus tracker;
87
88     /**
89      * Set up the meter registry for tests.
90      */
91     @BeforeClass
92     public static void setUpBeforeClass() {
93         Registry.registerOrReplace(PapConstants.REG_METER_REGISTRY, new SimpleMeterRegistry());
94     }
95
96     /**
97      * Tear down the meter registry after tests.
98      */
99     @AfterClass
100     public static void tearDownAfterClass() {
101         Registry.unregister(PapConstants.REG_METER_REGISTRY);
102     }
103
104     /**
105      * Sets up.
106      */
107     @Before
108     public void setUp() {
109         tracker = new DeploymentStatus(policyStatusService);
110
111         // @formatter:off
112         builder = PdpPolicyStatus.builder()
113                         .pdpGroup(GROUP_A)
114                         .pdpId(PDP_A)
115                         .pdpType(PDP_TYPE)
116                         .policy(POLICY_A)
117                         .policyType(POLICY_TYPE)
118                         .deploy(true)
119                         .state(State.SUCCESS);
120         // @formatter:on
121
122     }
123
124     @Test
125     public void testAddNotifications() {
126         PdpPolicyStatus create = builder.pdpId("created").state(State.FAILURE).build();
127         PdpPolicyStatus update = builder.pdpId("updated").state(State.SUCCESS).build();
128         PdpPolicyStatus delete = builder.pdpId("deleted").state(State.SUCCESS).build();
129         PdpPolicyStatus unchange = builder.pdpId("unchanged").state(State.FAILURE).build();
130
131         // @formatter:off
132         tracker.getRecordMap().putAll(makeMap(
133                         Action.CREATED, create,
134                         Action.UPDATED, update,
135                         Action.DELETED, delete,
136                         Action.UNCHANGED, unchange
137                         ));
138         // @formatter:on
139
140         PolicyNotification notif = new PolicyNotification();
141
142         tracker.addNotifications(notif);
143         assertThat(notif.getAdded()).hasSize(1);
144         assertThat(notif.getDeleted()).isEmpty();
145
146         PolicyStatus status = notif.getAdded().get(0);
147         assertThat(status.getFailureCount()).isEqualTo(2);
148         assertThat(status.getIncompleteCount()).isZero();
149         assertThat(status.getSuccessCount()).isEqualTo(1);
150         assertThat(status.getPolicy()).isEqualTo(POLICY_A);
151         assertThat(status.getPolicyType()).isEqualTo(POLICY_TYPE);
152
153         /*
154          * repeat - should be no notifications
155          */
156         notif = new PolicyNotification();
157         tracker.addNotifications(notif);
158         assertThat(notif.getAdded()).isEmpty();
159         assertThat(notif.getDeleted()).isEmpty();
160     }
161
162     @Test
163     public void testLoadByGroup() throws PfModelException {
164         PdpPolicyStatus status1 = builder.build();
165         PdpPolicyStatus status2 = builder.policy(POLICY_B).build();
166         PdpPolicyStatus status3 = builder.policy(POLICY_A).pdpId(PDP_B).build();
167
168         when(policyStatusService.getGroupPolicyStatus(GROUP_A)).thenReturn(List.of(status1, status2, status3));
169
170         tracker.loadByGroup(GROUP_A);
171
172         // @formatter:off
173         assertThat(tracker.getRecordMap()).isEqualTo(makeMap(
174             Action.UNCHANGED, status1,
175             Action.UNCHANGED, status2,
176             Action.UNCHANGED, status3
177             ));
178         // @formatter:on
179
180         // try again - should not reload
181         tracker.loadByGroup(GROUP_A);
182         verify(policyStatusService).getGroupPolicyStatus(anyString());
183     }
184
185     @Test
186     public void testFlushPdpNotification() {
187         PdpPolicyStatus create = builder.pdpId("created").state(State.FAILURE).build();
188         tracker.getRecordMap().putAll(makeMap(Action.CREATED, create));
189
190         PolicyNotification notif = new PolicyNotification();
191
192         tracker.flush(notif);
193
194         assertThat(notif.getAdded()).hasSize(1);
195         assertThat(notif.getDeleted()).isEmpty();
196     }
197
198     @Test
199     public void testFlush() throws PfModelException {
200         PdpPolicyStatus create1 = builder.pdpId("createA").build();
201         PdpPolicyStatus create2 = builder.pdpId("createB").build();
202         PdpPolicyStatus update1 = builder.pdpId("updateA").build();
203         PdpPolicyStatus update2 = builder.pdpId("updateB").build();
204         PdpPolicyStatus delete1 = builder.pdpId("deleteA").build();
205         PdpPolicyStatus delete2 = builder.pdpId("deleteB").build();
206         PdpPolicyStatus unchange1 = builder.pdpId("unchangeA").build();
207         PdpPolicyStatus unchange2 = builder.pdpId("unchangeB").build();
208
209         // @formatter:off
210         tracker.getRecordMap().putAll(makeMap(
211                         Action.CREATED, create1,
212                         Action.CREATED, create2,
213                         Action.UPDATED, update1,
214                         Action.UPDATED, update2,
215                         Action.DELETED, delete1,
216                         Action.DELETED, delete2,
217                         Action.UNCHANGED, unchange1,
218                         Action.UNCHANGED, unchange2
219                         ));
220         // @formatter:on
221
222         tracker.flush();
223
224         verify(policyStatusService).cudPolicyStatus(created.capture(), updated.capture(), deleted.capture());
225
226         assertThat(sort(created.getValue())).isEqualTo(List.of(create1, create2));
227         assertThat(sort(updated.getValue())).isEqualTo(List.of(update1, update2));
228         assertThat(sort(deleted.getValue())).isEqualTo(List.of(delete1, delete2));
229
230         // @formatter:off
231         assertThat(tracker.getRecordMap()).isEqualTo(makeMap(
232                         Action.UNCHANGED, create1,
233                         Action.UNCHANGED, create2,
234                         Action.UNCHANGED, update1,
235                         Action.UNCHANGED, update2,
236                         Action.UNCHANGED, unchange1,
237                         Action.UNCHANGED, unchange2
238                         ));
239         // @formatter:on
240     }
241
242     @Test
243     public void testDeleteUndeployments() {
244         builder.deploy(true);
245         PdpPolicyStatus delete = builder.policy(POLICY_A).build();
246         PdpPolicyStatus deployedComplete = builder.policy(POLICY_B).build();
247
248         builder.deploy(false);
249         PdpPolicyStatus undepComplete1 = builder.policy(POLICY_C).build();
250         PdpPolicyStatus undepIncomplete1 = builder.policy(POLICY_D).build();
251
252         builder.pdpId(PDP_B);
253         PdpPolicyStatus undepComplete2 = builder.policy(POLICY_C).build();
254         PdpPolicyStatus undepIncomplete2 = builder.policy(POLICY_D).state(State.WAITING).build();
255
256         // @formatter:off
257         Map<StatusKey, StatusAction> map = makeMap(
258                         Action.DELETED, delete,
259                         Action.UNCHANGED, deployedComplete,
260                         Action.UNCHANGED, undepComplete1,
261                         Action.UNCHANGED, undepComplete2,
262                         Action.UNCHANGED, undepIncomplete1,
263                         Action.UNCHANGED, undepIncomplete2
264                         );
265         // @formatter:on
266
267         tracker.getRecordMap().putAll(map);
268
269         tracker.deleteUndeployments();
270
271         // the completed undeployments should now be marked DELETED
272
273         // @formatter:off
274         assertThat(tracker.getRecordMap()).isEqualTo(makeMap(
275                         Action.DELETED, delete,
276                         Action.UNCHANGED, deployedComplete,
277                         Action.DELETED, undepComplete1,
278                         Action.DELETED, undepComplete2,
279                         Action.UNCHANGED, undepIncomplete1,
280                         Action.UNCHANGED, undepIncomplete2
281                         ));
282         // @formatter:on
283     }
284
285     @Test
286     public void testDeleteDeploymentString() {
287         PdpPolicyStatus statusaa = builder.pdpId(PDP_A).policy(POLICY_A).build();
288         PdpPolicyStatus statusab = builder.pdpId(PDP_A).policy(POLICY_B).build();
289         PdpPolicyStatus statusba = builder.pdpId(PDP_B).policy(POLICY_A).build();
290         PdpPolicyStatus statuscb = builder.pdpId(PDP_C).policy(POLICY_B).build();
291
292         // @formatter:off
293         tracker.getRecordMap().putAll(makeMap(
294                         Action.UNCHANGED, statusaa,
295                         Action.UNCHANGED, statusab,
296                         Action.UNCHANGED, statusba,
297                         Action.UNCHANGED, statuscb
298                         ));
299         // @formatter:on
300
301         tracker.deleteDeployment(PDP_A);
302
303         // @formatter:off
304         assertThat(tracker.getRecordMap()).isEqualTo(makeMap(
305                         Action.DELETED, statusaa,
306                         Action.DELETED, statusab,
307                         Action.UNCHANGED, statusba,
308                         Action.UNCHANGED, statuscb
309                         ));
310         // @formatter:on
311     }
312
313     @Test
314     public void testDeleteDeploymentToscaConceptIdentifierBoolean() {
315         PdpPolicyStatus deploy1A = builder.policy(POLICY_A).build();
316         PdpPolicyStatus deploy2A = builder.policy(POLICY_A).pdpId(PDP_B).build();
317         PdpPolicyStatus deployB = builder.policy(POLICY_B).pdpId(PDP_A).build();
318
319         builder.deploy(false);
320         PdpPolicyStatus undeployA = builder.policy(POLICY_A).build();
321         PdpPolicyStatus undeployB = builder.policy(POLICY_B).build();
322
323         // @formatter:off
324         tracker.getRecordMap().putAll(makeMap(
325                         Action.UNCHANGED, deploy1A,
326                         Action.UNCHANGED, deploy2A,
327                         Action.UNCHANGED, deployB,
328                         Action.UNCHANGED, undeployA,
329                         Action.UNCHANGED, undeployB
330                         ));
331         // @formatter:on
332
333         tracker.deleteDeployment(POLICY_A, true);
334
335         // @formatter:off
336         assertThat(tracker.getRecordMap()).isEqualTo(makeMap(
337                         Action.DELETED, deploy1A,
338                         Action.DELETED, deploy2A,
339                         Action.UNCHANGED, deployB,
340                         Action.UNCHANGED, undeployA,
341                         Action.UNCHANGED, undeployB
342                         ));
343         // @formatter:on
344
345         tracker.deleteDeployment(POLICY_B, false);
346
347         // @formatter:off
348         assertThat(tracker.getRecordMap()).isEqualTo(makeMap(
349                         Action.DELETED, deploy1A,
350                         Action.DELETED, deploy2A,
351                         Action.UNCHANGED, deployB,
352                         Action.UNCHANGED, undeployA,
353                         Action.DELETED, undeployB
354                         ));
355         // @formatter:on
356     }
357
358     @Test
359     public void testDeleteDeploymentBiPredicateOfStatusKeyStatusAction() {
360         PdpPolicyStatus create1 = builder.pdpId(PDP_A).build();
361         PdpPolicyStatus delete = builder.pdpId(PDP_B).build();
362         PdpPolicyStatus update = builder.pdpId(PDP_C).build();
363         PdpPolicyStatus unchange = builder.pdpId(PDP_D).build();
364
365         PdpPolicyStatus create2 = builder.pdpId(PDP_B).build();
366
367         // @formatter:off
368         tracker.getRecordMap().putAll(makeMap(
369                         Action.CREATED, create1,
370                         Action.CREATED, create2,
371                         Action.DELETED, delete,
372                         Action.UPDATED, update,
373                         Action.UNCHANGED, unchange
374                         ));
375         // @formatter:on
376
377         tracker.deleteDeployment(POLICY_A, true);
378
379         // @formatter:off
380         assertThat(tracker.getRecordMap()).isEqualTo(makeMap(
381                         Action.DELETED, delete,
382                         Action.DELETED, update,
383                         Action.DELETED, unchange
384                         ));
385         // @formatter:on
386     }
387
388     @Test
389     public void testDeploy() {
390         tracker.deploy(PDP_A, POLICY_A, POLICY_TYPE, GROUP_A, PDP_TYPE, true);
391
392         assertThat(tracker.getRecordMap()).hasSize(1);
393
394         StatusAction status2 = tracker.getRecordMap().values().iterator().next();
395
396         assertThat(status2.getAction()).isEqualTo(Action.CREATED);
397         assertThat(status2.getStatus().getState()).isEqualTo(State.WAITING);
398         assertThat(status2.getStatus().isDeploy()).isTrue();
399
400         /*
401          * repeat - should be the same status
402          */
403         tracker.deploy(PDP_A, POLICY_A, POLICY_TYPE, GROUP_A, PDP_TYPE, true);
404
405         assertThat(tracker.getRecordMap()).hasSize(1);
406         assertThat(tracker.getRecordMap().values().iterator().next()).isSameAs(status2);
407         assertThat(status2.getAction()).isEqualTo(Action.CREATED);
408         assertThat(status2.getStatus().getState()).isEqualTo(State.WAITING);
409         assertThat(status2.getStatus().isDeploy()).isTrue();
410
411         /*
412          * repeat, with different values - should be unchanged
413          */
414         status2.setAction(Action.UNCHANGED);
415         status2.getStatus().setDeploy(true);
416         status2.getStatus().setState(State.SUCCESS);
417
418         tracker.deploy(PDP_A, POLICY_A, POLICY_TYPE, GROUP_A, PDP_TYPE, true);
419
420         assertThat(tracker.getRecordMap()).hasSize(1);
421         assertThat(tracker.getRecordMap().values().iterator().next()).isSameAs(status2);
422         assertThat(status2.getAction()).isEqualTo(Action.UNCHANGED);
423         assertThat(status2.getStatus().getState()).isEqualTo(State.SUCCESS);
424         assertThat(status2.getStatus().isDeploy()).isTrue();
425
426         /*
427          * incorrect "deploy" value - should update it
428          */
429         status2.setAction(Action.UNCHANGED);
430         status2.getStatus().setDeploy(true);
431
432         tracker.deploy(PDP_A, POLICY_A, POLICY_TYPE, GROUP_A, PDP_TYPE, false);
433
434         assertThat(status2.getAction()).isEqualTo(Action.UPDATED);
435         assertThat(status2.getStatus().getState()).isEqualTo(State.WAITING);
436         assertThat(status2.getStatus().isDeploy()).isFalse();
437
438         /*
439          * marked for deletion - should reinstate it
440          */
441         status2.setAction(Action.DELETED);
442         status2.getStatus().setState(State.FAILURE);
443         status2.getStatus().setDeploy(false);
444
445         tracker.deploy(PDP_A, POLICY_A, POLICY_TYPE, GROUP_A, PDP_TYPE, false);
446
447         assertThat(status2.getAction()).isEqualTo(Action.UPDATED);
448         assertThat(status2.getStatus().getState()).isEqualTo(State.FAILURE);
449         assertThat(status2.getStatus().isDeploy()).isFalse();
450     }
451
452     @Test
453     public void testCompleteDeploy() {
454         tracker.deploy(PDP_A, POLICY_A, POLICY_TYPE, GROUP_A, PDP_TYPE, true);
455         assertThat(tracker.getRecordMap()).hasSize(1);
456
457         // deployed, but not expected to be deployed - record should be left as is
458         checkCompleteDeploy(true, Set.of(), Set.of(), Action.UNCHANGED, State.WAITING);
459         checkCompleteDeploy(true, Set.of(), Set.of(POLICY_A), Action.UNCHANGED, State.WAITING);
460
461         // expected, but not actually deployed - failure
462         checkCompleteDeploy(true, Set.of(POLICY_A), Set.of(), Action.UPDATED, State.FAILURE);
463
464         // expected and actually deployed - success
465         checkCompleteDeploy(true, Set.of(POLICY_A), Set.of(POLICY_A), Action.UPDATED, State.SUCCESS);
466         checkCompleteDeploy(true, Set.of(POLICY_A, POLICY_B), Set.of(POLICY_A), Action.UPDATED, State.SUCCESS);
467
468         // not expected and not actually deployed - success
469         checkCompleteDeploy(false, Set.of(), Set.of(), Action.UPDATED, State.SUCCESS);
470
471         // not expected, but actually deployed - failure
472         checkCompleteDeploy(false, Set.of(), Set.of(POLICY_A), Action.UPDATED, State.FAILURE);
473
474         // undeployed, but expected to be deployed - record should be left as is
475         checkCompleteDeploy(false, Set.of(POLICY_A), Set.of(), Action.UNCHANGED, State.WAITING);
476         checkCompleteDeploy(false, Set.of(POLICY_A), Set.of(POLICY_A), Action.UNCHANGED, State.WAITING);
477         checkCompleteDeploy(false, Set.of(POLICY_A, POLICY_B), Set.of(POLICY_A), Action.UNCHANGED, State.WAITING);
478
479         /*
480          * Try a case where the state is already correct.
481          */
482         StatusAction status = tracker.getRecordMap().values().iterator().next();
483         status.getStatus().setDeploy(false);
484         status.setAction(Action.UNCHANGED);
485         status.getStatus().setState(State.SUCCESS);
486
487         tracker.completeDeploy(PDP_A, Set.of(), Set.of());
488
489         assertThat(status.getAction()).isEqualTo(Action.UNCHANGED);
490         assertThat(status.getStatus().getState()).isEqualTo(State.SUCCESS);
491
492         /*
493          * Try a case where the PDP does not match the record.
494          */
495         status.getStatus().setDeploy(false);
496         status.setAction(Action.UNCHANGED);
497         status.getStatus().setState(State.WAITING);
498
499         tracker.completeDeploy(PDP_B, Set.of(), Set.of());
500
501         assertThat(status.getAction()).isEqualTo(Action.UNCHANGED);
502         assertThat(status.getStatus().getState()).isEqualTo(State.WAITING);
503     }
504
505     private void checkCompleteDeploy(boolean deploy, Set<ToscaConceptIdentifier> expected,
506                     Set<ToscaConceptIdentifier> actual, Action action, State state) {
507
508         StatusAction status = tracker.getRecordMap().values().iterator().next();
509         status.getStatus().setDeploy(deploy);
510         status.setAction(Action.UNCHANGED);
511         status.getStatus().setState(State.WAITING);
512
513         tracker.completeDeploy(PDP_A, expected, actual);
514
515         assertThat(status.getAction()).isEqualTo(action);
516         assertThat(status.getStatus().getState()).isEqualTo(state);
517     }
518
519     private List<PdpPolicyStatus> sort(List<PdpPolicyStatus> list) {
520
521         Collections.sort(list, (rec1, rec2) -> {
522
523             // @formatter:off
524             return new CompareToBuilder()
525                             .append(rec1.getPdpId(), rec2.getPdpId())
526                             .append(rec1.getPolicy(), rec2.getPolicy())
527                             .toComparison();
528             // @formatter:on
529         });
530
531         return list;
532     }
533
534     /**
535      * Makes a map.
536      *
537      * @param data pairs of (Action, PdpPolicyStatus)
538      * @return a new map containing the given data
539      */
540     private Map<StatusKey, StatusAction> makeMap(Object... data) {
541         Map<StatusKey, StatusAction> map = new HashMap<>();
542
543         assert (data.length % 2 == 0);
544
545         for (int idata = 0; idata < data.length; idata += 2) {
546             Action action = (Action) data[idata];
547             PdpPolicyStatus status = (PdpPolicyStatus) data[idata + 1];
548             map.put(new StatusKey(status), new StatusAction(action, status));
549         }
550
551         return map;
552     }
553 }