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.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.eventmanager.ControlLoopEventManager2;
80 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
81 import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager.NewEventStatus;
82 import org.onap.policy.drools.apps.controller.usecases.step.AaiCqStep2;
83 import org.onap.policy.drools.apps.controller.usecases.step.AaiGetPnfStep2;
84 import org.onap.policy.drools.apps.controller.usecases.step.AaiGetTenantStep2;
85 import org.onap.policy.drools.apps.controller.usecases.step.GetTargetEntityStep2;
86 import org.onap.policy.drools.apps.controller.usecases.step.GuardStep2;
87 import org.onap.policy.drools.apps.controller.usecases.step.Step2;
88 import org.onap.policy.drools.core.lock.LockCallback;
89 import org.onap.policy.drools.core.lock.LockImpl;
90 import org.onap.policy.drools.core.lock.LockState;
91 import org.onap.policy.drools.system.PolicyEngine;
92 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
93 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
94 import org.onap.policy.sdnr.PciBody;
95 import org.onap.policy.sdnr.PciMessage;
96 import org.onap.policy.sdnr.PciResponse;
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 MockitoAnnotations.initMocks(this);
151 when(actors.getActor(SIMPLE_ACTOR)).thenReturn(policyActor);
152 when(policyActor.getOperator(SIMPLE_OPERATION)).thenReturn(policyOperator);
153 when(policyOperator.buildOperation(any())).thenReturn(policyOperation);
154 when(policyOperation.getPropertyNames()).thenReturn(Collections.emptyList());
156 when(workMem.getFactHandle(any())).thenReturn(factHandle);
158 event = new VirtualControlLoopEvent();
159 event.setRequestId(REQ_ID);
160 event.setTarget(UsecasesConstants.VSERVER_VSERVER_NAME);
161 event.setAai(new TreeMap<>(Map.of(UsecasesConstants.VSERVER_VSERVER_NAME, MY_TARGET)));
162 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
163 event.setClosedLoopControlName(CL_NAME);
164 event.setTargetType(ControlLoopTargetType.VNF);
166 params = new ControlLoopParams();
167 params.setClosedLoopControlName(CL_NAME);
168 params.setPolicyName(POLICY_NAME);
169 params.setPolicyScope(POLICY_SCOPE);
170 params.setPolicyVersion(POLICY_VERSION);
172 loadPolicy(EVENT_MGR_SIMPLE_YAML);
174 locks = new ArrayList<>();
176 mgr = new MyManager(params, event, workMem);
180 public void testConstructor() {
181 assertEquals(POLICY_NAME, mgr.getPolicyName());
182 assertSame(event, mgr.getEvent());
184 Map<String, String> orig = event.getAai();
186 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
187 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
188 .hasMessage("is-closed-loop-disabled is set to true on VServer or VNF");
190 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS, "inactive"));
191 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
192 .hasMessage("prov-status is not ACTIVE on VServer or VNF");
196 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
199 event.setTarget("unknown-target");
200 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
201 .isInstanceOf(ControlLoopException.class);
205 public void testIsActive() throws Exception {
206 mgr = new UsecasesEventManager(params, event, workMem);
207 assertTrue(mgr.isActive());
209 // deserialized manager should be inactive
210 UsecasesEventManager mgr2 = Serializer.roundTrip(mgr);
211 assertFalse(mgr2.isActive());
215 public void testDestroy_testGetSteps() {
216 // add some steps to the queue
217 mgr.getSteps().add(stepa);
218 mgr.getSteps().add(stepb);
222 verify(stepa).cancel();
223 verify(stepb).cancel();
225 // if superclass destroy() was invoked, then freeLock() should have been submitted
227 verify(executor).execute(any());
231 public void testOnStart() throws ControlLoopException {
232 OperationOutcome outcome = makeOutcome();
235 mgr.onStart(outcome);
237 assertSame(outcome, mgr.getOutcomes().poll());
238 assertThat(mgr.getOutcomes()).isEmpty();
240 verify(workMem).update(factHandle, mgr);
244 public void testOnComplete() throws ControlLoopException {
245 OperationOutcome outcome = makeCompletedOutcome();
248 mgr.onComplete(outcome);
250 assertSame(outcome, mgr.getOutcomes().poll());
251 assertThat(mgr.getOutcomes()).isEmpty();
253 verify(workMem).update(factHandle, mgr);
257 public void testToString() {
258 assertNotNull(mgr.toString());
262 public void testStart() throws ControlLoopException {
267 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
268 .hasMessage("manager already started");
272 * Tests start() when the manager is not in working memory.
275 public void testStartNotInWorkingMemory() throws ControlLoopException {
276 when(workMem.getFactHandle(any())).thenReturn(null);
278 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
279 .hasMessage("manager is not in working memory");
283 * Tests start() when the manager is not active.
286 public void testStartInactive() throws Exception {
287 // make an inactive manager by deserializing it
288 mgr = Serializer.roundTrip(new UsecasesEventManager(params, event, workMem));
291 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
292 .hasMessage("manager is no longer active");
296 public void testAbort() {
297 mgr.abort(UsecasesEventManager.State.DONE, OperationFinalResult.FINAL_FAILURE_GUARD, "some message");
299 assertEquals(UsecasesEventManager.State.DONE, mgr.getState());
300 assertEquals(OperationFinalResult.FINAL_FAILURE_GUARD, mgr.getFinalResult());
301 assertEquals("some message", mgr.getFinalMessage());
304 assertThatThrownBy(() -> mgr.abort(null, OperationFinalResult.FINAL_FAILURE_GUARD, ""))
305 .isInstanceOf(NullPointerException.class).hasMessageContaining("finalState");
309 public void testLoadNextPolicy_testGetFullHistory_testGetPartialHistory() throws Exception {
310 loadPolicy(EVENT_MGR_MULTI_YAML);
311 mgr = new MyManager(params, event, workMem);
313 // start and load step for first policy
315 assertEquals("OperationA", mgr.getSteps().poll().getOperationName());
316 assertNull(mgr.getFinalResult());
319 OperationOutcome outcome = makeOutcome();
320 mgr.addToHistory(outcome);
322 // indicate success and load next policy
323 mgr.loadNextPolicy(OperationResult.SUCCESS);
324 assertEquals("OperationB", mgr.getSteps().poll().getOperationName());
325 assertNull(mgr.getFinalResult());
327 // loadPolicy() should clear the partial history, but not the full history
328 assertThat(mgr.getPartialHistory()).isEmpty();
329 assertThat(mgr.getFullHistory()).hasSize(1);
331 // indicate failure - should go to final failure
332 mgr.loadNextPolicy(OperationResult.FAILURE);
333 assertEquals(OperationFinalResult.FINAL_FAILURE, mgr.getFinalResult());
337 public void testLoadPolicy() throws ControlLoopException {
338 // start() will invoke loadPolicy()
341 assertNull(mgr.getFinalResult());
343 Step2 step = mgr.getSteps().peek();
345 assertEquals("First", step.getActorName());
346 assertEquals("OperationA", step.getOperationName());
348 ControlLoopOperationParams params2 = step.getParams();
349 assertSame(actors, params2.getActorService());
350 assertSame(REQ_ID, params2.getRequestId());
351 assertSame(ForkJoinPool.commonPool(), params2.getExecutor());
352 assertNotNull(params2.getTargetType());
353 assertNotNull(params2.getTargetEntityIds());
354 assertEquals(Integer.valueOf(300), params2.getTimeoutSec());
355 assertEquals(Integer.valueOf(0), params2.getRetry());
356 assertThat(params2.getPayload()).isEmpty();
357 assertNotNull(params2.getStartCallback());
358 assertNotNull(params2.getCompleteCallback());
362 public void testLoadPreprocessorSteps() {
363 stepa = new Step2(mgr, ControlLoopOperationParams.builder().build(), event) {
365 public List<String> getPropertyNames() {
366 return List.of(OperationProperties.AAI_DEFAULT_CLOUD_REGION);
370 protected Operation buildOperation() {
371 return policyOperation;
375 mgr.getSteps().add(stepa);
376 mgr.getSteps().add(stepb);
378 mgr.loadPreprocessorSteps();
380 Deque<Step2> steps = mgr.getSteps();
382 Step2 lockStep = steps.poll();
383 assertNotNull(lockStep);
384 assertEquals(ActorConstants.LOCK_ACTOR, lockStep.getActorName());
385 assertThat(steps.poll()).isInstanceOf(AaiCqStep2.class);
386 assertThat(steps.poll()).isInstanceOf(GuardStep2.class);
387 assertSame(stepa, steps.poll());
388 assertSame(stepb, steps.poll());
389 assertThat(steps).isEmpty();
393 * Tests loadPreprocessorSteps() when there are too many steps in the queue.
396 public void testLoadPreprocessorStepsTooManySteps() {
397 loadStepsWithProperties(OperationProperties.AAI_PNF);
399 Deque<Step2> steps = mgr.getSteps();
400 stepa = steps.getFirst();
403 // load up a bunch of steps
404 for (int nsteps = 0; nsteps < UsecasesEventManager.MAX_STEPS; ++nsteps) {
409 assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
411 // add another step, should still fail
413 assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
415 // remove two steps - should now succeed
419 int nsteps = steps.size();
421 mgr.loadPreprocessorSteps();
422 assertEquals(nsteps + 1, steps.size());
426 * Tests loadPreprocessorSteps() when no additional steps are needed.
429 public void testLoadPreprocessorStepsNothingToLoad() {
430 when(stepa.isPolicyStep()).thenReturn(false);
431 when(stepa.getPropertyNames()).thenReturn(List.of("unknown-property"));
433 Deque<Step2> steps = mgr.getSteps();
438 mgr.loadPreprocessorSteps();
440 assertSame(stepa, steps.poll());
441 assertSame(stepb, steps.poll());
442 assertThat(steps).isEmpty();
446 * Tests loadPreprocessorSteps() when an A&AI custom query is needed.
449 public void testLoadPreprocessorStepsCq() {
450 loadStepsWithProperties(OperationProperties.AAI_DEFAULT_CLOUD_REGION, OperationProperties.AAI_DEFAULT_TENANT);
453 mgr.loadPreprocessorSteps();
455 Deque<Step2> steps = mgr.getSteps();
457 assertThat(steps.poll()).isInstanceOf(AaiCqStep2.class);
458 assertSame(stepa, steps.poll());
459 assertSame(stepb, steps.poll());
460 assertThat(steps).isEmpty();
464 * Tests loadPreprocessorSteps() when an A&AI PNF query is needed.
467 public void testLoadPreprocessorStepsPnf() {
468 // doubling up the property to check both branches
469 loadStepsWithProperties(OperationProperties.AAI_PNF, OperationProperties.AAI_PNF);
472 mgr.loadPreprocessorSteps();
474 Deque<Step2> steps = mgr.getSteps();
476 assertThat(steps.poll()).isInstanceOf(AaiGetPnfStep2.class);
477 assertSame(stepa, steps.poll());
478 assertSame(stepb, steps.poll());
479 assertThat(steps).isEmpty();
483 * Tests loadPreprocessorSteps() when an A&AI Tenant query is needed.
486 public void testLoadPreprocessorStepsTenant() {
487 // doubling up the property to check both branches
488 event.getAai().put(Step2.VSERVER_VSERVER_NAME, "my-vserver");
489 loadStepsWithProperties(OperationProperties.AAI_VSERVER_LINK, OperationProperties.AAI_VSERVER_LINK);
492 mgr.loadPreprocessorSteps();
494 Deque<Step2> steps = mgr.getSteps();
496 assertThat(steps.poll()).isInstanceOf(AaiGetTenantStep2.class);
497 assertSame(stepa, steps.poll());
498 assertSame(stepb, steps.poll());
499 assertThat(steps).isEmpty();
503 * Tests loadPreprocessorSteps() when the target entity is unset.
506 public void testLoadPreprocessorStepsNeedTargetEntity() {
507 stepa = new Step2(mgr,
508 ControlLoopOperationParams.builder()
509 .targetType(TargetType.toTargetType(event.getTargetType()))
510 .targetEntityIds(Map.of()).build(), event) {
512 public List<String> getPropertyNames() {
513 return List.of(OperationProperties.AAI_TARGET_ENTITY);
517 protected Operation buildOperation() {
518 return policyOperation;
522 public boolean isPolicyStep() {
527 Deque<Step2> steps = mgr.getSteps();
531 mgr.loadPreprocessorSteps();
533 Step2 entityStep = steps.poll();
535 assertThat(entityStep).isInstanceOf(GetTargetEntityStep2.class);
536 assertSame(stepa, steps.poll());
537 assertSame(stepb, steps.poll());
538 assertThat(steps).isEmpty();
540 // put get-target-entity back onto the queue and ensure nothing else is added
541 steps.add(entityStep);
542 mgr.loadPreprocessorSteps();
543 assertSame(entityStep, steps.poll());
544 assertThat(steps).isEmpty();
548 public void testExecuteStep() {
551 // no steps to execute
552 assertFalse(mgr.executeStep());
553 assertEquals(0, mgr.getAttempts());
555 // add a step to the queue
556 mgr.getSteps().add(stepa);
558 // step returns false
559 when(stepa.start(anyLong())).thenReturn(false);
560 assertFalse(mgr.executeStep());
563 when(stepa.start(anyLong())).thenReturn(true);
564 assertTrue(mgr.executeStep());
568 public void testNextStep() {
569 mgr.getSteps().add(stepa);
573 assertThat(mgr.getSteps()).isEmpty();
577 public void testBumpAttempts() {
578 assertEquals(0, mgr.getAttempts());
582 assertEquals(2, mgr.getAttempts());
586 public void testIsAbort() {
587 OperationOutcome outcome = makeCompletedOutcome();
588 outcome.setResult(OperationResult.FAILURE);
590 // closed loop timeout
591 outcome.setActor(ActorConstants.CL_TIMEOUT_ACTOR);
592 assertTrue(mgr.isAbort(outcome));
595 outcome.setActor(ActorConstants.LOCK_ACTOR);
596 assertTrue(mgr.isAbort(outcome));
598 // no effect for success
599 outcome.setResult(OperationResult.SUCCESS);
600 assertFalse(mgr.isAbort(outcome));
604 public void testAddToHistory() throws ControlLoopException {
607 // add a "start" outcome
608 OperationOutcome outcome = makeOutcome();
609 mgr.addToHistory(outcome);
611 assertThat(mgr.getPartialHistory()).hasSize(1);
612 assertThat(mgr.getFullHistory()).hasSize(1);
614 // add a "completion" outcome - should replace the start
615 outcome = makeCompletedOutcome();
616 mgr.addToHistory(outcome);
618 assertThat(mgr.getPartialHistory()).hasSize(1);
619 assertThat(mgr.getFullHistory()).hasSize(1);
620 assertSame(outcome, mgr.getPartialHistory().peek().getOutcome());
621 assertSame(outcome, mgr.getFullHistory().peek().getOutcome());
624 outcome = makeOutcome();
625 mgr.addToHistory(outcome);
627 assertThat(mgr.getPartialHistory()).hasSize(2);
628 assertThat(mgr.getFullHistory()).hasSize(2);
629 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
630 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
632 // remove the last item from the full history and then add a "completion"
633 mgr.getFullHistory().removeLast();
634 outcome = makeCompletedOutcome();
635 mgr.addToHistory(outcome);
636 assertThat(mgr.getPartialHistory()).hasSize(2);
637 assertThat(mgr.getFullHistory()).hasSize(2);
639 // add another "start"
640 outcome = makeOutcome();
641 mgr.addToHistory(outcome);
642 assertThat(mgr.getPartialHistory()).hasSize(3);
643 assertThat(mgr.getFullHistory()).hasSize(3);
645 // add a "completion" for a different actor - should NOT replace the start
646 outcome = makeCompletedOutcome();
647 outcome.setActor("different-actor");
648 mgr.addToHistory(outcome);
649 assertThat(mgr.getPartialHistory()).hasSize(4);
650 assertThat(mgr.getFullHistory()).hasSize(4);
651 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
652 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
656 public void testMakeNotification() throws Exception {
657 loadPolicy(EVENT_MGR_MULTI_YAML);
658 mgr = new MyManager(params, event, workMem);
661 assertNotNull(mgr.makeNotification());
665 mgr.addToHistory(makeCompletedOutcome());
666 mgr.addToHistory(makeCompletedOutcome());
667 mgr.addToHistory(makeCompletedOutcome());
669 // check notification while running
670 VirtualControlLoopNotification notif = mgr.makeNotification();
671 assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
672 assertThat(notif.getHistory()).hasSize(3);
674 // indicate success and load the next policy - should clear the partial history
675 mgr.loadNextPolicy(OperationResult.SUCCESS);
677 // check notification
678 notif = mgr.makeNotification();
679 assertNull(notif.getMessage());
680 assertThat(notif.getHistory()).isEmpty();
682 // add outcomes and check again
683 mgr.addToHistory(makeCompletedOutcome());
684 mgr.addToHistory(makeCompletedOutcome());
686 notif = mgr.makeNotification();
687 assertNotNull(notif.getMessage());
689 // should only have history for last two outcomes
690 assertThat(notif.getHistory()).hasSize(2);
692 // indicate failure - should go to final state
693 mgr.loadNextPolicy(OperationResult.FAILURE);
695 // check notification
696 notif = mgr.makeNotification();
697 assertNull(notif.getMessage());
699 // should be no history
700 assertThat(notif.getHistory()).isEmpty();
703 assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
704 .hasMessageContaining("lastResult");
708 public void testDeliver() {
709 mgr.deliver(MY_SINK, null, "null notification", "null rule");
710 verify(engineMgr, never()).deliver(any(), any());
712 mgr.deliver(MY_SINK, "publishA", "A notification", "A rule");
713 verify(engineMgr).deliver(MY_SINK, "publishA");
715 // cause deliver() to throw an exception
716 when(engineMgr.deliver(any(), any())).thenThrow(new IllegalStateException("expected exception"));
717 assertThatCode(() -> mgr.deliver(MY_SINK, "publishB", "B notification", "B rule")).doesNotThrowAnyException();
721 public void testGetOperationMessage() throws ControlLoopException {
723 assertNull(mgr.getOperationMessage());
727 OperationOutcome outcome = makeOutcome();
728 mgr.addToHistory(outcome);
730 assertThat(mgr.getOperationMessage()).contains("actor=" + SIMPLE_ACTOR)
731 .contains("operation=" + SIMPLE_OPERATION);
735 public void testStoreInDataBase() throws ControlLoopException {
737 OperationOutcome outcome = makeOutcome();
738 mgr.addToHistory(outcome);
740 mgr.storeInDataBase(mgr.getPartialHistory().peekLast());
742 verify(dataMgr).store(REQ_ID.toString(), event, null, mgr.getPartialHistory().peekLast().getClOperation());
746 public void testMakeControlLoopResponse() {
747 final OperationOutcome outcome = new OperationOutcome();
749 // no message - should return null
750 checkResp(outcome, null);
752 // not a PciMessage - should return null
753 outcome.setResponse("not-a-pci-message");
754 checkResp(outcome, null);
757 * now work with a PciMessage
759 PciMessage msg = new PciMessage();
760 outcome.setResponse(msg);
762 PciBody body = new PciBody();
765 PciResponse output = new PciResponse();
766 body.setOutput(output);
768 output.setPayload("my-payload");
770 // should generate a response, with a payload
771 checkResp(outcome, "my-payload");
774 * these should generate a response, with null payload
776 output.setPayload(null);
777 checkResp(outcome, null);
779 body.setOutput(null);
780 checkResp(outcome, null);
783 checkResp(outcome, null);
785 outcome.setResponse(null);
786 checkResp(outcome, null);
790 public void testOnNewEvent() {
791 VirtualControlLoopEvent event2 = new VirtualControlLoopEvent(event);
792 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event2));
794 event2.setPayload("other payload");
795 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
796 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
797 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event));
799 event2.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
800 assertEquals(NewEventStatus.FIRST_ABATEMENT, mgr.onNewEvent(event2));
802 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
803 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
805 event2.setClosedLoopEventStatus(null);
806 assertEquals(NewEventStatus.SYNTAX_ERROR, mgr.onNewEvent(event2));
810 public void testCheckEventSyntax() {
811 // initially, it's valid
812 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
814 event.setTarget("unknown-target");
815 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
816 .hasMessage("target field invalid");
818 event.setTarget(null);
819 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
820 .hasMessage("No target field");
822 // abated supersedes previous errors - so it shouldn't throw an exception
823 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
824 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
826 event.setRequestId(null);
827 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
828 .hasMessage("No request ID");
830 event.setClosedLoopControlName(null);
831 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
832 .hasMessage("No control loop name");
836 public void testValidateStatus() {
837 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
838 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
840 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
841 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
843 event.setClosedLoopEventStatus(null);
844 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
845 .hasMessage("Invalid value in closedLoopEventStatus");
849 public void testValidateAaiData() {
850 event.setTargetType("unknown-target-type");
851 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
852 .hasMessage("The target type is not supported");
854 event.setTargetType(null);
855 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
856 .hasMessage("The Target type is null");
859 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
860 .hasMessage("AAI is null");
863 event.setTargetType(ControlLoopTargetType.VM);
864 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
865 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
867 event.setAai(Map.of());
868 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
871 event.setTargetType(ControlLoopTargetType.VNF);
872 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
873 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
875 event.setAai(Map.of());
876 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
879 event.setTargetType(ControlLoopTargetType.PNF);
880 event.setAai(Map.of(ControlLoopEventManager2.PNF_NAME, MY_TARGET));
881 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
883 event.setAai(Map.of());
884 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
888 public void testValidateAaiVmVnfData() {
889 event.setTargetType(ControlLoopTargetType.VM);
890 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
891 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
893 event.setAai(Map.of(ControlLoopEventManager2.VSERVER_VSERVER_NAME, MY_TARGET));
894 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
896 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_NAME, MY_TARGET));
897 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
899 event.setAai(Map.of());
900 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class).hasMessage(
901 "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
905 public void testValidateAaiPnfData() {
906 event.setTargetType(ControlLoopTargetType.PNF);
907 event.setAai(Map.of(ControlLoopEventManager2.PNF_NAME, MY_TARGET));
908 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
910 event.setAai(Map.of());
911 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
912 .hasMessage("AAI PNF object key pnf-name is missing");
916 public void testIsClosedLoopDisabled() {
917 Map<String, String> orig = event.getAai();
919 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
920 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
921 .isInstanceOf(IllegalStateException.class);
923 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED, "true"));
924 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
925 .isInstanceOf(IllegalStateException.class);
927 event.setAai(addAai(orig, ControlLoopEventManager2.PNF_IS_IN_MAINT, "true"));
928 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
929 .isInstanceOf(IllegalStateException.class);
933 public void testIsProvStatusInactive() {
934 Map<String, String> orig = event.getAai();
936 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "ACTIVE"));
937 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
939 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "inactive"));
940 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
941 .isInstanceOf(IllegalStateException.class);
943 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "ACTIVE"));
944 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
946 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "inactive"));
947 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
948 .isInstanceOf(IllegalStateException.class);
952 public void testIsAaiTrue() {
953 Map<String, String> orig = event.getAai();
955 for (String value : Arrays.asList("yes", "y", "true", "t", "yEs", "trUe")) {
956 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, value));
957 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
958 .isInstanceOf(IllegalStateException.class);
961 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "false"));
962 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
964 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "no"));
965 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
969 private Map<String, String> addAai(Map<String, String> original, String key, String value) {
970 Map<String, String> map = new TreeMap<>(original);
975 private void loadPolicy(String fileName) throws CoderException {
976 ToscaServiceTemplate template =
977 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
978 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
980 params.setToscaPolicy(tosca);
983 private void loadStepsWithProperties(String... properties) {
984 stepa = new Step2(mgr, ControlLoopOperationParams.builder().build(), event) {
987 public boolean isPolicyStep() {
992 public List<String> getPropertyNames() {
993 return List.of(properties);
997 protected Operation buildOperation() {
998 return policyOperation;
1002 mgr.getSteps().add(stepa);
1003 mgr.getSteps().add(stepb);
1006 private OperationOutcome makeCompletedOutcome() {
1007 OperationOutcome outcome = makeOutcome();
1008 outcome.setEnd(outcome.getStart());
1013 private OperationOutcome makeOutcome() {
1014 OperationOutcome outcome = new OperationOutcome();
1015 outcome.setActor(SIMPLE_ACTOR);
1016 outcome.setOperation(SIMPLE_OPERATION);
1017 outcome.setMessage(OUTCOME_MSG);
1018 outcome.setResult(OperationResult.SUCCESS);
1019 outcome.setStart(Instant.now());
1020 outcome.setTarget(MY_TARGET);
1025 private void checkResp(OperationOutcome outcome, String expectedPayload) {
1026 ControlLoopResponse resp = mgr.makeControlLoopResponse(outcome);
1027 assertNotNull(resp);
1028 assertEquals(REQ_ID, resp.getRequestId());
1029 assertEquals(expectedPayload, resp.getPayload());
1033 * Sets the target entity so a step doesn't have to be added to set it.
1035 private void setTargetEntity() {
1036 mgr.setProperty(OperationProperties.AAI_TARGET_ENTITY, MY_TARGET);
1040 private class MyManager extends UsecasesEventManager {
1041 private static final long serialVersionUID = 1L;
1043 public MyManager(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem)
1044 throws ControlLoopException {
1046 super(params, event, workMem);
1050 protected ExecutorService getBlockingExecutor() {
1055 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
1056 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
1058 callback.lockAvailable(lock);
1062 public ActorService getActorService() {
1067 public OperationHistoryDataManager getDataManager() {
1072 protected PolicyEngine getPolicyEngineManager() {