2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2021, 2023 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.drools.core.common.InternalFactHandle;
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
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 InternalFactHandle factHandle;
101 private Operator policyOperator;
103 private Operation policyOperation;
105 private Actor policyActor;
107 private EventManagerServices services;
109 private ActorService actors;
111 private OperationHistoryDataManager dataMgr;
113 private ExecutorService executor;
115 private MyStep stepa;
117 private MyStep stepb;
119 private List<LockImpl> locks;
120 private ToscaPolicy tosca;
121 private ControlLoopParams params;
122 private VirtualControlLoopEvent event;
123 private ClEventManagerWithEvent<MyStep> mgr;
129 public void setUp() throws ControlLoopException, CoderException {
130 when(services.getActorService()).thenReturn(actors);
131 when(services.getDataManager()).thenReturn(dataMgr);
133 when(workMem.getFactHandle(any())).thenReturn(factHandle);
135 event = new VirtualControlLoopEvent();
136 event.setRequestId(REQ_ID);
137 event.setTarget(TARGET_PROP);
138 event.setAai(new TreeMap<>(Map.of(TARGET_PROP, MY_TARGET)));
139 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
140 event.setClosedLoopControlName(CL_NAME);
141 event.setTargetType(ControlLoopTargetType.VNF);
143 params = new ControlLoopParams();
144 params.setClosedLoopControlName(CL_NAME);
145 params.setPolicyName(POLICY_NAME);
146 params.setPolicyScope(POLICY_SCOPE);
147 params.setPolicyVersion(POLICY_VERSION);
149 loadPolicy(EVENT_MGR_SIMPLE_YAML);
151 locks = new ArrayList<>();
153 mgr = new MyManager(services, params, event, workMem);
157 public void testConstructor() {
158 assertEquals(POLICY_NAME, mgr.getPolicyName());
159 assertSame(event, mgr.getEvent());
162 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
166 assertThatThrownBy(() -> new MyManager(services, params, event, workMem))
167 .isInstanceOf(ControlLoopException.class);
171 public void testPopulateNotification() throws Exception {
172 loadPolicy(EVENT_MGR_MULTI_YAML);
173 mgr = new MyManager(services, params, event, workMem);
176 assertNotNull(mgr.makeNotification());
180 mgr.addToHistory(makeCompletedOutcome());
181 mgr.addToHistory(makeCompletedOutcome());
182 mgr.addToHistory(makeCompletedOutcome());
184 // check notification while running
185 VirtualControlLoopNotification notif = mgr.makeNotification();
186 assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
187 assertThat(notif.getHistory()).hasSize(3);
188 assertThat(notif.getAai()).isEqualTo(event.getAai());
189 assertThat(notif.getClosedLoopAlarmEnd()).isEqualTo(event.getClosedLoopAlarmEnd());
190 assertThat(notif.getClosedLoopAlarmStart()).isEqualTo(event.getClosedLoopAlarmStart());
191 assertThat(notif.getClosedLoopControlName()).isEqualTo(event.getClosedLoopControlName());
192 assertThat(notif.getClosedLoopEventClient()).isEqualTo(event.getClosedLoopEventClient());
193 assertThat(notif.getFrom()).isEqualTo("policy");
194 assertThat(notif.getTarget()).isEqualTo(event.getTarget());
195 assertThat(notif.getTargetType()).isEqualTo(event.getTargetType());
197 // indicate success and load the next policy - should clear the partial history
198 mgr.loadNextPolicy(OperationResult.SUCCESS);
200 // check notification
201 notif = mgr.makeNotification();
202 assertNull(notif.getMessage());
203 assertThat(notif.getHistory()).isEmpty();
205 // add outcomes and check again
206 mgr.addToHistory(makeCompletedOutcome());
207 mgr.addToHistory(makeCompletedOutcome());
209 notif = mgr.makeNotification();
210 assertNotNull(notif.getMessage());
212 // should only have history for last two outcomes
213 assertThat(notif.getHistory()).hasSize(2);
215 // indicate failure - should go to final state
216 mgr.loadNextPolicy(OperationResult.FAILURE);
218 // check notification
219 notif = mgr.makeNotification();
220 assertNull(notif.getMessage());
222 // should be no history
223 assertThat(notif.getHistory()).isEmpty();
226 assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
227 .hasMessageContaining("lastResult");
231 public void testStoreInDataBase() throws ControlLoopException {
233 OperationOutcome outcome = makeOutcome();
234 mgr.addToHistory(outcome);
236 mgr.storeInDataBase(mgr.getPartialHistory().peekLast(), MY_TARGET);
238 verify(dataMgr).store(REQ_ID.toString(), event.getClosedLoopControlName(), event, MY_TARGET,
239 mgr.getPartialHistory().peekLast().getClOperation());
243 public void testMakeControlLoopResponse() {
244 final OperationOutcome outcome = new OperationOutcome();
246 ControlLoopResponse resp = mgr.makeControlLoopResponse(outcome);
248 assertEquals("DCAE", resp.getTarget());
249 assertEquals(event.getClosedLoopControlName(), resp.getClosedLoopControlName());
250 assertEquals(event.getPolicyName(), resp.getPolicyName());
251 assertEquals(event.getPolicyVersion(), resp.getPolicyVersion());
252 assertEquals(REQ_ID, resp.getRequestId());
253 assertEquals(event.getVersion(), resp.getVersion());
257 public void testOnNewEvent() {
258 VirtualControlLoopEvent event2 = new VirtualControlLoopEvent(event);
259 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event2));
261 event2.setPayload("other payload");
262 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
263 assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
264 assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event));
266 event2.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
267 assertEquals(NewEventStatus.FIRST_ABATEMENT, mgr.onNewEvent(event2));
269 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
270 assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
272 event2.setClosedLoopEventStatus(null);
273 assertEquals(NewEventStatus.SYNTAX_ERROR, mgr.onNewEvent(event2));
277 public void testCheckEventSyntax() {
278 // initially, it's valid
279 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
281 event.setTarget(null);
282 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
283 .hasMessage("No target field");
285 // abated supersedes previous errors - so it shouldn't throw an exception
286 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
287 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
289 event.setRequestId(null);
290 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
291 .hasMessage("No request ID");
293 event.setClosedLoopControlName(null);
294 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
295 .hasMessage("No control loop name");
299 public void testValidateStatus() {
300 event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
301 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
303 event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
304 assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
306 event.setClosedLoopEventStatus(null);
307 assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
308 .hasMessage("Invalid value in closedLoopEventStatus");
311 private void loadPolicy(String fileName) throws CoderException {
312 ToscaServiceTemplate template =
313 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
314 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
316 params.setToscaPolicy(tosca);
319 private OperationOutcome makeCompletedOutcome() {
320 OperationOutcome outcome = makeOutcome();
321 outcome.setEnd(outcome.getStart());
326 private OperationOutcome makeOutcome() {
327 OperationOutcome outcome = new OperationOutcome();
328 outcome.setActor(SIMPLE_ACTOR);
329 outcome.setOperation(SIMPLE_OPERATION);
330 outcome.setMessage(OUTCOME_MSG);
331 outcome.setResult(OperationResult.SUCCESS);
332 outcome.setStart(Instant.now());
333 outcome.setTarget(MY_TARGET);
339 private class MyManager extends ClEventManagerWithEvent<MyStep> {
340 private static final long serialVersionUID = 1L;
342 public MyManager(EventManagerServices services, ControlLoopParams params, VirtualControlLoopEvent event,
343 WorkingMemory workMem) throws ControlLoopException {
345 super(services, params, event, workMem);
349 protected ExecutorService getBlockingExecutor() {
354 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
355 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
357 callback.lockAvailable(lock);
361 protected PolicyEngine getPolicyEngineManager() {
366 protected void loadPolicyStep(ControlLoopOperationParams params) {
367 getSteps().add(new MyStep(this, params, getEvent()));
371 private static class MyStep extends Step {
372 public MyStep(StepContext stepContext, ControlLoopOperationParams params, VirtualControlLoopEvent event) {
373 super(params, new AtomicReference<>());