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.eventmanager.ControlLoopEventManager2Drools;
81 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
82 import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager.NewEventStatus;
83 import org.onap.policy.drools.apps.controller.usecases.step.AaiCqStep2;
84 import org.onap.policy.drools.apps.controller.usecases.step.AaiGetPnfStep2;
85 import org.onap.policy.drools.apps.controller.usecases.step.AaiGetTenantStep2;
86 import org.onap.policy.drools.apps.controller.usecases.step.GetTargetEntityStep2;
87 import org.onap.policy.drools.apps.controller.usecases.step.GuardStep2;
88 import org.onap.policy.drools.apps.controller.usecases.step.Step2;
89 import org.onap.policy.drools.core.lock.LockCallback;
90 import org.onap.policy.drools.core.lock.LockImpl;
91 import org.onap.policy.drools.core.lock.LockState;
92 import org.onap.policy.drools.system.PolicyEngine;
93 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
94 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
95 import org.onap.policy.sdnr.PciBody;
96 import org.onap.policy.sdnr.PciMessage;
97 import org.onap.policy.sdnr.PciResponse;
99 public class UsecasesEventManagerTest {
100 private static final UUID REQ_ID = UUID.randomUUID();
101 private static final String CL_NAME = "my-closed-loop-name";
102 private static final String POLICY_NAME = "my-policy-name";
103 private static final String POLICY_SCOPE = "my-scope";
104 private static final String POLICY_VERSION = "1.2.3";
105 private static final String SIMPLE_ACTOR = "First";
106 private static final String SIMPLE_OPERATION = "OperationA";
107 private static final String MY_TARGET = "my-target";
108 private static final String EVENT_MGR_MULTI_YAML =
109 "../eventmanager/src/test/resources/eventManager/event-mgr-multi.yaml";
110 private static final String EVENT_MGR_SIMPLE_YAML =
111 "../eventmanager/src/test/resources/eventManager/event-mgr-simple.yaml";
112 private static final Coder yamlCoder = new StandardYamlCoder();
113 private static final String OUTCOME_MSG = "my outcome message";
114 private static final String MY_SINK = "my-topic-sink";
117 private PolicyEngine engineMgr;
119 private WorkingMemory workMem;
121 private FactHandle factHandle;
123 private Operator policyOperator;
125 private Operation policyOperation;
127 private Actor policyActor;
129 private ActorService actors;
131 private OperationHistoryDataManager dataMgr;
133 private ExecutorService executor;
139 private List<LockImpl> locks;
140 private ToscaPolicy tosca;
141 private ControlLoopParams params;
142 private VirtualControlLoopEvent event;
143 private UsecasesEventManager mgr;
149 public void setUp() throws ControlLoopException, CoderException {
150 MockitoAnnotations.initMocks(this);
152 when(actors.getActor(SIMPLE_ACTOR)).thenReturn(policyActor);
153 when(policyActor.getOperator(SIMPLE_OPERATION)).thenReturn(policyOperator);
154 when(policyOperator.buildOperation(any())).thenReturn(policyOperation);
155 when(policyOperation.getPropertyNames()).thenReturn(Collections.emptyList());
157 when(workMem.getFactHandle(any())).thenReturn(factHandle);
159 event = new VirtualControlLoopEvent();
160 event.setRequestId(REQ_ID);
161 event.setTarget(UsecasesConstants.VSERVER_VSERVER_NAME);
162 event.setAai(new TreeMap<>(Map.of(UsecasesConstants.VSERVER_VSERVER_NAME, MY_TARGET)));
163 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
164 event.setClosedLoopControlName(CL_NAME);
165 event.setTargetType(ControlLoopTargetType.VNF);
167 params = new ControlLoopParams();
168 params.setClosedLoopControlName(CL_NAME);
169 params.setPolicyName(POLICY_NAME);
170 params.setPolicyScope(POLICY_SCOPE);
171 params.setPolicyVersion(POLICY_VERSION);
173 loadPolicy(EVENT_MGR_SIMPLE_YAML);
175 locks = new ArrayList<>();
177 mgr = new MyManager(params, event, workMem);
181 public void testConstructor() {
182 assertEquals(POLICY_NAME, mgr.getPolicyName());
183 assertSame(event, mgr.getEvent());
185 Map<String, String> orig = event.getAai();
187 event.setAai(addAai(orig, UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
188 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
189 .hasMessage("is-closed-loop-disabled is set to true on VServer or VNF");
192 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS,
193 UsecasesConstants.PROV_STATUS_ACTIVE.toUpperCase()));
194 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
197 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS,
198 UsecasesConstants.PROV_STATUS_ACTIVE.toLowerCase()));
199 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
202 event.setAai(addAai(orig, UsecasesConstants.VSERVER_PROV_STATUS, "inactive"));
203 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
204 .hasMessage("prov-status is not ACTIVE on VServer or VNF");
207 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS,
208 UsecasesConstants.PROV_STATUS_ACTIVE.toUpperCase()));
209 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
212 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS,
213 UsecasesConstants.PROV_STATUS_ACTIVE.toLowerCase()));
214 assertThatCode(() -> new UsecasesEventManager(params, event, workMem)).doesNotThrowAnyException();
217 event.setAai(addAai(orig, UsecasesConstants.GENERIC_VNF_PROV_STATUS, "inactive"));
218 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
219 .hasMessage("prov-status is not ACTIVE on VServer or VNF");
223 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
226 event.setTarget("unknown-target");
227 assertThatThrownBy(() -> new UsecasesEventManager(params, event, workMem))
228 .isInstanceOf(ControlLoopException.class);
232 public void testIsActive() throws Exception {
233 mgr = new UsecasesEventManager(params, event, workMem);
234 assertTrue(mgr.isActive());
236 // deserialized manager should be inactive
237 UsecasesEventManager mgr2 = Serializer.roundTrip(mgr);
238 assertFalse(mgr2.isActive());
242 public void testDestroy_testGetSteps() {
243 // add some steps to the queue
244 mgr.getSteps().add(stepa);
245 mgr.getSteps().add(stepb);
249 verify(stepa).cancel();
250 verify(stepb).cancel();
252 // if superclass destroy() was invoked, then freeLock() should have been submitted
254 verify(executor).execute(any());
258 public void testOnStart() throws ControlLoopException {
259 OperationOutcome outcome = makeOutcome();
262 mgr.onStart(outcome);
264 assertSame(outcome, mgr.getOutcomes().poll());
265 assertThat(mgr.getOutcomes()).isEmpty();
267 verify(workMem).update(factHandle, mgr);
271 public void testOnComplete() throws ControlLoopException {
272 OperationOutcome outcome = makeCompletedOutcome();
275 mgr.onComplete(outcome);
277 assertSame(outcome, mgr.getOutcomes().poll());
278 assertThat(mgr.getOutcomes()).isEmpty();
280 verify(workMem).update(factHandle, mgr);
284 public void testToString() {
285 assertNotNull(mgr.toString());
289 public void testStart() throws ControlLoopException {
294 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
295 .hasMessage("manager already started");
299 * Tests start() when the manager is not in working memory.
302 public void testStartNotInWorkingMemory() throws ControlLoopException {
303 when(workMem.getFactHandle(any())).thenReturn(null);
305 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
306 .hasMessage("manager is not in working memory");
310 * Tests start() when the manager is not active.
313 public void testStartInactive() throws Exception {
314 // make an inactive manager by deserializing it
315 mgr = Serializer.roundTrip(new UsecasesEventManager(params, event, workMem));
318 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
319 .hasMessage("manager is no longer active");
323 public void testAbort() {
324 mgr.abort(UsecasesEventManager.State.DONE, OperationFinalResult.FINAL_FAILURE_GUARD, "some message");
326 assertEquals(UsecasesEventManager.State.DONE, mgr.getState());
327 assertEquals(OperationFinalResult.FINAL_FAILURE_GUARD, mgr.getFinalResult());
328 assertEquals("some message", mgr.getFinalMessage());
331 assertThatThrownBy(() -> mgr.abort(null, OperationFinalResult.FINAL_FAILURE_GUARD, ""))
332 .isInstanceOf(NullPointerException.class).hasMessageContaining("finalState");
336 public void testLoadNextPolicy_testGetFullHistory_testGetPartialHistory() throws Exception {
337 loadPolicy(EVENT_MGR_MULTI_YAML);
338 mgr = new MyManager(params, event, workMem);
340 // start and load step for first policy
342 assertEquals("OperationA", mgr.getSteps().poll().getOperationName());
343 assertNull(mgr.getFinalResult());
346 OperationOutcome outcome = makeOutcome();
347 mgr.addToHistory(outcome);
349 // indicate success and load next policy
350 mgr.loadNextPolicy(OperationResult.SUCCESS);
351 assertEquals("OperationB", mgr.getSteps().poll().getOperationName());
352 assertNull(mgr.getFinalResult());
354 // loadPolicy() should clear the partial history, but not the full history
355 assertThat(mgr.getPartialHistory()).isEmpty();
356 assertThat(mgr.getFullHistory()).hasSize(1);
358 // indicate failure - should go to final failure
359 mgr.loadNextPolicy(OperationResult.FAILURE);
360 assertEquals(OperationFinalResult.FINAL_FAILURE, mgr.getFinalResult());
364 public void testLoadPolicy() throws ControlLoopException {
365 // start() will invoke loadPolicy()
368 assertNull(mgr.getFinalResult());
370 Step2 step = mgr.getSteps().peek();
372 assertEquals("First", step.getActorName());
373 assertEquals("OperationA", step.getOperationName());
375 ControlLoopOperationParams params2 = step.getParams();
376 assertSame(actors, params2.getActorService());
377 assertSame(REQ_ID, params2.getRequestId());
378 assertSame(ForkJoinPool.commonPool(), params2.getExecutor());
379 assertNotNull(params2.getTargetType());
380 assertNotNull(params2.getTargetEntityIds());
381 assertEquals(Integer.valueOf(300), params2.getTimeoutSec());
382 assertEquals(Integer.valueOf(0), params2.getRetry());
383 assertThat(params2.getPayload()).isEmpty();
384 assertNotNull(params2.getStartCallback());
385 assertNotNull(params2.getCompleteCallback());
389 public void testLoadPreprocessorSteps() {
390 stepa = new Step2(mgr, ControlLoopOperationParams.builder().build(), event) {
392 public List<String> getPropertyNames() {
393 return List.of(OperationProperties.AAI_DEFAULT_CLOUD_REGION);
397 protected Operation buildOperation() {
398 return policyOperation;
402 mgr.getSteps().add(stepa);
403 mgr.getSteps().add(stepb);
405 mgr.loadPreprocessorSteps();
407 Deque<Step2> steps = mgr.getSteps();
409 Step2 lockStep = steps.poll();
410 assertNotNull(lockStep);
411 assertEquals(ActorConstants.LOCK_ACTOR, lockStep.getActorName());
412 assertThat(steps.poll()).isInstanceOf(AaiCqStep2.class);
413 assertThat(steps.poll()).isInstanceOf(GuardStep2.class);
414 assertSame(stepa, steps.poll());
415 assertSame(stepb, steps.poll());
416 assertThat(steps).isEmpty();
420 * Tests loadPreprocessorSteps() when there are too many steps in the queue.
423 public void testLoadPreprocessorStepsTooManySteps() {
424 loadStepsWithProperties(OperationProperties.AAI_PNF);
426 Deque<Step2> steps = mgr.getSteps();
427 stepa = steps.getFirst();
430 // load up a bunch of steps
431 for (int nsteps = 0; nsteps < UsecasesEventManager.MAX_STEPS; ++nsteps) {
436 assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
438 // add another step, should still fail
440 assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
442 // remove two steps - should now succeed
446 int nsteps = steps.size();
448 mgr.loadPreprocessorSteps();
449 assertEquals(nsteps + 1, steps.size());
453 * Tests loadPreprocessorSteps() when no additional steps are needed.
456 public void testLoadPreprocessorStepsNothingToLoad() {
457 when(stepa.isPolicyStep()).thenReturn(false);
458 when(stepa.getPropertyNames()).thenReturn(List.of("unknown-property"));
460 Deque<Step2> steps = mgr.getSteps();
465 mgr.loadPreprocessorSteps();
467 assertSame(stepa, steps.poll());
468 assertSame(stepb, steps.poll());
469 assertThat(steps).isEmpty();
473 * Tests loadPreprocessorSteps() when an A&AI custom query is needed.
476 public void testLoadPreprocessorStepsCq() {
477 loadStepsWithProperties(OperationProperties.AAI_DEFAULT_CLOUD_REGION, OperationProperties.AAI_DEFAULT_TENANT);
480 mgr.loadPreprocessorSteps();
482 Deque<Step2> steps = mgr.getSteps();
484 assertThat(steps.poll()).isInstanceOf(AaiCqStep2.class);
485 assertSame(stepa, steps.poll());
486 assertSame(stepb, steps.poll());
487 assertThat(steps).isEmpty();
491 * Tests loadPreprocessorSteps() when an A&AI PNF query is needed.
494 public void testLoadPreprocessorStepsPnf() {
495 // doubling up the property to check both branches
496 loadStepsWithProperties(OperationProperties.AAI_PNF, OperationProperties.AAI_PNF);
499 mgr.loadPreprocessorSteps();
501 Deque<Step2> steps = mgr.getSteps();
503 assertThat(steps.poll()).isInstanceOf(AaiGetPnfStep2.class);
504 assertSame(stepa, steps.poll());
505 assertSame(stepb, steps.poll());
506 assertThat(steps).isEmpty();
510 * Tests loadPreprocessorSteps() when an A&AI Tenant query is needed.
513 public void testLoadPreprocessorStepsTenant() {
514 // doubling up the property to check both branches
515 event.getAai().put(Step2.VSERVER_VSERVER_NAME, "my-vserver");
516 loadStepsWithProperties(OperationProperties.AAI_VSERVER_LINK, OperationProperties.AAI_VSERVER_LINK);
519 mgr.loadPreprocessorSteps();
521 Deque<Step2> steps = mgr.getSteps();
523 assertThat(steps.poll()).isInstanceOf(AaiGetTenantStep2.class);
524 assertSame(stepa, steps.poll());
525 assertSame(stepb, steps.poll());
526 assertThat(steps).isEmpty();
530 * Tests loadPreprocessorSteps() when the target entity is unset.
533 public void testLoadPreprocessorStepsNeedTargetEntity() {
534 stepa = new Step2(mgr,
535 ControlLoopOperationParams.builder()
536 .targetType(TargetType.toTargetType(event.getTargetType()))
537 .targetEntityIds(Map.of()).build(), event) {
539 public List<String> getPropertyNames() {
540 return List.of(OperationProperties.AAI_TARGET_ENTITY);
544 protected Operation buildOperation() {
545 return policyOperation;
549 public boolean isPolicyStep() {
554 Deque<Step2> steps = mgr.getSteps();
558 mgr.loadPreprocessorSteps();
560 Step2 entityStep = steps.poll();
562 assertThat(entityStep).isInstanceOf(GetTargetEntityStep2.class);
563 assertSame(stepa, steps.poll());
564 assertSame(stepb, steps.poll());
565 assertThat(steps).isEmpty();
567 // put get-target-entity back onto the queue and ensure nothing else is added
568 steps.add(entityStep);
569 mgr.loadPreprocessorSteps();
570 assertSame(entityStep, steps.poll());
571 assertThat(steps).isEmpty();
575 public void testExecuteStep() {
578 // no steps to execute
579 assertFalse(mgr.executeStep());
580 assertEquals(0, mgr.getAttempts());
582 // add a step to the queue
583 mgr.getSteps().add(stepa);
585 // step returns false
586 when(stepa.start(anyLong())).thenReturn(false);
587 assertFalse(mgr.executeStep());
590 when(stepa.start(anyLong())).thenReturn(true);
591 assertTrue(mgr.executeStep());
595 public void testNextStep() {
596 mgr.getSteps().add(stepa);
600 assertThat(mgr.getSteps()).isEmpty();
604 public void testBumpAttempts() {
605 assertEquals(0, mgr.getAttempts());
609 assertEquals(2, mgr.getAttempts());
613 public void testIsAbort() {
614 OperationOutcome outcome = makeCompletedOutcome();
615 outcome.setResult(OperationResult.FAILURE);
617 // closed loop timeout
618 outcome.setActor(ActorConstants.CL_TIMEOUT_ACTOR);
619 assertTrue(mgr.isAbort(outcome));
622 outcome.setActor(ActorConstants.LOCK_ACTOR);
623 assertTrue(mgr.isAbort(outcome));
625 // no effect for success
626 outcome.setResult(OperationResult.SUCCESS);
627 assertFalse(mgr.isAbort(outcome));
631 public void testAddToHistory() throws ControlLoopException {
634 // add a "start" outcome
635 OperationOutcome outcome = makeOutcome();
636 mgr.addToHistory(outcome);
638 assertThat(mgr.getPartialHistory()).hasSize(1);
639 assertThat(mgr.getFullHistory()).hasSize(1);
641 // add a "completion" outcome - should replace the start
642 outcome = makeCompletedOutcome();
643 mgr.addToHistory(outcome);
645 assertThat(mgr.getPartialHistory()).hasSize(1);
646 assertThat(mgr.getFullHistory()).hasSize(1);
647 assertSame(outcome, mgr.getPartialHistory().peek().getOutcome());
648 assertSame(outcome, mgr.getFullHistory().peek().getOutcome());
651 outcome = makeOutcome();
652 mgr.addToHistory(outcome);
654 assertThat(mgr.getPartialHistory()).hasSize(2);
655 assertThat(mgr.getFullHistory()).hasSize(2);
656 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
657 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
659 // remove the last item from the full history and then add a "completion"
660 mgr.getFullHistory().removeLast();
661 outcome = makeCompletedOutcome();
662 mgr.addToHistory(outcome);
663 assertThat(mgr.getPartialHistory()).hasSize(2);
664 assertThat(mgr.getFullHistory()).hasSize(2);
666 // add another "start"
667 outcome = makeOutcome();
668 mgr.addToHistory(outcome);
669 assertThat(mgr.getPartialHistory()).hasSize(3);
670 assertThat(mgr.getFullHistory()).hasSize(3);
672 // add a "completion" for a different actor - should NOT replace the start
673 outcome = makeCompletedOutcome();
674 outcome.setActor("different-actor");
675 mgr.addToHistory(outcome);
676 assertThat(mgr.getPartialHistory()).hasSize(4);
677 assertThat(mgr.getFullHistory()).hasSize(4);
678 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
679 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
683 public void testMakeNotification() throws Exception {
684 loadPolicy(EVENT_MGR_MULTI_YAML);
685 mgr = new MyManager(params, event, workMem);
688 assertNotNull(mgr.makeNotification());
692 mgr.addToHistory(makeCompletedOutcome());
693 mgr.addToHistory(makeCompletedOutcome());
694 mgr.addToHistory(makeCompletedOutcome());
696 // check notification while running
697 VirtualControlLoopNotification notif = mgr.makeNotification();
698 assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
699 assertThat(notif.getHistory()).hasSize(3);
701 // indicate success and load the next policy - should clear the partial history
702 mgr.loadNextPolicy(OperationResult.SUCCESS);
704 // check notification
705 notif = mgr.makeNotification();
706 assertNull(notif.getMessage());
707 assertThat(notif.getHistory()).isEmpty();
709 // add outcomes and check again
710 mgr.addToHistory(makeCompletedOutcome());
711 mgr.addToHistory(makeCompletedOutcome());
713 notif = mgr.makeNotification();
714 assertNotNull(notif.getMessage());
716 // should only have history for last two outcomes
717 assertThat(notif.getHistory()).hasSize(2);
719 // indicate failure - should go to final state
720 mgr.loadNextPolicy(OperationResult.FAILURE);
722 // check notification
723 notif = mgr.makeNotification();
724 assertNull(notif.getMessage());
726 // should be no history
727 assertThat(notif.getHistory()).isEmpty();
730 assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
731 .hasMessageContaining("lastResult");
735 public void testDeliver() {
736 mgr.deliver(MY_SINK, null, "null notification", "null rule");
737 verify(engineMgr, never()).deliver(any(), any());
739 mgr.deliver(MY_SINK, "publishA", "A notification", "A rule");
740 verify(engineMgr).deliver(MY_SINK, "publishA");
742 // cause deliver() to throw an exception
743 when(engineMgr.deliver(any(), any())).thenThrow(new IllegalStateException("expected exception"));
744 assertThatCode(() -> mgr.deliver(MY_SINK, "publishB", "B notification", "B rule")).doesNotThrowAnyException();
748 public void testGetOperationMessage() throws ControlLoopException {
750 assertNull(mgr.getOperationMessage());
754 OperationOutcome outcome = makeOutcome();
755 mgr.addToHistory(outcome);
757 assertThat(mgr.getOperationMessage()).contains("actor=" + SIMPLE_ACTOR)
758 .contains("operation=" + SIMPLE_OPERATION);
762 public void testStoreInDataBase() throws ControlLoopException {
764 OperationOutcome outcome = makeOutcome();
765 mgr.addToHistory(outcome);
767 mgr.storeInDataBase(mgr.getPartialHistory().peekLast());
769 verify(dataMgr).store(REQ_ID.toString(), event, null, mgr.getPartialHistory().peekLast().getClOperation());
773 public void testMakeControlLoopResponse() {
774 final OperationOutcome outcome = new OperationOutcome();
776 // no message - should return null
777 checkResp(outcome, null);
779 // not a PciMessage - should return null
780 outcome.setResponse("not-a-pci-message");
781 checkResp(outcome, null);
784 * now work with a PciMessage
786 PciMessage msg = new PciMessage();
787 outcome.setResponse(msg);
789 PciBody body = new PciBody();
792 PciResponse output = new PciResponse();
793 body.setOutput(output);
795 output.setPayload("my-payload");
797 // should generate a response, with a payload
798 checkResp(outcome, "my-payload");
801 * these should generate a response, with null payload
803 output.setPayload(null);
804 checkResp(outcome, null);
806 body.setOutput(null);
807 checkResp(outcome, null);
810 checkResp(outcome, null);
812 outcome.setResponse(null);
813 checkResp(outcome, null);
817 public void testOnNewEvent() {
818 VirtualControlLoopEvent event2 = new VirtualControlLoopEvent(event);
819 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event2));
821 event2.setPayload("other payload");
822 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
823 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
824 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event));
826 event2.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
827 assertEquals(NewEventStatus.FIRST_ABATEMENT, mgr.onNewEvent(event2));
829 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
830 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
832 event2.setClosedLoopEventStatus(null);
833 assertEquals(NewEventStatus.SYNTAX_ERROR, mgr.onNewEvent(event2));
837 public void testCheckEventSyntax() {
838 // initially, it's valid
839 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
841 event.setTarget("unknown-target");
842 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
843 .hasMessage("target field invalid");
845 event.setTarget(null);
846 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
847 .hasMessage("No target field");
849 // abated supersedes previous errors - so it shouldn't throw an exception
850 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
851 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
853 event.setRequestId(null);
854 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
855 .hasMessage("No request ID");
857 event.setClosedLoopControlName(null);
858 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
859 .hasMessage("No control loop name");
863 public void testValidateStatus() {
864 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
865 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
867 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
868 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
870 event.setClosedLoopEventStatus(null);
871 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
872 .hasMessage("Invalid value in closedLoopEventStatus");
876 public void testValidateAaiData() {
877 event.setTargetType("unknown-target-type");
878 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
879 .hasMessage("The target type is not supported");
881 event.setTargetType(null);
882 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
883 .hasMessage("The Target type is null");
886 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
887 .hasMessage("AAI is null");
890 event.setTargetType(ControlLoopTargetType.VM);
891 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
892 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
894 event.setAai(Map.of());
895 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
898 event.setTargetType(ControlLoopTargetType.VNF);
899 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
900 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
902 event.setAai(Map.of());
903 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
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);
915 public void testValidateAaiVmVnfData() {
916 event.setTargetType(ControlLoopTargetType.VM);
917 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
918 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
920 event.setAai(Map.of(ControlLoopEventManager2.VSERVER_VSERVER_NAME, MY_TARGET));
921 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
923 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_NAME, MY_TARGET));
924 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
926 event.setAai(Map.of());
927 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class).hasMessage(
928 "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
932 public void testValidateAaiPnfData() {
933 event.setTargetType(ControlLoopTargetType.PNF);
934 event.setAai(Map.of(ControlLoopEventManager2.PNF_NAME, MY_TARGET));
935 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
937 event.setAai(Map.of());
938 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
939 .hasMessage("AAI PNF object key pnf-name is missing");
943 public void testIsClosedLoopDisabled() {
944 Map<String, String> orig = event.getAai();
946 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
947 assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
948 .isInstanceOf(IllegalStateException.class);
950 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED, "true"));
951 assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
952 .isInstanceOf(IllegalStateException.class);
954 event.setAai(addAai(orig, ControlLoopEventManager2.PNF_IS_IN_MAINT, "true"));
955 assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
956 .isInstanceOf(IllegalStateException.class);
960 public void testIsProvStatusInactive() {
961 Map<String, String> orig = event.getAai();
963 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "ACTIVE"));
964 assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException();
966 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "inactive"));
967 assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
968 .isInstanceOf(IllegalStateException.class);
970 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "ACTIVE"));
971 assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException();
973 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "inactive"));
974 assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
975 .isInstanceOf(IllegalStateException.class);
979 public void testIsAaiTrue() {
980 Map<String, String> orig = event.getAai();
982 for (String value : Arrays.asList("yes", "y", "true", "t", "yEs", "trUe")) {
983 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, value));
984 assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem))
985 .isInstanceOf(IllegalStateException.class);
988 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "false"));
989 assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException();
991 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "no"));
992 assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException();
996 private Map<String, String> addAai(Map<String, String> original, String key, String value) {
997 Map<String, String> map = new TreeMap<>(original);
1002 private void loadPolicy(String fileName) throws CoderException {
1003 ToscaServiceTemplate template =
1004 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
1005 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
1007 params.setToscaPolicy(tosca);
1010 private void loadStepsWithProperties(String... properties) {
1011 stepa = new Step2(mgr, ControlLoopOperationParams.builder().build(), event) {
1014 public boolean isPolicyStep() {
1019 public List<String> getPropertyNames() {
1020 return List.of(properties);
1024 protected Operation buildOperation() {
1025 return policyOperation;
1029 mgr.getSteps().add(stepa);
1030 mgr.getSteps().add(stepb);
1033 private OperationOutcome makeCompletedOutcome() {
1034 OperationOutcome outcome = makeOutcome();
1035 outcome.setEnd(outcome.getStart());
1040 private OperationOutcome makeOutcome() {
1041 OperationOutcome outcome = new OperationOutcome();
1042 outcome.setActor(SIMPLE_ACTOR);
1043 outcome.setOperation(SIMPLE_OPERATION);
1044 outcome.setMessage(OUTCOME_MSG);
1045 outcome.setResult(OperationResult.SUCCESS);
1046 outcome.setStart(Instant.now());
1047 outcome.setTarget(MY_TARGET);
1052 private void checkResp(OperationOutcome outcome, String expectedPayload) {
1053 ControlLoopResponse resp = mgr.makeControlLoopResponse(outcome);
1054 assertNotNull(resp);
1055 assertEquals(REQ_ID, resp.getRequestId());
1056 assertEquals(expectedPayload, resp.getPayload());
1060 * Sets the target entity so a step doesn't have to be added to set it.
1062 private void setTargetEntity() {
1063 mgr.setProperty(OperationProperties.AAI_TARGET_ENTITY, MY_TARGET);
1067 private class MyManager extends UsecasesEventManager {
1068 private static final long serialVersionUID = 1L;
1070 public MyManager(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem)
1071 throws ControlLoopException {
1073 super(params, event, workMem);
1077 protected ExecutorService getBlockingExecutor() {
1082 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
1083 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
1085 callback.lockAvailable(lock);
1089 public ActorService getActorService() {
1094 public OperationHistoryDataManager getDataManager() {
1099 protected PolicyEngine getPolicyEngineManager() {