d64d2bbc5126f344870ee36cebad618abc29031d
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.policy.controlloop.eventmanager;
22
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;
33
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.junit.Before;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 import org.kie.api.runtime.rule.FactHandle;
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.ActorService;
55 import org.onap.policy.controlloop.actorserviceprovider.Operation;
56 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
57 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
58 import org.onap.policy.controlloop.actorserviceprovider.Operator;
59 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
60 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
61 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
62 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
63 import org.onap.policy.drools.core.lock.LockCallback;
64 import org.onap.policy.drools.core.lock.LockImpl;
65 import org.onap.policy.drools.core.lock.LockState;
66 import org.onap.policy.drools.system.PolicyEngine;
67 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
68 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
69
70 @RunWith(MockitoJUnitRunner.class)
71 public class ClEventManagerWithOutcomeTest {
72     private static final UUID REQ_ID = UUID.randomUUID();
73     private static final String CL_NAME = "my-closed-loop-name";
74     private static final String POLICY_NAME = "my-policy-name";
75     private static final String POLICY_SCOPE = "my-scope";
76     private static final String POLICY_VERSION = "1.2.3";
77     private static final String SIMPLE_ACTOR = "First";
78     private static final String SIMPLE_OPERATION = "OperationA";
79     private static final String MY_TARGET = "my-target";
80     private static final String EVENT_MGR_MULTI_YAML =
81                     "../eventmanager/src/test/resources/eventManager/event-mgr-multi.yaml";
82     private static final String EVENT_MGR_SIMPLE_YAML =
83                     "../eventmanager/src/test/resources/eventManager/event-mgr-simple.yaml";
84     private static final Coder yamlCoder = new StandardYamlCoder();
85     private static final String OUTCOME_MSG = "my outcome message";
86
87     @Mock
88     private PolicyEngine engineMgr;
89     @Mock
90     private WorkingMemory workMem;
91     @Mock
92     private FactHandle factHandle;
93     @Mock
94     private Operator policyOperator;
95     @Mock
96     private Operation policyOperation;
97     @Mock
98     private Actor policyActor;
99     @Mock
100     private ActorService actors;
101     @Mock
102     private OperationHistoryDataManager dataMgr;
103     @Mock
104     private ExecutorService executor;
105     @Mock
106     private MyStep stepa;
107     @Mock
108     private MyStep stepb;
109
110     private List<LockImpl> locks;
111     private ToscaPolicy tosca;
112     private ControlLoopParams params;
113     private ClEventManagerWithOutcome<MyStep> mgr;
114
115     /**
116      * Sets up.
117      */
118     @Before
119     public void setUp() throws ControlLoopException, CoderException {
120         when(workMem.getFactHandle(any())).thenReturn(factHandle);
121
122         params = new ControlLoopParams();
123         params.setClosedLoopControlName(CL_NAME);
124         params.setPolicyName(POLICY_NAME);
125         params.setPolicyScope(POLICY_SCOPE);
126         params.setPolicyVersion(POLICY_VERSION);
127
128         loadPolicy(EVENT_MGR_SIMPLE_YAML);
129
130         locks = new ArrayList<>();
131
132         mgr = new MyManager(params, REQ_ID, workMem);
133     }
134
135     @Test
136     public void testConstructor() {
137         assertEquals(POLICY_NAME, mgr.getPolicyName());
138
139         // invalid
140         assertThatThrownBy(() -> new MyManager(params, null, workMem)).isInstanceOf(ControlLoopException.class);
141     }
142
143     @Test
144     public void testLoadNextPolicy_testGetFullHistory_testGetPartialHistory() throws Exception {
145         loadPolicy(EVENT_MGR_MULTI_YAML);
146         mgr = new MyManager(params, REQ_ID, workMem);
147
148         // start and load step for first policy
149         mgr.start();
150         assertEquals("OperationA", mgr.getSteps().poll().getOperationName());
151         assertNull(mgr.getFinalResult());
152
153         // add an outcome
154         OperationOutcome outcome = makeOutcome();
155         mgr.addToHistory(outcome);
156
157         // indicate success and load next policy
158         mgr.loadNextPolicy(OperationResult.SUCCESS);
159         assertEquals("OperationB", mgr.getSteps().poll().getOperationName());
160         assertNull(mgr.getFinalResult());
161
162         // loadPolicy() should clear the partial history, but not the full history
163         assertThat(mgr.getPartialHistory()).isEmpty();
164         assertThat(mgr.getFullHistory()).hasSize(1);
165     }
166
167     @Test
168     public void testExecuteStep() {
169         mgr.bumpAttempts();
170
171         // no steps to execute
172         assertFalse(mgr.executeStep());
173         assertEquals(0, mgr.getAttempts());
174     }
175
176     @Test
177     public void testBumpAttempts() {
178         assertEquals(0, mgr.getAttempts());
179
180         mgr.bumpAttempts();
181         mgr.bumpAttempts();
182         assertEquals(2, mgr.getAttempts());
183     }
184
185     @Test
186     public void testIsAbort() {
187         OperationOutcome outcome = makeCompletedOutcome();
188
189         outcome.setResult(OperationResult.FAILURE);
190         assertTrue(mgr.isAbort(outcome));
191
192         // no effect for success
193         outcome.setResult(OperationResult.SUCCESS);
194         assertFalse(mgr.isAbort(outcome));
195     }
196
197     @Test
198     public void testAddToHistory() throws ControlLoopException {
199         mgr.start();
200
201         // add a "start" outcome
202         OperationOutcome outcome = makeOutcome();
203         mgr.addToHistory(outcome);
204
205         assertThat(mgr.getPartialHistory()).hasSize(1);
206         assertThat(mgr.getFullHistory()).hasSize(1);
207
208         // add a "completion" outcome - should replace the start
209         outcome = makeCompletedOutcome();
210         mgr.addToHistory(outcome);
211
212         assertThat(mgr.getPartialHistory()).hasSize(1);
213         assertThat(mgr.getFullHistory()).hasSize(1);
214         assertSame(outcome, mgr.getPartialHistory().peek().getOutcome());
215         assertSame(outcome, mgr.getFullHistory().peek().getOutcome());
216
217         // add another start
218         outcome = makeOutcome();
219         mgr.addToHistory(outcome);
220
221         assertThat(mgr.getPartialHistory()).hasSize(2);
222         assertThat(mgr.getFullHistory()).hasSize(2);
223         assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
224         assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
225
226         // remove the last item from the full history and then add a "completion"
227         mgr.getFullHistory().removeLast();
228         outcome = makeCompletedOutcome();
229         mgr.addToHistory(outcome);
230         assertThat(mgr.getPartialHistory()).hasSize(2);
231         assertThat(mgr.getFullHistory()).hasSize(2);
232
233         // add another "start"
234         outcome = makeOutcome();
235         mgr.addToHistory(outcome);
236         assertThat(mgr.getPartialHistory()).hasSize(3);
237         assertThat(mgr.getFullHistory()).hasSize(3);
238
239         // add a "completion" for a different actor - should NOT replace the start
240         outcome = makeCompletedOutcome();
241         outcome.setActor("different-actor");
242         mgr.addToHistory(outcome);
243         assertThat(mgr.getPartialHistory()).hasSize(4);
244         assertThat(mgr.getFullHistory()).hasSize(4);
245         assertSame(outcome, mgr.getPartialHistory().peekLast().getOutcome());
246         assertSame(outcome, mgr.getFullHistory().peekLast().getOutcome());
247     }
248
249     @Test
250     public void testMakeNotification() throws Exception {
251         loadPolicy(EVENT_MGR_MULTI_YAML);
252         mgr = new MyManager(params, REQ_ID, workMem);
253
254         // before started
255         assertNotNull(mgr.makeNotification());
256
257         mgr.start();
258
259         mgr.addToHistory(makeCompletedOutcome());
260         mgr.addToHistory(makeCompletedOutcome());
261         mgr.addToHistory(makeCompletedOutcome());
262
263         // check notification while running
264         VirtualControlLoopNotification notif = mgr.makeNotification();
265         assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
266         assertThat(notif.getHistory()).hasSize(3);
267
268         // indicate success and load the next policy - should clear the partial history
269         mgr.loadNextPolicy(OperationResult.SUCCESS);
270
271         // check notification
272         notif = mgr.makeNotification();
273         assertNull(notif.getMessage());
274         assertThat(notif.getHistory()).isEmpty();
275
276         // add outcomes and check again
277         mgr.addToHistory(makeCompletedOutcome());
278         mgr.addToHistory(makeCompletedOutcome());
279
280         notif = mgr.makeNotification();
281         assertNotNull(notif.getMessage());
282
283         // should only have history for last two outcomes
284         assertThat(notif.getHistory()).hasSize(2);
285
286         // indicate failure - should go to final state
287         mgr.loadNextPolicy(OperationResult.FAILURE);
288
289         // check notification
290         notif = mgr.makeNotification();
291         assertNull(notif.getMessage());
292
293         // should be no history
294         assertThat(notif.getHistory()).isEmpty();
295
296         // null case
297         assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
298                         .hasMessageContaining("lastResult");
299     }
300
301     @Test
302     public void testGetOperationMessage() throws ControlLoopException {
303         // no history yet
304         assertNull(mgr.getOperationMessage());
305
306         // add an outcome
307         mgr.start();
308         OperationOutcome outcome = makeOutcome();
309         mgr.addToHistory(outcome);
310
311         assertThat(mgr.getOperationMessage()).contains("actor=" + SIMPLE_ACTOR)
312                         .contains("operation=" + SIMPLE_OPERATION);
313     }
314
315     @Test
316     public void testMakeControlLoopResponse() {
317         final OperationOutcome outcome = new OperationOutcome();
318         outcome.setActor(SIMPLE_ACTOR);
319
320         ControlLoopResponse resp = mgr.makeControlLoopResponse(outcome);
321         assertNotNull(resp);
322         assertEquals(SIMPLE_ACTOR, resp.getFrom());
323     }
324
325     private void loadPolicy(String fileName) throws CoderException {
326         ToscaServiceTemplate template =
327                         yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
328         tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
329
330         params.setToscaPolicy(tosca);
331     }
332
333     private OperationOutcome makeCompletedOutcome() {
334         OperationOutcome outcome = makeOutcome();
335         outcome.setEnd(outcome.getStart());
336
337         return outcome;
338     }
339
340     private OperationOutcome makeOutcome() {
341         OperationOutcome outcome = new OperationOutcome();
342         outcome.setActor(SIMPLE_ACTOR);
343         outcome.setOperation(SIMPLE_OPERATION);
344         outcome.setMessage(OUTCOME_MSG);
345         outcome.setResult(OperationResult.SUCCESS);
346         outcome.setStart(Instant.now());
347         outcome.setTarget(MY_TARGET);
348
349         return outcome;
350     }
351
352
353     private class MyManager extends ClEventManagerWithOutcome<MyStep> {
354         private static final long serialVersionUID = 1L;
355
356         public MyManager(ControlLoopParams params, UUID requestId, WorkingMemory workMem) throws ControlLoopException {
357
358             super(params, requestId, workMem);
359         }
360
361         @Override
362         protected ExecutorService getBlockingExecutor() {
363             return executor;
364         }
365
366         @Override
367         protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
368             LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
369             locks.add(lock);
370             callback.lockAvailable(lock);
371         }
372
373         @Override
374         public ActorService getActorService() {
375             return actors;
376         }
377
378         @Override
379         public OperationHistoryDataManager getDataManager() {
380             return dataMgr;
381         }
382
383         @Override
384         protected PolicyEngine getPolicyEngineManager() {
385             return engineMgr;
386         }
387
388         @Override
389         protected void loadPolicyStep(ControlLoopOperationParams params) {
390             getSteps().add(new MyStep(this, params));
391         }
392     }
393
394
395     private static class MyStep extends Step {
396         public MyStep(StepContext stepContext, ControlLoopOperationParams params) {
397             super(params, new AtomicReference<>());
398         }
399     }
400 }