2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.policy.controlloop.eventmanager;
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;
35 import java.time.Instant;
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;
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";
76 private Operator policyOperator;
78 private Operation policyOperation;
80 private Actor policyActor;
82 private ActorService actors;
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;
100 future = new CompletableFuture<>();
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);
109 entityIds = Map.of("entity-name-A", "entity-value-A");
111 target = OperationalTarget.builder()
112 .targetType(ControlLoopTargetType.VM)
113 .entityIds(entityIds)
116 payload = Map.of(PAYLOAD_KEY, PAYLOAD_VALUE);
118 event = new VirtualControlLoopEvent();
119 event.setRequestId(REQ_ID);
121 starts = new LinkedBlockingQueue<>();
122 completions = new LinkedBlockingQueue<>();
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();
130 startTime = new AtomicReference<>();
132 step = new Step(params, startTime);
136 public void testConstructor() {
137 assertTrue(step.isPolicyStep());
138 assertSame(params, step.getParams());
139 assertNull(step.getParentStep());
141 // check that it recorded the startTime by starting and checking it
143 step.start(REMAINING_MS);
145 assertNotNull(startTime.get());
147 // try with null start time
148 assertThatThrownBy(() -> new Step(params, null)).isInstanceOf(NullPointerException.class)
149 .hasMessageContaining("startTime");
153 public void testConstructorWithOtherStep_testInitStartTime_testGetStartTimeRef() {
154 Step step2 = new Step(step, "actorB", "operB");
155 assertFalse(step2.isPolicyStep());
156 assertSame(step, step2.getParentStep());
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());
167 when(actors.getActor(params2.getActor())).thenReturn(policyActor);
168 when(policyActor.getOperator(params2.getOperation())).thenReturn(policyOperator);
170 assertNull(step2.getStartTime());
172 // check that it recorded the startTime by starting and checking it
174 step2.start(REMAINING_MS);
176 Instant instant = startTime.get();
177 assertNotNull(instant);
178 assertSame(instant, step2.getStartTime());
180 // launch the original step, too, so we can test the other branch of
183 step.start(REMAINING_MS);
185 assertSame(instant, startTime.get());
186 assertSame(instant, step.getStartTime());
190 public void testGetActorName_testGetOperationName() {
191 assertEquals(POLICY_ACTOR, step.getActorName());
192 assertEquals(POLICY_OPERATION, step.getOperationName());
196 public void testIsInitialized_testInit_testGetOperation() {
197 assertFalse(step.isInitialized());
199 // verify it's unchanged
200 assertFalse(step.isInitialized());
202 assertNull(step.getOperation());
206 assertSame(policyOperation, step.getOperation());
207 assertTrue(step.isInitialized());
209 // repeat - should be unchanged
211 assertSame(policyOperation, step.getOperation());
212 assertTrue(step.isInitialized());
214 // repeat without init - should be unchanged
215 assertSame(policyOperation, step.getOperation());
216 assertTrue(step.isInitialized());
220 public void testStart() {
221 assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
222 .withMessage("step has not been initialized");
224 // initialize it, by calling getOperation(), and then try again
226 assertTrue(step.start(REMAINING_MS));
228 assertNotNull(startTime.get());
230 // should fail if we try again
231 assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
232 .withMessage("step is already running");
236 * Tests start() when the operation.start() throws an exception.
239 public void testStartException() {
240 when(policyOperation.start()).thenThrow(new RuntimeException());
243 assertTrue(step.start(REMAINING_MS));
245 // exception should be immediate
246 OperationOutcome outcome = completions.poll();
247 assertNotNull(outcome);
249 assertNotEquals(OperationResult.SUCCESS, outcome.getResult());
250 assertEquals(POLICY_ACTOR, outcome.getActor());
251 assertTrue(outcome.isFinalOutcome());
255 * Tests start() when the operation throws an asynchronous exception.
258 public void testStartAsyncException() {
260 step.start(REMAINING_MS);
262 future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION));
264 // exception should be immediate
265 OperationOutcome outcome = completions.poll();
266 assertNotNull(outcome);
268 assertNotEquals(OperationResult.SUCCESS, outcome.getResult());
269 assertEquals(POLICY_ACTOR, outcome.getActor());
270 assertTrue(outcome.isFinalOutcome());
274 * Tests handleException() when the exception is a CancellationException.
277 public void testHandleExceptionCancellationException() {
279 step.start(REMAINING_MS);
281 future.completeExceptionally(new CancellationException(EXPECTED_EXCEPTION));
283 // should not have generated an outcome
284 assertNull(completions.peek());
288 public void testHandleExceptionCauseCancellationException() {
290 step.start(REMAINING_MS);
292 future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION, new CancellationException()));
294 // should not have generated an outcome
295 assertNull(completions.peek());
299 public void testHandleException() {
300 when(policyOperation.start()).thenThrow(new RuntimeException());
304 assertTrue(step.start(REMAINING_MS));
306 // exception should be immediate
307 OperationOutcome outcome = completions.poll();
308 assertNotNull(outcome);
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());
320 public void testHandleTimeout() throws InterruptedException {
323 long tstart = System.currentTimeMillis();
325 // give it a short timeout
328 OperationOutcome outcome = completions.poll(5, TimeUnit.SECONDS);
329 assertNotNull(outcome);
331 // should not have timed out before 100ms
332 assertTrue(tstart + 100 <= System.currentTimeMillis());
334 // must wait for the future to complete before checking that it was cancelled
335 assertThatThrownBy(() -> future.get(5, TimeUnit.SECONDS)).isInstanceOf(Exception.class);
337 // verify that the future was cancelled
338 assertTrue(future.isCancelled());
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());
350 public void testCancel() {
351 // should have no effect
356 step.start(REMAINING_MS);
359 assertTrue(future.isCancelled());
363 public void testBuildOperation() {
364 assertSame(policyOperation, step.buildOperation());
368 public void testMakeOutcome() {
370 assertEquals(MY_TARGET, step.makeOutcome().getTarget());
374 public void testToString() {
375 assertNotNull(step.toString());