2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.policy.drools.apps.controller.usecases;
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.assertj.core.api.Assertions.assertThatCode;
25 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
26 import static org.assertj.core.api.Assertions.assertThatThrownBy;
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertFalse;
29 import static org.junit.Assert.assertNotNull;
30 import static org.junit.Assert.assertNull;
31 import static org.junit.Assert.assertSame;
32 import static org.junit.Assert.assertTrue;
33 import static org.mockito.ArgumentMatchers.any;
34 import static org.mockito.ArgumentMatchers.anyLong;
35 import static org.mockito.Mockito.never;
36 import static org.mockito.Mockito.verify;
37 import static org.mockito.Mockito.when;
39 import java.time.Instant;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.Deque;
44 import java.util.List;
46 import java.util.TreeMap;
47 import java.util.UUID;
48 import java.util.concurrent.ExecutorService;
49 import java.util.concurrent.ForkJoinPool;
50 import org.drools.core.WorkingMemory;
51 import org.junit.Before;
52 import org.junit.Test;
53 import org.kie.api.runtime.rule.FactHandle;
54 import org.mockito.Mock;
55 import org.mockito.MockitoAnnotations;
56 import org.onap.policy.common.utils.coder.Coder;
57 import org.onap.policy.common.utils.coder.CoderException;
58 import org.onap.policy.common.utils.coder.StandardYamlCoder;
59 import org.onap.policy.common.utils.io.Serializer;
60 import org.onap.policy.common.utils.resources.ResourceUtils;
61 import org.onap.policy.controlloop.ControlLoopEventStatus;
62 import org.onap.policy.controlloop.ControlLoopException;
63 import org.onap.policy.controlloop.ControlLoopResponse;
64 import org.onap.policy.controlloop.ControlLoopTargetType;
65 import org.onap.policy.controlloop.VirtualControlLoopEvent;
66 import org.onap.policy.controlloop.VirtualControlLoopNotification;
67 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
68 import org.onap.policy.controlloop.actorserviceprovider.Operation;
69 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
70 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
71 import org.onap.policy.controlloop.actorserviceprovider.Operator;
72 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
73 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
74 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
75 import org.onap.policy.controlloop.eventmanager.ActorConstants;
76 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager2;
77 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
78 import org.onap.policy.controlloop.policy.FinalResult;
79 import org.onap.policy.controlloop.policy.PolicyResult;
80 import org.onap.policy.controlloop.policy.Target;
81 import org.onap.policy.controlloop.policy.TargetType;
82 import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager.NewEventStatus;
83 import org.onap.policy.drools.apps.controller.usecases.step.AaiCqStep2;
84 import org.onap.policy.drools.apps.controller.usecases.step.AaiGetPnfStep2;
85 import org.onap.policy.drools.apps.controller.usecases.step.AaiGetTenantStep2;
86 import org.onap.policy.drools.apps.controller.usecases.step.GetTargetEntityStep2;
87 import org.onap.policy.drools.apps.controller.usecases.step.GuardStep2;
88 import org.onap.policy.drools.apps.controller.usecases.step.Step2;
89 import org.onap.policy.drools.core.lock.LockCallback;
90 import org.onap.policy.drools.core.lock.LockImpl;
91 import org.onap.policy.drools.core.lock.LockState;
92 import org.onap.policy.drools.system.PolicyEngine;
93 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
94 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
95 import org.onap.policy.sdnr.PciBody;
96 import org.onap.policy.sdnr.PciMessage;
97 import org.onap.policy.sdnr.PciResponse;
99 public class UsecasesEventManagerTest {
100 private static final UUID REQ_ID = UUID.randomUUID();
101 private static final String CL_NAME = "my-closed-loop-name";
102 private static final String POLICY_NAME = "my-policy-name";
103 private static final String POLICY_SCOPE = "my-scope";
104 private static final String POLICY_VERSION = "1.2.3";
105 private static final String SIMPLE_ACTOR = "First";
106 private static final String SIMPLE_OPERATION = "OperationA";
107 private static final String MY_TARGET = "my-target";
108 private static final String EVENT_MGR_MULTI_YAML =
109 "../eventmanager/src/test/resources/eventManager/event-mgr-multi.yaml";
110 private static final String EVENT_MGR_SIMPLE_YAML =
111 "../eventmanager/src/test/resources/eventManager/event-mgr-simple.yaml";
112 private static final Coder yamlCoder = new StandardYamlCoder();
113 private static final String OUTCOME_MSG = "my outcome message";
114 private static final String MY_SINK = "my-topic-sink";
117 private PolicyEngine engineMgr;
119 private WorkingMemory workMem;
121 private FactHandle factHandle;
123 private Operator policyOperator;
125 private Operation policyOperation;
127 private Actor policyActor;
129 private ActorService actors;
131 private OperationHistoryDataManager dataMgr;
133 private ExecutorService executor;
139 private List<LockImpl> locks;
140 private Target target;
141 private ToscaPolicy tosca;
142 private ControlLoopParams params;
143 private VirtualControlLoopEvent event;
144 private UsecasesEventManager mgr;
150 public void setUp() throws ControlLoopException, CoderException {
151 MockitoAnnotations.initMocks(this);
153 when(actors.getActor(SIMPLE_ACTOR)).thenReturn(policyActor);
154 when(policyActor.getOperator(SIMPLE_OPERATION)).thenReturn(policyOperator);
155 when(policyOperator.buildOperation(any())).thenReturn(policyOperation);
156 when(policyOperation.getPropertyNames()).thenReturn(Collections.emptyList());
158 when(workMem.getFactHandle(any())).thenReturn(factHandle);
160 event = new VirtualControlLoopEvent();
161 event.setRequestId(REQ_ID);
162 event.setTarget(UsecasesConstants.VSERVER_VSERVER_NAME);
163 event.setAai(new TreeMap<>(Map.of(UsecasesConstants.VSERVER_VSERVER_NAME, MY_TARGET)));
164 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
165 event.setClosedLoopControlName(CL_NAME);
166 event.setTargetType(TargetType.VNF.toString());
168 target = new Target();
169 target.setType(TargetType.VNF);
171 params = new ControlLoopParams();
172 params.setClosedLoopControlName(CL_NAME);
173 params.setPolicyName(POLICY_NAME);
174 params.setPolicyScope(POLICY_SCOPE);
175 params.setPolicyVersion(POLICY_VERSION);
177 loadPolicy(EVENT_MGR_SIMPLE_YAML);
179 locks = new ArrayList<>();
181 mgr = new MyManager(params, event, workMem);
185 public void testConstructor() {
186 assertEquals(POLICY_NAME, mgr.getPolicyName());
187 assertSame(event, mgr.getEvent());
189 Map<String, String> orig = event.getAai();
191 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
192 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
193 .hasMessage("is-closed-loop-disabled is set to true on VServer or VNF");
195 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS, "inactive"));
196 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
197 .hasMessage("prov-status is not ACTIVE on VServer or VNF");
201 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
204 event.setTarget("unknown-target");
205 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
206 .isInstanceOf(ControlLoopException.class);
210 public void testIsActive() throws Exception {
211 mgr = new UsecasesEventManager(params, event, workMem);
212 assertTrue(mgr.isActive());
214 // deserialized manager should be inactive
215 UsecasesEventManager mgr2 = Serializer.roundTrip(mgr);
216 assertFalse(mgr2.isActive());
220 public void testDestroy_testGetSteps() {
221 // add some steps to the queue
222 mgr.getSteps().add(stepa);
223 mgr.getSteps().add(stepb);
227 verify(stepa).cancel();
228 verify(stepb).cancel();
230 // if superclass destroy() was invoked, then freeLock() should have been submitted
232 verify(executor).execute(any());
236 public void testOnStart() throws ControlLoopException {
237 OperationOutcome outcome = makeOutcome();
240 mgr.onStart(outcome);
242 assertSame(outcome, mgr.getOutcomes().poll());
243 assertThat(mgr.getOutcomes()).isEmpty();
245 verify(workMem).update(factHandle, mgr);
249 public void testOnComplete() throws ControlLoopException {
250 OperationOutcome outcome = makeCompletedOutcome();
253 mgr.onComplete(outcome);
255 assertSame(outcome, mgr.getOutcomes().poll());
256 assertThat(mgr.getOutcomes()).isEmpty();
258 verify(workMem).update(factHandle, mgr);
262 public void testToString() {
263 assertNotNull(mgr.toString());
267 public void testStart() throws ControlLoopException {
272 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
273 .hasMessage("manager already started");
277 * Tests start() when the manager is not in working memory.
280 public void testStartNotInWorkingMemory() throws ControlLoopException {
281 when(workMem.getFactHandle(any())).thenReturn(null);
283 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
284 .hasMessage("manager is not in working memory");
288 * Tests start() when the manager is not active.
291 public void testStartInactive() throws Exception {
292 // make an inactive manager by deserializing it
293 mgr = Serializer.roundTrip(new UsecasesEventManager(params, event, workMem));
296 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
297 .hasMessage("manager is no longer active");
301 public void testAbort() {
302 mgr.abort(UsecasesEventManager.State.DONE, FinalResult.FINAL_FAILURE_GUARD, "some message");
304 assertEquals(UsecasesEventManager.State.DONE, mgr.getState());
305 assertEquals(FinalResult.FINAL_FAILURE_GUARD, mgr.getFinalResult());
306 assertEquals("some message", mgr.getFinalMessage());
309 assertThatThrownBy(() -> mgr.abort(null, FinalResult.FINAL_FAILURE_GUARD, ""))
310 .isInstanceOf(NullPointerException.class).hasMessageContaining("finalState");
314 public void testLoadNextPolicy_testGetFullHistory_testGetPartialHistory() throws Exception {
315 loadPolicy(EVENT_MGR_MULTI_YAML);
316 mgr = new MyManager(params, event, workMem);
318 // start and load step for first policy
320 assertEquals("OperationA", mgr.getSteps().poll().getOperationName());
321 assertNull(mgr.getFinalResult());
324 OperationOutcome outcome = makeOutcome();
325 mgr.addToHistory(outcome);
327 // indicate success and load next policy
328 mgr.loadNextPolicy(PolicyResult.SUCCESS);
329 assertEquals("OperationB", mgr.getSteps().poll().getOperationName());
330 assertNull(mgr.getFinalResult());
332 // loadPolicy() should clear the partial history, but not the full history
333 assertThat(mgr.getPartialHistory()).isEmpty();
334 assertThat(mgr.getFullHistory()).hasSize(1);
336 // indicate failure - should go to final failure
337 mgr.loadNextPolicy(PolicyResult.FAILURE);
338 assertEquals(FinalResult.FINAL_FAILURE, mgr.getFinalResult());
342 public void testLoadPolicy() throws ControlLoopException {
343 // start() will invoke loadPolicy()
346 assertNull(mgr.getFinalResult());
348 Step2 step = mgr.getSteps().peek();
350 assertEquals("First", step.getActorName());
351 assertEquals("OperationA", step.getOperationName());
353 ControlLoopOperationParams params2 = step.getParams();
354 assertSame(actors, params2.getActorService());
355 assertSame(REQ_ID, params2.getRequestId());
356 assertSame(ForkJoinPool.commonPool(), params2.getExecutor());
357 assertNotNull(params2.getTarget());
358 assertEquals(Integer.valueOf(300), params2.getTimeoutSec());
359 assertEquals(Integer.valueOf(0), params2.getRetry());
360 assertThat(params2.getPayload()).isEmpty();
361 assertNotNull(params2.getStartCallback());
362 assertNotNull(params2.getCompleteCallback());
366 public void testLoadPreprocessorSteps() {
367 stepa = new Step2(mgr, ControlLoopOperationParams.builder().build(), event) {
369 public List<String> getPropertyNames() {
370 return List.of(OperationProperties.AAI_DEFAULT_CLOUD_REGION);
374 protected Operation buildOperation() {
375 return policyOperation;
379 mgr.getSteps().add(stepa);
380 mgr.getSteps().add(stepb);
382 mgr.loadPreprocessorSteps();
384 Deque<Step2> steps = mgr.getSteps();
386 Step2 lockStep = steps.poll();
387 assertNotNull(lockStep);
388 assertEquals(ActorConstants.LOCK_ACTOR, lockStep.getActorName());
389 assertThat(steps.poll()).isInstanceOf(AaiCqStep2.class);
390 assertThat(steps.poll()).isInstanceOf(GuardStep2.class);
391 assertSame(stepa, steps.poll());
392 assertSame(stepb, steps.poll());
393 assertThat(steps).isEmpty();
397 * Tests loadPreprocessorSteps() when there are too many steps in the queue.
400 public void testLoadPreprocessorStepsTooManySteps() {
401 loadStepsWithProperties(OperationProperties.AAI_PNF);
403 Deque<Step2> steps = mgr.getSteps();
404 stepa = steps.getFirst();
407 // load up a bunch of steps
408 for (int nsteps = 0; nsteps < UsecasesEventManager.MAX_STEPS; ++nsteps) {
413 assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
415 // add another step, should still fail
417 assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
419 // remove two steps - should now succeed
423 int nsteps = steps.size();
425 mgr.loadPreprocessorSteps();
426 assertEquals(nsteps + 1, steps.size());
430 * Tests loadPreprocessorSteps() when no additional steps are needed.
433 public void testLoadPreprocessorStepsNothingToLoad() {
434 when(stepa.isPolicyStep()).thenReturn(false);
435 when(stepa.getPropertyNames()).thenReturn(List.of("unknown-property"));
437 Deque<Step2> steps = mgr.getSteps();
442 mgr.loadPreprocessorSteps();
444 assertSame(stepa, steps.poll());
445 assertSame(stepb, steps.poll());
446 assertThat(steps).isEmpty();
450 * Tests loadPreprocessorSteps() when an A&AI custom query is needed.
453 public void testLoadPreprocessorStepsCq() {
454 loadStepsWithProperties(OperationProperties.AAI_DEFAULT_CLOUD_REGION, OperationProperties.AAI_DEFAULT_TENANT);
457 mgr.loadPreprocessorSteps();
459 Deque<Step2> steps = mgr.getSteps();
461 assertThat(steps.poll()).isInstanceOf(AaiCqStep2.class);
462 assertSame(stepa, steps.poll());
463 assertSame(stepb, steps.poll());
464 assertThat(steps).isEmpty();
468 * Tests loadPreprocessorSteps() when an A&AI PNF query is needed.
471 public void testLoadPreprocessorStepsPnf() {
472 // doubling up the property to check both branches
473 loadStepsWithProperties(OperationProperties.AAI_PNF, OperationProperties.AAI_PNF);
476 mgr.loadPreprocessorSteps();
478 Deque<Step2> steps = mgr.getSteps();
480 assertThat(steps.poll()).isInstanceOf(AaiGetPnfStep2.class);
481 assertSame(stepa, steps.poll());
482 assertSame(stepb, steps.poll());
483 assertThat(steps).isEmpty();
487 * Tests loadPreprocessorSteps() when an A&AI Tenant query is needed.
490 public void testLoadPreprocessorStepsTenant() {
491 // doubling up the property to check both branches
492 event.getAai().put(Step2.VSERVER_VSERVER_NAME, "my-vserver");
493 loadStepsWithProperties(OperationProperties.AAI_VSERVER_LINK, OperationProperties.AAI_VSERVER_LINK);
496 mgr.loadPreprocessorSteps();
498 Deque<Step2> steps = mgr.getSteps();
500 assertThat(steps.poll()).isInstanceOf(AaiGetTenantStep2.class);
501 assertSame(stepa, steps.poll());
502 assertSame(stepb, steps.poll());
503 assertThat(steps).isEmpty();
507 * Tests loadPreprocessorSteps() when the target entity is unset.
510 public void testLoadPreprocessorStepsNeedTargetEntity() {
511 stepa = new Step2(mgr, ControlLoopOperationParams.builder().target(target).build(), event) {
513 public List<String> getPropertyNames() {
514 return List.of(OperationProperties.AAI_TARGET_ENTITY);
518 protected Operation buildOperation() {
519 return policyOperation;
523 public boolean isPolicyStep() {
528 Deque<Step2> steps = mgr.getSteps();
532 mgr.loadPreprocessorSteps();
534 Step2 entityStep = steps.poll();
536 assertThat(entityStep).isInstanceOf(GetTargetEntityStep2.class);
537 assertSame(stepa, steps.poll());
538 assertSame(stepb, steps.poll());
539 assertThat(steps).isEmpty();
541 // put get-target-entity back onto the queue and ensure nothing else is added
542 steps.add(entityStep);
543 mgr.loadPreprocessorSteps();
544 assertSame(entityStep, steps.poll());
545 assertThat(steps).isEmpty();
549 public void testExecuteStep() {
552 // no steps to execute
553 assertFalse(mgr.executeStep());
554 assertEquals(0, mgr.getAttempts());
556 // add a step to the queue
557 mgr.getSteps().add(stepa);
559 // step returns false
560 when(stepa.start(anyLong())).thenReturn(false);
561 assertFalse(mgr.executeStep());
564 when(stepa.start(anyLong())).thenReturn(true);
565 assertTrue(mgr.executeStep());
569 public void testNextStep() {
570 mgr.getSteps().add(stepa);
574 assertThat(mgr.getSteps()).isEmpty();
578 public void testBumpAttempts() {
579 assertEquals(0, mgr.getAttempts());
583 assertEquals(2, mgr.getAttempts());
587 public void testIsAbort() {
588 OperationOutcome outcome = makeCompletedOutcome();
589 outcome.setResult(PolicyResult.FAILURE);
591 // closed loop timeout
592 outcome.setActor(ActorConstants.CL_TIMEOUT_ACTOR);
593 assertTrue(mgr.isAbort(outcome));
596 outcome.setActor(ActorConstants.LOCK_ACTOR);
597 assertTrue(mgr.isAbort(outcome));
599 // no effect for success
600 outcome.setResult(PolicyResult.SUCCESS);
601 assertFalse(mgr.isAbort(outcome));
605 public void testAddToHistory() throws ControlLoopException {
608 // add a "start" outcome
609 OperationOutcome outcome = makeOutcome();
610 mgr.addToHistory(outcome);
612 assertThat(mgr.getPartialHistory()).hasSize(1);
613 assertThat(mgr.getFullHistory()).hasSize(1);
615 // add a "completion" outcome - should replace the start
616 outcome = makeCompletedOutcome();
617 mgr.addToHistory(outcome);
619 assertThat(mgr.getPartialHistory()).hasSize(1);
620 assertThat(mgr.getFullHistory()).hasSize(1);
621 assertSame(outcome, mgr.getPartialHistory().peek().getOutcome());
622 assertSame(outcome, mgr.getFullHistory().peek().getOutcome());
625 outcome = makeOutcome();
626 mgr.addToHistory(outcome);
628 assertThat(mgr.getPartialHistory()).hasSize(2);
629 assertThat(mgr.getFullHistory()).hasSize(2);
630 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
631 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
633 // remove the last item from the full history and then add a "completion"
634 mgr.getFullHistory().removeLast();
635 outcome = makeCompletedOutcome();
636 mgr.addToHistory(outcome);
637 assertThat(mgr.getPartialHistory()).hasSize(2);
638 assertThat(mgr.getFullHistory()).hasSize(2);
640 // add another "start"
641 outcome = makeOutcome();
642 mgr.addToHistory(outcome);
643 assertThat(mgr.getPartialHistory()).hasSize(3);
644 assertThat(mgr.getFullHistory()).hasSize(3);
646 // add a "completion" for a different actor - should NOT replace the start
647 outcome = makeCompletedOutcome();
648 outcome.setActor("different-actor");
649 mgr.addToHistory(outcome);
650 assertThat(mgr.getPartialHistory()).hasSize(4);
651 assertThat(mgr.getFullHistory()).hasSize(4);
652 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
653 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
657 public void testMakeNotification() throws Exception {
658 loadPolicy(EVENT_MGR_MULTI_YAML);
659 mgr = new MyManager(params, event, workMem);
662 assertNotNull(mgr.makeNotification());
666 mgr.addToHistory(makeCompletedOutcome());
667 mgr.addToHistory(makeCompletedOutcome());
668 mgr.addToHistory(makeCompletedOutcome());
670 // check notification while running
671 VirtualControlLoopNotification notif = mgr.makeNotification();
672 assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
673 assertThat(notif.getHistory()).hasSize(3);
675 // indicate success and load the next policy - should clear the partial history
676 mgr.loadNextPolicy(PolicyResult.SUCCESS);
678 // check notification
679 notif = mgr.makeNotification();
680 assertNull(notif.getMessage());
681 assertThat(notif.getHistory()).isEmpty();
683 // add outcomes and check again
684 mgr.addToHistory(makeCompletedOutcome());
685 mgr.addToHistory(makeCompletedOutcome());
687 notif = mgr.makeNotification();
688 assertNotNull(notif.getMessage());
690 // should only have history for last two outcomes
691 assertThat(notif.getHistory()).hasSize(2);
693 // indicate failure - should go to final state
694 mgr.loadNextPolicy(PolicyResult.FAILURE);
696 // check notification
697 notif = mgr.makeNotification();
698 assertNull(notif.getMessage());
700 // should be no history
701 assertThat(notif.getHistory()).isEmpty();
704 assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
705 .hasMessageContaining("lastResult");
709 public void testDeliver() {
710 mgr.deliver(MY_SINK, null, "null notification", "null rule");
711 verify(engineMgr, never()).deliver(any(), any());
713 mgr.deliver(MY_SINK, "publishA", "A notification", "A rule");
714 verify(engineMgr).deliver(MY_SINK, "publishA");
716 // cause deliver() to throw an exception
717 when(engineMgr.deliver(any(), any())).thenThrow(new IllegalStateException("expected exception"));
718 assertThatCode(() -> mgr.deliver(MY_SINK, "publishB", "B notification", "B rule")).doesNotThrowAnyException();
722 public void testGetOperationMessage() throws ControlLoopException {
724 assertNull(mgr.getOperationMessage());
728 OperationOutcome outcome = makeOutcome();
729 mgr.addToHistory(outcome);
731 assertThat(mgr.getOperationMessage()).contains("actor=" + SIMPLE_ACTOR)
732 .contains("operation=" + SIMPLE_OPERATION);
736 public void testStoreInDataBase() throws ControlLoopException {
738 OperationOutcome outcome = makeOutcome();
739 mgr.addToHistory(outcome);
741 mgr.storeInDataBase(mgr.getPartialHistory().peekLast());
743 verify(dataMgr).store(REQ_ID.toString(), event, null, mgr.getPartialHistory().peekLast().getClOperation());
747 public void testMakeControlLoopResponse() {
748 final OperationOutcome outcome = new OperationOutcome();
750 // no message - should return null
751 checkResp(outcome, null);
753 // not a PciMessage - should return null
754 outcome.setResponse("not-a-pci-message");
755 checkResp(outcome, null);
758 * now work with a PciMessage
760 PciMessage msg = new PciMessage();
761 outcome.setResponse(msg);
763 PciBody body = new PciBody();
766 PciResponse output = new PciResponse();
767 body.setOutput(output);
769 output.setPayload("my-payload");
771 // should generate a response, with a payload
772 checkResp(outcome, "my-payload");
775 * these should generate a response, with null payload
777 output.setPayload(null);
778 checkResp(outcome, null);
780 body.setOutput(null);
781 checkResp(outcome, null);
784 checkResp(outcome, null);
786 outcome.setResponse(null);
787 checkResp(outcome, null);
791 public void testOnNewEvent() {
792 VirtualControlLoopEvent event2 = new VirtualControlLoopEvent(event);
793 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event2));
795 event2.setPayload("other payload");
796 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
797 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
798 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event));
800 event2.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
801 assertEquals(NewEventStatus.FIRST_ABATEMENT, mgr.onNewEvent(event2));
803 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
804 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
806 event2.setClosedLoopEventStatus(null);
807 assertEquals(NewEventStatus.SYNTAX_ERROR, mgr.onNewEvent(event2));
811 public void testCheckEventSyntax() {
812 // initially, it's valid
813 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
815 event.setTarget("unknown-target");
816 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
817 .hasMessage("target field invalid");
819 event.setTarget(null);
820 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
821 .hasMessage("No target field");
823 // abated supersedes previous errors - so it shouldn't throw an exception
824 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
825 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
827 event.setRequestId(null);
828 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
829 .hasMessage("No request ID");
831 event.setClosedLoopControlName(null);
832 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
833 .hasMessage("No control loop name");
837 public void testValidateStatus() {
838 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
839 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
841 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
842 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
844 event.setClosedLoopEventStatus(null);
845 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
846 .hasMessage("Invalid value in closedLoopEventStatus");
850 public void testValidateAaiData() {
851 event.setTargetType("unknown-target-type");
852 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
853 .hasMessage("The target type is not supported");
855 event.setTargetType(null);
856 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
857 .hasMessage("The Target type is null");
860 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
861 .hasMessage("AAI is null");
864 event.setTargetType(ControlLoopTargetType.VM);
865 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
866 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
868 event.setAai(Map.of());
869 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
872 event.setTargetType(ControlLoopTargetType.VNF);
873 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
874 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
876 event.setAai(Map.of());
877 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
880 event.setTargetType(ControlLoopTargetType.PNF);
881 event.setAai(Map.of(ControlLoopEventManager2.PNF_NAME, MY_TARGET));
882 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
884 event.setAai(Map.of());
885 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
889 public void testValidateAaiVmVnfData() {
890 event.setTargetType(ControlLoopTargetType.VM);
891 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
892 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
894 event.setAai(Map.of(ControlLoopEventManager2.VSERVER_VSERVER_NAME, MY_TARGET));
895 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
897 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_NAME, MY_TARGET));
898 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
900 event.setAai(Map.of());
901 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class).hasMessage(
902 "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
906 public void testValidateAaiPnfData() {
907 event.setTargetType(ControlLoopTargetType.PNF);
908 event.setAai(Map.of(ControlLoopEventManager2.PNF_NAME, MY_TARGET));
909 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
911 event.setAai(Map.of());
912 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
913 .hasMessage("AAI PNF object key pnf-name is missing");
917 public void testIsClosedLoopDisabled() {
918 Map<String, String> orig = event.getAai();
920 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
921 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
922 .isInstanceOf(IllegalStateException.class);
924 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED, "true"));
925 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
926 .isInstanceOf(IllegalStateException.class);
928 event.setAai(addAai(orig, ControlLoopEventManager2.PNF_IS_IN_MAINT, "true"));
929 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
930 .isInstanceOf(IllegalStateException.class);
934 public void testIsProvStatusInactive() {
935 Map<String, String> orig = event.getAai();
937 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "ACTIVE"));
938 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
940 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "inactive"));
941 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
942 .isInstanceOf(IllegalStateException.class);
944 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "ACTIVE"));
945 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
947 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "inactive"));
948 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
949 .isInstanceOf(IllegalStateException.class);
953 public void testIsAaiTrue() {
954 Map<String, String> orig = event.getAai();
956 for (String value : Arrays.asList("yes", "y", "true", "t", "yEs", "trUe")) {
957 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, value));
958 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
959 .isInstanceOf(IllegalStateException.class);
962 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "false"));
963 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
965 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "no"));
966 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
970 private Map<String, String> addAai(Map<String, String> original, String key, String value) {
971 Map<String, String> map = new TreeMap<>(original);
976 private void loadPolicy(String fileName) throws CoderException {
977 ToscaServiceTemplate template =
978 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
979 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
981 params.setToscaPolicy(tosca);
984 private void loadStepsWithProperties(String... properties) {
985 stepa = new Step2(mgr, ControlLoopOperationParams.builder().build(), event) {
988 public boolean isPolicyStep() {
993 public List<String> getPropertyNames() {
994 return List.of(properties);
998 protected Operation buildOperation() {
999 return policyOperation;
1003 mgr.getSteps().add(stepa);
1004 mgr.getSteps().add(stepb);
1007 private OperationOutcome makeCompletedOutcome() {
1008 OperationOutcome outcome = makeOutcome();
1009 outcome.setEnd(outcome.getStart());
1014 private OperationOutcome makeOutcome() {
1015 OperationOutcome outcome = new OperationOutcome();
1016 outcome.setActor(SIMPLE_ACTOR);
1017 outcome.setOperation(SIMPLE_OPERATION);
1018 outcome.setMessage(OUTCOME_MSG);
1019 outcome.setResult(PolicyResult.SUCCESS);
1020 outcome.setStart(Instant.now());
1021 outcome.setTarget(MY_TARGET);
1026 private void checkResp(OperationOutcome outcome, String expectedPayload) {
1027 ControlLoopResponse resp = mgr.makeControlLoopResponse(outcome);
1028 assertNotNull(resp);
1029 assertEquals(REQ_ID, resp.getRequestId());
1030 assertEquals(expectedPayload, resp.getPayload());
1034 * Sets the target entity so a step doesn't have to be added to set it.
1036 private void setTargetEntity() {
1037 mgr.setProperty(OperationProperties.AAI_TARGET_ENTITY, MY_TARGET);
1041 private class MyManager extends UsecasesEventManager {
1042 private static final long serialVersionUID = 1L;
1044 public MyManager(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem)
1045 throws ControlLoopException {
1047 super(params, event, workMem);
1051 protected ExecutorService getBlockingExecutor() {
1056 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
1057 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
1059 callback.lockAvailable(lock);
1063 public ActorService getActorService() {
1068 public OperationHistoryDataManager getDataManager() {
1073 protected PolicyEngine getPolicyEngineManager() {