2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2021, 2023 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2023 Nordix Foundation.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.controlloop.eventmanager;
24 import static org.assertj.core.api.Assertions.assertThat;
25 import static org.assertj.core.api.Assertions.assertThatThrownBy;
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertFalse;
28 import static org.junit.jupiter.api.Assertions.assertNotNull;
29 import static org.junit.jupiter.api.Assertions.assertNull;
30 import static org.junit.jupiter.api.Assertions.assertSame;
31 import static org.junit.jupiter.api.Assertions.assertTrue;
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.Mockito.mock;
34 import static org.mockito.Mockito.when;
36 import java.time.Instant;
37 import java.util.ArrayList;
38 import java.util.List;
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.jupiter.api.BeforeEach;
45 import org.junit.jupiter.api.Test;
46 import org.onap.policy.common.utils.coder.Coder;
47 import org.onap.policy.common.utils.coder.CoderException;
48 import org.onap.policy.common.utils.coder.StandardYamlCoder;
49 import org.onap.policy.common.utils.resources.ResourceUtils;
50 import org.onap.policy.controlloop.ControlLoopException;
51 import org.onap.policy.controlloop.actorserviceprovider.Operation;
52 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
53 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
54 import org.onap.policy.controlloop.actorserviceprovider.Operator;
55 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
56 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
57 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
58 import org.onap.policy.drools.core.lock.LockCallback;
59 import org.onap.policy.drools.core.lock.LockImpl;
60 import org.onap.policy.drools.core.lock.LockState;
61 import org.onap.policy.drools.system.PolicyEngine;
62 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
63 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
65 class ClEventManagerWithOutcomeTest {
66 private static final UUID REQ_ID = UUID.randomUUID();
67 private static final String CL_NAME = "my-closed-loop-name";
68 private static final String POLICY_NAME = "my-policy-name";
69 private static final String POLICY_SCOPE = "my-scope";
70 private static final String POLICY_VERSION = "1.2.3";
71 private static final String SIMPLE_ACTOR = "First";
72 private static final String SIMPLE_OPERATION = "OperationA";
73 private static final String MY_TARGET = "my-target";
74 private static final String EVENT_MGR_MULTI_YAML =
75 "../eventmanager/src/test/resources/eventManager/event-mgr-multi.yaml";
76 private static final String EVENT_MGR_SIMPLE_YAML =
77 "../eventmanager/src/test/resources/eventManager/event-mgr-simple.yaml";
78 private static final Coder yamlCoder = new StandardYamlCoder();
79 private static final String OUTCOME_MSG = "my outcome message";
81 private final PolicyEngine engineMgr = mock(PolicyEngine.class);
82 private final WorkingMemory workMem = mock(WorkingMemory.class);
83 private final InternalFactHandle factHandle = mock(InternalFactHandle.class);
84 private final Operator policyOperator = mock(Operator.class);
85 private final Operation policyOperation = mock(Operation.class);
86 private final Actor policyActor = mock(Actor.class);
87 private final EventManagerServices services = mock(EventManagerServices.class);
88 private final ExecutorService executor = mock(ExecutorService.class);
89 private final MyStep stepa = mock(MyStep.class);
90 private final MyStep stepb = mock(MyStep.class);
92 private List<LockImpl> locks;
93 private ToscaPolicy tosca;
94 private ControlLoopParams params;
95 private ClEventManagerWithOutcome<MyStep> mgr;
101 public void setUp() throws ControlLoopException, CoderException {
102 when(workMem.getFactHandle(any())).thenReturn(factHandle);
104 params = new ControlLoopParams();
105 params.setClosedLoopControlName(CL_NAME);
106 params.setPolicyName(POLICY_NAME);
107 params.setPolicyScope(POLICY_SCOPE);
108 params.setPolicyVersion(POLICY_VERSION);
110 loadPolicy(EVENT_MGR_SIMPLE_YAML);
112 locks = new ArrayList<>();
114 mgr = new MyManager(services, params, REQ_ID, workMem);
118 void testConstructor() {
119 assertEquals(POLICY_NAME, mgr.getPolicyName());
122 assertThatThrownBy(() -> new MyManager(services, params, null, workMem))
123 .isInstanceOf(ControlLoopException.class);
127 void testLoadNextPolicy_testGetFullHistory_testGetPartialHistory() throws Exception {
128 loadPolicy(EVENT_MGR_MULTI_YAML);
129 mgr = new MyManager(services, params, REQ_ID, workMem);
131 // start and load step for first policy
133 assertEquals("OperationA", mgr.getSteps().poll().getOperationName());
134 assertNull(mgr.getFinalResult());
137 var outcome = makeOutcome();
138 mgr.addToHistory(outcome);
140 // indicate success and load next policy
141 mgr.loadNextPolicy(OperationResult.SUCCESS);
142 assertEquals("OperationB", mgr.getSteps().poll().getOperationName());
143 assertNull(mgr.getFinalResult());
145 // loadPolicy() should clear the partial history, but not the full history
146 assertThat(mgr.getPartialHistory()).isEmpty();
147 assertThat(mgr.getFullHistory()).hasSize(1);
151 void testExecuteStep() {
154 // no steps to execute
155 assertFalse(mgr.executeStep());
156 assertEquals(0, mgr.getAttempts());
160 void testBumpAttempts() {
161 assertEquals(0, mgr.getAttempts());
165 assertEquals(2, mgr.getAttempts());
170 var outcome = makeCompletedOutcome();
172 outcome.setResult(OperationResult.FAILURE);
173 assertTrue(mgr.isAbort(outcome));
175 // no effect for success
176 outcome.setResult(OperationResult.SUCCESS);
177 assertFalse(mgr.isAbort(outcome));
181 void testAddToHistory() throws ControlLoopException {
184 // add a "start" outcome
185 var outcome = makeOutcome();
186 mgr.addToHistory(outcome);
188 assertThat(mgr.getPartialHistory()).hasSize(1);
189 assertThat(mgr.getFullHistory()).hasSize(1);
191 // add a "completion" outcome - should replace the start
192 outcome = makeCompletedOutcome();
193 mgr.addToHistory(outcome);
195 assertThat(mgr.getPartialHistory()).hasSize(1);
196 assertThat(mgr.getFullHistory()).hasSize(1);
197 assertSame(outcome, mgr.getPartialHistory().peek().getOutcome());
198 assertSame(outcome, mgr.getFullHistory().peek().getOutcome());
201 outcome = makeOutcome();
202 mgr.addToHistory(outcome);
204 assertThat(mgr.getPartialHistory()).hasSize(2);
205 assertThat(mgr.getFullHistory()).hasSize(2);
206 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
207 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
209 // remove the last item from the full history and then add a "completion"
210 mgr.getFullHistory().removeLast();
211 outcome = makeCompletedOutcome();
212 mgr.addToHistory(outcome);
213 assertThat(mgr.getPartialHistory()).hasSize(2);
214 assertThat(mgr.getFullHistory()).hasSize(2);
216 // add another "start"
217 outcome = makeOutcome();
218 mgr.addToHistory(outcome);
219 assertThat(mgr.getPartialHistory()).hasSize(3);
220 assertThat(mgr.getFullHistory()).hasSize(3);
222 // add a "completion" for a different actor - should NOT replace the start
223 outcome = makeCompletedOutcome();
224 outcome.setActor("different-actor");
225 mgr.addToHistory(outcome);
226 assertThat(mgr.getPartialHistory()).hasSize(4);
227 assertThat(mgr.getFullHistory()).hasSize(4);
228 assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
229 assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
233 void testMakeNotification() throws Exception {
234 loadPolicy(EVENT_MGR_MULTI_YAML);
235 mgr = new MyManager(services, params, REQ_ID, workMem);
238 assertNotNull(mgr.makeNotification());
242 mgr.addToHistory(makeCompletedOutcome());
243 mgr.addToHistory(makeCompletedOutcome());
244 mgr.addToHistory(makeCompletedOutcome());
246 // check notification while running
247 var notif = mgr.makeNotification();
248 assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
249 assertThat(notif.getHistory()).hasSize(3);
251 // indicate success and load the next policy - should clear the partial history
252 mgr.loadNextPolicy(OperationResult.SUCCESS);
254 // check notification
255 notif = mgr.makeNotification();
256 assertNull(notif.getMessage());
257 assertThat(notif.getHistory()).isEmpty();
259 // add outcomes and check again
260 mgr.addToHistory(makeCompletedOutcome());
261 mgr.addToHistory(makeCompletedOutcome());
263 notif = mgr.makeNotification();
264 assertNotNull(notif.getMessage());
266 // should only have history for last two outcomes
267 assertThat(notif.getHistory()).hasSize(2);
269 // indicate failure - should go to final state
270 mgr.loadNextPolicy(OperationResult.FAILURE);
272 // check notification
273 notif = mgr.makeNotification();
274 assertNull(notif.getMessage());
276 // should be no history
277 assertThat(notif.getHistory()).isEmpty();
280 assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
281 .hasMessageContaining("lastResult");
285 void testGetOperationMessage() throws ControlLoopException {
287 assertNull(mgr.getOperationMessage());
291 var outcome = makeOutcome();
292 mgr.addToHistory(outcome);
294 assertThat(mgr.getOperationMessage()).contains("actor=" + SIMPLE_ACTOR)
295 .contains("operation=" + SIMPLE_OPERATION);
299 void testMakeControlLoopResponse() {
300 final var outcome = new OperationOutcome();
301 outcome.setActor(SIMPLE_ACTOR);
303 var resp = mgr.makeControlLoopResponse(outcome);
305 assertEquals(SIMPLE_ACTOR, resp.getFrom());
308 private void loadPolicy(String fileName) throws CoderException {
309 var template = yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
310 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
312 params.setToscaPolicy(tosca);
315 private OperationOutcome makeCompletedOutcome() {
316 var outcome = makeOutcome();
317 outcome.setEnd(outcome.getStart());
322 private OperationOutcome makeOutcome() {
323 var outcome = new OperationOutcome();
324 outcome.setActor(SIMPLE_ACTOR);
325 outcome.setOperation(SIMPLE_OPERATION);
326 outcome.setMessage(OUTCOME_MSG);
327 outcome.setResult(OperationResult.SUCCESS);
328 outcome.setStart(Instant.now());
329 outcome.setTarget(MY_TARGET);
335 private class MyManager extends ClEventManagerWithOutcome<MyStep> {
336 private static final long serialVersionUID = 1L;
338 public MyManager(EventManagerServices services, ControlLoopParams params, UUID requestId, WorkingMemory workMem)
339 throws ControlLoopException {
341 super(services, params, requestId, workMem);
345 protected ExecutorService getBlockingExecutor() {
350 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
351 var lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
353 callback.lockAvailable(lock);
357 protected PolicyEngine getPolicyEngineManager() {
362 protected void loadPolicyStep(ControlLoopOperationParams params) {
363 getSteps().add(new MyStep(this, params));
368 private static class MyStep extends Step {
369 public MyStep(StepContext stepContext, ControlLoopOperationParams params) {
370 super(params, new AtomicReference<>());