c4121bb384c2c7861c0481463ce10492c3aca470
[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         assertNull(step.getParentStep());
151
152         // check that it recorded the startTime by starting and checking it
153         step.init();
154         step.start(REMAINING_MS);
155
156         assertNotNull(startTime.get());
157
158         // try with null start time
159         assertThatThrownBy(() -> new Step(params, null)).isInstanceOf(NullPointerException.class)
160                         .hasMessageContaining("startTime");
161     }
162
163     @Test
164     public void testConstructorWithOtherStep_testInitStartTime_testGetStartTimeRef() {
165         Step step2 = new Step(step, "actorB", "operB");
166         assertFalse(step2.isPolicyStep());
167         assertSame(step, step2.getParentStep());
168
169         ControlLoopOperationParams params2 = step2.getParams();
170         assertEquals("actorB", params2.getActor());
171         assertEquals("operB", params2.getOperation());
172         assertNull(params2.getRetry());
173         assertNull(params2.getTimeoutSec());
174         assertSame(target, params2.getTarget());
175         assertEquals(MY_TARGET, params2.getTargetEntity());
176         assertTrue(params2.getPayload().isEmpty());
177
178         when(actors.getActor(params2.getActor())).thenReturn(policyActor);
179         when(policyActor.getOperator(params2.getOperation())).thenReturn(policyOperator);
180
181         assertNull(step2.getStartTime());
182
183         // check that it recorded the startTime by starting and checking it
184         step2.init();
185         step2.start(REMAINING_MS);
186
187         Instant instant = startTime.get();
188         assertNotNull(instant);
189         assertSame(instant, step2.getStartTime());
190
191         // launch the original step, too, so we can test the other branch of
192         // initStartTime()
193         step.init();
194         step.start(REMAINING_MS);
195
196         assertSame(instant, startTime.get());
197         assertSame(instant, step.getStartTime());
198     }
199
200     @Test
201     public void testGetActorName_testGetOperationName() {
202         assertEquals(POLICY_ACTOR, step.getActorName());
203         assertEquals(POLICY_OPERATION, step.getOperationName());
204     }
205
206     @Test
207     public void testIsInitialized_testInit_testGetOperation() {
208         assertFalse(step.isInitialized());
209
210         // verify it's unchanged
211         assertFalse(step.isInitialized());
212
213         assertNull(step.getOperation());
214
215         step.init();
216
217         assertSame(policyOperation, step.getOperation());
218         assertTrue(step.isInitialized());
219
220         // repeat - should be unchanged
221         step.init();
222         assertSame(policyOperation, step.getOperation());
223         assertTrue(step.isInitialized());
224
225         // repeat without init - should be unchanged
226         assertSame(policyOperation, step.getOperation());
227         assertTrue(step.isInitialized());
228     }
229
230     @Test
231     public void testStart() {
232         assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
233                         .withMessage("step has not been initialized");
234
235         // initialize it, by calling getOperation(), and then try again
236         step.init();
237         assertTrue(step.start(REMAINING_MS));
238
239         assertNotNull(startTime.get());
240
241         // should fail if we try again
242         assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
243                         .withMessage("step is already running");
244     }
245
246     /**
247      * Tests start() when the operation.start() throws an exception.
248      */
249     @Test
250     public void testStartException() {
251         when(policyOperation.start()).thenThrow(new RuntimeException());
252         step.init();
253
254         assertTrue(step.start(REMAINING_MS));
255
256         // exception should be immediate
257         OperationOutcome outcome = completions.poll();
258         assertNotNull(outcome);
259
260         assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
261         assertEquals(POLICY_ACTOR, outcome.getActor());
262         assertTrue(outcome.isFinalOutcome());
263     }
264
265     /**
266      * Tests start() when the operation throws an asynchronous exception.
267      */
268     @Test
269     public void testStartAsyncException() {
270         step.init();
271         step.start(REMAINING_MS);
272
273         future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION));
274
275         // exception should be immediate
276         OperationOutcome outcome = completions.poll();
277         assertNotNull(outcome);
278
279         assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
280         assertEquals(POLICY_ACTOR, outcome.getActor());
281         assertTrue(outcome.isFinalOutcome());
282     }
283
284     /**
285      * Tests handleException() when the exception is a CancellationException.
286      */
287     @Test
288     public void testHandleExceptionCancellationException() {
289         step.init();
290         step.start(REMAINING_MS);
291
292         future.completeExceptionally(new CancellationException(EXPECTED_EXCEPTION));
293
294         // should not have generated an outcome
295         assertNull(completions.peek());
296     }
297
298     @Test
299     public void testHandleExceptionCauseCancellationException() {
300         step.init();
301         step.start(REMAINING_MS);
302
303         future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION, new CancellationException()));
304
305         // should not have generated an outcome
306         assertNull(completions.peek());
307     }
308
309     @Test
310     public void testHandleException() {
311         when(policyOperation.start()).thenThrow(new RuntimeException());
312
313         step.init();
314
315         assertTrue(step.start(REMAINING_MS));
316
317         // exception should be immediate
318         OperationOutcome outcome = completions.poll();
319         assertNotNull(outcome);
320
321         assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
322         assertEquals(POLICY_ACTOR, outcome.getActor());
323         assertTrue(outcome.isFinalOutcome());
324         assertEquals(POLICY_OPERATION, outcome.getOperation());
325         assertSame(startTime.get(), outcome.getStart());
326         assertNotNull(outcome.getEnd());
327         assertTrue(outcome.getEnd().getEpochSecond() >= startTime.get().getEpochSecond());
328     }
329
330     @Test
331     public void testHandleTimeout() throws InterruptedException {
332         step.init();
333
334         long tstart = System.currentTimeMillis();
335
336         // give it a short timeout
337         step.start(100);
338
339         OperationOutcome outcome = completions.poll(5, TimeUnit.SECONDS);
340         assertNotNull(outcome);
341
342         // should not have timed out before 100ms
343         assertTrue(tstart + 100 <= System.currentTimeMillis());
344
345         // must wait for the future to complete before checking that it was cancelled
346         assertThatThrownBy(() -> future.get(5, TimeUnit.SECONDS)).isInstanceOf(Exception.class);
347
348         // verify that the future was cancelled
349         assertTrue(future.isCancelled());
350
351         assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
352         assertEquals(ActorConstants.CL_TIMEOUT_ACTOR, outcome.getActor());
353         assertTrue(outcome.isFinalOutcome());
354         assertNull(outcome.getOperation());
355         assertSame(startTime.get(), outcome.getStart());
356         assertNotNull(outcome.getEnd());
357         assertTrue(outcome.getEnd().getEpochSecond() >= startTime.get().getEpochSecond());
358     }
359
360     @Test
361     public void testCancel() {
362         // should have no effect
363         step.cancel();
364
365         step.init();
366
367         step.start(REMAINING_MS);
368         step.cancel();
369
370         assertTrue(future.isCancelled());
371     }
372
373     @Test
374     public void testBuildOperation() {
375         assertSame(policyOperation, step.buildOperation());
376     }
377
378     @Test
379     public void testToString() {
380         assertNotNull(step.toString());
381     }
382 }