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