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.controlloop.eventmanager;
23 import static org.assertj.core.api.Assertions.assertThatCode;
24 import static org.assertj.core.api.Assertions.assertThatThrownBy;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assert.assertNull;
29 import static org.junit.Assert.assertSame;
30 import static org.junit.Assert.assertTrue;
31 import static org.mockito.ArgumentMatchers.any;
32 import static org.mockito.ArgumentMatchers.anyLong;
33 import static org.mockito.Mockito.never;
34 import static org.mockito.Mockito.times;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.when;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
42 import java.util.TreeMap;
43 import java.util.UUID;
44 import java.util.concurrent.CompletableFuture;
45 import java.util.concurrent.ExecutorService;
46 import java.util.function.Consumer;
47 import org.drools.core.WorkingMemory;
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.kie.api.runtime.rule.FactHandle;
51 import org.mockito.ArgumentCaptor;
52 import org.mockito.Mock;
53 import org.mockito.MockitoAnnotations;
54 import org.onap.policy.common.utils.coder.Coder;
55 import org.onap.policy.common.utils.coder.CoderException;
56 import org.onap.policy.common.utils.coder.StandardYamlCoder;
57 import org.onap.policy.common.utils.io.Serializer;
58 import org.onap.policy.common.utils.resources.ResourceUtils;
59 import org.onap.policy.controlloop.ControlLoopEventStatus;
60 import org.onap.policy.controlloop.ControlLoopException;
61 import org.onap.policy.controlloop.ControlLoopNotificationType;
62 import org.onap.policy.controlloop.ControlLoopOperation;
63 import org.onap.policy.controlloop.ControlLoopTargetType;
64 import org.onap.policy.controlloop.VirtualControlLoopEvent;
65 import org.onap.policy.controlloop.VirtualControlLoopNotification;
66 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
67 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
68 import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
69 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
70 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager2.NewEventStatus;
71 import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager2.State;
72 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
73 import org.onap.policy.controlloop.policy.Policy;
74 import org.onap.policy.controlloop.policy.PolicyResult;
75 import org.onap.policy.controlloop.policy.Target;
76 import org.onap.policy.controlloop.policy.TargetType;
77 import org.onap.policy.drools.core.lock.LockCallback;
78 import org.onap.policy.drools.core.lock.LockImpl;
79 import org.onap.policy.drools.core.lock.LockState;
80 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
81 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
83 public class ControlLoopEventManager2Test {
84 private static final UUID REQ_ID = UUID.randomUUID();
85 private static final String CL_NAME = "my-closed-loop-name";
86 private static final String POLICY_NAME = "my-policy-name";
87 private static final String POLICY_SCOPE = "my-scope";
88 private static final String POLICY_VERSION = "1.2.3";
89 private static final String MY_TARGET = "my-target";
90 private static final String LOCK1 = "my-lock-A";
91 private static final String LOCK2 = "my-lock-B";
92 private static final Coder yamlCoder = new StandardYamlCoder();
95 private WorkingMemory workMem;
97 private Consumer<OperationOutcome> callback1;
99 private Consumer<OperationOutcome> callback2;
101 private Consumer<OperationOutcome> callback3;
103 private FactHandle factHandle;
105 private ActorService actors;
107 private OperationHistoryDataManager dataMgr;
109 private ControlLoopOperationManager2 oper1;
111 private ControlLoopOperationManager2 oper2;
113 private ControlLoopOperationManager2 oper3;
115 private ExecutorService executor;
117 private long preCreateTimeMs;
118 private List<LockImpl> locks;
119 private Target target;
120 private ToscaPolicy tosca;
121 private ControlLoopParams params;
122 private VirtualControlLoopEvent event;
123 private int updateCount;
124 private ControlLoopEventManager2 mgr;
130 public void setUp() throws ControlLoopException, CoderException {
131 MockitoAnnotations.initMocks(this);
133 when(oper1.getHistory()).thenReturn(makeHistory("A"));
134 when(oper2.getHistory()).thenReturn(makeHistory("B"));
135 when(oper3.getHistory()).thenReturn(makeHistory("C"));
137 when(oper1.getActor()).thenReturn("First");
138 when(oper1.getOperation()).thenReturn("OperationA");
139 when(oper1.getOperationMessage()).thenReturn("message-A");
141 when(oper2.getActor()).thenReturn("Second");
142 when(oper2.getOperation()).thenReturn("OperationB");
143 when(oper2.getOperationMessage()).thenReturn("message-B");
145 when(oper3.getActor()).thenReturn("Third");
146 when(oper3.getOperation()).thenReturn("OperationC");
147 when(oper3.getOperationMessage()).thenReturn("message-C");
149 when(workMem.getFactHandle(any())).thenReturn(factHandle);
151 event = new VirtualControlLoopEvent();
152 event.setRequestId(REQ_ID);
153 event.setTarget(ControlLoopOperationManager2.VSERVER_VSERVER_NAME);
154 event.setAai(new TreeMap<>(Map.of(ControlLoopOperationManager2.VSERVER_VSERVER_NAME, MY_TARGET)));
155 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
156 event.setClosedLoopControlName(CL_NAME);
157 event.setTargetType(TargetType.VNF.toString());
159 target = new Target();
160 target.setType(TargetType.VNF);
162 params = new ControlLoopParams();
163 params.setClosedLoopControlName(CL_NAME);
164 params.setPolicyName(POLICY_NAME);
165 params.setPolicyScope(POLICY_SCOPE);
166 params.setPolicyVersion(POLICY_VERSION);
168 loadPolicy("eventManager/event-mgr-simple.yaml");
170 locks = new ArrayList<>();
174 preCreateTimeMs = System.currentTimeMillis();
176 mgr = new MyManagerWithOper(params, event, workMem);
180 public void testConstructor() {
181 assertEquals(POLICY_NAME, mgr.getPolicyName());
183 Map<String, String> orig = event.getAai();
185 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
186 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
187 .hasMessage("is-closed-loop-disabled is set to true on VServer or VNF");
189 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "inactive"));
190 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem))
191 .hasMessage("prov-status is not ACTIVE on VServer or VNF");
195 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
198 event.setTarget("unknown-target");
199 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem));
203 * Runs through a policy that has several operations.
206 public void testMultiOperation() throws Exception {
208 loadPolicy("eventManager/event-mgr-multi.yaml");
210 mgr = new MyManagerWithOper(params, event, workMem);
213 for (ControlLoopOperationManager2 oper : Arrays.asList(oper1, oper2, oper3)) {
214 assertTrue(mgr.isActive());
215 nextStep(oper, true, PolicyResult.SUCCESS);
218 assertTrue(mgr.isActive());
219 nextStep(oper, false, PolicyResult.SUCCESS);
223 assertFalse(mgr.isActive());
227 public void testStart() throws Exception {
232 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
233 .hasMessage("manager already started");
237 * Tests start() error cases.
240 public void testStartErrors() throws Exception {
242 ControlLoopEventManager2 mgr2 = new ControlLoopEventManager2(params, event, workMem);
243 ControlLoopEventManager2 mgr3 = Serializer.roundTrip(mgr2);
244 assertThatCode(() -> mgr3.start()).isInstanceOf(IllegalStateException.class)
245 .hasMessage("manager is no longer active");
248 when(workMem.getFactHandle(any())).thenReturn(null);
249 assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
250 .hasMessage("manager is not in working memory");
254 public void testNextStep_testStartOperationSuccess() throws ControlLoopException {
255 runOperation(PolicyResult.SUCCESS);
257 VirtualControlLoopNotification notif = mgr.getNotification();
258 assertEquals(ControlLoopNotificationType.FINAL_SUCCESS, notif.getNotification());
259 assertNull(notif.getMessage());
261 assertThatCode(() -> mgr.nextStep()).doesNotThrowAnyException();
265 * Tests nextStep() when the next step is invalid, which should cause an exception to
266 * be thrown by the processor.
269 public void testNextStepMissing() throws Exception {
272 when(oper1.nextStep()).thenThrow(new IllegalArgumentException("expected exception"));
276 assertFalse(mgr.isActive());
278 VirtualControlLoopNotification notif = mgr.getNotification();
279 assertEquals(ControlLoopNotificationType.FINAL_FAILURE, notif.getNotification());
280 assertEquals("Policy processing aborted due to policy error", notif.getMessage());
281 assertTrue(notif.getHistory().isEmpty());
285 * Tests startOperation() with FINAL_FAILURE_EXCEPTION.
288 public void testStartOperationException() throws ControlLoopException {
289 runOperation(PolicyResult.FAILURE_EXCEPTION);
291 VirtualControlLoopNotification notif = mgr.getNotification();
292 assertEquals(ControlLoopNotificationType.FINAL_FAILURE, notif.getNotification());
293 assertEquals("Exception in processing closed loop", notif.getMessage());
297 * Tests startOperation() with FINAL_FAILURE.
300 public void testStartOperationFailure() throws ControlLoopException {
301 runOperation(PolicyResult.FAILURE);
303 VirtualControlLoopNotification notif = mgr.getNotification();
304 assertEquals(ControlLoopNotificationType.FINAL_FAILURE, notif.getNotification());
305 assertNull(notif.getMessage());
309 * Tests startOperation() with FINAL_OPENLOOP.
312 public void testStartOperationOpenLoop() throws ControlLoopException {
313 runOperation(PolicyResult.FAILURE_GUARD);
315 VirtualControlLoopNotification notif = mgr.getNotification();
316 assertEquals(ControlLoopNotificationType.FINAL_OPENLOOP, notif.getNotification());
317 assertNull(notif.getMessage());
321 public void testIsActive() throws Exception {
322 mgr = new ControlLoopEventManager2(params, event, workMem);
323 assertTrue(mgr.isActive());
325 ControlLoopEventManager2 mgr2 = Serializer.roundTrip(mgr);
326 assertFalse(mgr2.isActive());
330 public void testUpdated() throws ControlLoopException {
333 // not the active operation - should be ignored
335 verify(workMem, never()).update(any(), any());
337 VirtualControlLoopNotification notif;
339 // check notification data
340 when(oper1.getState()).thenReturn(State.LOCK_DENIED);
342 notif = mgr.getNotification();
343 assertNotNull(notif.getHistory());
346 * try the various cases
348 when(oper1.getState()).thenReturn(State.LOCK_DENIED);
350 verifyNotification(ControlLoopNotificationType.REJECTED, "The target my-target is already locked");
352 when(oper1.getState()).thenReturn(State.LOCK_LOST);
354 verifyNotification(ControlLoopNotificationType.OPERATION_FAILURE, "The target my-target is no longer locked");
356 when(oper1.getState()).thenReturn(State.GUARD_STARTED);
358 verifyNotification(ControlLoopNotificationType.OPERATION, "Sending guard query for First OperationA");
360 when(oper1.getState()).thenReturn(State.GUARD_PERMITTED);
362 verifyNotification(ControlLoopNotificationType.OPERATION, "Guard result for First OperationA is Permit");
364 when(oper1.getState()).thenReturn(State.GUARD_DENIED);
366 verifyNotification(ControlLoopNotificationType.OPERATION, "Guard result for First OperationA is Deny");
368 when(oper1.getState()).thenReturn(State.OPERATION_SUCCESS);
370 verifyNotification(ControlLoopNotificationType.OPERATION_SUCCESS, "message-A");
372 when(oper1.getState()).thenReturn(State.OPERATION_FAILURE);
374 verifyNotification(ControlLoopNotificationType.OPERATION_FAILURE, "message-A");
376 // should still be active
377 assertTrue(mgr.isActive());
382 when(oper1.getState()).thenReturn(State.CONTROL_LOOP_TIMEOUT);
384 verifyNotification(ControlLoopNotificationType.FINAL_FAILURE, "Control Loop timed out");
386 // should now be done
387 assertFalse(mgr.isActive());
391 public void testDestroy() {
392 mgr.requestLock(LOCK1, callback1);
393 mgr.requestLock(LOCK2, callback2);
394 mgr.requestLock(LOCK1, callback3);
400 for (LockImpl lock : locks) {
401 assertTrue(lock.isUnavailable());
406 * Tests destroy() once it has been started.
409 public void testDestroyStarted() throws ControlLoopException {
412 mgr.requestLock(LOCK1, callback1);
413 mgr.requestLock(LOCK2, callback2);
414 mgr.requestLock(LOCK1, callback3);
420 // should have canceled the operation
421 verify(oper1).cancel();
423 for (LockImpl lock : locks) {
424 assertTrue(lock.isUnavailable());
429 public void testMakeNotification() throws ControlLoopException {
432 nextStep(oper1, true, PolicyResult.SUCCESS);
435 // check notification while running
436 VirtualControlLoopNotification notif = mgr.getNotification();
437 assertEquals("message-A", notif.getMessage());
439 List<ControlLoopOperation> history = notif.getHistory();
440 assertNotNull(history);
442 nextStep(oper1, false, PolicyResult.SUCCESS);
445 assertFalse(mgr.isActive());
447 // check notification when complete
448 notif = mgr.getNotification();
449 assertNull(notif.getMessage());
450 assertEquals(history, notif.getHistory());
454 public void testOnNewEvent() {
455 VirtualControlLoopEvent event2 = new VirtualControlLoopEvent(event);
456 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event2));
458 event2.setPayload("other payload");
459 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
460 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
461 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event));
463 event2.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
464 assertEquals(NewEventStatus.FIRST_ABATEMENT, mgr.onNewEvent(event2));
466 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
467 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
469 event2.setClosedLoopEventStatus(null);
470 assertEquals(NewEventStatus.SYNTAX_ERROR, mgr.onNewEvent(event2));
474 public void testDetmControlLoopTimeoutMs() throws Exception {
475 verifyTimeout(1200 * 1000L);
478 private void verifyTimeout(long timeMs) {
479 long end = mgr.getEndTimeMs();
480 assertTrue(end >= preCreateTimeMs + timeMs);
481 assertTrue(end < preCreateTimeMs + timeMs + 5000);
485 public void testCheckEventSyntax() {
486 // initially, it's valid
487 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
489 event.setTarget("unknown-target");
490 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
491 .hasMessage("target field invalid");
493 event.setTarget(null);
494 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
495 .hasMessage("No target field");
497 // abated supersedes previous errors - so it shouldn't throw an exception
498 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
499 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
501 event.setRequestId(null);
502 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
503 .hasMessage("No request ID");
505 event.setClosedLoopControlName(null);
506 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
507 .hasMessage("No control loop name");
511 public void testValidateStatus() {
512 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
513 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
515 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
516 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
518 event.setClosedLoopEventStatus(null);
519 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
520 .hasMessage("Invalid value in closedLoopEventStatus");
524 public void testValidateAaiData() {
525 event.setTargetType("unknown-target-type");
526 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
527 .hasMessage("The target type is not supported");
529 event.setTargetType(null);
530 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
531 .hasMessage("The Target type is null");
534 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
535 .hasMessage("AAI is null");
538 event.setTargetType(ControlLoopTargetType.VM);
539 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
540 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
542 event.setAai(Map.of());
543 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
546 event.setTargetType(ControlLoopTargetType.VNF);
547 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
548 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
550 event.setAai(Map.of());
551 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
554 event.setTargetType(ControlLoopTargetType.PNF);
555 event.setAai(Map.of(ControlLoopEventManager2.PNF_NAME, MY_TARGET));
556 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
558 event.setAai(Map.of());
559 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class);
563 public void testValidateAaiVmVnfData() {
564 event.setTargetType(ControlLoopTargetType.VM);
565 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_ID, MY_TARGET));
566 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
568 event.setAai(Map.of(ControlLoopEventManager2.VSERVER_VSERVER_NAME, MY_TARGET));
569 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
571 event.setAai(Map.of(ControlLoopEventManager2.GENERIC_VNF_VNF_NAME, MY_TARGET));
572 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
574 event.setAai(Map.of());
575 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class).hasMessage(
576 "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
580 public void testValidateAaiPnfData() {
581 event.setTargetType(ControlLoopTargetType.PNF);
582 event.setAai(Map.of(ControlLoopEventManager2.PNF_NAME, MY_TARGET));
583 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
585 event.setAai(Map.of());
586 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
587 .hasMessage("AAI PNF object key pnf-name is missing");
591 public void testIsClosedLoopDisabled() {
592 Map<String, String> orig = event.getAai();
594 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "true"));
595 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem));
597 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED, "true"));
598 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem));
600 event.setAai(addAai(orig, ControlLoopEventManager2.PNF_IS_IN_MAINT, "true"));
601 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem));
604 private Map<String, String> addAai(Map<String, String> original, String key, String value) {
605 Map<String, String> map = new TreeMap<>(original);
611 public void testIsProvStatusInactive() {
612 Map<String, String> orig = event.getAai();
614 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "ACTIVE"));
615 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
617 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "inactive"));
618 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem));
620 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "ACTIVE"));
621 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
623 event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "inactive"));
624 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem));
628 public void testIsAaiTrue() {
629 Map<String, String> orig = event.getAai();
631 for (String value : Arrays.asList("yes", "y", "true", "t", "yEs", "trUe")) {
632 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, value));
633 assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem));
636 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "false"));
637 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
639 event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "no"));
640 assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException();
644 public void testRequestLock() {
645 final CompletableFuture<OperationOutcome> future1 = mgr.requestLock(LOCK1, callback1);
646 final CompletableFuture<OperationOutcome> future2 = mgr.requestLock(LOCK2, callback2);
647 assertSame(future1, mgr.requestLock(LOCK1, callback3));
649 assertEquals(2, locks.size());
651 assertTrue(future1.isDone());
652 assertTrue(future2.isDone());
654 verify(callback1, never()).accept(any());
655 verify(callback2, never()).accept(any());
656 verify(callback3, never()).accept(any());
658 // indicate that the first lock failed
659 locks.get(0).notifyUnavailable();
661 verify(callback1).accept(any());
662 verify(callback2, never()).accept(any());
663 verify(callback3).accept(any());
667 public void testMakeOperationManager() throws ControlLoopException {
668 // use a manager that creates real operation managers
669 mgr = new MyManager(params, event, workMem);
671 assertThatCode(() -> mgr.start()).doesNotThrowAnyException();
675 public void testGetBlockingExecutor() throws Exception {
676 mgr = new ControlLoopEventManager2(params, event, workMem);
677 assertThatCode(() -> mgr.getBlockingExecutor()).doesNotThrowAnyException();
681 public void testToString() {
682 assertNotNull(mgr.toString());
686 private void nextStep(ControlLoopOperationManager2 oper, boolean moreSteps, PolicyResult result) {
687 when(oper.nextStep()).thenReturn(moreSteps);
688 when(oper.getOperationResult()).thenReturn(result);
690 if (result == PolicyResult.SUCCESS) {
691 when(oper.getState()).thenReturn(State.OPERATION_SUCCESS);
693 when(oper.getState()).thenReturn(State.OPERATION_FAILURE);
700 verify(workMem, times(updateCount)).update(factHandle, mgr);
703 private void runRule() {
704 assertTrue(mgr.isActive());
708 private void runOperation(PolicyResult finalResult) throws ControlLoopException {
710 verify(oper1).start(anyLong());
712 assertTrue(mgr.isActive());
714 nextStep(oper1, true, PolicyResult.SUCCESS);
717 nextStep(oper1, false, finalResult);
720 assertFalse(mgr.isActive());
722 // should have no effect, because it's done
724 verify(workMem, times(updateCount)).update(any(), any());
727 private void verifyNotification(ControlLoopNotificationType expectedType, String expectedMsg) {
728 VirtualControlLoopNotification notif = mgr.getNotification();
729 assertEquals(expectedType, notif.getNotification());
730 assertEquals(expectedMsg, notif.getMessage());
733 private List<ControlLoopOperation> makeHistory(String message) {
734 ControlLoopOperation clo = new ControlLoopOperation();
735 clo.setMessage("history-" + message);
740 private void loadPolicy(String fileName) throws CoderException {
741 ToscaServiceTemplate template =
742 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
743 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
745 params.setToscaPolicy(tosca);
748 private void freeLocks() {
749 ArgumentCaptor<Runnable> runCaptor = ArgumentCaptor.forClass(Runnable.class);
750 verify(executor).execute(runCaptor.capture());
752 runCaptor.getValue().run();
756 private class MyManager extends ControlLoopEventManager2 {
757 private static final long serialVersionUID = 1L;
759 public MyManager(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem)
760 throws ControlLoopException {
762 super(params, event, workMem);
766 protected ExecutorService getBlockingExecutor() {
771 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
772 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
774 callback.lockAvailable(lock);
778 public ActorService getActorService() {
783 public OperationHistoryDataManager getDataManager() {
789 private class MyManagerWithOper extends MyManager {
790 private static final long serialVersionUID = 1L;
792 public MyManagerWithOper(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem)
793 throws ControlLoopException {
795 super(params, event, workMem);
799 protected ControlLoopOperationManager2 makeOperationManager(ControlLoopEventContext ctx, Policy policy) {
800 switch (policy.getActor()) {
808 throw new IllegalArgumentException("unknown policy actor " + policy.getActor());