da37e6fc37dabdd0abdfdeb0064bebeef6511d63
[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.assertThatCode;
24 import static org.assertj.core.api.Assertions.assertThatThrownBy;
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.anyLong;
33 import static org.mockito.Mockito.never;
34 import static org.mockito.Mockito.times;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.when;
37
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.TreeMap;
43 import java.util.UUID;
44 import java.util.concurrent.CompletableFuture;
45 import java.util.concurrent.ExecutorService;
46 import java.util.function.Consumer;
47 import org.drools.core.WorkingMemory;
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.kie.api.runtime.rule.FactHandle;
51 import org.mockito.ArgumentCaptor;
52 import org.mockito.Mock;
53 import org.mockito.MockitoAnnotations;
54 import org.onap.policy.common.utils.coder.Coder;
55 import org.onap.policy.common.utils.coder.CoderException;
56 import org.onap.policy.common.utils.coder.StandardYamlCoder;
57 import org.onap.policy.common.utils.io.Serializer;
58 import org.onap.policy.common.utils.resources.ResourceUtils;
59 import org.onap.policy.controlloop.ControlLoopEventStatus;
60 import org.onap.policy.controlloop.ControlLoopException;
61 import org.onap.policy.controlloop.ControlLoopNotificationType;
62 import org.onap.policy.controlloop.ControlLoopOperation;
63 import org.onap.policy.controlloop.ControlLoopTargetType;
64 import org.onap.policy.controlloop.VirtualControlLoopEvent;
65 import org.onap.policy.controlloop.VirtualControlLoopNotification;
66 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
67 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
68 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
69 import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
70 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
71 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager2.NewEventStatus;
72 import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager2.State;
73 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
74 import org.onap.policy.drools.core.lock.LockCallback;
75 import org.onap.policy.drools.core.lock.LockImpl;
76 import org.onap.policy.drools.core.lock.LockState;
77 import org.onap.policy.drools.domain.models.operational.Operation;
78 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
79 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
80
81 public class ControlLoopEventManager2Test {
82     private static final UUID REQ_ID = UUID.randomUUID();
83     private static final String CL_NAME = "my-closed-loop-name";
84     private static final String POLICY_NAME = "my-policy-name";
85     private static final String POLICY_SCOPE = "my-scope";
86     private static final String POLICY_VERSION = "1.2.3";
87     private static final String MY_TARGET = "my-target";
88     private static final String LOCK1 = "my-lock-A";
89     private static final String LOCK2 = "my-lock-B";
90     private static final Coder yamlCoder = new StandardYamlCoder();
91
92     @Mock
93     private WorkingMemory workMem;
94     @Mock
95     private Consumer<OperationOutcome> callback1;
96     @Mock
97     private Consumer<OperationOutcome> callback2;
98     @Mock
99     private Consumer<OperationOutcome> callback3;
100     @Mock
101     private FactHandle factHandle;
102     @Mock
103     private ActorService actors;
104     @Mock
105     private OperationHistoryDataManager dataMgr;
106     @Mock
107     private ControlLoopOperationManager2 oper1;
108     @Mock
109     private ControlLoopOperationManager2 oper2;
110     @Mock
111     private ControlLoopOperationManager2 oper3;
112     @Mock
113     private ExecutorService executor;
114
115     private long preCreateTimeMs;
116     private List<LockImpl> locks;
117     private ToscaPolicy tosca;
118     private ControlLoopParams params;
119     private VirtualControlLoopEvent event;
120     private int updateCount;
121     private ControlLoopEventManager2Drools mgr;
122
123     /**
124      * Sets up.
125      */
126     @Before
127     public void setUp() throws ControlLoopException, CoderException {
128         MockitoAnnotations.initMocks(this);
129
130         when(oper1.getHistory()).thenReturn(makeHistory("A"));
131         when(oper2.getHistory()).thenReturn(makeHistory("B"));
132         when(oper3.getHistory()).thenReturn(makeHistory("C"));
133
134         when(oper1.getActor()).thenReturn("First");
135         when(oper1.getOperation()).thenReturn("OperationA");
136         when(oper1.getOperationMessage()).thenReturn("message-A");
137         when(oper1.getOperationHistory()).thenReturn("history-A");
138
139         when(oper2.getActor()).thenReturn("Second");
140         when(oper2.getOperation()).thenReturn("OperationB");
141         when(oper2.getOperationMessage()).thenReturn("message-B");
142         when(oper2.getOperationHistory()).thenReturn("history-B");
143
144         when(oper3.getActor()).thenReturn("Third");
145         when(oper3.getOperation()).thenReturn("OperationC");
146         when(oper3.getOperationMessage()).thenReturn("message-C");
147         when(oper3.getOperationHistory()).thenReturn("history-C");
148
149         when(workMem.getFactHandle(any())).thenReturn(factHandle);
150
151         event = new VirtualControlLoopEvent();
152         event.setRequestId(REQ_ID);
153         event.setTarget(ControlLoopOperationManager2.VSERVER_VSERVER_NAME);
154         event.setAai(new TreeMap<>(Map.of(ControlLoopOperationManager2.VSERVER_VSERVER_NAME, MY_TARGET)));
155         event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
156         event.setClosedLoopControlName(CL_NAME);
157         event.setTargetType(ControlLoopTargetType.VNF);
158
159         params = new ControlLoopParams();
160         params.setClosedLoopControlName(CL_NAME);
161         params.setPolicyName(POLICY_NAME);
162         params.setPolicyScope(POLICY_SCOPE);
163         params.setPolicyVersion(POLICY_VERSION);
164
165         loadPolicy("eventManager/event-mgr-simple.yaml");
166
167         locks = new ArrayList<>();
168
169         updateCount = 0;
170
171         preCreateTimeMs = System.currentTimeMillis();
172
173         mgr = new MyManagerWithOper(params, event, workMem);
174     }
175
176     @Test
177     public void testConstructor() {
178         assertEquals(POLICY_NAME, mgr.getPolicyName());
179
180         Map<String, String> orig = event.getAai();
181
182         event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
183         assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
184                         .hasMessage("is-closed-loop-disabled is set to true on VServer or VNF");
185
186         event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "inactive"));
187         assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
188                         .hasMessage("prov-status is not ACTIVE on VServer or VNF");
189
190         // valid
191         event.setAai(orig);
192         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
193
194         // invalid
195         event.setTarget("unknown-target");
196         assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
197                         .isInstanceOf(ControlLoopException.class);
198     }
199
200     /**
201      * Runs through a policy that has several operations.
202      */
203     @Test
204     public void testMultiOperation() throws Exception {
205
206         loadPolicy("eventManager/event-mgr-multi.yaml");
207
208         mgr = new MyManagerWithOper(params, event, workMem);
209         mgr.start();
210
211         for (ControlLoopOperationManager2 oper : Arrays.asList(oper1, oper2, oper3)) {
212             assertTrue(mgr.isActive());
213             nextStep(oper, true, OperationResult.SUCCESS);
214             runRule();
215
216             assertTrue(mgr.isActive());
217             nextStep(oper, false, OperationResult.SUCCESS);
218             runRule();
219         }
220
221         assertFalse(mgr.isActive());
222     }
223
224     @Test
225     public void testStart() throws Exception {
226         // start it
227         mgr.start();
228
229         // cannot re-start
230         assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
231                         .hasMessage("manager already started");
232     }
233
234     /**
235      * Tests start() error cases.
236      */
237     @Test
238     public void testStartErrors() throws Exception {
239         // wrong jvm
240         ControlLoopEventManager2Drools mgr2 = new ControlLoopEventManager2Drools(params, event, workMem);
241         ControlLoopEventManager2Drools mgr3 = Serializer.roundTrip(mgr2);
242         assertThatCode(() -> mgr3.start()).isInstanceOf(IllegalStateException.class)
243                         .hasMessage("manager is no longer active");
244
245         // no fact handle
246         when(workMem.getFactHandle(any())).thenReturn(null);
247         assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
248                         .hasMessage("manager is not in working memory");
249     }
250
251     @Test
252     public void testNextStep_testStartOperationSuccess() throws ControlLoopException {
253         runOperation(OperationResult.SUCCESS);
254
255         VirtualControlLoopNotification notif = mgr.getNotification();
256         assertEquals(ControlLoopNotificationType.FINAL_SUCCESS, notif.getNotification());
257         assertNull(notif.getMessage());
258
259         assertThatCode(() -> mgr.nextStep()).doesNotThrowAnyException();
260     }
261
262     /**
263      * Tests nextStep() when the next step is invalid, which should cause an exception to
264      * be thrown by the processor.
265      */
266     @Test
267     public void testNextStepMissing() throws Exception {
268         mgr.start();
269
270         when(oper1.nextStep()).thenThrow(new IllegalArgumentException("expected exception"));
271
272         mgr.nextStep();
273
274         assertFalse(mgr.isActive());
275
276         VirtualControlLoopNotification notif = mgr.getNotification();
277         assertEquals(ControlLoopNotificationType.FINAL_FAILURE, notif.getNotification());
278         assertEquals("Policy processing aborted due to policy error", notif.getMessage());
279         assertTrue(notif.getHistory().isEmpty());
280     }
281
282     /**
283      * Tests startOperation() with FINAL_FAILURE_EXCEPTION.
284      */
285     @Test
286     public void testStartOperationException() throws ControlLoopException {
287         runOperation(OperationResult.FAILURE_EXCEPTION);
288
289         VirtualControlLoopNotification notif = mgr.getNotification();
290         assertEquals(ControlLoopNotificationType.FINAL_FAILURE, notif.getNotification());
291         assertEquals("Exception in processing closed loop", notif.getMessage());
292     }
293
294     /**
295      * Tests startOperation() with FINAL_FAILURE.
296      */
297     @Test
298     public void testStartOperationFailure() throws ControlLoopException {
299         runOperation(OperationResult.FAILURE);
300
301         VirtualControlLoopNotification notif = mgr.getNotification();
302         assertEquals(ControlLoopNotificationType.FINAL_FAILURE, notif.getNotification());
303         assertNull(notif.getMessage());
304     }
305
306     /**
307      * Tests startOperation() with FINAL_OPENLOOP.
308      */
309     @Test
310     public void testStartOperationOpenLoop() throws ControlLoopException {
311         runOperation(OperationResult.FAILURE_GUARD);
312
313         VirtualControlLoopNotification notif = mgr.getNotification();
314         assertEquals(ControlLoopNotificationType.FINAL_OPENLOOP, notif.getNotification());
315         assertNull(notif.getMessage());
316     }
317
318     @Test
319     public void testIsActive() throws Exception {
320         mgr = new ControlLoopEventManager2Drools(params, event, workMem);
321         assertTrue(mgr.isActive());
322
323         ControlLoopEventManager2Drools mgr2 = Serializer.roundTrip(mgr);
324         assertFalse(mgr2.isActive());
325     }
326
327     @Test
328     public void testUpdated() throws ControlLoopException {
329         mgr.start();
330
331         // not the active operation - should be ignored
332         mgr.updated(oper3);
333         verify(workMem, never()).update(any(), any());
334
335         VirtualControlLoopNotification notif;
336
337         // check notification data
338         when(oper1.getState()).thenReturn(State.LOCK_DENIED);
339         mgr.updated(oper1);
340         notif = mgr.getNotification();
341         assertNotNull(notif.getHistory());
342
343         /*
344          * try the various cases
345          */
346         when(oper1.getState()).thenReturn(State.LOCK_DENIED);
347         mgr.updated(oper1);
348         verifyNotification(ControlLoopNotificationType.REJECTED, "The target my-target is already locked");
349
350         when(oper1.getState()).thenReturn(State.LOCK_LOST);
351         mgr.updated(oper1);
352         verifyNotification(ControlLoopNotificationType.OPERATION_FAILURE, "The target my-target is no longer locked");
353
354         when(oper1.getState()).thenReturn(State.GUARD_STARTED);
355         mgr.updated(oper1);
356         verifyNotification(ControlLoopNotificationType.OPERATION, "Sending guard query for First OperationA");
357
358         when(oper1.getState()).thenReturn(State.GUARD_PERMITTED);
359         mgr.updated(oper1);
360         verifyNotification(ControlLoopNotificationType.OPERATION, "Guard result for First OperationA is Permit");
361
362         when(oper1.getState()).thenReturn(State.GUARD_DENIED);
363         mgr.updated(oper1);
364         verifyNotification(ControlLoopNotificationType.OPERATION, "Guard result for First OperationA is Deny");
365
366         when(oper1.getState()).thenReturn(State.OPERATION_STARTED);
367         mgr.updated(oper1);
368         verifyNotification(ControlLoopNotificationType.OPERATION, "message-A");
369
370         when(oper1.getState()).thenReturn(State.OPERATION_SUCCESS);
371         mgr.updated(oper1);
372         verifyNotification(ControlLoopNotificationType.OPERATION_SUCCESS, "history-A");
373
374         when(oper1.getState()).thenReturn(State.OPERATION_FAILURE);
375         mgr.updated(oper1);
376         verifyNotification(ControlLoopNotificationType.OPERATION_FAILURE, "history-A");
377
378         // should still be active
379         assertTrue(mgr.isActive());
380
381         /*
382          * control loop time
383          */
384         when(oper1.getState()).thenReturn(State.CONTROL_LOOP_TIMEOUT);
385         mgr.updated(oper1);
386         verifyNotification(ControlLoopNotificationType.FINAL_FAILURE, "Control Loop timed out");
387
388         // should now be done
389         assertFalse(mgr.isActive());
390     }
391
392     @Test
393     public void testDestroy() {
394         mgr.requestLock(LOCK1, callback1);
395         mgr.requestLock(LOCK2, callback2);
396         mgr.requestLock(LOCK1, callback3);
397
398         mgr.destroy();
399
400         freeLocks();
401
402         for (LockImpl lock : locks) {
403             assertTrue(lock.isUnavailable());
404         }
405     }
406
407     /**
408      * Tests destroy() once it has been started.
409      */
410     @Test
411     public void testDestroyStarted() throws ControlLoopException {
412         mgr.start();
413
414         mgr.requestLock(LOCK1, callback1);
415         mgr.requestLock(LOCK2, callback2);
416         mgr.requestLock(LOCK1, callback3);
417
418         mgr.destroy();
419
420         freeLocks();
421
422         // should have canceled the operation
423         verify(oper1).cancel();
424
425         for (LockImpl lock : locks) {
426             assertTrue(lock.isUnavailable());
427         }
428     }
429
430     @Test
431     public void testMakeNotification() throws ControlLoopException {
432         // before started
433         assertNotNull(mgr.makeNotification());
434
435         mgr.start();
436
437         nextStep(oper1, true, OperationResult.SUCCESS);
438         runRule();
439
440         // check notification while running
441         VirtualControlLoopNotification notif = mgr.getNotification();
442         assertEquals("history-A", notif.getMessage());
443
444         List<ControlLoopOperation> history = notif.getHistory();
445         assertNotNull(history);
446
447         nextStep(oper1, false, OperationResult.SUCCESS);
448         runRule();
449
450         assertFalse(mgr.isActive());
451
452         // check notification when complete
453         notif = mgr.getNotification();
454         assertNull(notif.getMessage());
455         assertEquals(history, notif.getHistory());
456     }
457
458     @Test
459     public void testOnNewEvent() {
460         VirtualControlLoopEvent event2 = new VirtualControlLoopEvent(event);
461         assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event2));
462
463         event2.setPayload("other payload");
464         assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
465         assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
466         assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event));
467
468         event2.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
469         assertEquals(NewEventStatus.FIRST_ABATEMENT, mgr.onNewEvent(event2));
470
471         assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
472         assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
473
474         event2.setClosedLoopEventStatus(null);
475         assertEquals(NewEventStatus.SYNTAX_ERROR, mgr.onNewEvent(event2));
476     }
477
478     @Test
479     public void testDetmControlLoopTimeoutMs() throws Exception {
480         verifyTimeout(1200 * 1000L);
481     }
482
483     private void verifyTimeout(long timeMs) {
484         long end = mgr.getEndTimeMs();
485         assertTrue(end >= preCreateTimeMs + timeMs);
486         assertTrue(end < preCreateTimeMs + timeMs + 5000);
487     }
488
489     @Test
490     public void testCheckEventSyntax() {
491         // initially, it's valid
492         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
493
494         event.setTarget("unknown-target");
495         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
496                         .hasMessage("target field invalid");
497
498         event.setTarget(null);
499         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
500                         .hasMessage("No target field");
501
502         // abated supersedes previous errors - so it shouldn't throw an exception
503         event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
504         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
505
506         event.setRequestId(null);
507         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
508                         .hasMessage("No request ID");
509
510         event.setClosedLoopControlName(null);
511         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
512                         .hasMessage("No control loop name");
513     }
514
515     @Test
516     public void testValidateStatus() {
517         event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
518         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
519
520         event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
521         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
522
523         event.setClosedLoopEventStatus(null);
524         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
525                         .hasMessage("Invalid value in closedLoopEventStatus");
526     }
527
528     @Test
529     public void testValidateAaiData() {
530         event.setTargetType("unknown-target-type");
531         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
532                         .hasMessage("The target type is not supported");
533
534         event.setTargetType(null);
535         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
536                         .hasMessage("The Target type is null");
537
538         event.setAai(null);
539         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
540                         .hasMessage("AAI is null");
541
542         // VM case
543         event.setTargetType(ControlLoopTargetType.VM);
544         event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
545         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
546
547         event.setAai(Map.of());
548         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
549
550         // VNF case
551         event.setTargetType(ControlLoopTargetType.VNF);
552         event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
553         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
554
555         event.setAai(Map.of());
556         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
557
558         // PNF case
559         event.setTargetType(ControlLoopTargetType.PNF);
560         event.setAai(Map.of(ControlLoopEventManager2.PNF_NAME, MY_TARGET));
561         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
562
563         event.setAai(Map.of());
564         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
565     }
566
567     @Test
568     public void testValidateAaiVmVnfData() {
569         event.setTargetType(ControlLoopTargetType.VM);
570         event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
571         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
572
573         event.setAai(Map.of(ControlLoopEventManager2.VSERVER_VSERVER_NAME, MY_TARGET));
574         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
575
576         event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_NAME, MY_TARGET));
577         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
578
579         event.setAai(Map.of());
580         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class).hasMessage(
581                         "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
582     }
583
584     @Test
585     public void testValidateAaiPnfData() {
586         event.setTargetType(ControlLoopTargetType.PNF);
587         event.setAai(Map.of(ControlLoopEventManager2.PNF_NAME, MY_TARGET));
588         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
589
590         event.setAai(Map.of());
591         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
592                         .hasMessage("AAI PNF object key pnf-name is missing");
593     }
594
595     @Test
596     public void testIsClosedLoopDisabled() {
597         Map<String, String> orig = event.getAai();
598
599         event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
600         assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
601                         .isInstanceOf(IllegalStateException.class);
602
603         event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED, "true"));
604         assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
605                         .isInstanceOf(IllegalStateException.class);
606
607         event.setAai(addAai(orig, ControlLoopEventManager2.PNF_IS_IN_MAINT, "true"));
608         assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
609                         .isInstanceOf(IllegalStateException.class);
610     }
611
612     private Map<String, String> addAai(Map<String, String> original, String key, String value) {
613         Map<String, String> map = new TreeMap<>(original);
614         map.put(key, value);
615         return map;
616     }
617
618     @Test
619     public void testIsProvStatusInactive() {
620         Map<String, String> orig = event.getAai();
621
622         event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "ACTIVE"));
623         assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException();
624
625         event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "inactive"));
626         assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
627                         .isInstanceOf(IllegalStateException.class);
628
629         event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "ACTIVE"));
630         assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException();
631         event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "inactive"));
632         assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
633                         .isInstanceOf(IllegalStateException.class);
634     }
635
636     @Test
637     public void testIsAaiTrue() {
638         Map<String, String> orig = event.getAai();
639
640         for (String value : Arrays.asList("yes", "y", "true", "t", "yEs", "trUe")) {
641             event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, value));
642             assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
643                             .isInstanceOf(IllegalStateException.class);
644         }
645
646         event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "false"));
647         assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException();
648
649         event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "no"));
650         assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException();
651     }
652
653     @Test
654     public void testRequestLock() {
655         final CompletableFuture<OperationOutcome> future1 = mgr.requestLock(LOCK1, callback1);
656         final CompletableFuture<OperationOutcome> future2 = mgr.requestLock(LOCK2, callback2);
657         assertSame(future1, mgr.requestLock(LOCK1, callback3));
658
659         assertEquals(2, locks.size());
660
661         assertTrue(future1.isDone());
662         assertTrue(future2.isDone());
663
664         verify(callback1, never()).accept(any());
665         verify(callback2, never()).accept(any());
666         verify(callback3, never()).accept(any());
667
668         // indicate that the first lock failed
669         locks.get(0).notifyUnavailable();
670
671         verify(callback1).accept(any());
672         verify(callback2, never()).accept(any());
673         verify(callback3).accept(any());
674     }
675
676     @Test
677     public void testMakeOperationManager() throws ControlLoopException {
678         // use a manager that creates real operation managers
679         mgr = new MyManager(params, event, workMem);
680
681         assertThatCode(() -> mgr.start()).doesNotThrowAnyException();
682     }
683
684     @Test
685     public void testGetBlockingExecutor() throws Exception {
686         mgr = new ControlLoopEventManager2Drools(params, event, workMem);
687         assertThatCode(() -> mgr.getBlockingExecutor()).doesNotThrowAnyException();
688     }
689
690     @Test
691     public void testToString() {
692         assertNotNull(mgr.toString());
693     }
694
695
696     private void nextStep(ControlLoopOperationManager2 oper, boolean moreSteps, OperationResult result) {
697         when(oper.nextStep()).thenReturn(moreSteps);
698         when(oper.getOperationResult()).thenReturn(result);
699
700         if (result == OperationResult.SUCCESS) {
701             when(oper.getState()).thenReturn(State.OPERATION_SUCCESS);
702         } else {
703             when(oper.getState()).thenReturn(State.OPERATION_FAILURE);
704         }
705
706         mgr.updated(oper);
707
708         updateCount++;
709
710         verify(workMem, times(updateCount)).update(factHandle, mgr);
711     }
712
713     private void runRule() {
714         assertTrue(mgr.isActive());
715         mgr.nextStep();
716     }
717
718     private void runOperation(OperationResult finalResult) throws ControlLoopException {
719         mgr.start();
720         verify(oper1).start(anyLong());
721
722         assertTrue(mgr.isActive());
723
724         nextStep(oper1, true, OperationResult.SUCCESS);
725         runRule();
726
727         nextStep(oper1, false, finalResult);
728         runRule();
729
730         assertFalse(mgr.isActive());
731
732         // should have no effect, because it's done
733         mgr.updated(oper1);
734         verify(workMem, times(updateCount)).update(any(), any());
735     }
736
737     private void verifyNotification(ControlLoopNotificationType expectedType, String expectedMsg) {
738         VirtualControlLoopNotification notif = mgr.getNotification();
739         assertEquals(expectedType, notif.getNotification());
740         assertEquals(expectedMsg, notif.getMessage());
741     }
742
743     private List<ControlLoopOperation> makeHistory(String message) {
744         ControlLoopOperation clo = new ControlLoopOperation();
745         clo.setMessage("history-" + message);
746
747         return List.of(clo);
748     }
749
750     private void loadPolicy(String fileName) throws CoderException {
751         ToscaServiceTemplate template =
752                         yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
753         tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
754
755         params.setToscaPolicy(tosca);
756     }
757
758     private void freeLocks() {
759         ArgumentCaptor<Runnable> runCaptor = ArgumentCaptor.forClass(Runnable.class);
760         verify(executor).execute(runCaptor.capture());
761
762         runCaptor.getValue().run();
763     }
764
765
766     private class MyManager extends ControlLoopEventManager2Drools {
767         private static final long serialVersionUID = 1L;
768
769         public MyManager(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem)
770                         throws ControlLoopException {
771
772             super(params, event, workMem);
773         }
774
775         @Override
776         protected ExecutorService getBlockingExecutor() {
777             return executor;
778         }
779
780         @Override
781         protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
782             LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
783             locks.add(lock);
784             callback.lockAvailable(lock);
785         }
786
787         @Override
788         public ActorService getActorService() {
789             return actors;
790         }
791
792         @Override
793         public OperationHistoryDataManager getDataManager() {
794             return dataMgr;
795         }
796     }
797
798
799     private class MyManagerWithOper extends MyManager {
800         private static final long serialVersionUID = 1L;
801
802         public MyManagerWithOper(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem)
803                         throws ControlLoopException {
804
805             super(params, event, workMem);
806         }
807
808         @Override
809         protected ControlLoopOperationManager2 makeOperationManager(ControlLoopEventContext ctx, Operation policy) {
810             switch (policy.getActorOperation().getActor()) {
811                 case "First":
812                     return oper1;
813                 case "Second":
814                     return oper2;
815                 case "Third":
816                     return oper3;
817                 default:
818                     throw new IllegalArgumentException("unknown policy actor " + policy.getActorOperation().getActor());
819             }
820         }
821     }
822 }