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