2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2020-2021 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.Deque;
43 import java.util.List;
45 import java.util.TreeMap;
46 import java.util.UUID;
47 import java.util.concurrent.ExecutorService;
48 import java.util.concurrent.ForkJoinPool;
49 import org.drools.core.WorkingMemory;
50 import org.junit.Before;
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 import org.kie.api.runtime.rule.FactHandle;
54 import org.mockito.Mock;
55 import org.mockito.junit.MockitoJUnitRunner;
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.OperationFinalResult;
70 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
71 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
72 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
73 import org.onap.policy.controlloop.actorserviceprovider.Operator;
74 import org.onap.policy.controlloop.actorserviceprovider.TargetType;
75 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
76 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
77 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
78 import org.onap.policy.controlloop.eventmanager.ActorConstants;
79 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
80 import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager.NewEventStatus;
81 import org.onap.policy.drools.apps.controller.usecases.step.AaiCqStep2;
82 import org.onap.policy.drools.apps.controller.usecases.step.AaiGetPnfStep2;
83 import org.onap.policy.drools.apps.controller.usecases.step.AaiGetTenantStep2;
84 import org.onap.policy.drools.apps.controller.usecases.step.GetTargetEntityStep2;
85 import org.onap.policy.drools.apps.controller.usecases.step.GuardStep2;
86 import org.onap.policy.drools.apps.controller.usecases.step.Step2;
87 import org.onap.policy.drools.core.lock.LockCallback;
88 import org.onap.policy.drools.core.lock.LockImpl;
89 import org.onap.policy.drools.core.lock.LockState;
90 import org.onap.policy.drools.system.PolicyEngine;
91 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
92 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
93 import org.onap.policy.sdnr.PciBody;
94 import org.onap.policy.sdnr.PciMessage;
95 import org.onap.policy.sdnr.PciResponse;
97 @RunWith(MockitoJUnitRunner.class)
98 public class UsecasesEventManagerTest {
99 private static final UUID REQ_ID = UUID.randomUUID();
100 private static final String CL_NAME = "my-closed-loop-name";
101 private static final String POLICY_NAME = "my-policy-name";
102 private static final String POLICY_SCOPE = "my-scope";
103 private static final String POLICY_VERSION = "1.2.3";
104 private static final String SIMPLE_ACTOR = "First";
105 private static final String SIMPLE_OPERATION = "OperationA";
106 private static final String MY_TARGET = "my-target";
107 private static final String EVENT_MGR_MULTI_YAML =
108 "../eventmanager/src/test/resources/eventManager/event-mgr-multi.yaml";
109 private static final String EVENT_MGR_SIMPLE_YAML =
110 "../eventmanager/src/test/resources/eventManager/event-mgr-simple.yaml";
111 private static final Coder yamlCoder = new StandardYamlCoder();
112 private static final String OUTCOME_MSG = "my outcome message";
113 private static final String MY_SINK = "my-topic-sink";
116 private PolicyEngine engineMgr;
118 private WorkingMemory workMem;
120 private FactHandle factHandle;
122 private Operator policyOperator;
124 private Operation policyOperation;
126 private Actor policyActor;
128 private ActorService actors;
130 private OperationHistoryDataManager dataMgr;
132 private ExecutorService executor;
138 private List<LockImpl> locks;
139 private ToscaPolicy tosca;
140 private ControlLoopParams params;
141 private VirtualControlLoopEvent event;
142 private UsecasesEventManager mgr;
148 public void setUp() throws ControlLoopException, CoderException {
149 when(workMem.getFactHandle(any())).thenReturn(factHandle);
151 event = new VirtualControlLoopEvent();
152 event.setRequestId(REQ_ID);
153 event.setTarget(UsecasesConstants.VSERVER_VSERVER_NAME);
154 event.setAai(new TreeMap<>(Map.of(UsecasesConstants.VSERVER_VSERVER_NAME, MY_TARGET)));
155 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
156 event.setClosedLoopControlName(CL_NAME);
157 event.setTargetType(ControlLoopTargetType.VNF);
159 params = new ControlLoopParams();
160 params.setClosedLoopControlName(CL_NAME);
161 params.setPolicyName(POLICY_NAME);
162 params.setPolicyScope(POLICY_SCOPE);
163 params.setPolicyVersion(POLICY_VERSION);
165 loadPolicy(EVENT_MGR_SIMPLE_YAML);
167 locks = new ArrayList<>();
169 mgr = new MyManager(params, event, workMem);
173 public void testConstructor() {
174 assertEquals(POLICY_NAME, mgr.getPolicyName());
175 assertSame(event, mgr.getEvent());
177 Map<String, String> orig = event.getAai();
179 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
180 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
181 .hasMessage("is-closed-loop-disabled is set to true on VServer or VNF");
184 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS,
185 UsecasesConstants.PROV_STATUS_ACTIVE.toUpperCase()));
186 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
189 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS,
190 UsecasesConstants.PROV_STATUS_ACTIVE.toLowerCase()));
191 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
194 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS, "inactive"));
195 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
196 .hasMessage("prov-status is not ACTIVE on VServer or VNF");
199 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS,
200 UsecasesConstants.PROV_STATUS_ACTIVE.toUpperCase()));
201 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
204 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS,
205 UsecasesConstants.PROV_STATUS_ACTIVE.toLowerCase()));
206 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
209 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS, "inactive"));
210 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
211 .hasMessage("prov-status is not ACTIVE on VServer or VNF");
215 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
218 event.setTarget("unknown-target");
219 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
220 .isInstanceOf(ControlLoopException.class);
224 public void testIsActive() throws Exception {
225 mgr = new UsecasesEventManager(params, event, workMem);
226 assertTrue(mgr.isActive());
228 // deserialized manager should be inactive
229 UsecasesEventManager mgr2 = Serializer.roundTrip(mgr);
230 assertFalse(mgr2.isActive());
234 public void testDestroy_testGetSteps() {
235 // add some steps to the queue
236 mgr.getSteps().add(stepa);
237 mgr.getSteps().add(stepb);
241 verify(stepa).cancel();
242 verify(stepb).cancel();
244 // if superclass destroy() was invoked, then freeLock() should have been submitted
246 verify(executor).execute(any());
250 public void testOnStart() throws ControlLoopException {
251 OperationOutcome outcome = makeOutcome();
254 mgr.onStart(outcome);
256 assertSame(outcome, mgr.getOutcomes().poll());
257 assertThat(mgr.getOutcomes()).isEmpty();
259 verify(workMem).update(factHandle, mgr);
263 public void testOnComplete() throws ControlLoopException {
264 OperationOutcome outcome = makeCompletedOutcome();
267 mgr.onComplete(outcome);
269 assertSame(outcome, mgr.getOutcomes().poll());
270 assertThat(mgr.getOutcomes()).isEmpty();
272 verify(workMem).update(factHandle, mgr);
276 public void testToString() {
277 assertNotNull(mgr.toString());
281 public void testStart() throws ControlLoopException {
286 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
287 .hasMessage("manager already started");
291 * Tests start() when the manager is not in working memory.
294 public void testStartNotInWorkingMemory() throws ControlLoopException {
295 when(workMem.getFactHandle(any())).thenReturn(null);
297 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
298 .hasMessage("manager is not in working memory");
302 * Tests start() when the manager is not active.
305 public void testStartInactive() throws Exception {
306 // make an inactive manager by deserializing it
307 mgr = Serializer.roundTrip(new UsecasesEventManager(params, event, workMem));
310 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
311 .hasMessage("manager is no longer active");
315 public void testAbort() {
316 mgr.abort(UsecasesEventManager.State.DONE, OperationFinalResult.FINAL_FAILURE_GUARD, "some message");
318 assertEquals(UsecasesEventManager.State.DONE, mgr.getState());
319 assertEquals(OperationFinalResult.FINAL_FAILURE_GUARD, mgr.getFinalResult());
320 assertEquals("some message", mgr.getFinalMessage());
323 assertThatThrownBy(() -> mgr.abort(null, OperationFinalResult.FINAL_FAILURE_GUARD, ""))
324 .isInstanceOf(NullPointerException.class).hasMessageContaining("finalState");
328 public void testLoadNextPolicy_testGetFullHistory_testGetPartialHistory() throws Exception {
329 loadPolicy(EVENT_MGR_MULTI_YAML);
330 mgr = new MyManager(params, event, workMem);
332 // start and load step for first policy
334 assertEquals("OperationA", mgr.getSteps().poll().getOperationName());
335 assertNull(mgr.getFinalResult());
338 OperationOutcome outcome = makeOutcome();
339 mgr.addToHistory(outcome);
341 // indicate success and load next policy
342 mgr.loadNextPolicy(OperationResult.SUCCESS);
343 assertEquals("OperationB", mgr.getSteps().poll().getOperationName());
344 assertNull(mgr.getFinalResult());
346 // loadPolicy() should clear the partial history, but not the full history
347 assertThat(mgr.getPartialHistory()).isEmpty();
348 assertThat(mgr.getFullHistory()).hasSize(1);
350 // indicate failure - should go to final failure
351 mgr.loadNextPolicy(OperationResult.FAILURE);
352 assertEquals(OperationFinalResult.FINAL_FAILURE, mgr.getFinalResult());
356 public void testLoadPolicy() throws ControlLoopException {
357 // start() will invoke loadPolicy()
360 assertNull(mgr.getFinalResult());
362 Step2 step = mgr.getSteps().peek();
364 assertEquals("First", step.getActorName());
365 assertEquals("OperationA", step.getOperationName());
367 ControlLoopOperationParams params2 = step.getParams();
368 assertSame(actors, params2.getActorService());
369 assertSame(REQ_ID, params2.getRequestId());
370 assertSame(ForkJoinPool.commonPool(), params2.getExecutor());
371 assertNotNull(params2.getTargetType());
372 assertNotNull(params2.getTargetEntityIds());
373 assertEquals(Integer.valueOf(300), params2.getTimeoutSec());
374 assertEquals(Integer.valueOf(0), params2.getRetry());
375 assertThat(params2.getPayload()).isEmpty();
376 assertNotNull(params2.getStartCallback());
377 assertNotNull(params2.getCompleteCallback());
381 public void testLoadPreprocessorSteps() {
382 stepa = new Step2(mgr, ControlLoopOperationParams.builder().build(), event) {
384 public List<String> getPropertyNames() {
385 return List.of(OperationProperties.AAI_DEFAULT_CLOUD_REGION);
389 protected Operation buildOperation() {
390 return policyOperation;
394 mgr.getSteps().add(stepa);
395 mgr.getSteps().add(stepb);
397 mgr.loadPreprocessorSteps();
399 Deque<Step2> steps = mgr.getSteps();
401 Step2 lockStep = steps.poll();
402 assertNotNull(lockStep);
403 assertEquals(ActorConstants.LOCK_ACTOR, lockStep.getActorName());
404 assertThat(steps.poll()).isInstanceOf(AaiCqStep2.class);
405 assertThat(steps.poll()).isInstanceOf(GuardStep2.class);
406 assertSame(stepa, steps.poll());
407 assertSame(stepb, steps.poll());
408 assertThat(steps).isEmpty();
412 * Tests loadPreprocessorSteps() when there are too many steps in the queue.
415 public void testLoadPreprocessorStepsTooManySteps() {
416 loadStepsWithProperties(OperationProperties.AAI_PNF);
418 Deque<Step2> steps = mgr.getSteps();
419 stepa = steps.getFirst();
422 // load up a bunch of steps
423 for (int nsteps = 0; nsteps < UsecasesEventManager.MAX_STEPS; ++nsteps) {
428 assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
430 // add another step, should still fail
432 assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
434 // remove two steps - should now succeed
438 int nsteps = steps.size();
440 mgr.loadPreprocessorSteps();
441 assertEquals(nsteps + 1, steps.size());
445 * Tests loadPreprocessorSteps() when no additional steps are needed.
448 public void testLoadPreprocessorStepsNothingToLoad() {
449 when(stepa.isPolicyStep()).thenReturn(false);
450 when(stepa.getPropertyNames()).thenReturn(List.of("unknown-property"));
452 Deque<Step2> steps = mgr.getSteps();
457 mgr.loadPreprocessorSteps();
459 assertSame(stepa, steps.poll());
460 assertSame(stepb, steps.poll());
461 assertThat(steps).isEmpty();
465 * Tests loadPreprocessorSteps() when an A&AI custom query is needed.
468 public void testLoadPreprocessorStepsCq() {
469 loadStepsWithProperties(OperationProperties.AAI_DEFAULT_CLOUD_REGION, OperationProperties.AAI_DEFAULT_TENANT);
472 mgr.loadPreprocessorSteps();
474 Deque<Step2> steps = mgr.getSteps();
476 assertThat(steps.poll()).isInstanceOf(AaiCqStep2.class);
477 assertSame(stepa, steps.poll());
478 assertSame(stepb, steps.poll());
479 assertThat(steps).isEmpty();
483 * Tests loadPreprocessorSteps() when an A&AI PNF query is needed.
486 public void testLoadPreprocessorStepsPnf() {
487 // doubling up the property to check both branches
488 loadStepsWithProperties(OperationProperties.AAI_PNF, OperationProperties.AAI_PNF);
491 mgr.loadPreprocessorSteps();
493 Deque<Step2> steps = mgr.getSteps();
495 assertThat(steps.poll()).isInstanceOf(AaiGetPnfStep2.class);
496 assertSame(stepa, steps.poll());
497 assertSame(stepb, steps.poll());
498 assertThat(steps).isEmpty();
502 * Tests loadPreprocessorSteps() when an A&AI Tenant query is needed.
505 public void testLoadPreprocessorStepsTenant() {
506 // doubling up the property to check both branches
507 event.getAai().put(Step2.VSERVER_VSERVER_NAME, "my-vserver");
508 loadStepsWithProperties(OperationProperties.AAI_VSERVER_LINK, OperationProperties.AAI_VSERVER_LINK);
511 mgr.loadPreprocessorSteps();
513 Deque<Step2> steps = mgr.getSteps();
515 assertThat(steps.poll()).isInstanceOf(AaiGetTenantStep2.class);
516 assertSame(stepa, steps.poll());
517 assertSame(stepb, steps.poll());
518 assertThat(steps).isEmpty();
522 * Tests loadPreprocessorSteps() when the target entity is unset.
525 public void testLoadPreprocessorStepsNeedTargetEntity() {
526 stepa = new Step2(mgr,
527 ControlLoopOperationParams.builder()
528 .targetType(TargetType.toTargetType(event.getTargetType()))
529 .targetEntityIds(Map.of()).build(), event) {
531 public List<String> getPropertyNames() {
532 return List.of(OperationProperties.AAI_TARGET_ENTITY);
536 protected Operation buildOperation() {
537 return policyOperation;
541 public boolean isPolicyStep() {
546 Deque<Step2> steps = mgr.getSteps();
550 mgr.loadPreprocessorSteps();
552 Step2 entityStep = steps.poll();
554 assertThat(entityStep).isInstanceOf(GetTargetEntityStep2.class);
555 assertSame(stepa, steps.poll());
556 assertSame(stepb, steps.poll());
557 assertThat(steps).isEmpty();
559 // put get-target-entity back onto the queue and ensure nothing else is added
560 steps.add(entityStep);
561 mgr.loadPreprocessorSteps();
562 assertSame(entityStep, steps.poll());
563 assertThat(steps).isEmpty();
567 public void testExecuteStep() {
570 // no steps to execute
571 assertFalse(mgr.executeStep());
572 assertEquals(0, mgr.getAttempts());
574 // add a step to the queue
575 mgr.getSteps().add(stepa);
577 // step returns false
578 when(stepa.start(anyLong())).thenReturn(false);
579 assertFalse(mgr.executeStep());
582 when(stepa.start(anyLong())).thenReturn(true);
583 assertTrue(mgr.executeStep());
587 public void testNextStep() {
588 mgr.getSteps().add(stepa);
592 assertThat(mgr.getSteps()).isEmpty();
596 public void testBumpAttempts() {
597 assertEquals(0, mgr.getAttempts());
601 assertEquals(2, mgr.getAttempts());
605 public void testIsAbort() {
606 OperationOutcome outcome = makeCompletedOutcome();
607 outcome.setResult(OperationResult.FAILURE);
609 // closed loop timeout
610 outcome.setActor(ActorConstants.CL_TIMEOUT_ACTOR);
611 assertTrue(mgr.isAbort(outcome));
614 outcome.setActor(ActorConstants.LOCK_ACTOR);
615 assertTrue(mgr.isAbort(outcome));
617 // no effect for success
618 outcome.setResult(OperationResult.SUCCESS);
619 assertFalse(mgr.isAbort(outcome));
623 public void testAddToHistory() throws ControlLoopException {
626 // add a "start" outcome
627 OperationOutcome outcome = makeOutcome();
628 mgr.addToHistory(outcome);
630 assertThat(mgr.getPartialHistory()).hasSize(1);
631 assertThat(mgr.getFullHistory()).hasSize(1);
633 // add a "completion" outcome - should replace the start
634 outcome = makeCompletedOutcome();
635 mgr.addToHistory(outcome);
637 assertThat(mgr.getPartialHistory()).hasSize(1);
638 assertThat(mgr.getFullHistory()).hasSize(1);
639 assertSame(outcome, mgr.getPartialHistory().peek().getOutcome());
640 assertSame(outcome, mgr.getFullHistory().peek().getOutcome());
643 outcome = makeOutcome();
644 mgr.addToHistory(outcome);
646 assertThat(mgr.getPartialHistory()).hasSize(2);
647 assertThat(mgr.getFullHistory()).hasSize(2);
648 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
649 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
651 // remove the last item from the full history and then add a "completion"
652 mgr.getFullHistory().removeLast();
653 outcome = makeCompletedOutcome();
654 mgr.addToHistory(outcome);
655 assertThat(mgr.getPartialHistory()).hasSize(2);
656 assertThat(mgr.getFullHistory()).hasSize(2);
658 // add another "start"
659 outcome = makeOutcome();
660 mgr.addToHistory(outcome);
661 assertThat(mgr.getPartialHistory()).hasSize(3);
662 assertThat(mgr.getFullHistory()).hasSize(3);
664 // add a "completion" for a different actor - should NOT replace the start
665 outcome = makeCompletedOutcome();
666 outcome.setActor("different-actor");
667 mgr.addToHistory(outcome);
668 assertThat(mgr.getPartialHistory()).hasSize(4);
669 assertThat(mgr.getFullHistory()).hasSize(4);
670 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
671 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
675 public void testMakeNotification() throws Exception {
676 loadPolicy(EVENT_MGR_MULTI_YAML);
677 mgr = new MyManager(params, event, workMem);
680 assertNotNull(mgr.makeNotification());
684 mgr.addToHistory(makeCompletedOutcome());
685 mgr.addToHistory(makeCompletedOutcome());
686 mgr.addToHistory(makeCompletedOutcome());
688 // check notification while running
689 VirtualControlLoopNotification notif = mgr.makeNotification();
690 assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
691 assertThat(notif.getHistory()).hasSize(3);
693 // indicate success and load the next policy - should clear the partial history
694 mgr.loadNextPolicy(OperationResult.SUCCESS);
696 // check notification
697 notif = mgr.makeNotification();
698 assertNull(notif.getMessage());
699 assertThat(notif.getHistory()).isEmpty();
701 // add outcomes and check again
702 mgr.addToHistory(makeCompletedOutcome());
703 mgr.addToHistory(makeCompletedOutcome());
705 notif = mgr.makeNotification();
706 assertNotNull(notif.getMessage());
708 // should only have history for last two outcomes
709 assertThat(notif.getHistory()).hasSize(2);
711 // indicate failure - should go to final state
712 mgr.loadNextPolicy(OperationResult.FAILURE);
714 // check notification
715 notif = mgr.makeNotification();
716 assertNull(notif.getMessage());
718 // should be no history
719 assertThat(notif.getHistory()).isEmpty();
722 assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
723 .hasMessageContaining("lastResult");
727 public void testDeliver() {
728 mgr.deliver(MY_SINK, null, "null notification", "null rule");
729 verify(engineMgr, never()).deliver(any(), any());
731 mgr.deliver(MY_SINK, "publishA", "A notification", "A rule");
732 verify(engineMgr).deliver(MY_SINK, "publishA");
734 // cause deliver() to throw an exception
735 when(engineMgr.deliver(any(), any())).thenThrow(new IllegalStateException("expected exception"));
736 assertThatCode(() -> mgr.deliver(MY_SINK, "publishB", "B notification", "B rule")).doesNotThrowAnyException();
740 public void testGetOperationMessage() throws ControlLoopException {
742 assertNull(mgr.getOperationMessage());
746 OperationOutcome outcome = makeOutcome();
747 mgr.addToHistory(outcome);
749 assertThat(mgr.getOperationMessage()).contains("actor=" + SIMPLE_ACTOR)
750 .contains("operation=" + SIMPLE_OPERATION);
754 public void testStoreInDataBase() throws ControlLoopException {
756 OperationOutcome outcome = makeOutcome();
757 mgr.addToHistory(outcome);
759 mgr.storeInDataBase(mgr.getPartialHistory().peekLast());
761 verify(dataMgr).store(REQ_ID.toString(), event, null, mgr.getPartialHistory().peekLast().getClOperation());
765 public void testMakeControlLoopResponse() {
766 final OperationOutcome outcome = new OperationOutcome();
768 // no message - should return null
769 checkResp(outcome, null);
771 // not a PciMessage - should return null
772 outcome.setResponse("not-a-pci-message");
773 checkResp(outcome, null);
776 * now work with a PciMessage
778 PciMessage msg = new PciMessage();
779 outcome.setResponse(msg);
781 PciBody body = new PciBody();
784 PciResponse output = new PciResponse();
785 body.setOutput(output);
787 output.setPayload("my-payload");
789 // should generate a response, with a payload
790 checkResp(outcome, "my-payload");
793 * these should generate a response, with null payload
795 output.setPayload(null);
796 checkResp(outcome, null);
798 body.setOutput(null);
799 checkResp(outcome, null);
802 checkResp(outcome, null);
804 outcome.setResponse(null);
805 checkResp(outcome, null);
809 public void testOnNewEvent() {
810 VirtualControlLoopEvent event2 = new VirtualControlLoopEvent(event);
811 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event2));
813 event2.setPayload("other payload");
814 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
815 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
816 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event));
818 event2.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
819 assertEquals(NewEventStatus.FIRST_ABATEMENT, mgr.onNewEvent(event2));
821 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
822 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
824 event2.setClosedLoopEventStatus(null);
825 assertEquals(NewEventStatus.SYNTAX_ERROR, mgr.onNewEvent(event2));
829 public void testCheckEventSyntax() {
830 // initially, it's valid
831 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
833 event.setTarget("unknown-target");
834 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
835 .hasMessage("target field invalid");
837 event.setTarget(null);
838 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
839 .hasMessage("No target field");
841 // abated supersedes previous errors - so it shouldn't throw an exception
842 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
843 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
845 event.setRequestId(null);
846 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
847 .hasMessage("No request ID");
849 event.setClosedLoopControlName(null);
850 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
851 .hasMessage("No control loop name");
855 public void testValidateStatus() {
856 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
857 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
859 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
860 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
862 event.setClosedLoopEventStatus(null);
863 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
864 .hasMessage("Invalid value in closedLoopEventStatus");
868 public void testValidateAaiData() {
869 event.setTargetType("unknown-target-type");
870 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
871 .hasMessage("The target type is not supported");
873 event.setTargetType(null);
874 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
875 .hasMessage("The Target type is null");
878 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
879 .hasMessage("AAI is null");
882 event.setTargetType(ControlLoopTargetType.VM);
883 event.setAai(Map.of(UsecasesConstants.GENERIC_VNF_VNF_ID, MY_TARGET));
884 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
886 event.setAai(Map.of());
887 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
890 event.setTargetType(ControlLoopTargetType.VNF);
891 event.setAai(Map.of(UsecasesConstants.GENERIC_VNF_VNF_ID, MY_TARGET));
892 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
894 event.setAai(Map.of());
895 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
898 event.setTargetType(ControlLoopTargetType.PNF);
899 event.setAai(Map.of(UsecasesConstants.PNF_NAME, MY_TARGET));
900 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
902 event.setAai(Map.of());
903 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
907 public void testValidateAaiVmVnfData() {
908 event.setTargetType(ControlLoopTargetType.VM);
909 event.setAai(Map.of(UsecasesConstants.GENERIC_VNF_VNF_ID, MY_TARGET));
910 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
912 event.setAai(Map.of(UsecasesConstants.VSERVER_VSERVER_NAME, MY_TARGET));
913 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
915 event.setAai(Map.of(UsecasesConstants.GENERIC_VNF_VNF_NAME, MY_TARGET));
916 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
918 event.setAai(Map.of());
919 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class).hasMessage(
920 "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
924 public void testValidateAaiPnfData() {
925 event.setTargetType(ControlLoopTargetType.PNF);
926 event.setAai(Map.of(UsecasesConstants.PNF_NAME, MY_TARGET));
927 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
929 event.setAai(Map.of());
930 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
931 .hasMessage("AAI PNF object key pnf-name is missing");
935 public void testIsClosedLoopDisabled() {
936 Map<String, String> orig = event.getAai();
938 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
939 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
940 .isInstanceOf(IllegalStateException.class);
942 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED, "true"));
943 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
944 .isInstanceOf(IllegalStateException.class);
946 event.setAai(addAai(orig, UsecasesConstants.PNF_IS_IN_MAINT, "true"));
947 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
948 .isInstanceOf(IllegalStateException.class);
952 public void testIsProvStatusInactive() {
953 Map<String, String> orig = event.getAai();
955 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS, "ACTIVE"));
956 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
958 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS, "inactive"));
959 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
960 .isInstanceOf(IllegalStateException.class);
962 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS, "ACTIVE"));
963 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
965 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS, "inactive"));
966 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
967 .isInstanceOf(IllegalStateException.class);
971 public void testIsAaiTrue() {
972 Map<String, String> orig = event.getAai();
974 for (String value : Arrays.asList("yes", "y", "true", "t", "yEs", "trUe")) {
975 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, value));
976 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
977 .isInstanceOf(IllegalStateException.class);
980 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "false"));
981 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
983 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "no"));
984 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
988 private Map<String, String> addAai(Map<String, String> original, String key, String value) {
989 Map<String, String> map = new TreeMap<>(original);
994 private void loadPolicy(String fileName) throws CoderException {
995 ToscaServiceTemplate template =
996 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
997 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
999 params.setToscaPolicy(tosca);
1002 private void loadStepsWithProperties(String... properties) {
1003 stepa = new Step2(mgr, ControlLoopOperationParams.builder().build(), event) {
1006 public boolean isPolicyStep() {
1011 public List<String> getPropertyNames() {
1012 return List.of(properties);
1016 protected Operation buildOperation() {
1017 return policyOperation;
1021 mgr.getSteps().add(stepa);
1022 mgr.getSteps().add(stepb);
1025 private OperationOutcome makeCompletedOutcome() {
1026 OperationOutcome outcome = makeOutcome();
1027 outcome.setEnd(outcome.getStart());
1032 private OperationOutcome makeOutcome() {
1033 OperationOutcome outcome = new OperationOutcome();
1034 outcome.setActor(SIMPLE_ACTOR);
1035 outcome.setOperation(SIMPLE_OPERATION);
1036 outcome.setMessage(OUTCOME_MSG);
1037 outcome.setResult(OperationResult.SUCCESS);
1038 outcome.setStart(Instant.now());
1039 outcome.setTarget(MY_TARGET);
1044 private void checkResp(OperationOutcome outcome, String expectedPayload) {
1045 ControlLoopResponse resp = mgr.makeControlLoopResponse(outcome);
1046 assertNotNull(resp);
1047 assertEquals(REQ_ID, resp.getRequestId());
1048 assertEquals(expectedPayload, resp.getPayload());
1052 * Sets the target entity so a step doesn't have to be added to set it.
1054 private void setTargetEntity() {
1055 mgr.setProperty(OperationProperties.AAI_TARGET_ENTITY, MY_TARGET);
1059 private class MyManager extends UsecasesEventManager {
1060 private static final long serialVersionUID = 1L;
1062 public MyManager(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem)
1063 throws ControlLoopException {
1065 super(params, event, workMem);
1069 protected ExecutorService getBlockingExecutor() {
1074 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
1075 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
1077 callback.lockAvailable(lock);
1081 public ActorService getActorService() {
1086 public OperationHistoryDataManager getDataManager() {
1091 protected PolicyEngine getPolicyEngineManager() {