2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.controlloop.eventmanager;
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.assertThatThrownBy;
26 import static org.junit.Assert.assertEquals;
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.mockito.ArgumentMatchers.any;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
34 import java.time.Instant;
35 import java.util.ArrayList;
36 import java.util.List;
38 import java.util.TreeMap;
39 import java.util.UUID;
40 import java.util.concurrent.ExecutorService;
41 import java.util.concurrent.atomic.AtomicReference;
42 import org.drools.core.WorkingMemory;
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 import org.kie.api.runtime.rule.FactHandle;
47 import org.mockito.Mock;
48 import org.mockito.junit.MockitoJUnitRunner;
49 import org.onap.policy.common.utils.coder.Coder;
50 import org.onap.policy.common.utils.coder.CoderException;
51 import org.onap.policy.common.utils.coder.StandardYamlCoder;
52 import org.onap.policy.common.utils.resources.ResourceUtils;
53 import org.onap.policy.controlloop.ControlLoopEventStatus;
54 import org.onap.policy.controlloop.ControlLoopException;
55 import org.onap.policy.controlloop.ControlLoopResponse;
56 import org.onap.policy.controlloop.ControlLoopTargetType;
57 import org.onap.policy.controlloop.VirtualControlLoopEvent;
58 import org.onap.policy.controlloop.VirtualControlLoopNotification;
59 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
60 import org.onap.policy.controlloop.actorserviceprovider.Operation;
61 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
62 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
63 import org.onap.policy.controlloop.actorserviceprovider.Operator;
64 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
65 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
66 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
67 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithEvent.NewEventStatus;
68 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
69 import org.onap.policy.drools.core.lock.LockCallback;
70 import org.onap.policy.drools.core.lock.LockImpl;
71 import org.onap.policy.drools.core.lock.LockState;
72 import org.onap.policy.drools.system.PolicyEngine;
73 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
74 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
76 @RunWith(MockitoJUnitRunner.class)
77 public class ClEventManagerWithEventTest {
78 private static final UUID REQ_ID = UUID.randomUUID();
79 private static final String CL_NAME = "my-closed-loop-name";
80 private static final String POLICY_NAME = "my-policy-name";
81 private static final String POLICY_SCOPE = "my-scope";
82 private static final String POLICY_VERSION = "1.2.3";
83 private static final String SIMPLE_ACTOR = "First";
84 private static final String SIMPLE_OPERATION = "OperationA";
85 private static final String TARGET_PROP = "my-target-property";
86 private static final String MY_TARGET = "my-target";
87 private static final String EVENT_MGR_MULTI_YAML =
88 "../eventmanager/src/test/resources/eventManager/event-mgr-multi.yaml";
89 private static final String EVENT_MGR_SIMPLE_YAML =
90 "../eventmanager/src/test/resources/eventManager/event-mgr-simple.yaml";
91 private static final Coder yamlCoder = new StandardYamlCoder();
92 private static final String OUTCOME_MSG = "my outcome message";
95 private PolicyEngine engineMgr;
97 private WorkingMemory workMem;
99 private FactHandle factHandle;
101 private Operator policyOperator;
103 private Operation policyOperation;
105 private Actor policyActor;
107 private ActorService actors;
109 private OperationHistoryDataManager dataMgr;
111 private ExecutorService executor;
113 private MyStep stepa;
115 private MyStep stepb;
117 private List<LockImpl> locks;
118 private ToscaPolicy tosca;
119 private ControlLoopParams params;
120 private VirtualControlLoopEvent event;
121 private ClEventManagerWithEvent<MyStep> mgr;
127 public void setUp() throws ControlLoopException, CoderException {
128 when(workMem.getFactHandle(any())).thenReturn(factHandle);
130 event = new VirtualControlLoopEvent();
131 event.setRequestId(REQ_ID);
132 event.setTarget(TARGET_PROP);
133 event.setAai(new TreeMap<>(Map.of(TARGET_PROP, MY_TARGET)));
134 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
135 event.setClosedLoopControlName(CL_NAME);
136 event.setTargetType(ControlLoopTargetType.VNF);
138 params = new ControlLoopParams();
139 params.setClosedLoopControlName(CL_NAME);
140 params.setPolicyName(POLICY_NAME);
141 params.setPolicyScope(POLICY_SCOPE);
142 params.setPolicyVersion(POLICY_VERSION);
144 loadPolicy(EVENT_MGR_SIMPLE_YAML);
146 locks = new ArrayList<>();
148 mgr = new MyManager(params, event, workMem);
152 public void testConstructor() {
153 assertEquals(POLICY_NAME, mgr.getPolicyName());
154 assertSame(event, mgr.getEvent());
157 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
161 assertThatThrownBy(() -> new MyManager(params, event, workMem)).isInstanceOf(ControlLoopException.class);
165 public void testPopulateNotification() throws Exception {
166 loadPolicy(EVENT_MGR_MULTI_YAML);
167 mgr = new MyManager(params, event, workMem);
170 assertNotNull(mgr.makeNotification());
174 mgr.addToHistory(makeCompletedOutcome());
175 mgr.addToHistory(makeCompletedOutcome());
176 mgr.addToHistory(makeCompletedOutcome());
178 // check notification while running
179 VirtualControlLoopNotification notif = mgr.makeNotification();
180 assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
181 assertThat(notif.getHistory()).hasSize(3);
182 assertThat(notif.getAai()).isEqualTo(event.getAai());
183 assertThat(notif.getClosedLoopAlarmEnd()).isEqualTo(event.getClosedLoopAlarmEnd());
184 assertThat(notif.getClosedLoopAlarmStart()).isEqualTo(event.getClosedLoopAlarmStart());
185 assertThat(notif.getClosedLoopControlName()).isEqualTo(event.getClosedLoopControlName());
186 assertThat(notif.getClosedLoopEventClient()).isEqualTo(event.getClosedLoopEventClient());
187 assertThat(notif.getFrom()).isEqualTo("policy");
188 assertThat(notif.getTarget()).isEqualTo(event.getTarget());
189 assertThat(notif.getTargetType()).isEqualTo(event.getTargetType());
191 // indicate success and load the next policy - should clear the partial history
192 mgr.loadNextPolicy(OperationResult.SUCCESS);
194 // check notification
195 notif = mgr.makeNotification();
196 assertNull(notif.getMessage());
197 assertThat(notif.getHistory()).isEmpty();
199 // add outcomes and check again
200 mgr.addToHistory(makeCompletedOutcome());
201 mgr.addToHistory(makeCompletedOutcome());
203 notif = mgr.makeNotification();
204 assertNotNull(notif.getMessage());
206 // should only have history for last two outcomes
207 assertThat(notif.getHistory()).hasSize(2);
209 // indicate failure - should go to final state
210 mgr.loadNextPolicy(OperationResult.FAILURE);
212 // check notification
213 notif = mgr.makeNotification();
214 assertNull(notif.getMessage());
216 // should be no history
217 assertThat(notif.getHistory()).isEmpty();
220 assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
221 .hasMessageContaining("lastResult");
225 public void testStoreInDataBase() throws ControlLoopException {
227 OperationOutcome outcome = makeOutcome();
228 mgr.addToHistory(outcome);
230 mgr.storeInDataBase(mgr.getPartialHistory().peekLast(), MY_TARGET);
232 verify(dataMgr).store(REQ_ID.toString(), event.getClosedLoopControlName(), event, MY_TARGET,
233 mgr.getPartialHistory().peekLast().getClOperation());
237 public void testMakeControlLoopResponse() {
238 final OperationOutcome outcome = new OperationOutcome();
240 ControlLoopResponse resp = mgr.makeControlLoopResponse(outcome);
242 assertEquals("DCAE", resp.getTarget());
243 assertEquals(event.getClosedLoopControlName(), resp.getClosedLoopControlName());
244 assertEquals(event.getPolicyName(), resp.getPolicyName());
245 assertEquals(event.getPolicyVersion(), resp.getPolicyVersion());
246 assertEquals(REQ_ID, resp.getRequestId());
247 assertEquals(event.getVersion(), resp.getVersion());
251 public void testOnNewEvent() {
252 VirtualControlLoopEvent event2 = new VirtualControlLoopEvent(event);
253 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event2));
255 event2.setPayload("other payload");
256 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
257 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
258 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event));
260 event2.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
261 assertEquals(NewEventStatus.FIRST_ABATEMENT, mgr.onNewEvent(event2));
263 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
264 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
266 event2.setClosedLoopEventStatus(null);
267 assertEquals(NewEventStatus.SYNTAX_ERROR, mgr.onNewEvent(event2));
271 public void testCheckEventSyntax() {
272 // initially, it's valid
273 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
275 event.setTarget(null);
276 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
277 .hasMessage("No target field");
279 // abated supersedes previous errors - so it shouldn't throw an exception
280 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
281 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
283 event.setRequestId(null);
284 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
285 .hasMessage("No request ID");
287 event.setClosedLoopControlName(null);
288 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
289 .hasMessage("No control loop name");
293 public void testValidateStatus() {
294 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
295 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
297 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
298 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
300 event.setClosedLoopEventStatus(null);
301 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
302 .hasMessage("Invalid value in closedLoopEventStatus");
305 private void loadPolicy(String fileName) throws CoderException {
306 ToscaServiceTemplate template =
307 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
308 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
310 params.setToscaPolicy(tosca);
313 private OperationOutcome makeCompletedOutcome() {
314 OperationOutcome outcome = makeOutcome();
315 outcome.setEnd(outcome.getStart());
320 private OperationOutcome makeOutcome() {
321 OperationOutcome outcome = new OperationOutcome();
322 outcome.setActor(SIMPLE_ACTOR);
323 outcome.setOperation(SIMPLE_OPERATION);
324 outcome.setMessage(OUTCOME_MSG);
325 outcome.setResult(OperationResult.SUCCESS);
326 outcome.setStart(Instant.now());
327 outcome.setTarget(MY_TARGET);
333 private class MyManager extends ClEventManagerWithEvent<MyStep> {
334 private static final long serialVersionUID = 1L;
336 public MyManager(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem)
337 throws ControlLoopException {
339 super(params, event, workMem);
343 protected ExecutorService getBlockingExecutor() {
348 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
349 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
351 callback.lockAvailable(lock);
355 public ActorService getActorService() {
360 public OperationHistoryDataManager getDataManager() {
365 protected PolicyEngine getPolicyEngineManager() {
370 protected void loadPolicyStep(ControlLoopOperationParams params) {
371 getSteps().add(new MyStep(this, params, getEvent()));
375 private static class MyStep extends Step {
376 public MyStep(StepContext stepContext, ControlLoopOperationParams params, VirtualControlLoopEvent event) {
377 super(params, new AtomicReference<>());