Make drools-pdp work with drools and java versions compatible
[policy/drools-applications.git] / controlloop / common / eventmanager / src / test / java / org / onap / policy / controlloop / eventmanager / ClEventManagerWithStepsTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2021, 2023 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2023-2024 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
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
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=========================================================
20  */
21
22 package org.onap.policy.controlloop.eventmanager;
23
24 import static org.assertj.core.api.Assertions.assertThat;
25 import static org.assertj.core.api.Assertions.assertThatCode;
26 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
27 import static org.assertj.core.api.Assertions.assertThatThrownBy;
28 import static org.junit.jupiter.api.Assertions.assertEquals;
29 import static org.junit.jupiter.api.Assertions.assertFalse;
30 import static org.junit.jupiter.api.Assertions.assertNotNull;
31 import static org.junit.jupiter.api.Assertions.assertNull;
32 import static org.junit.jupiter.api.Assertions.assertSame;
33 import static org.junit.jupiter.api.Assertions.assertTrue;
34 import static org.mockito.ArgumentMatchers.any;
35 import static org.mockito.ArgumentMatchers.anyLong;
36 import static org.mockito.Mockito.mock;
37 import static org.mockito.Mockito.never;
38 import static org.mockito.Mockito.verify;
39 import static org.mockito.Mockito.when;
40
41 import java.time.Instant;
42 import java.util.ArrayList;
43 import java.util.List;
44 import java.util.Objects;
45 import java.util.UUID;
46 import java.util.concurrent.ExecutorService;
47 import java.util.concurrent.ForkJoinPool;
48 import java.util.concurrent.atomic.AtomicReference;
49 import org.drools.core.WorkingMemory;
50 import org.drools.core.common.InternalFactHandle;
51 import org.junit.jupiter.api.BeforeEach;
52 import org.junit.jupiter.api.Test;
53 import org.onap.policy.common.utils.coder.Coder;
54 import org.onap.policy.common.utils.coder.CoderException;
55 import org.onap.policy.common.utils.coder.StandardYamlCoder;
56 import org.onap.policy.common.utils.io.Serializer;
57 import org.onap.policy.common.utils.resources.ResourceUtils;
58 import org.onap.policy.controlloop.ControlLoopException;
59 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
60 import org.onap.policy.controlloop.actorserviceprovider.Operation;
61 import org.onap.policy.controlloop.actorserviceprovider.OperationFinalResult;
62 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
63 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
64 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
65 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
66 import org.onap.policy.drools.core.lock.LockCallback;
67 import org.onap.policy.drools.core.lock.LockImpl;
68 import org.onap.policy.drools.core.lock.LockState;
69 import org.onap.policy.drools.system.PolicyEngine;
70 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
71 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
72
73 class ClEventManagerWithStepsTest {
74     private static final UUID REQ_ID = UUID.randomUUID();
75     private static final String CL_NAME = "my-closed-loop-name";
76     private static final String POLICY_NAME = "my-policy-name";
77     private static final String POLICY_SCOPE = "my-scope";
78     private static final String POLICY_VERSION = "1.2.3";
79     private static final String SIMPLE_ACTOR = "First";
80     private static final String SIMPLE_OPERATION = "OperationA";
81     private static final String MY_TARGET = "my-target";
82     private static final String EVENT_MGR_MULTI_YAML =
83                     "../eventmanager/src/test/resources/eventManager/event-mgr-multi.yaml";
84     private static final String EVENT_MGR_SIMPLE_YAML =
85                     "../eventmanager/src/test/resources/eventManager/event-mgr-simple.yaml";
86     private static final Coder yamlCoder = new StandardYamlCoder();
87     private static final String OUTCOME_MSG = "my outcome message";
88     private static final String MY_SINK = "my-topic-sink";
89
90     private final PolicyEngine engineMgr = mock(PolicyEngine.class);
91     private final WorkingMemory workMem = mock(WorkingMemory.class);
92     private final InternalFactHandle factHandle = mock(InternalFactHandle.class);
93     private final Operation policyOperation = mock(Operation.class);
94     private final ExecutorService executor = mock(ExecutorService.class);
95     private final EventManagerServices services = mock(EventManagerServices.class);
96     private final ActorService actors = mock(ActorService.class);
97     private MyStep stepa = mock(MyStep.class);
98     private final MyStep stepb = mock(MyStep.class);
99
100     private List<LockImpl> locks;
101     private ControlLoopParams params;
102     private ClEventManagerWithSteps<MyStep> mgr;
103
104     /**
105      * Sets up.
106      */
107     @BeforeEach
108     public void setUp() throws ControlLoopException, CoderException {
109         when(services.getActorService()).thenReturn(actors);
110
111         when(workMem.getFactHandle(any())).thenReturn(factHandle);
112
113         params = new ControlLoopParams();
114         params.setClosedLoopControlName(CL_NAME);
115         params.setPolicyName(POLICY_NAME);
116         params.setPolicyScope(POLICY_SCOPE);
117         params.setPolicyVersion(POLICY_VERSION);
118
119         loadPolicy(EVENT_MGR_SIMPLE_YAML);
120
121         locks = new ArrayList<>();
122
123         mgr = new MyManager(services, params, REQ_ID, workMem);
124     }
125
126     @Test
127     void testConstructor() {
128         assertEquals(POLICY_NAME, mgr.getPolicyName());
129
130         // invalid
131         assertThatThrownBy(() -> new MyManager(services, params, null, workMem))
132                         .isInstanceOf(ControlLoopException.class);
133     }
134
135     @Test
136     void testDestroy_testGetSteps() {
137         // add some steps to the queue
138         mgr.getSteps().add(stepa);
139         mgr.getSteps().add(stepb);
140
141         mgr.destroy();
142
143         verify(stepa).cancel();
144         verify(stepb).cancel();
145
146         // if superclass destroy() was invoked, then freeLock() should have been submitted
147         // to the executor
148         verify(executor).execute(any());
149     }
150
151     @Test
152     void testOnStart() throws ControlLoopException {
153         var outcome = makeOutcome();
154
155         mgr.start();
156         mgr.onStart(outcome);
157
158         assertSame(outcome, mgr.getOutcomes().poll());
159         assertThat(mgr.getOutcomes()).isEmpty();
160
161         verify(workMem).update(factHandle, mgr);
162     }
163
164     @Test
165     void testOnComplete() throws ControlLoopException {
166         var outcome = makeCompletedOutcome();
167
168         mgr.start();
169         mgr.onComplete(outcome);
170
171         assertSame(outcome, mgr.getOutcomes().poll());
172         assertThat(mgr.getOutcomes()).isEmpty();
173
174         verify(workMem).update(factHandle, mgr);
175     }
176
177     @Test
178     void testToString() {
179         assertNotNull(mgr.toString());
180     }
181
182     @Test
183     void testStart() throws ControlLoopException {
184         // start it
185         mgr.start();
186
187         // cannot re-start
188         assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
189                         .hasMessage("manager already started");
190     }
191
192     /**
193      * Tests start() when the manager is not in working memory.
194      */
195     @Test
196     void testStartNotInWorkingMemory() throws ControlLoopException {
197         when(workMem.getFactHandle(any())).thenReturn(null);
198
199         assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
200                         .hasMessage("manager is not in working memory");
201     }
202
203     /**
204      * Tests start() when the manager is not active.
205      */
206     @Test
207     void testStartInactive() throws Exception {
208         // make an inactive manager by deserializing it
209         mgr = Serializer.roundTrip(new RealManager(services, params, REQ_ID, workMem));
210
211         // cannot re-start
212         assertThatCode(() -> mgr.start()).isInstanceOf(IllegalStateException.class)
213                         .hasMessage("manager is no longer active");
214     }
215
216     @Test
217     void testAbort() {
218         mgr.abort(ClEventManagerWithSteps.State.DONE, OperationFinalResult.FINAL_FAILURE_GUARD, "some message");
219
220         assertEquals(ClEventManagerWithSteps.State.DONE, mgr.getState());
221         assertEquals(OperationFinalResult.FINAL_FAILURE_GUARD, mgr.getFinalResult());
222         assertEquals("some message", mgr.getFinalMessage());
223
224         // try null state
225         assertThatThrownBy(() -> mgr.abort(null, OperationFinalResult.FINAL_FAILURE_GUARD, ""))
226                         .isInstanceOf(NullPointerException.class).hasMessageContaining("finalState");
227     }
228
229     @Test
230     void testLoadNextPolicy() throws Exception {
231         loadPolicy(EVENT_MGR_MULTI_YAML);
232         mgr = new MyManager(services, params, REQ_ID, workMem);
233
234         // start and load step for first policy
235         mgr.start();
236         assertEquals("OperationA", Objects.requireNonNull(mgr.getSteps().poll()).getOperationName());
237         assertNull(mgr.getFinalResult());
238
239         // indicate success and load next policy
240         mgr.loadNextPolicy(OperationResult.SUCCESS);
241         assertEquals("OperationB", Objects.requireNonNull(mgr.getSteps().poll()).getOperationName());
242         assertNull(mgr.getFinalResult());
243
244         // indicate failure - should go to final failure
245         mgr.loadNextPolicy(OperationResult.FAILURE);
246         assertEquals(OperationFinalResult.FINAL_FAILURE, mgr.getFinalResult());
247     }
248
249     @Test
250     void testLoadPolicy() throws ControlLoopException {
251         // start() will invoke loadPolicy()
252         mgr.start();
253
254         assertNull(mgr.getFinalResult());
255
256         var step = mgr.getSteps().peek();
257         assertNotNull(step);
258         assertEquals("First", step.getActorName());
259         assertEquals("OperationA", step.getOperationName());
260
261         var params2 = step.getParams();
262         assertSame(actors, params2.getActorService());
263         assertSame(REQ_ID, params2.getRequestId());
264         assertSame(ForkJoinPool.commonPool(), params2.getExecutor());
265         assertNotNull(params2.getTargetType());
266         assertNotNull(params2.getTargetEntityIds());
267         assertEquals(Integer.valueOf(300), params2.getTimeoutSec());
268         assertEquals(Integer.valueOf(0), params2.getRetry());
269         assertThat(params2.getPayload()).isEmpty();
270         assertNotNull(params2.getStartCallback());
271         assertNotNull(params2.getCompleteCallback());
272     }
273
274     @Test
275     void testLoadPreprocessorSteps() {
276         stepa = new MyStep(mgr, ControlLoopOperationParams.builder().build()) {
277             @Override
278             protected Operation buildOperation() {
279                 return policyOperation;
280             }
281         };
282
283         var steps = mgr.getSteps();
284         steps.add(stepa);
285         steps.add(stepb);
286
287         mgr.loadPreprocessorSteps();
288
289         // no additional steps should have been loaded
290         assertThat(steps).hasSize(2);
291
292         assertSame(stepa, steps.poll());
293         assertSame(stepb, steps.poll());
294         assertThat(steps).isEmpty();
295
296         assertNotNull(stepa.getOperation());
297         assertNull(stepb.getOperation());
298     }
299
300     /**
301      * Tests loadPreprocessorSteps() when there are too many steps in the queue.
302      */
303     @Test
304     void testLoadPreprocessorStepsTooManySteps() {
305         stepa = new MyStep(mgr, ControlLoopOperationParams.builder().build()) {
306             @Override
307             protected Operation buildOperation() {
308                 return policyOperation;
309             }
310         };
311
312         var steps = mgr.getSteps();
313
314         // load up a bunch of steps
315         for (int nsteps = 0; nsteps < ClEventManagerWithSteps.MAX_STEPS; ++nsteps) {
316             steps.add(stepa);
317         }
318
319         // should fail
320         assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
321
322         // add another step, should still fail
323         steps.add(stepa);
324         assertThatIllegalStateException().isThrownBy(() -> mgr.loadPreprocessorSteps()).withMessage("too many steps");
325
326         // remove two steps - should now succeed
327         steps.remove();
328         steps.remove();
329
330         int nsteps = steps.size();
331
332         mgr.loadPreprocessorSteps();
333         assertEquals(nsteps, steps.size());
334     }
335
336     @Test
337     void testExecuteStep() {
338         // no steps to execute
339         assertFalse(mgr.executeStep());
340
341         // add a step to the queue
342         mgr.getSteps().add(stepa);
343
344         // step returns false
345         when(stepa.start(anyLong())).thenReturn(false);
346         assertFalse(mgr.executeStep());
347
348         // step returns true
349         when(stepa.start(anyLong())).thenReturn(true);
350         assertTrue(mgr.executeStep());
351     }
352
353     @Test
354     void testNextStep() {
355         mgr.getSteps().add(stepa);
356
357         mgr.nextStep();
358
359         assertThat(mgr.getSteps()).isEmpty();
360     }
361
362     @Test
363     void testDeliver() {
364         mgr.deliver(MY_SINK, null, "null notification", "null rule");
365         verify(engineMgr, never()).deliver(any(), any());
366
367         mgr.deliver(MY_SINK, "publishA", "A notification", "A rule");
368         verify(engineMgr).deliver(MY_SINK, "publishA");
369
370         // cause deliver() to throw an exception
371         when(engineMgr.deliver(any(), any())).thenThrow(new IllegalStateException("expected exception"));
372         assertThatCode(() -> mgr.deliver(MY_SINK, "publishB", "B notification", "B rule")).doesNotThrowAnyException();
373     }
374
375     private void loadPolicy(String fileName) throws CoderException {
376         var template = yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
377         ToscaPolicy tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
378
379         params.setToscaPolicy(tosca);
380     }
381
382     private OperationOutcome makeCompletedOutcome() {
383         var outcome = makeOutcome();
384         outcome.setEnd(outcome.getStart());
385
386         return outcome;
387     }
388
389     private OperationOutcome makeOutcome() {
390         var outcome = new OperationOutcome();
391         outcome.setActor(SIMPLE_ACTOR);
392         outcome.setOperation(SIMPLE_OPERATION);
393         outcome.setMessage(OUTCOME_MSG);
394         outcome.setResult(OperationResult.SUCCESS);
395         outcome.setStart(Instant.now());
396         outcome.setTarget(MY_TARGET);
397
398         return outcome;
399     }
400
401
402     private class MyManager extends ClEventManagerWithSteps<MyStep> {
403         private static final long serialVersionUID = 1L;
404
405         public MyManager(EventManagerServices services, ControlLoopParams params, UUID requestId, WorkingMemory workMem)
406                         throws ControlLoopException {
407
408             super(services, params, requestId, workMem);
409         }
410
411         @Override
412         protected ExecutorService getBlockingExecutor() {
413             return executor;
414         }
415
416         @Override
417         protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
418             var lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
419             locks.add(lock);
420             callback.lockAvailable(lock);
421         }
422
423         @Override
424         protected PolicyEngine getPolicyEngineManager() {
425             return engineMgr;
426         }
427
428         @Override
429         protected void loadPolicyStep(ControlLoopOperationParams params) {
430             getSteps().add(new MyStep(this, params));
431         }
432     }
433
434
435     private static class RealManager extends ClEventManagerWithSteps<MyStep> {
436         private static final long serialVersionUID = 1L;
437
438         public RealManager(EventManagerServices services, ControlLoopParams params, UUID requestId,
439                         WorkingMemory workMem) throws ControlLoopException {
440
441             super(services, params, requestId, workMem);
442         }
443
444         @Override
445         protected void loadPolicyStep(ControlLoopOperationParams params) {
446             getSteps().add(new MyStep(this, params));
447         }
448     }
449
450     private static class MyStep extends Step {
451         public MyStep(StepContext stepContext, ControlLoopOperationParams params) {
452             super(params, new AtomicReference<>());
453         }
454     }
455 }