2 * ============LICENSE_START=======================================================
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
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.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;
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";
77 private Operator policyOperator;
79 private Operation policyOperation;
81 private Actor policyActor;
83 private ActorService actors;
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;
101 public void setUp() {
102 MockitoAnnotations.initMocks(this);
104 future = new CompletableFuture<>();
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);
112 target = new Target();
113 target.setType(TargetType.VM);
115 payload = Map.of(PAYLOAD_KEY, PAYLOAD_VALUE);
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);
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)));
131 context = new ControlLoopEventContext(event);
133 starts = new LinkedBlockingQueue<>();
134 completions = new LinkedBlockingQueue<>();
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();
141 startTime = new AtomicReference<>();
143 step = new Step(params, startTime);
147 public void testConstructor() {
148 assertTrue(step.isPolicyStep());
149 assertSame(params, step.getParams());
150 assertNull(step.getParentStep());
152 // check that it recorded the startTime by starting and checking it
154 step.start(REMAINING_MS);
156 assertNotNull(startTime.get());
158 // try with null start time
159 assertThatThrownBy(() -> new Step(params, null)).isInstanceOf(NullPointerException.class)
160 .hasMessageContaining("startTime");
164 public void testConstructorWithOtherStep_testInitStartTime_testGetStartTimeRef() {
165 Step step2 = new Step(step, "actorB", "operB");
166 assertFalse(step2.isPolicyStep());
167 assertSame(step, step2.getParentStep());
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());
178 when(actors.getActor(params2.getActor())).thenReturn(policyActor);
179 when(policyActor.getOperator(params2.getOperation())).thenReturn(policyOperator);
181 assertNull(step2.getStartTime());
183 // check that it recorded the startTime by starting and checking it
185 step2.start(REMAINING_MS);
187 Instant instant = startTime.get();
188 assertNotNull(instant);
189 assertSame(instant, step2.getStartTime());
191 // launch the original step, too, so we can test the other branch of
194 step.start(REMAINING_MS);
196 assertSame(instant, startTime.get());
197 assertSame(instant, step.getStartTime());
201 public void testGetActorName_testGetOperationName() {
202 assertEquals(POLICY_ACTOR, step.getActorName());
203 assertEquals(POLICY_OPERATION, step.getOperationName());
207 public void testIsInitialized_testInit_testGetOperation() {
208 assertFalse(step.isInitialized());
210 // verify it's unchanged
211 assertFalse(step.isInitialized());
213 assertNull(step.getOperation());
217 assertSame(policyOperation, step.getOperation());
218 assertTrue(step.isInitialized());
220 // repeat - should be unchanged
222 assertSame(policyOperation, step.getOperation());
223 assertTrue(step.isInitialized());
225 // repeat without init - should be unchanged
226 assertSame(policyOperation, step.getOperation());
227 assertTrue(step.isInitialized());
231 public void testStart() {
232 assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
233 .withMessage("step has not been initialized");
235 // initialize it, by calling getOperation(), and then try again
237 assertTrue(step.start(REMAINING_MS));
239 assertNotNull(startTime.get());
241 // should fail if we try again
242 assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
243 .withMessage("step is already running");
247 * Tests start() when the operation.start() throws an exception.
250 public void testStartException() {
251 when(policyOperation.start()).thenThrow(new RuntimeException());
254 assertTrue(step.start(REMAINING_MS));
256 // exception should be immediate
257 OperationOutcome outcome = completions.poll();
258 assertNotNull(outcome);
260 assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
261 assertEquals(POLICY_ACTOR, outcome.getActor());
262 assertTrue(outcome.isFinalOutcome());
266 * Tests start() when the operation throws an asynchronous exception.
269 public void testStartAsyncException() {
271 step.start(REMAINING_MS);
273 future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION));
275 // exception should be immediate
276 OperationOutcome outcome = completions.poll();
277 assertNotNull(outcome);
279 assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
280 assertEquals(POLICY_ACTOR, outcome.getActor());
281 assertTrue(outcome.isFinalOutcome());
285 * Tests handleException() when the exception is a CancellationException.
288 public void testHandleExceptionCancellationException() {
290 step.start(REMAINING_MS);
292 future.completeExceptionally(new CancellationException(EXPECTED_EXCEPTION));
294 // should not have generated an outcome
295 assertNull(completions.peek());
299 public void testHandleExceptionCauseCancellationException() {
301 step.start(REMAINING_MS);
303 future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION, new CancellationException()));
305 // should not have generated an outcome
306 assertNull(completions.peek());
310 public void testHandleException() {
311 when(policyOperation.start()).thenThrow(new RuntimeException());
315 assertTrue(step.start(REMAINING_MS));
317 // exception should be immediate
318 OperationOutcome outcome = completions.poll();
319 assertNotNull(outcome);
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());
331 public void testHandleTimeout() throws InterruptedException {
334 long tstart = System.currentTimeMillis();
336 // give it a short timeout
339 OperationOutcome outcome = completions.poll(5, TimeUnit.SECONDS);
340 assertNotNull(outcome);
342 // should not have timed out before 100ms
343 assertTrue(tstart + 100 <= System.currentTimeMillis());
345 // must wait for the future to complete before checking that it was cancelled
346 assertThatThrownBy(() -> future.get(5, TimeUnit.SECONDS)).isInstanceOf(Exception.class);
348 // verify that the future was cancelled
349 assertTrue(future.isCancelled());
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());
361 public void testCancel() {
362 // should have no effect
367 step.start(REMAINING_MS);
370 assertTrue(future.isCancelled());
374 public void testBuildOperation() {
375 assertSame(policyOperation, step.buildOperation());
379 public void testToString() {
380 assertNotNull(step.toString());