1472adc1858062a9c36ac2d919995eceb0fa47ec
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020 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.assertThatIllegalStateException;
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.assertNotEquals;
28 import static org.junit.Assert.assertNotNull;
29 import static org.junit.Assert.assertNull;
30 import static org.junit.Assert.assertSame;
31 import static org.junit.Assert.assertTrue;
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.Mockito.when;
34
35 import java.time.Instant;
36 import java.util.Map;
37 import java.util.TreeMap;
38 import java.util.UUID;
39 import java.util.concurrent.BlockingQueue;
40 import java.util.concurrent.CancellationException;
41 import java.util.concurrent.CompletableFuture;
42 import java.util.concurrent.ForkJoinPool;
43 import java.util.concurrent.LinkedBlockingQueue;
44 import java.util.concurrent.TimeUnit;
45 import java.util.concurrent.atomic.AtomicReference;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.mockito.Mock;
49 import org.mockito.MockitoAnnotations;
50 import org.onap.policy.controlloop.VirtualControlLoopEvent;
51 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
52 import org.onap.policy.controlloop.actorserviceprovider.Operation;
53 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
54 import org.onap.policy.controlloop.actorserviceprovider.Operator;
55 import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
56 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
57 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
58 import org.onap.policy.controlloop.policy.Policy;
59 import org.onap.policy.controlloop.policy.PolicyResult;
60 import org.onap.policy.controlloop.policy.Target;
61 import org.onap.policy.controlloop.policy.TargetType;
62
63 public class StepTest {
64     private static final UUID REQ_ID = UUID.randomUUID();
65     private static final String POLICY_ID = "my-policy";
66     private static final String POLICY_ACTOR = "my-actor";
67     private static final String POLICY_OPERATION = "my-operation";
68     private static final String MY_TARGET = "my-target";
69     private static final String PAYLOAD_KEY = "payload-key";
70     private static final String PAYLOAD_VALUE = "payload-value";
71     private static final long REMAINING_MS = 5000;
72     private static final Integer POLICY_RETRY = 3;
73     private static final Integer POLICY_TIMEOUT = 20;
74     private static final String EXPECTED_EXCEPTION = "expected exception";
75
76     @Mock
77     private Operator policyOperator;
78     @Mock
79     private Operation policyOperation;
80     @Mock
81     private Actor policyActor;
82     @Mock
83     private ActorService actors;
84
85     private CompletableFuture<OperationOutcome> future;
86     private Target target;
87     private Map<String, String> payload;
88     private Policy policy;
89     private VirtualControlLoopEvent event;
90     private ControlLoopEventContext context;
91     private BlockingQueue<OperationOutcome> starts;
92     private BlockingQueue<OperationOutcome> completions;
93     private ControlLoopOperationParams params;
94     private AtomicReference<Instant> startTime;
95     private Step step;
96
97     /**
98      * Sets up.
99      */
100     @Before
101     public void setUp() {
102         MockitoAnnotations.initMocks(this);
103
104         future = new CompletableFuture<>();
105
106         // configure policy operation
107         when(actors.getActor(POLICY_ACTOR)).thenReturn(policyActor);
108         when(policyActor.getOperator(POLICY_OPERATION)).thenReturn(policyOperator);
109         when(policyOperator.buildOperation(any())).thenReturn(policyOperation);
110         when(policyOperation.start()).thenReturn(future);
111
112         target = new Target();
113         target.setType(TargetType.VM);
114
115         payload = Map.of(PAYLOAD_KEY, PAYLOAD_VALUE);
116
117         policy = new Policy();
118         policy.setId(POLICY_ID);
119         policy.setActor(POLICY_ACTOR);
120         policy.setRecipe(POLICY_OPERATION);
121         policy.setTarget(target);
122         policy.setPayload(payload);
123         policy.setRetry(POLICY_RETRY);
124         policy.setTimeout(POLICY_TIMEOUT);
125
126         event = new VirtualControlLoopEvent();
127         event.setRequestId(REQ_ID);
128         event.setTarget(ControlLoopOperationManager2.VSERVER_VSERVER_NAME);
129         event.setAai(new TreeMap<>(Map.of(ControlLoopOperationManager2.VSERVER_VSERVER_NAME, MY_TARGET)));
130
131         context = new ControlLoopEventContext(event);
132
133         starts = new LinkedBlockingQueue<>();
134         completions = new LinkedBlockingQueue<>();
135
136         params = ControlLoopOperationParams.builder().actor(POLICY_ACTOR).actorService(actors)
137                         .completeCallback(completions::add).context(context).executor(ForkJoinPool.commonPool())
138                         .operation(POLICY_OPERATION).payload(new TreeMap<>(payload)).startCallback(starts::add)
139                         .target(target).targetEntity(MY_TARGET).build();
140
141         startTime = new AtomicReference<>();
142
143         step = new Step(params, startTime);
144     }
145
146     @Test
147     public void testConstructor() {
148         assertTrue(step.isPolicyStep());
149         assertSame(params, step.getParams());
150
151         // check that it recorded the startTime by starting and checking it
152         step.init();
153         step.start(REMAINING_MS);
154
155         assertNotNull(startTime.get());
156
157         // try with null start time
158         assertThatThrownBy(() -> new Step(params, null)).isInstanceOf(NullPointerException.class)
159                         .hasMessageContaining("startTime");
160     }
161
162     @Test
163     public void testConstructorWithOtherStep_testInitStartTime_testGetStartTimeRef() {
164         Step step2 = new Step(step, "actorB", "operB");
165         assertFalse(step2.isPolicyStep());
166
167         ControlLoopOperationParams params2 = step2.getParams();
168         assertEquals("actorB", params2.getActor());
169         assertEquals("operB", params2.getOperation());
170         assertNull(params2.getRetry());
171         assertNull(params2.getTimeoutSec());
172         assertSame(target, params2.getTarget());
173         assertEquals(MY_TARGET, params2.getTargetEntity());
174         assertTrue(params2.getPayload().isEmpty());
175
176         when(actors.getActor(params2.getActor())).thenReturn(policyActor);
177         when(policyActor.getOperator(params2.getOperation())).thenReturn(policyOperator);
178
179         assertNull(step2.getStartTime());
180
181         // check that it recorded the startTime by starting and checking it
182         step2.init();
183         step2.start(REMAINING_MS);
184
185         Instant instant = startTime.get();
186         assertNotNull(instant);
187         assertSame(instant, step2.getStartTime());
188
189         // launch the original step, too, so we can test the other branch of
190         // initStartTime()
191         step.init();
192         step.start(REMAINING_MS);
193
194         assertSame(instant, startTime.get());
195         assertSame(instant, step.getStartTime());
196     }
197
198     @Test
199     public void testGetActorName_testGetOperationName() {
200         assertEquals(POLICY_ACTOR, step.getActorName());
201         assertEquals(POLICY_OPERATION, step.getOperationName());
202     }
203
204     @Test
205     public void testIsInitialized_testInit_testGetOperation() {
206         assertFalse(step.isInitialized());
207
208         // verify it's unchanged
209         assertFalse(step.isInitialized());
210
211         assertNull(step.getOperation());
212
213         step.init();
214
215         assertSame(policyOperation, step.getOperation());
216         assertTrue(step.isInitialized());
217
218         // repeat - should be unchanged
219         step.init();
220         assertSame(policyOperation, step.getOperation());
221         assertTrue(step.isInitialized());
222
223         // repeat without init - should be unchanged
224         assertSame(policyOperation, step.getOperation());
225         assertTrue(step.isInitialized());
226     }
227
228     @Test
229     public void testStart() {
230         assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
231                         .withMessage("step has not been initialized");
232
233         // initialize it, by calling getOperation(), and then try again
234         step.init();
235         assertTrue(step.start(REMAINING_MS));
236
237         assertNotNull(startTime.get());
238
239         // should fail if we try again
240         assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
241                         .withMessage("step is already running");
242     }
243
244     /**
245      * Tests start() when the operation.start() throws an exception.
246      */
247     @Test
248     public void testStartException() {
249         when(policyOperation.start()).thenThrow(new RuntimeException());
250         step.init();
251
252         assertTrue(step.start(REMAINING_MS));
253
254         // exception should be immediate
255         OperationOutcome outcome = completions.poll();
256         assertNotNull(outcome);
257
258         assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
259         assertEquals(POLICY_ACTOR, outcome.getActor());
260         assertTrue(outcome.isFinalOutcome());
261     }
262
263     /**
264      * Tests start() when the operation throws an asynchronous exception.
265      */
266     @Test
267     public void testStartAsyncException() {
268         step.init();
269         step.start(REMAINING_MS);
270
271         future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION));
272
273         // exception should be immediate
274         OperationOutcome outcome = completions.poll();
275         assertNotNull(outcome);
276
277         assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
278         assertEquals(POLICY_ACTOR, outcome.getActor());
279         assertTrue(outcome.isFinalOutcome());
280     }
281
282     /**
283      * Tests handleException() when the exception is a CancellationException.
284      */
285     @Test
286     public void testHandleExceptionCancellationException() {
287         step.init();
288         step.start(REMAINING_MS);
289
290         future.completeExceptionally(new CancellationException(EXPECTED_EXCEPTION));
291
292         // should not have generated an outcome
293         assertNull(completions.peek());
294     }
295
296     @Test
297     public void testHandleExceptionCauseCancellationException() {
298         step.init();
299         step.start(REMAINING_MS);
300
301         future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION, new CancellationException()));
302
303         // should not have generated an outcome
304         assertNull(completions.peek());
305     }
306
307     @Test
308     public void testHandleException() {
309         when(policyOperation.start()).thenThrow(new RuntimeException());
310
311         step.init();
312
313         assertTrue(step.start(REMAINING_MS));
314
315         // exception should be immediate
316         OperationOutcome outcome = completions.poll();
317         assertNotNull(outcome);
318
319         assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
320         assertEquals(POLICY_ACTOR, outcome.getActor());
321         assertTrue(outcome.isFinalOutcome());
322         assertEquals(POLICY_OPERATION, outcome.getOperation());
323         assertSame(startTime.get(), outcome.getStart());
324         assertNotNull(outcome.getEnd());
325         assertTrue(outcome.getEnd().getEpochSecond() >= startTime.get().getEpochSecond());
326     }
327
328     @Test
329     public void testHandleTimeout() throws InterruptedException {
330         step.init();
331
332         long tstart = System.currentTimeMillis();
333
334         // give it a short timeout
335         step.start(100);
336
337         OperationOutcome outcome = completions.poll(5, TimeUnit.SECONDS);
338         assertNotNull(outcome);
339
340         // should not have timed out before 100ms
341         assertTrue(tstart + 100 <= System.currentTimeMillis());
342
343         // must wait for the future to complete before checking that it was cancelled
344         assertThatThrownBy(() -> future.get(5, TimeUnit.SECONDS)).isInstanceOf(Exception.class);
345
346         // verify that the future was cancelled
347         assertTrue(future.isCancelled());
348
349         assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
350         assertEquals(ActorConstants.CL_TIMEOUT_ACTOR, outcome.getActor());
351         assertTrue(outcome.isFinalOutcome());
352         assertNull(outcome.getOperation());
353         assertSame(startTime.get(), outcome.getStart());
354         assertNotNull(outcome.getEnd());
355         assertTrue(outcome.getEnd().getEpochSecond() >= startTime.get().getEpochSecond());
356     }
357
358     @Test
359     public void testCancel() {
360         // should have no effect
361         step.cancel();
362
363         step.init();
364
365         step.start(REMAINING_MS);
366         step.cancel();
367
368         assertTrue(future.isCancelled());
369     }
370
371     @Test
372     public void testBuildOperation() {
373         assertSame(policyOperation, step.buildOperation());
374     }
375
376     @Test
377     public void testToString() {
378         assertNotNull(step.toString());
379     }
380 }