0b066651b3a6f1c5d7ead59f2aba5064403e6632
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.controlloop.eventmanager;
22
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assert.assertNull;
29 import static org.junit.Assert.assertSame;
30 import static org.junit.Assert.assertTrue;
31 import static org.mockito.ArgumentMatchers.any;
32 import static org.mockito.ArgumentMatchers.eq;
33 import static org.mockito.Mockito.doAnswer;
34 import static org.mockito.Mockito.never;
35 import static org.mockito.Mockito.times;
36 import static org.mockito.Mockito.verify;
37 import static org.mockito.Mockito.when;
38
39 import java.time.Instant;
40 import java.util.Map;
41 import java.util.TreeMap;
42 import java.util.UUID;
43 import java.util.concurrent.CompletableFuture;
44 import java.util.concurrent.CountDownLatch;
45 import java.util.concurrent.TimeUnit;
46 import java.util.function.Consumer;
47 import org.junit.Before;
48 import org.junit.Test;
49 import org.mockito.ArgumentCaptor;
50 import org.mockito.Captor;
51 import org.mockito.Mock;
52 import org.mockito.MockitoAnnotations;
53 import org.onap.aai.domain.yang.GenericVnf;
54 import org.onap.policy.aai.AaiCqResponse;
55 import org.onap.policy.common.utils.time.PseudoExecutor;
56 import org.onap.policy.controlloop.ControlLoopOperation;
57 import org.onap.policy.controlloop.ControlLoopResponse;
58 import org.onap.policy.controlloop.VirtualControlLoopEvent;
59 import org.onap.policy.controlloop.actor.guard.DecisionOperation;
60 import org.onap.policy.controlloop.actor.guard.GuardActor;
61 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
62 import org.onap.policy.controlloop.actorserviceprovider.Operation;
63 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
64 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
65 import org.onap.policy.controlloop.actorserviceprovider.Operator;
66 import org.onap.policy.controlloop.actorserviceprovider.TargetType;
67 import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
68 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
69 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
70 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
71 import org.onap.policy.drools.domain.models.operational.ActorOperation;
72 import org.onap.policy.drools.domain.models.operational.OperationalTarget;
73 import org.onap.policy.sdnr.PciBody;
74 import org.onap.policy.sdnr.PciMessage;
75 import org.onap.policy.sdnr.PciResponse;
76
77 public class ControlLoopOperationManager2Test {
78     private static final UUID REQ_ID = UUID.randomUUID();
79     private static final String MISMATCH = "mismatch";
80     private static final String POLICY_ID = "my-policy";
81     private static final String POLICY_ACTOR = "my-actor";
82     private static final String POLICY_OPERATION = "my-operation";
83     private static final String OTHER_ACTOR = "another-actor";
84     private static final String MY_TARGET = "my-target";
85     private static final String MY_VNF_ID = "my-vnf-id";
86     private static final String PAYLOAD_KEY = "payload-key";
87     private static final String PAYLOAD_VALUE = "payload-value";
88     private static final long REMAINING_MS = 5000;
89     private static final int MAX_RUN = 100;
90     private static final Integer POLICY_RETRY = 3;
91     private static final Integer POLICY_TIMEOUT = 20;
92     private static final IllegalArgumentException EXPECTED_EXCEPTION =
93                     new IllegalArgumentException("expected exception");
94
95     @Captor
96     private ArgumentCaptor<Consumer<OperationOutcome>> lockCallback;
97
98     @Mock
99     private OperationHistoryDataManager dataMgr;
100     @Mock
101     private ManagerContext mgrctx;
102     @Mock
103     private Operator policyOperator;
104     @Mock
105     private Operation policyOperation;
106     @Mock
107     private Actor policyActor;
108     @Mock
109     private ActorService actors;
110     @Mock
111     private AaiCqResponse cqdata;
112     @Mock
113     private GenericVnf vnf;
114
115     private CompletableFuture<OperationOutcome> lockFuture;
116     private CompletableFuture<OperationOutcome> policyFuture;
117     private ActorOperation operation;
118     private OperationalTarget target;
119     private Map<String, String> entityIds;
120     private Map<String, String> payload;
121     private org.onap.policy.drools.domain.models.operational.Operation policy;
122     private VirtualControlLoopEvent event;
123     private ControlLoopEventContext context;
124     private PseudoExecutor executor;
125     private ControlLoopOperationManager2 mgr;
126
127     /**
128      * Sets up.
129      */
130     @Before
131     public void setUp() {
132         MockitoAnnotations.initMocks(this);
133
134         lockFuture = new CompletableFuture<>();
135         policyFuture = new CompletableFuture<>();
136
137         when(mgrctx.getActorService()).thenReturn(actors);
138         when(mgrctx.getDataManager()).thenReturn(dataMgr);
139         when(mgrctx.requestLock(any(), any())).thenReturn(lockFuture);
140
141         // configure policy operation
142         when(actors.getActor(POLICY_ACTOR)).thenReturn(policyActor);
143         when(policyActor.getOperator(POLICY_OPERATION)).thenReturn(policyOperator);
144         when(policyOperator.buildOperation(any())).thenReturn(policyOperation);
145         when(policyOperation.start()).thenReturn(policyFuture);
146
147         when(vnf.getVnfId()).thenReturn(MY_VNF_ID);
148         when(cqdata.getDefaultGenericVnf()).thenReturn(vnf);
149
150         entityIds = Map.of("entity-name-A", "entity-value-A");
151
152         target = OperationalTarget.builder()
153                         .targetType(TargetType.VM.toString())
154                         .entityIds(entityIds)
155                         .build();
156
157         payload = Map.of(PAYLOAD_KEY, PAYLOAD_VALUE);
158
159         operation = ActorOperation.builder()
160                         .actor(POLICY_ACTOR)
161                         .operation(POLICY_OPERATION)
162                         .payload(payload)
163                         .target(target)
164                         .build();
165
166         policy = org.onap.policy.drools.domain.models.operational.Operation.builder()
167                         .id(POLICY_ID)
168                         .actorOperation(operation)
169                         .retries(POLICY_RETRY)
170                         .timeout(POLICY_TIMEOUT)
171                         .build();
172
173         event = new VirtualControlLoopEvent();
174         event.setRequestId(REQ_ID);
175         event.setTarget(ControlLoopOperationManager2.VSERVER_VSERVER_NAME);
176         event.setAai(new TreeMap<>(Map.of(ControlLoopOperationManager2.VSERVER_VSERVER_NAME, MY_TARGET)));
177
178         context = new ControlLoopEventContext(event);
179         context.setProperty(AaiCqResponse.CONTEXT_KEY, cqdata);
180
181         executor = new PseudoExecutor();
182
183         mgr = new ControlLoopOperationManager2(mgrctx, context, policy, executor);
184     }
185
186     @Test
187     public void testStart() {
188         mgr.start(REMAINING_MS);
189
190         // should have determined the target entity by now
191         assertEquals(MY_TARGET, mgr.getTargetEntity());
192
193         verify(mgrctx).requestLock(eq(MY_TARGET), any());
194
195         lockFuture.complete(new OperationOutcome());
196         genGuardOutcome();
197         policyFuture.complete(genOpOutcome());
198         runToCompletion();
199
200         assertEquals(ControlLoopOperationManager2.State.GUARD_STARTED, mgr.getState());
201
202         assertTrue(mgr.nextStep());
203         assertEquals(ControlLoopOperationManager2.State.GUARD_PERMITTED, mgr.getState());
204
205         assertTrue(mgr.nextStep());
206         assertEquals(ControlLoopOperationManager2.State.OPERATION_STARTED, mgr.getState());
207
208         assertTrue(mgr.nextStep());
209         assertEquals(ControlLoopOperationManager2.State.OPERATION_SUCCESS, mgr.getState());
210
211         assertFalse(mgr.nextStep());
212
213         OperationOutcome outcome = mgr.getOutcomes().peek();
214         assertEquals(OperationResult.SUCCESS, outcome.getResult());
215         assertTrue(outcome.isFinalOutcome());
216
217         verify(mgrctx, times(4)).updated(mgr);
218     }
219
220     /**
221      * Tests start() when detmTarget() (i.e., the first task) throws an exception.
222      */
223     @Test
224     public void testStartDetmTargetException() {
225         operation.setTarget(OperationalTarget.builder().build());
226         mgr = new ControlLoopOperationManager2(mgrctx, context, policy, executor);
227         mgr.start(REMAINING_MS);
228
229         runToCompletion();
230
231         assertFalse(mgr.nextStep());
232         assertEquals(ControlLoopOperationManager2.State.OPERATION_FAILURE, mgr.getState());
233
234         // should have called update() for operation-start, but not for any nextStep()
235         verify(mgrctx).updated(mgr);
236     }
237
238     /**
239      * Tests start() when a subsequent task throws an exception.
240      */
241     @Test
242     public void testStartException() {
243         when(policyOperation.start()).thenThrow(EXPECTED_EXCEPTION);
244
245         mgr.start(REMAINING_MS);
246
247         lockFuture.complete(new OperationOutcome());
248         runToCompletion();
249
250         assertFalse(mgr.nextStep());
251         assertEquals(ControlLoopOperationManager2.State.OPERATION_FAILURE, mgr.getState());
252
253         // should have called update() for operation-start, but not for any nextStep()
254         verify(mgrctx).updated(mgr);
255     }
256
257     /**
258      * Tests start() when the control loop times out before the operation starts.
259      */
260     @Test
261     public void testStartClTimeout_testHandleTimeout() throws InterruptedException {
262         // catch the callback when it times out
263         CountDownLatch updatedLatch = new CountDownLatch(1);
264         doAnswer(args -> {
265             updatedLatch.countDown();
266             return null;
267         }).when(mgrctx).updated(any());
268
269         long tstart = System.currentTimeMillis();
270
271         // give it a short timeout
272         mgr.start(100);
273
274         assertTrue(updatedLatch.await(5, TimeUnit.SECONDS));
275         assertTrue(System.currentTimeMillis() - tstart >= 100);
276
277         // don't generate any responses
278         runToCompletion();
279
280         // wait for the future to be canceled, via a background thread
281         CountDownLatch futureLatch = new CountDownLatch(1);
282         mgr.getFuture().whenComplete((unused, thrown) -> futureLatch.countDown());
283         assertTrue(futureLatch.await(5, TimeUnit.SECONDS));
284
285         // lock should have been canceled
286         assertTrue(mgr.getFuture().isCancelled());
287
288         assertFalse(mgr.nextStep());
289         assertEquals(ControlLoopOperationManager2.State.CONTROL_LOOP_TIMEOUT, mgr.getState());
290
291         // should have called update() for operation-start, but not for any nextStep()
292         verify(mgrctx).updated(mgr);
293
294         // should have added a record to the DB
295         verify(dataMgr).store(any(), any(), any(), any());
296     }
297
298     @Test
299     public void testStartOperation() {
300         mgr.start(REMAINING_MS);
301
302         lockFuture.complete(new OperationOutcome());
303         genGuardOutcome();
304         runToCompletion();
305
306         verify(policyOperation).start();
307
308         ArgumentCaptor<ControlLoopOperationParams> captor = ArgumentCaptor.forClass(ControlLoopOperationParams.class);
309         verify(policyOperator).buildOperation(captor.capture());
310
311         ControlLoopOperationParams params = captor.getValue();
312
313         assertNotNull(params);
314         assertEquals(POLICY_ACTOR, params.getActor());
315         assertSame(actors, params.getActorService());
316         assertNotNull(params.getCompleteCallback());
317         assertSame(context, params.getContext());
318         assertSame(executor, params.getExecutor());
319         assertEquals(POLICY_OPERATION, params.getOperation());
320         assertEquals(payload, params.getPayload());
321         assertSame(REQ_ID, params.getRequestId());
322         assertSame(POLICY_RETRY, params.getRetry());
323         assertNotNull(params.getStartCallback());
324         assertEquals(target.getTargetType().toString(), params.getTargetType().toString());
325         assertSame(entityIds, params.getTargetEntityIds());
326         assertEquals(MY_TARGET, params.getTargetEntity());
327         assertSame(POLICY_TIMEOUT, params.getTimeoutSec());
328     }
329
330     @Test
331     public void testStartOperationNullPayload() {
332         operation.setPayload(null);
333         mgr.start(REMAINING_MS);
334
335         lockFuture.complete(new OperationOutcome());
336         genGuardOutcome();
337         runToCompletion();
338
339         verify(policyOperation).start();
340
341         ArgumentCaptor<ControlLoopOperationParams> captor = ArgumentCaptor.forClass(ControlLoopOperationParams.class);
342         verify(policyOperator).buildOperation(captor.capture());
343
344         ControlLoopOperationParams params = captor.getValue();
345
346         assertNotNull(params);
347         assertEquals(POLICY_ACTOR, params.getActor());
348         assertSame(actors, params.getActorService());
349         assertNotNull(params.getCompleteCallback());
350         assertSame(context, params.getContext());
351         assertSame(executor, params.getExecutor());
352         assertEquals(POLICY_OPERATION, params.getOperation());
353         assertTrue(params.getPayload().isEmpty());
354         assertSame(REQ_ID, params.getRequestId());
355         assertSame(POLICY_RETRY, params.getRetry());
356         assertNotNull(params.getStartCallback());
357         assertEquals(target.getTargetType().toString(), params.getTargetType().toString());
358         assertSame(entityIds, params.getTargetEntityIds());
359         assertEquals(MY_TARGET, params.getTargetEntity());
360         assertSame(POLICY_TIMEOUT, params.getTimeoutSec());
361     }
362
363     @Test
364     public void testMakeControlLoopResponse() {
365         final OperationOutcome outcome = new OperationOutcome();
366         PciMessage msg = new PciMessage();
367         outcome.setResponse(msg);
368
369         PciBody body = new PciBody();
370         msg.setBody(body);
371
372         PciResponse output = new PciResponse();
373         body.setOutput(output);
374
375         output.setPayload("my-payload");
376
377
378         // not an SDNR action - should return null
379         assertNull(mgr.makeControlLoopResponse(outcome));
380
381         /*
382          * now work with SDNR actor
383          */
384         operation.setActor("SDNR");
385         mgr = new ControlLoopOperationManager2(mgrctx, context, policy, executor);
386
387         // should return null for a null input
388         assertNull(mgr.makeControlLoopResponse(null));
389
390         // should generate a response, with a payload
391         checkResp(outcome, "my-payload");
392
393         /*
394          * these should generate a response, with null payload
395          */
396         output.setPayload(null);
397         checkResp(outcome, null);
398
399         body.setOutput(null);
400         checkResp(outcome, null);
401
402         msg.setBody(null);
403         checkResp(outcome, null);
404
405         outcome.setResponse(null);
406         checkResp(outcome, null);
407     }
408
409     @Test
410     public void testGetOperationMessage() {
411         // no history yet
412         assertNull(mgr.getOperationMessage());
413
414         runCyle();
415         assertThat(mgr.getOperationMessage()).contains("actor=my-actor").contains("operation=my-operation");
416     }
417
418     @Test
419     public void testGetOperationResult() {
420         // no history yet
421         assertNotNull(mgr.getOperationResult());
422
423         runCyle();
424         assertEquals(OperationResult.SUCCESS, mgr.getOperationResult());
425     }
426
427     /**
428      * Tests getOperationResult() when it ends in a failure.
429      */
430     @Test
431     public void testGetOperationResultFailure() {
432         mgr.start(REMAINING_MS);
433
434         genLockFailure();
435         runToCompletion();
436
437         assertEquals(OperationResult.FAILURE_GUARD, mgr.getOperationResult());
438     }
439
440     /**
441      * Tests handleException() when the exception is a "cancel".
442      */
443     @Test
444     public void testHandleExceptionCanceled() {
445         lockFuture.cancel(false);
446
447         mgr.start(REMAINING_MS);
448
449         runToCompletion();
450
451         assertTrue(mgr.nextStep());
452         assertEquals(ControlLoopOperationManager2.State.ACTIVE, mgr.getState());
453     }
454
455     @Test
456     public void testCancel() {
457         mgr.start(REMAINING_MS);
458
459         mgr.cancel();
460         assertTrue(mgr.getFuture().isCancelled());
461     }
462
463     /**
464      * Tests cancel() when the operation hasn't been started.
465      */
466     @Test
467     public void testCancelNotStarted() {
468         assertNull(mgr.getFuture());
469
470         mgr.cancel();
471         assertNull(mgr.getFuture());
472     }
473
474     @Test
475     public void testLockUnavailable() {
476         mgr.start(REMAINING_MS);
477
478         runToCompletion();
479
480         // lock failure outcome
481         final OperationOutcome outcome = genLockFailure();
482
483         runToCompletion();
484
485         assertFalse(mgr.nextStep());
486         assertEquals(ControlLoopOperationManager2.State.LOCK_DENIED, mgr.getState());
487
488         assertEquals(outcome, mgr.getOutcomes().peek());
489
490         // should have called update() for operation-start, but not for any nextStep()
491         verify(mgrctx).updated(mgr);
492     }
493
494     /**
495      * Tests onStart() and onComplete() with other actors.
496      */
497     @Test
498     public void testOnStart_testOnComplete() {
499         mgr.start(REMAINING_MS);
500
501         lockFuture.complete(new OperationOutcome());
502         genGuardOutcome();
503
504         // generate failure outcome for ANOTHER actor - should be ignored
505         OperationOutcome outcome = mgr.getParams().makeOutcome();
506         outcome.setActor(OTHER_ACTOR);
507         outcome.setResult(OperationResult.FAILURE);
508         outcome.setStart(Instant.now());
509         mgr.getParams().callbackStarted(new OperationOutcome(outcome));
510
511         outcome.setEnd(Instant.now());
512         mgr.getParams().callbackCompleted(outcome);
513
514         policyFuture.complete(genOpOutcome());
515         runToCompletion();
516
517         // should not include the other actor's outcome
518         assertEquals(ControlLoopOperationManager2.State.GUARD_STARTED, mgr.getState());
519
520         assertTrue(mgr.nextStep());
521         assertEquals(ControlLoopOperationManager2.State.GUARD_PERMITTED, mgr.getState());
522
523         assertTrue(mgr.nextStep());
524         assertEquals(ControlLoopOperationManager2.State.OPERATION_STARTED, mgr.getState());
525
526         assertTrue(mgr.nextStep());
527         assertEquals(ControlLoopOperationManager2.State.OPERATION_SUCCESS, mgr.getState());
528
529         assertFalse(mgr.nextStep());
530
531         assertEquals(OperationResult.SUCCESS, mgr.getOutcomes().peek().getResult());
532
533         verify(mgrctx, times(4)).updated(mgr);
534     }
535
536     @Test
537     public void testNextStep() {
538         mgr.start(REMAINING_MS);
539
540         // only do the lock and the guard
541         lockFuture.complete(new OperationOutcome());
542         genGuardOutcome();
543         runToCompletion();
544
545         assertEquals(ControlLoopOperationManager2.State.GUARD_STARTED, mgr.getState());
546
547         assertTrue(mgr.nextStep());
548         assertEquals(ControlLoopOperationManager2.State.GUARD_PERMITTED, mgr.getState());
549
550         assertTrue(mgr.nextStep());
551         assertTrue(mgr.nextStep());
552
553         verify(mgrctx, times(2)).updated(mgr);
554     }
555
556     /**
557      * Tests processOutcome() when the lock is denied.
558      */
559     @Test
560     public void testProcessOutcomeLockDenied() {
561         mgr.start(REMAINING_MS);
562
563         // unavailable from the start => "denied"
564         genLockFailure();
565
566         runToCompletion();
567
568         assertEquals(ControlLoopOperationManager2.State.LOCK_DENIED, mgr.getState());
569
570         assertFalse(mgr.nextStep());
571         verify(mgrctx).updated(mgr);
572
573         verifyDb(1, OperationResult.FAILURE_GUARD, "Operation denied by Lock");
574     }
575
576     /**
577      * Tests processOutcome() when the lock is lost.
578      */
579     @Test
580     public void testProcessOutcomeLockLost() {
581         mgr.start(REMAINING_MS);
582
583         // indicate lock success initially
584         lockFuture.complete(new OperationOutcome());
585
586         // do the guard
587         genGuardOutcome();
588
589         // now generate a lock failure => "lost"
590         genLockFailure();
591
592         runToCompletion();
593
594         assertEquals(ControlLoopOperationManager2.State.GUARD_STARTED, mgr.getState());
595
596         assertTrue(mgr.nextStep());
597         assertEquals(ControlLoopOperationManager2.State.GUARD_PERMITTED, mgr.getState());
598
599         assertTrue(mgr.nextStep());
600         assertEquals(ControlLoopOperationManager2.State.LOCK_LOST, mgr.getState());
601
602         assertFalse(mgr.nextStep());
603         verify(mgrctx, times(3)).updated(mgr);
604
605         verifyDb(1, OperationResult.FAILURE, "Operation aborted by Lock");
606     }
607
608     /**
609      * Tests processOutcome() when the guard is permitted.
610      */
611     @Test
612     public void testProcessOutcomeGuardPermit() {
613         mgr.start(REMAINING_MS);
614
615         lockFuture.complete(new OperationOutcome());
616         genGuardOutcome();
617
618         runToCompletion();
619
620         assertEquals(ControlLoopOperationManager2.State.GUARD_STARTED, mgr.getState());
621
622         assertTrue(mgr.nextStep());
623         assertEquals(ControlLoopOperationManager2.State.GUARD_PERMITTED, mgr.getState());
624
625         assertTrue(mgr.nextStep());
626         verify(mgrctx, times(2)).updated(mgr);
627
628         verify(dataMgr, never()).store(any(), any(), any(), any());
629     }
630
631     /**
632      * Tests processOutcome() when the guard is permitted.
633      */
634     @Test
635     public void testProcessOutcomeGuardDenied() {
636         mgr.start(REMAINING_MS);
637
638         lockFuture.complete(new OperationOutcome());
639         genGuardOutcome(false);
640
641         runToCompletion();
642
643         assertEquals(ControlLoopOperationManager2.State.GUARD_STARTED, mgr.getState());
644
645         assertTrue(mgr.nextStep());
646         assertEquals(ControlLoopOperationManager2.State.GUARD_DENIED, mgr.getState());
647
648         assertFalse(mgr.nextStep());
649         verify(mgrctx, times(2)).updated(mgr);
650
651         verifyDb(1, OperationResult.FAILURE_GUARD, "Operation denied by Guard");
652     }
653
654     /**
655      * Tests processOutcome() when the operation is a success.
656      */
657     @Test
658     public void testProcessOutcomeOperSuccess() {
659         mgr.start(REMAINING_MS);
660
661         lockFuture.complete(new OperationOutcome());
662         genGuardOutcome();
663         genOpOutcome();
664
665         runToCompletion();
666
667         assertEquals(ControlLoopOperationManager2.State.GUARD_STARTED, mgr.getState());
668
669         assertTrue(mgr.nextStep());
670         assertEquals(ControlLoopOperationManager2.State.GUARD_PERMITTED, mgr.getState());
671
672         assertTrue(mgr.nextStep());
673         assertEquals(ControlLoopOperationManager2.State.OPERATION_STARTED, mgr.getState());
674
675         assertTrue(mgr.nextStep());
676         assertEquals(ControlLoopOperationManager2.State.OPERATION_SUCCESS, mgr.getState());
677
678         assertFalse(mgr.nextStep());
679         verify(mgrctx, times(4)).updated(mgr);
680
681         verifyDb(2, OperationResult.SUCCESS, null);
682     }
683
684     /**
685      * Tests processOutcome() when the operation is a failure.
686      */
687     @Test
688     public void testProcessOutcomeOperFailure() {
689         mgr.start(REMAINING_MS);
690
691         lockFuture.complete(new OperationOutcome());
692         genGuardOutcome();
693         genOpOutcome(false);
694
695         runToCompletion();
696
697         assertEquals(ControlLoopOperationManager2.State.GUARD_STARTED, mgr.getState());
698
699         assertTrue(mgr.nextStep());
700         assertEquals(ControlLoopOperationManager2.State.GUARD_PERMITTED, mgr.getState());
701
702         assertTrue(mgr.nextStep());
703         assertEquals(ControlLoopOperationManager2.State.OPERATION_STARTED, mgr.getState());
704
705         assertTrue(mgr.nextStep());
706         assertEquals(ControlLoopOperationManager2.State.OPERATION_FAILURE, mgr.getState());
707         verifyDb(2, OperationResult.FAILURE, null);
708
709         assertThat(mgr.toString()).contains("attempts=1");
710
711         // next failure
712         genOpOutcome(false);
713         runToCompletion();
714
715         assertTrue(mgr.nextStep());
716         assertEquals(ControlLoopOperationManager2.State.OPERATION_STARTED, mgr.getState());
717
718         assertTrue(mgr.nextStep());
719         assertEquals(ControlLoopOperationManager2.State.OPERATION_FAILURE, mgr.getState());
720         verifyDb(4, OperationResult.FAILURE, null);
721
722         assertThat(mgr.toString()).contains("attempts=2");
723
724         // and finally a success
725         genOpOutcome();
726
727         assertTrue(mgr.nextStep());
728         assertEquals(ControlLoopOperationManager2.State.OPERATION_STARTED, mgr.getState());
729
730         assertTrue(mgr.nextStep());
731         assertEquals(ControlLoopOperationManager2.State.OPERATION_SUCCESS, mgr.getState());
732         verifyDb(6, OperationResult.SUCCESS, null);
733
734         assertThat(mgr.toString()).contains("attempts=3");
735
736         assertFalse(mgr.nextStep());
737         verify(mgrctx, times(8)).updated(mgr);
738     }
739
740     @Test
741     public void testGetOperationHistory() {
742         // no history yet
743         assertNull(mgr.getOperationHistory());
744
745         runCyle();
746         assertThat(mgr.getOperationHistory()).contains("actor=my-actor").contains("operation=my-operation")
747                         .contains("outcome=Success");
748     }
749
750     @Test
751     public void testGetHistory() {
752         // no history yet
753         assertEquals(0, mgr.getHistory().size());
754
755         runCyle();
756         assertEquals(1, mgr.getHistory().size());
757     }
758
759     @Test
760     public void testDetmTargetVm() {
761         target.setTargetType(TargetType.VM.toString());
762         assertNull(mgr.detmTarget());
763         assertEquals(MY_TARGET, mgr.getTargetEntity());
764
765         target.setTargetType(TargetType.VNF.toString());
766         assertNull(mgr.detmTarget());
767         assertEquals(MY_TARGET, mgr.getTargetEntity());
768
769         target.setTargetType(TargetType.VFMODULE.toString());
770         assertNull(mgr.detmTarget());
771         assertEquals(MY_TARGET, mgr.getTargetEntity());
772
773         // unsupported type
774         target.setTargetType(TargetType.VFC.toString());
775         assertThatIllegalArgumentException().isThrownBy(() -> mgr.detmTarget())
776                         .withMessage("The target type is not supported");
777
778         // null type
779         target.setTargetType(null);
780         assertThatIllegalArgumentException().isThrownBy(() -> mgr.detmTarget()).withMessage("The target type is null");
781
782         // null target
783         operation.setTarget(null);
784         mgr = new ControlLoopOperationManager2(mgrctx, context, policy, executor);
785         assertThatIllegalArgumentException().isThrownBy(() -> mgr.detmTarget()).withMessage("The target is null");
786     }
787
788     @Test
789     public void testDetmPnfTarget() {
790         setTargetPnf();
791         assertNull(mgr.detmTarget());
792         assertEquals(MY_TARGET, mgr.getTargetEntity());
793
794         // missing enrichment data
795         event.getAai().clear();
796         assertThatIllegalArgumentException().isThrownBy(() -> mgr.detmTarget())
797                         .withMessage("AAI section is missing " + ControlLoopOperationManager2.PNF_NAME);
798
799         // wrong target
800         event.setTarget(MISMATCH);
801         assertThatIllegalArgumentException().isThrownBy(() -> mgr.detmTarget())
802                         .withMessage("Target does not match target type");
803     }
804
805     @Test
806     public void testDetmVfModuleTarget() {
807         // vserver
808         event.setTarget(ControlLoopOperationManager2.VSERVER_VSERVER_NAME);
809         event.getAai().clear();
810         event.getAai().putAll(Map.of(ControlLoopOperationManager2.VSERVER_VSERVER_NAME, MY_TARGET));
811         assertNull(mgr.detmTarget());
812         assertEquals(MY_TARGET, mgr.getTargetEntity());
813
814         // vnf-id
815         event.setTarget(ControlLoopOperationManager2.GENERIC_VNF_VNF_ID);
816         event.getAai().clear();
817         event.getAai().putAll(Map.of(ControlLoopOperationManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
818         assertNull(mgr.detmTarget());
819         assertEquals(MY_TARGET, mgr.getTargetEntity());
820
821         // wrong type
822         event.setTarget(MISMATCH);
823         assertThatIllegalArgumentException().isThrownBy(() -> mgr.detmTarget())
824                         .withMessage("Target does not match target type");
825
826         // missing enrichment data
827         event.setTarget(ControlLoopOperationManager2.VSERVER_VSERVER_NAME);
828         event.getAai().clear();
829         assertThatIllegalArgumentException().isThrownBy(() -> mgr.detmTarget())
830                         .withMessage("Enrichment data is missing " + ControlLoopOperationManager2.VSERVER_VSERVER_NAME);
831
832         // null target
833         event.setTarget(null);
834         assertThatIllegalArgumentException().isThrownBy(() -> mgr.detmTarget()).withMessage("Target is null");
835     }
836
837     @Test
838     public void testDetmVnfName() {
839         setTargetVnfName();
840         assertNull(mgr.detmTarget());
841         assertEquals(MY_TARGET, mgr.getTargetEntity());
842
843         // force it to be gotten from the CQ data
844         event.getAai().clear();
845         assertNull(mgr.detmTarget());
846         assertEquals(MY_VNF_ID, mgr.getTargetEntity());
847     }
848
849     @Test
850     public void testExtractVnfFromCq() {
851         // force it to be gotten from the CQ data
852         setTargetVnfName();
853         event.getAai().clear();
854
855         // missing vnf id in CQ data
856         when(vnf.getVnfId()).thenReturn(null);
857         assertThatIllegalArgumentException().isThrownBy(() -> mgr.detmTarget()).withMessage("No vnf-id found");
858
859         // missing default vnf in CQ data
860         when(cqdata.getDefaultGenericVnf()).thenReturn(null);
861         assertThatIllegalArgumentException().isThrownBy(() -> mgr.detmTarget()).withMessage("No vnf-id found");
862     }
863
864     @Test
865     public void testGetState_testGetActor_testGetOperation() {
866         assertEquals(ControlLoopOperationManager2.State.ACTIVE, mgr.getState());
867         assertEquals(POLICY_ACTOR, mgr.getActor());
868         assertEquals(POLICY_OPERATION, mgr.getOperation());
869     }
870
871     @Test
872     public void testToString() {
873         assertThat(mgr.toString()).contains("state").contains("requestId").contains("policyId").contains("attempts");
874     }
875
876     /**
877      * Runs a cycle, from start to completion.
878      */
879     private void runCyle() {
880         mgr.start(REMAINING_MS);
881
882         lockFuture.complete(new OperationOutcome());
883         genGuardOutcome();
884         genOpOutcome();
885
886         runToCompletion();
887
888         // guard start
889         assertTrue(mgr.nextStep());
890
891         // guard permit
892         assertTrue(mgr.nextStep());
893
894         // operation start
895         assertTrue(mgr.nextStep());
896
897         // operation success
898         assertFalse(mgr.nextStep());
899     }
900
901     /**
902      * Runs everything until the executor queue is empty.
903      */
904     private void runToCompletion() {
905         assertTrue(executor.runAll(MAX_RUN));
906     }
907
908     /**
909      * Generates a failure outcome for the lock, and invokes the callbacks.
910      *
911      * @return the generated outcome
912      */
913     private OperationOutcome genLockFailure() {
914         OperationOutcome outcome = new OperationOutcome();
915         outcome.setActor(ControlLoopOperationManager2.LOCK_ACTOR);
916         outcome.setOperation(ControlLoopOperationManager2.LOCK_OPERATION);
917         outcome.setResult(OperationResult.FAILURE);
918         outcome.setStart(Instant.now());
919         outcome.setEnd(Instant.now());
920         outcome.setFinalOutcome(true);
921
922         verify(mgrctx).requestLock(eq(MY_TARGET), lockCallback.capture());
923         lockCallback.getValue().accept(outcome);
924
925         lockFuture.complete(outcome);
926
927         return outcome;
928     }
929
930     /**
931      * Generates an outcome for the guard, and invokes the callbacks.
932      *
933      * @return the generated outcome
934      */
935     private OperationOutcome genGuardOutcome() {
936         return genGuardOutcome(true);
937     }
938
939     /**
940      * Generates an outcome for the guard, and invokes the callbacks.
941      *
942      * @param permit {@code true} if the guard should be permitted, {@code false} if
943      *        denied
944      * @return the generated outcome
945      */
946     private OperationOutcome genGuardOutcome(boolean permit) {
947         OperationOutcome outcome = mgr.getParams().makeOutcome();
948         outcome.setActor(GuardActor.NAME);
949         outcome.setOperation(DecisionOperation.NAME);
950         outcome.setStart(Instant.now());
951         mgr.getParams().callbackStarted(new OperationOutcome(outcome));
952
953         if (!permit) {
954             outcome.setResult(OperationResult.FAILURE);
955         }
956
957         outcome.setEnd(Instant.now());
958         mgr.getParams().callbackCompleted(outcome);
959
960         return outcome;
961     }
962
963     /**
964      * Generates an outcome for the operation, itself, and invokes the callbacks.
965      *
966      * @return the generated outcome
967      */
968     private OperationOutcome genOpOutcome() {
969         return genOpOutcome(true);
970     }
971
972     /**
973      * Generates an outcome for the operation, itself, and invokes the callbacks.
974      *
975      * @param success {@code true} if the outcome should be a success, {@code false} if a
976      *        failure
977      * @return the generated outcome
978      */
979     private OperationOutcome genOpOutcome(boolean success) {
980         OperationOutcome outcome = mgr.getParams().makeOutcome();
981         outcome.setStart(Instant.now());
982         mgr.getParams().callbackStarted(new OperationOutcome(outcome));
983
984         if (success) {
985             outcome.setFinalOutcome(true);
986         } else {
987             outcome.setResult(OperationResult.FAILURE);
988         }
989
990         outcome.setEnd(Instant.now());
991         mgr.getParams().callbackCompleted(outcome);
992
993         return outcome;
994     }
995
996     /**
997      * Configures the data for a PNF target.
998      */
999     private void setTargetPnf() {
1000         event.setTarget(ControlLoopOperationManager2.PNF_NAME);
1001         event.getAai().clear();
1002         event.getAai().putAll(Map.of(ControlLoopOperationManager2.PNF_NAME, MY_TARGET));
1003
1004         target.setTargetType(TargetType.PNF.toString());
1005     }
1006
1007     /**
1008      * Configures the data for a VNF-NAME target.
1009      */
1010     private void setTargetVnfName() {
1011         event.setTarget(ControlLoopOperationManager2.GENERIC_VNF_VNF_NAME);
1012         event.getAai().clear();
1013         event.getAai().putAll(Map.of(ControlLoopOperationManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
1014
1015         target.setTargetType(TargetType.VNF.toString());
1016     }
1017
1018     private void checkResp(OperationOutcome outcome, String expectedPayload) {
1019         ControlLoopResponse resp = mgr.makeControlLoopResponse(outcome);
1020         assertNotNull(resp);
1021         assertEquals(REQ_ID, resp.getRequestId());
1022         assertEquals(expectedPayload, resp.getPayload());
1023     }
1024
1025     private void verifyDb(int nrecords, OperationResult expectedResult, String expectedMsg) {
1026         ArgumentCaptor<String> entityCaptor = ArgumentCaptor.forClass(String.class);
1027         ArgumentCaptor<ControlLoopOperation> opCaptor = ArgumentCaptor.forClass(ControlLoopOperation.class);
1028         verify(dataMgr, times(nrecords)).store(any(), any(), entityCaptor.capture(), opCaptor.capture());
1029
1030         assertEquals(MY_TARGET, entityCaptor.getValue());
1031
1032         ControlLoopOperation oper = opCaptor.getValue();
1033
1034         assertEquals(expectedResult.toString(), oper.getOutcome());
1035         assertEquals(expectedMsg, oper.getMessage());
1036     }
1037 }