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