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.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 public class UsecasesEventManagerTest {
98 private static final UUID REQ_ID = UUID.randomUUID();
99 private static final String CL_NAME = "my-closed-loop-name";
100 private static final String POLICY_NAME = "my-policy-name";
101 private static final String POLICY_SCOPE = "my-scope";
102 private static final String POLICY_VERSION = "1.2.3";
103 private static final String SIMPLE_ACTOR = "First";
104 private static final String SIMPLE_OPERATION = "OperationA";
105 private static final String MY_TARGET = "my-target";
106 private static final String EVENT_MGR_MULTI_YAML =
107 "../eventmanager/src/test/resources/eventManager/event-mgr-multi.yaml";
108 private static final String EVENT_MGR_SIMPLE_YAML =
109 "../eventmanager/src/test/resources/eventManager/event-mgr-simple.yaml";
110 private static final Coder yamlCoder = new StandardYamlCoder();
111 private static final String OUTCOME_MSG = "my outcome message";
112 private static final String MY_SINK = "my-topic-sink";
115 private PolicyEngine engineMgr;
117 private WorkingMemory workMem;
119 private FactHandle factHandle;
121 private Operator policyOperator;
123 private Operation policyOperation;
125 private Actor policyActor;
127 private ActorService actors;
129 private OperationHistoryDataManager dataMgr;
131 private ExecutorService executor;
137 private List<LockImpl> locks;
138 private ToscaPolicy tosca;
139 private ControlLoopParams params;
140 private VirtualControlLoopEvent event;
141 private UsecasesEventManager mgr;
147 public void setUp() throws ControlLoopException, CoderException {
148 MockitoAnnotations.initMocks(this);
150 when(actors.getActor(SIMPLE_ACTOR)).thenReturn(policyActor);
151 when(policyActor.getOperator(SIMPLE_OPERATION)).thenReturn(policyOperator);
152 when(policyOperator.buildOperation(any())).thenReturn(policyOperation);
153 when(policyOperation.getPropertyNames()).thenReturn(Collections.emptyList());
155 when(workMem.getFactHandle(any())).thenReturn(factHandle);
157 event = new VirtualControlLoopEvent();
158 event.setRequestId(REQ_ID);
159 event.setTarget(UsecasesConstants.VSERVER_VSERVER_NAME);
160 event.setAai(new TreeMap<>(Map.of(UsecasesConstants.VSERVER_VSERVER_NAME, MY_TARGET)));
161 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
162 event.setClosedLoopControlName(CL_NAME);
163 event.setTargetType(ControlLoopTargetType.VNF);
165 params = new ControlLoopParams();
166 params.setClosedLoopControlName(CL_NAME);
167 params.setPolicyName(POLICY_NAME);
168 params.setPolicyScope(POLICY_SCOPE);
169 params.setPolicyVersion(POLICY_VERSION);
171 loadPolicy(EVENT_MGR_SIMPLE_YAML);
173 locks = new ArrayList<>();
175 mgr = new MyManager(params, event, workMem);
179 public void testConstructor() {
180 assertEquals(POLICY_NAME, mgr.getPolicyName());
181 assertSame(event, mgr.getEvent());
183 Map<String, String> orig = event.getAai();
185 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
186 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
187 .hasMessage("is-closed-loop-disabled is set to true on VServer or VNF");
190 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS,
191 UsecasesConstants.PROV_STATUS_ACTIVE.toUpperCase()));
192 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
195 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS,
196 UsecasesConstants.PROV_STATUS_ACTIVE.toLowerCase()));
197 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
200 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS, "inactive"));
201 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
202 .hasMessage("prov-status is not ACTIVE on VServer or VNF");
205 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS,
206 UsecasesConstants.PROV_STATUS_ACTIVE.toUpperCase()));
207 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
210 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS,
211 UsecasesConstants.PROV_STATUS_ACTIVE.toLowerCase()));
212 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
215 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS, "inactive"));
216 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
217 .hasMessage("prov-status is not ACTIVE on VServer or VNF");
221 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
224 event.setTarget("unknown-target");
225 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
226 .isInstanceOf(ControlLoopException.class);
230 public void testIsActive() throws Exception {
231 mgr = new UsecasesEventManager(params, event, workMem);
232 assertTrue(mgr.isActive());
234 // deserialized manager should be inactive
235 UsecasesEventManager mgr2 = Serializer.roundTrip(mgr);
236 assertFalse(mgr2.isActive());
240 public void testDestroy_testGetSteps() {
241 // add some steps to the queue
242 mgr.getSteps().add(stepa);
243 mgr.getSteps().add(stepb);
247 verify(stepa).cancel();
248 verify(stepb).cancel();
250 // if superclass destroy() was invoked, then freeLock() should have been submitted
252 verify(executor).execute(any());
256 public void testOnStart() throws ControlLoopException {
257 OperationOutcome outcome = makeOutcome();
260 mgr.onStart(outcome);
262 assertSame(outcome, mgr.getOutcomes().poll());
263 assertThat(mgr.getOutcomes()).isEmpty();
265 verify(workMem).update(factHandle, mgr);
269 public void testOnComplete() throws ControlLoopException {
270 OperationOutcome outcome = makeCompletedOutcome();
273 mgr.onComplete(outcome);
275 assertSame(outcome, mgr.getOutcomes().poll());
276 assertThat(mgr.getOutcomes()).isEmpty();
278 verify(workMem).update(factHandle, mgr);
282 public void testToString() {
283 assertNotNull(mgr.toString());
287 public void testStart() throws ControlLoopException {
292 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
293 .hasMessage("manager already started");
297 * Tests start() when the manager is not in working memory.
300 public void testStartNotInWorkingMemory() throws ControlLoopException {
301 when(workMem.getFactHandle(any())).thenReturn(null);
303 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
304 .hasMessage("manager is not in working memory");
308 * Tests start() when the manager is not active.
311 public void testStartInactive() throws Exception {
312 // make an inactive manager by deserializing it
313 mgr = Serializer.roundTrip(new UsecasesEventManager(params, event, workMem));
316 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
317 .hasMessage("manager is no longer active");
321 public void testAbort() {
322 mgr.abort(UsecasesEventManager.State.DONE, OperationFinalResult.FINAL_FAILURE_GUARD, "some message");
324 assertEquals(UsecasesEventManager.State.DONE, mgr.getState());
325 assertEquals(OperationFinalResult.FINAL_FAILURE_GUARD, mgr.getFinalResult());
326 assertEquals("some message", mgr.getFinalMessage());
329 assertThatThrownBy(() -> mgr.abort(null, OperationFinalResult.FINAL_FAILURE_GUARD, ""))
330 .isInstanceOf(NullPointerException.class).hasMessageContaining("finalState");
334 public void testLoadNextPolicy_testGetFullHistory_testGetPartialHistory() throws Exception {
335 loadPolicy(EVENT_MGR_MULTI_YAML);
336 mgr = new MyManager(params, event, workMem);
338 // start and load step for first policy
340 assertEquals("OperationA", mgr.getSteps().poll().getOperationName());
341 assertNull(mgr.getFinalResult());
344 OperationOutcome outcome = makeOutcome();
345 mgr.addToHistory(outcome);
347 // indicate success and load next policy
348 mgr.loadNextPolicy(OperationResult.SUCCESS);
349 assertEquals("OperationB", mgr.getSteps().poll().getOperationName());
350 assertNull(mgr.getFinalResult());
352 // loadPolicy() should clear the partial history, but not the full history
353 assertThat(mgr.getPartialHistory()).isEmpty();
354 assertThat(mgr.getFullHistory()).hasSize(1);
356 // indicate failure - should go to final failure
357 mgr.loadNextPolicy(OperationResult.FAILURE);
358 assertEquals(OperationFinalResult.FINAL_FAILURE, mgr.getFinalResult());
362 public void testLoadPolicy() throws ControlLoopException {
363 // start() will invoke loadPolicy()
366 assertNull(mgr.getFinalResult());
368 Step2 step = mgr.getSteps().peek();
370 assertEquals("First", step.getActorName());
371 assertEquals("OperationA", step.getOperationName());
373 ControlLoopOperationParams params2 = step.getParams();
374 assertSame(actors, params2.getActorService());
375 assertSame(REQ_ID, params2.getRequestId());
376 assertSame(ForkJoinPool.commonPool(), params2.getExecutor());
377 assertNotNull(params2.getTargetType());
378 assertNotNull(params2.getTargetEntityIds());
379 assertEquals(Integer.valueOf(300), params2.getTimeoutSec());
380 assertEquals(Integer.valueOf(0), params2.getRetry());
381 assertThat(params2.getPayload()).isEmpty();
382 assertNotNull(params2.getStartCallback());
383 assertNotNull(params2.getCompleteCallback());
387 public void testLoadPreprocessorSteps() {
388 stepa = new Step2(mgr, ControlLoopOperationParams.builder().build(), event) {
390 public List<String> getPropertyNames() {
391 return List.of(OperationProperties.AAI_DEFAULT_CLOUD_REGION);
395 protected Operation buildOperation() {
396 return policyOperation;
400 mgr.getSteps().add(stepa);
401 mgr.getSteps().add(stepb);
403 mgr.loadPreprocessorSteps();
405 Deque<Step2> steps = mgr.getSteps();
407 Step2 lockStep = steps.poll();
408 assertNotNull(lockStep);
409 assertEquals(ActorConstants.LOCK_ACTOR, lockStep.getActorName());
410 assertThat(steps.poll()).isInstanceOf(AaiCqStep2.class);
411 assertThat(steps.poll()).isInstanceOf(GuardStep2.class);
412 assertSame(stepa, steps.poll());
413 assertSame(stepb, steps.poll());
414 assertThat(steps).isEmpty();
418 * Tests loadPreprocessorSteps() when there are too many steps in the queue.
421 public void testLoadPreprocessorStepsTooManySteps() {
422 loadStepsWithProperties(OperationProperties.AAI_PNF);
424 Deque<Step2> steps = mgr.getSteps();
425 stepa = steps.getFirst();
428 // load up a bunch of steps
429 for (int nsteps = 0; nsteps < UsecasesEventManager.MAX_STEPS; ++nsteps) {
434 assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
436 // add another step, should still fail
438 assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
440 // remove two steps - should now succeed
444 int nsteps = steps.size();
446 mgr.loadPreprocessorSteps();
447 assertEquals(nsteps + 1, steps.size());
451 * Tests loadPreprocessorSteps() when no additional steps are needed.
454 public void testLoadPreprocessorStepsNothingToLoad() {
455 when(stepa.isPolicyStep()).thenReturn(false);
456 when(stepa.getPropertyNames()).thenReturn(List.of("unknown-property"));
458 Deque<Step2> steps = mgr.getSteps();
463 mgr.loadPreprocessorSteps();
465 assertSame(stepa, steps.poll());
466 assertSame(stepb, steps.poll());
467 assertThat(steps).isEmpty();
471 * Tests loadPreprocessorSteps() when an A&AI custom query is needed.
474 public void testLoadPreprocessorStepsCq() {
475 loadStepsWithProperties(OperationProperties.AAI_DEFAULT_CLOUD_REGION, OperationProperties.AAI_DEFAULT_TENANT);
478 mgr.loadPreprocessorSteps();
480 Deque<Step2> steps = mgr.getSteps();
482 assertThat(steps.poll()).isInstanceOf(AaiCqStep2.class);
483 assertSame(stepa, steps.poll());
484 assertSame(stepb, steps.poll());
485 assertThat(steps).isEmpty();
489 * Tests loadPreprocessorSteps() when an A&AI PNF query is needed.
492 public void testLoadPreprocessorStepsPnf() {
493 // doubling up the property to check both branches
494 loadStepsWithProperties(OperationProperties.AAI_PNF, OperationProperties.AAI_PNF);
497 mgr.loadPreprocessorSteps();
499 Deque<Step2> steps = mgr.getSteps();
501 assertThat(steps.poll()).isInstanceOf(AaiGetPnfStep2.class);
502 assertSame(stepa, steps.poll());
503 assertSame(stepb, steps.poll());
504 assertThat(steps).isEmpty();
508 * Tests loadPreprocessorSteps() when an A&AI Tenant query is needed.
511 public void testLoadPreprocessorStepsTenant() {
512 // doubling up the property to check both branches
513 event.getAai().put(Step2.VSERVER_VSERVER_NAME, "my-vserver");
514 loadStepsWithProperties(OperationProperties.AAI_VSERVER_LINK, OperationProperties.AAI_VSERVER_LINK);
517 mgr.loadPreprocessorSteps();
519 Deque<Step2> steps = mgr.getSteps();
521 assertThat(steps.poll()).isInstanceOf(AaiGetTenantStep2.class);
522 assertSame(stepa, steps.poll());
523 assertSame(stepb, steps.poll());
524 assertThat(steps).isEmpty();
528 * Tests loadPreprocessorSteps() when the target entity is unset.
531 public void testLoadPreprocessorStepsNeedTargetEntity() {
532 stepa = new Step2(mgr,
533 ControlLoopOperationParams.builder()
534 .targetType(TargetType.toTargetType(event.getTargetType()))
535 .targetEntityIds(Map.of()).build(), event) {
537 public List<String> getPropertyNames() {
538 return List.of(OperationProperties.AAI_TARGET_ENTITY);
542 protected Operation buildOperation() {
543 return policyOperation;
547 public boolean isPolicyStep() {
552 Deque<Step2> steps = mgr.getSteps();
556 mgr.loadPreprocessorSteps();
558 Step2 entityStep = steps.poll();
560 assertThat(entityStep).isInstanceOf(GetTargetEntityStep2.class);
561 assertSame(stepa, steps.poll());
562 assertSame(stepb, steps.poll());
563 assertThat(steps).isEmpty();
565 // put get-target-entity back onto the queue and ensure nothing else is added
566 steps.add(entityStep);
567 mgr.loadPreprocessorSteps();
568 assertSame(entityStep, steps.poll());
569 assertThat(steps).isEmpty();
573 public void testExecuteStep() {
576 // no steps to execute
577 assertFalse(mgr.executeStep());
578 assertEquals(0, mgr.getAttempts());
580 // add a step to the queue
581 mgr.getSteps().add(stepa);
583 // step returns false
584 when(stepa.start(anyLong())).thenReturn(false);
585 assertFalse(mgr.executeStep());
588 when(stepa.start(anyLong())).thenReturn(true);
589 assertTrue(mgr.executeStep());
593 public void testNextStep() {
594 mgr.getSteps().add(stepa);
598 assertThat(mgr.getSteps()).isEmpty();
602 public void testBumpAttempts() {
603 assertEquals(0, mgr.getAttempts());
607 assertEquals(2, mgr.getAttempts());
611 public void testIsAbort() {
612 OperationOutcome outcome = makeCompletedOutcome();
613 outcome.setResult(OperationResult.FAILURE);
615 // closed loop timeout
616 outcome.setActor(ActorConstants.CL_TIMEOUT_ACTOR);
617 assertTrue(mgr.isAbort(outcome));
620 outcome.setActor(ActorConstants.LOCK_ACTOR);
621 assertTrue(mgr.isAbort(outcome));
623 // no effect for success
624 outcome.setResult(OperationResult.SUCCESS);
625 assertFalse(mgr.isAbort(outcome));
629 public void testAddToHistory() throws ControlLoopException {
632 // add a "start" outcome
633 OperationOutcome outcome = makeOutcome();
634 mgr.addToHistory(outcome);
636 assertThat(mgr.getPartialHistory()).hasSize(1);
637 assertThat(mgr.getFullHistory()).hasSize(1);
639 // add a "completion" outcome - should replace the start
640 outcome = makeCompletedOutcome();
641 mgr.addToHistory(outcome);
643 assertThat(mgr.getPartialHistory()).hasSize(1);
644 assertThat(mgr.getFullHistory()).hasSize(1);
645 assertSame(outcome, mgr.getPartialHistory().peek().getOutcome());
646 assertSame(outcome, mgr.getFullHistory().peek().getOutcome());
649 outcome = makeOutcome();
650 mgr.addToHistory(outcome);
652 assertThat(mgr.getPartialHistory()).hasSize(2);
653 assertThat(mgr.getFullHistory()).hasSize(2);
654 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
655 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
657 // remove the last item from the full history and then add a "completion"
658 mgr.getFullHistory().removeLast();
659 outcome = makeCompletedOutcome();
660 mgr.addToHistory(outcome);
661 assertThat(mgr.getPartialHistory()).hasSize(2);
662 assertThat(mgr.getFullHistory()).hasSize(2);
664 // add another "start"
665 outcome = makeOutcome();
666 mgr.addToHistory(outcome);
667 assertThat(mgr.getPartialHistory()).hasSize(3);
668 assertThat(mgr.getFullHistory()).hasSize(3);
670 // add a "completion" for a different actor - should NOT replace the start
671 outcome = makeCompletedOutcome();
672 outcome.setActor("different-actor");
673 mgr.addToHistory(outcome);
674 assertThat(mgr.getPartialHistory()).hasSize(4);
675 assertThat(mgr.getFullHistory()).hasSize(4);
676 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
677 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
681 public void testMakeNotification() throws Exception {
682 loadPolicy(EVENT_MGR_MULTI_YAML);
683 mgr = new MyManager(params, event, workMem);
686 assertNotNull(mgr.makeNotification());
690 mgr.addToHistory(makeCompletedOutcome());
691 mgr.addToHistory(makeCompletedOutcome());
692 mgr.addToHistory(makeCompletedOutcome());
694 // check notification while running
695 VirtualControlLoopNotification notif = mgr.makeNotification();
696 assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
697 assertThat(notif.getHistory()).hasSize(3);
699 // indicate success and load the next policy - should clear the partial history
700 mgr.loadNextPolicy(OperationResult.SUCCESS);
702 // check notification
703 notif = mgr.makeNotification();
704 assertNull(notif.getMessage());
705 assertThat(notif.getHistory()).isEmpty();
707 // add outcomes and check again
708 mgr.addToHistory(makeCompletedOutcome());
709 mgr.addToHistory(makeCompletedOutcome());
711 notif = mgr.makeNotification();
712 assertNotNull(notif.getMessage());
714 // should only have history for last two outcomes
715 assertThat(notif.getHistory()).hasSize(2);
717 // indicate failure - should go to final state
718 mgr.loadNextPolicy(OperationResult.FAILURE);
720 // check notification
721 notif = mgr.makeNotification();
722 assertNull(notif.getMessage());
724 // should be no history
725 assertThat(notif.getHistory()).isEmpty();
728 assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
729 .hasMessageContaining("lastResult");
733 public void testDeliver() {
734 mgr.deliver(MY_SINK, null, "null notification", "null rule");
735 verify(engineMgr, never()).deliver(any(), any());
737 mgr.deliver(MY_SINK, "publishA", "A notification", "A rule");
738 verify(engineMgr).deliver(MY_SINK, "publishA");
740 // cause deliver() to throw an exception
741 when(engineMgr.deliver(any(), any())).thenThrow(new IllegalStateException("expected exception"));
742 assertThatCode(() -> mgr.deliver(MY_SINK, "publishB", "B notification", "B rule")).doesNotThrowAnyException();
746 public void testGetOperationMessage() throws ControlLoopException {
748 assertNull(mgr.getOperationMessage());
752 OperationOutcome outcome = makeOutcome();
753 mgr.addToHistory(outcome);
755 assertThat(mgr.getOperationMessage()).contains("actor=" + SIMPLE_ACTOR)
756 .contains("operation=" + SIMPLE_OPERATION);
760 public void testStoreInDataBase() throws ControlLoopException {
762 OperationOutcome outcome = makeOutcome();
763 mgr.addToHistory(outcome);
765 mgr.storeInDataBase(mgr.getPartialHistory().peekLast());
767 verify(dataMgr).store(REQ_ID.toString(), event, null, mgr.getPartialHistory().peekLast().getClOperation());
771 public void testMakeControlLoopResponse() {
772 final OperationOutcome outcome = new OperationOutcome();
774 // no message - should return null
775 checkResp(outcome, null);
777 // not a PciMessage - should return null
778 outcome.setResponse("not-a-pci-message");
779 checkResp(outcome, null);
782 * now work with a PciMessage
784 PciMessage msg = new PciMessage();
785 outcome.setResponse(msg);
787 PciBody body = new PciBody();
790 PciResponse output = new PciResponse();
791 body.setOutput(output);
793 output.setPayload("my-payload");
795 // should generate a response, with a payload
796 checkResp(outcome, "my-payload");
799 * these should generate a response, with null payload
801 output.setPayload(null);
802 checkResp(outcome, null);
804 body.setOutput(null);
805 checkResp(outcome, null);
808 checkResp(outcome, null);
810 outcome.setResponse(null);
811 checkResp(outcome, null);
815 public void testOnNewEvent() {
816 VirtualControlLoopEvent event2 = new VirtualControlLoopEvent(event);
817 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event2));
819 event2.setPayload("other payload");
820 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
821 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
822 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event));
824 event2.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
825 assertEquals(NewEventStatus.FIRST_ABATEMENT, mgr.onNewEvent(event2));
827 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
828 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
830 event2.setClosedLoopEventStatus(null);
831 assertEquals(NewEventStatus.SYNTAX_ERROR, mgr.onNewEvent(event2));
835 public void testCheckEventSyntax() {
836 // initially, it's valid
837 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
839 event.setTarget("unknown-target");
840 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
841 .hasMessage("target field invalid");
843 event.setTarget(null);
844 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
845 .hasMessage("No target field");
847 // abated supersedes previous errors - so it shouldn't throw an exception
848 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
849 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
851 event.setRequestId(null);
852 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
853 .hasMessage("No request ID");
855 event.setClosedLoopControlName(null);
856 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
857 .hasMessage("No control loop name");
861 public void testValidateStatus() {
862 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
863 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
865 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
866 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
868 event.setClosedLoopEventStatus(null);
869 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
870 .hasMessage("Invalid value in closedLoopEventStatus");
874 public void testValidateAaiData() {
875 event.setTargetType("unknown-target-type");
876 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
877 .hasMessage("The target type is not supported");
879 event.setTargetType(null);
880 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
881 .hasMessage("The Target type is null");
884 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
885 .hasMessage("AAI is null");
888 event.setTargetType(ControlLoopTargetType.VM);
889 event.setAai(Map.of(UsecasesConstants.GENERIC_VNF_VNF_ID, MY_TARGET));
890 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
892 event.setAai(Map.of());
893 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
896 event.setTargetType(ControlLoopTargetType.VNF);
897 event.setAai(Map.of(UsecasesConstants.GENERIC_VNF_VNF_ID, MY_TARGET));
898 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
900 event.setAai(Map.of());
901 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
904 event.setTargetType(ControlLoopTargetType.PNF);
905 event.setAai(Map.of(UsecasesConstants.PNF_NAME, MY_TARGET));
906 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
908 event.setAai(Map.of());
909 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
913 public void testValidateAaiVmVnfData() {
914 event.setTargetType(ControlLoopTargetType.VM);
915 event.setAai(Map.of(UsecasesConstants.GENERIC_VNF_VNF_ID, MY_TARGET));
916 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
918 event.setAai(Map.of(UsecasesConstants.VSERVER_VSERVER_NAME, MY_TARGET));
919 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
921 event.setAai(Map.of(UsecasesConstants.GENERIC_VNF_VNF_NAME, MY_TARGET));
922 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
924 event.setAai(Map.of());
925 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class).hasMessage(
926 "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
930 public void testValidateAaiPnfData() {
931 event.setTargetType(ControlLoopTargetType.PNF);
932 event.setAai(Map.of(UsecasesConstants.PNF_NAME, MY_TARGET));
933 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
935 event.setAai(Map.of());
936 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
937 .hasMessage("AAI PNF object key pnf-name is missing");
941 public void testIsClosedLoopDisabled() {
942 Map<String, String> orig = event.getAai();
944 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
945 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
946 .isInstanceOf(IllegalStateException.class);
948 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED, "true"));
949 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
950 .isInstanceOf(IllegalStateException.class);
952 event.setAai(addAai(orig, UsecasesConstants.PNF_IS_IN_MAINT, "true"));
953 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
954 .isInstanceOf(IllegalStateException.class);
958 public void testIsProvStatusInactive() {
959 Map<String, String> orig = event.getAai();
961 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS, "ACTIVE"));
962 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
964 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS, "inactive"));
965 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
966 .isInstanceOf(IllegalStateException.class);
968 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS, "ACTIVE"));
969 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
971 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS, "inactive"));
972 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
973 .isInstanceOf(IllegalStateException.class);
977 public void testIsAaiTrue() {
978 Map<String, String> orig = event.getAai();
980 for (String value : Arrays.asList("yes", "y", "true", "t", "yEs", "trUe")) {
981 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, value));
982 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
983 .isInstanceOf(IllegalStateException.class);
986 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "false"));
987 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
989 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "no"));
990 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
994 private Map<String, String> addAai(Map<String, String> original, String key, String value) {
995 Map<String, String> map = new TreeMap<>(original);
1000 private void loadPolicy(String fileName) throws CoderException {
1001 ToscaServiceTemplate template =
1002 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
1003 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
1005 params.setToscaPolicy(tosca);
1008 private void loadStepsWithProperties(String... properties) {
1009 stepa = new Step2(mgr, ControlLoopOperationParams.builder().build(), event) {
1012 public boolean isPolicyStep() {
1017 public List<String> getPropertyNames() {
1018 return List.of(properties);
1022 protected Operation buildOperation() {
1023 return policyOperation;
1027 mgr.getSteps().add(stepa);
1028 mgr.getSteps().add(stepb);
1031 private OperationOutcome makeCompletedOutcome() {
1032 OperationOutcome outcome = makeOutcome();
1033 outcome.setEnd(outcome.getStart());
1038 private OperationOutcome makeOutcome() {
1039 OperationOutcome outcome = new OperationOutcome();
1040 outcome.setActor(SIMPLE_ACTOR);
1041 outcome.setOperation(SIMPLE_OPERATION);
1042 outcome.setMessage(OUTCOME_MSG);
1043 outcome.setResult(OperationResult.SUCCESS);
1044 outcome.setStart(Instant.now());
1045 outcome.setTarget(MY_TARGET);
1050 private void checkResp(OperationOutcome outcome, String expectedPayload) {
1051 ControlLoopResponse resp = mgr.makeControlLoopResponse(outcome);
1052 assertNotNull(resp);
1053 assertEquals(REQ_ID, resp.getRequestId());
1054 assertEquals(expectedPayload, resp.getPayload());
1058 * Sets the target entity so a step doesn't have to be added to set it.
1060 private void setTargetEntity() {
1061 mgr.setProperty(OperationProperties.AAI_TARGET_ENTITY, MY_TARGET);
1065 private class MyManager extends UsecasesEventManager {
1066 private static final long serialVersionUID = 1L;
1068 public MyManager(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem)
1069 throws ControlLoopException {
1071 super(params, event, workMem);
1075 protected ExecutorService getBlockingExecutor() {
1080 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
1081 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
1083 callback.lockAvailable(lock);
1087 public ActorService getActorService() {
1092 public OperationHistoryDataManager getDataManager() {
1097 protected PolicyEngine getPolicyEngineManager() {