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.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.Mockito.when;
34 import java.time.Instant;
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.UUID;
38 import java.util.concurrent.ExecutorService;
39 import java.util.concurrent.atomic.AtomicReference;
40 import org.drools.core.WorkingMemory;
41 import org.drools.core.common.InternalFactHandle;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.mockito.Mock;
46 import org.mockito.junit.MockitoJUnitRunner;
47 import org.onap.policy.common.utils.coder.Coder;
48 import org.onap.policy.common.utils.coder.CoderException;
49 import org.onap.policy.common.utils.coder.StandardYamlCoder;
50 import org.onap.policy.common.utils.resources.ResourceUtils;
51 import org.onap.policy.controlloop.ControlLoopException;
52 import org.onap.policy.controlloop.ControlLoopResponse;
53 import org.onap.policy.controlloop.VirtualControlLoopNotification;
54 import org.onap.policy.controlloop.actorserviceprovider.Operation;
55 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
56 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
57 import org.onap.policy.controlloop.actorserviceprovider.Operator;
58 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
59 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
60 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
61 import org.onap.policy.drools.core.lock.LockCallback;
62 import org.onap.policy.drools.core.lock.LockImpl;
63 import org.onap.policy.drools.core.lock.LockState;
64 import org.onap.policy.drools.system.PolicyEngine;
65 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
66 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
68 @RunWith(MockitoJUnitRunner.class)
69 public class ClEventManagerWithOutcomeTest {
70 private static final UUID REQ_ID = UUID.randomUUID();
71 private static final String CL_NAME = "my-closed-loop-name";
72 private static final String POLICY_NAME = "my-policy-name";
73 private static final String POLICY_SCOPE = "my-scope";
74 private static final String POLICY_VERSION = "1.2.3";
75 private static final String SIMPLE_ACTOR = "First";
76 private static final String SIMPLE_OPERATION = "OperationA";
77 private static final String MY_TARGET = "my-target";
78 private static final String EVENT_MGR_MULTI_YAML =
79 "../eventmanager/src/test/resources/eventManager/event-mgr-multi.yaml";
80 private static final String EVENT_MGR_SIMPLE_YAML =
81 "../eventmanager/src/test/resources/eventManager/event-mgr-simple.yaml";
82 private static final Coder yamlCoder = new StandardYamlCoder();
83 private static final String OUTCOME_MSG = "my outcome message";
86 private PolicyEngine engineMgr;
88 private WorkingMemory workMem;
90 private InternalFactHandle factHandle;
92 private Operator policyOperator;
94 private Operation policyOperation;
96 private Actor policyActor;
98 private EventManagerServices services;
100 private ExecutorService executor;
102 private MyStep stepa;
104 private MyStep stepb;
106 private List<LockImpl> locks;
107 private ToscaPolicy tosca;
108 private ControlLoopParams params;
109 private ClEventManagerWithOutcome<MyStep> mgr;
115 public void setUp() throws ControlLoopException, CoderException {
116 when(workMem.getFactHandle(any())).thenReturn(factHandle);
118 params = new ControlLoopParams();
119 params.setClosedLoopControlName(CL_NAME);
120 params.setPolicyName(POLICY_NAME);
121 params.setPolicyScope(POLICY_SCOPE);
122 params.setPolicyVersion(POLICY_VERSION);
124 loadPolicy(EVENT_MGR_SIMPLE_YAML);
126 locks = new ArrayList<>();
128 mgr = new MyManager(services, params, REQ_ID, workMem);
132 public void testConstructor() {
133 assertEquals(POLICY_NAME, mgr.getPolicyName());
136 assertThatThrownBy(() -> new MyManager(services, params, null, workMem))
137 .isInstanceOf(ControlLoopException.class);
141 public void testLoadNextPolicy_testGetFullHistory_testGetPartialHistory() throws Exception {
142 loadPolicy(EVENT_MGR_MULTI_YAML);
143 mgr = new MyManager(services, params, REQ_ID, workMem);
145 // start and load step for first policy
147 assertEquals("OperationA", mgr.getSteps().poll().getOperationName());
148 assertNull(mgr.getFinalResult());
151 OperationOutcome outcome = makeOutcome();
152 mgr.addToHistory(outcome);
154 // indicate success and load next policy
155 mgr.loadNextPolicy(OperationResult.SUCCESS);
156 assertEquals("OperationB", mgr.getSteps().poll().getOperationName());
157 assertNull(mgr.getFinalResult());
159 // loadPolicy() should clear the partial history, but not the full history
160 assertThat(mgr.getPartialHistory()).isEmpty();
161 assertThat(mgr.getFullHistory()).hasSize(1);
165 public void testExecuteStep() {
168 // no steps to execute
169 assertFalse(mgr.executeStep());
170 assertEquals(0, mgr.getAttempts());
174 public void testBumpAttempts() {
175 assertEquals(0, mgr.getAttempts());
179 assertEquals(2, mgr.getAttempts());
183 public void testIsAbort() {
184 OperationOutcome outcome = makeCompletedOutcome();
186 outcome.setResult(OperationResult.FAILURE);
187 assertTrue(mgr.isAbort(outcome));
189 // no effect for success
190 outcome.setResult(OperationResult.SUCCESS);
191 assertFalse(mgr.isAbort(outcome));
195 public void testAddToHistory() throws ControlLoopException {
198 // add a "start" outcome
199 OperationOutcome outcome = makeOutcome();
200 mgr.addToHistory(outcome);
202 assertThat(mgr.getPartialHistory()).hasSize(1);
203 assertThat(mgr.getFullHistory()).hasSize(1);
205 // add a "completion" outcome - should replace the start
206 outcome = makeCompletedOutcome();
207 mgr.addToHistory(outcome);
209 assertThat(mgr.getPartialHistory()).hasSize(1);
210 assertThat(mgr.getFullHistory()).hasSize(1);
211 assertSame(outcome, mgr.getPartialHistory().peek().getOutcome());
212 assertSame(outcome, mgr.getFullHistory().peek().getOutcome());
215 outcome = makeOutcome();
216 mgr.addToHistory(outcome);
218 assertThat(mgr.getPartialHistory()).hasSize(2);
219 assertThat(mgr.getFullHistory()).hasSize(2);
220 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
221 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
223 // remove the last item from the full history and then add a "completion"
224 mgr.getFullHistory().removeLast();
225 outcome = makeCompletedOutcome();
226 mgr.addToHistory(outcome);
227 assertThat(mgr.getPartialHistory()).hasSize(2);
228 assertThat(mgr.getFullHistory()).hasSize(2);
230 // add another "start"
231 outcome = makeOutcome();
232 mgr.addToHistory(outcome);
233 assertThat(mgr.getPartialHistory()).hasSize(3);
234 assertThat(mgr.getFullHistory()).hasSize(3);
236 // add a "completion" for a different actor - should NOT replace the start
237 outcome = makeCompletedOutcome();
238 outcome.setActor("different-actor");
239 mgr.addToHistory(outcome);
240 assertThat(mgr.getPartialHistory()).hasSize(4);
241 assertThat(mgr.getFullHistory()).hasSize(4);
242 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
243 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
247 public void testMakeNotification() throws Exception {
248 loadPolicy(EVENT_MGR_MULTI_YAML);
249 mgr = new MyManager(services, params, REQ_ID, workMem);
252 assertNotNull(mgr.makeNotification());
256 mgr.addToHistory(makeCompletedOutcome());
257 mgr.addToHistory(makeCompletedOutcome());
258 mgr.addToHistory(makeCompletedOutcome());
260 // check notification while running
261 VirtualControlLoopNotification notif = mgr.makeNotification();
262 assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
263 assertThat(notif.getHistory()).hasSize(3);
265 // indicate success and load the next policy - should clear the partial history
266 mgr.loadNextPolicy(OperationResult.SUCCESS);
268 // check notification
269 notif = mgr.makeNotification();
270 assertNull(notif.getMessage());
271 assertThat(notif.getHistory()).isEmpty();
273 // add outcomes and check again
274 mgr.addToHistory(makeCompletedOutcome());
275 mgr.addToHistory(makeCompletedOutcome());
277 notif = mgr.makeNotification();
278 assertNotNull(notif.getMessage());
280 // should only have history for last two outcomes
281 assertThat(notif.getHistory()).hasSize(2);
283 // indicate failure - should go to final state
284 mgr.loadNextPolicy(OperationResult.FAILURE);
286 // check notification
287 notif = mgr.makeNotification();
288 assertNull(notif.getMessage());
290 // should be no history
291 assertThat(notif.getHistory()).isEmpty();
294 assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
295 .hasMessageContaining("lastResult");
299 public void testGetOperationMessage() throws ControlLoopException {
301 assertNull(mgr.getOperationMessage());
305 OperationOutcome outcome = makeOutcome();
306 mgr.addToHistory(outcome);
308 assertThat(mgr.getOperationMessage()).contains("actor=" + SIMPLE_ACTOR)
309 .contains("operation=" + SIMPLE_OPERATION);
313 public void testMakeControlLoopResponse() {
314 final OperationOutcome outcome = new OperationOutcome();
315 outcome.setActor(SIMPLE_ACTOR);
317 ControlLoopResponse resp = mgr.makeControlLoopResponse(outcome);
319 assertEquals(SIMPLE_ACTOR, resp.getFrom());
322 private void loadPolicy(String fileName) throws CoderException {
323 ToscaServiceTemplate template =
324 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
325 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
327 params.setToscaPolicy(tosca);
330 private OperationOutcome makeCompletedOutcome() {
331 OperationOutcome outcome = makeOutcome();
332 outcome.setEnd(outcome.getStart());
337 private OperationOutcome makeOutcome() {
338 OperationOutcome outcome = new OperationOutcome();
339 outcome.setActor(SIMPLE_ACTOR);
340 outcome.setOperation(SIMPLE_OPERATION);
341 outcome.setMessage(OUTCOME_MSG);
342 outcome.setResult(OperationResult.SUCCESS);
343 outcome.setStart(Instant.now());
344 outcome.setTarget(MY_TARGET);
350 private class MyManager extends ClEventManagerWithOutcome<MyStep> {
351 private static final long serialVersionUID = 1L;
353 public MyManager(EventManagerServices services, ControlLoopParams params, UUID requestId, WorkingMemory workMem)
354 throws ControlLoopException {
356 super(services, params, requestId, workMem);
360 protected ExecutorService getBlockingExecutor() {
365 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
366 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
368 callback.lockAvailable(lock);
372 protected PolicyEngine getPolicyEngineManager() {
377 protected void loadPolicyStep(ControlLoopOperationParams params) {
378 getSteps().add(new MyStep(this, params));
383 private static class MyStep extends Step {
384 public MyStep(StepContext stepContext, ControlLoopOperationParams params) {
385 super(params, new AtomicReference<>());