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());
151 // check that it recorded the startTime by starting and checking it
153 step.start(REMAINING_MS);
155 assertNotNull(startTime.get());
157 // try with null start time
158 assertThatThrownBy(() -> new Step(params, null)).isInstanceOf(NullPointerException.class)
159 .hasMessageContaining("startTime");
163 public void testConstructorWithOtherStep_testInitStartTime_testGetStartTimeRef() {
164 Step step2 = new Step(step, "actorB", "operB");
165 assertFalse(step2.isPolicyStep());
167 ControlLoopOperationParams params2 = step2.getParams();
168 assertEquals("actorB", params2.getActor());
169 assertEquals("operB", params2.getOperation());
170 assertNull(params2.getRetry());
171 assertNull(params2.getTimeoutSec());
172 assertSame(target, params2.getTarget());
173 assertEquals(MY_TARGET, params2.getTargetEntity());
174 assertTrue(params2.getPayload().isEmpty());
176 when(actors.getActor(params2.getActor())).thenReturn(policyActor);
177 when(policyActor.getOperator(params2.getOperation())).thenReturn(policyOperator);
179 assertNull(step2.getStartTime());
181 // check that it recorded the startTime by starting and checking it
183 step2.start(REMAINING_MS);
185 Instant instant = startTime.get();
186 assertNotNull(instant);
187 assertSame(instant, step2.getStartTime());
189 // launch the original step, too, so we can test the other branch of
192 step.start(REMAINING_MS);
194 assertSame(instant, startTime.get());
195 assertSame(instant, step.getStartTime());
199 public void testGetActorName_testGetOperationName() {
200 assertEquals(POLICY_ACTOR, step.getActorName());
201 assertEquals(POLICY_OPERATION, step.getOperationName());
205 public void testIsInitialized_testInit_testGetOperation() {
206 assertFalse(step.isInitialized());
208 // verify it's unchanged
209 assertFalse(step.isInitialized());
211 assertNull(step.getOperation());
215 assertSame(policyOperation, step.getOperation());
216 assertTrue(step.isInitialized());
218 // repeat - should be unchanged
220 assertSame(policyOperation, step.getOperation());
221 assertTrue(step.isInitialized());
223 // repeat without init - should be unchanged
224 assertSame(policyOperation, step.getOperation());
225 assertTrue(step.isInitialized());
229 public void testStart() {
230 assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
231 .withMessage("step has not been initialized");
233 // initialize it, by calling getOperation(), and then try again
235 assertTrue(step.start(REMAINING_MS));
237 assertNotNull(startTime.get());
239 // should fail if we try again
240 assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
241 .withMessage("step is already running");
245 * Tests start() when the operation.start() throws an exception.
248 public void testStartException() {
249 when(policyOperation.start()).thenThrow(new RuntimeException());
252 assertTrue(step.start(REMAINING_MS));
254 // exception should be immediate
255 OperationOutcome outcome = completions.poll();
256 assertNotNull(outcome);
258 assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
259 assertEquals(POLICY_ACTOR, outcome.getActor());
260 assertTrue(outcome.isFinalOutcome());
264 * Tests start() when the operation throws an asynchronous exception.
267 public void testStartAsyncException() {
269 step.start(REMAINING_MS);
271 future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION));
273 // exception should be immediate
274 OperationOutcome outcome = completions.poll();
275 assertNotNull(outcome);
277 assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
278 assertEquals(POLICY_ACTOR, outcome.getActor());
279 assertTrue(outcome.isFinalOutcome());
283 * Tests handleException() when the exception is a CancellationException.
286 public void testHandleExceptionCancellationException() {
288 step.start(REMAINING_MS);
290 future.completeExceptionally(new CancellationException(EXPECTED_EXCEPTION));
292 // should not have generated an outcome
293 assertNull(completions.peek());
297 public void testHandleExceptionCauseCancellationException() {
299 step.start(REMAINING_MS);
301 future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION, new CancellationException()));
303 // should not have generated an outcome
304 assertNull(completions.peek());
308 public void testHandleException() {
309 when(policyOperation.start()).thenThrow(new RuntimeException());
313 assertTrue(step.start(REMAINING_MS));
315 // exception should be immediate
316 OperationOutcome outcome = completions.poll();
317 assertNotNull(outcome);
319 assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
320 assertEquals(POLICY_ACTOR, outcome.getActor());
321 assertTrue(outcome.isFinalOutcome());
322 assertEquals(POLICY_OPERATION, outcome.getOperation());
323 assertSame(startTime.get(), outcome.getStart());
324 assertNotNull(outcome.getEnd());
325 assertTrue(outcome.getEnd().getEpochSecond() >= startTime.get().getEpochSecond());
329 public void testHandleTimeout() throws InterruptedException {
332 long tstart = System.currentTimeMillis();
334 // give it a short timeout
337 OperationOutcome outcome = completions.poll(5, TimeUnit.SECONDS);
338 assertNotNull(outcome);
340 // should not have timed out before 100ms
341 assertTrue(tstart + 100 <= System.currentTimeMillis());
343 // must wait for the future to complete before checking that it was cancelled
344 assertThatThrownBy(() -> future.get(5, TimeUnit.SECONDS)).isInstanceOf(Exception.class);
346 // verify that the future was cancelled
347 assertTrue(future.isCancelled());
349 assertNotEquals(PolicyResult.SUCCESS, outcome.getResult());
350 assertEquals(ActorConstants.CL_TIMEOUT_ACTOR, outcome.getActor());
351 assertTrue(outcome.isFinalOutcome());
352 assertNull(outcome.getOperation());
353 assertSame(startTime.get(), outcome.getStart());
354 assertNotNull(outcome.getEnd());
355 assertTrue(outcome.getEnd().getEpochSecond() >= startTime.get().getEpochSecond());
359 public void testCancel() {
360 // should have no effect
365 step.start(REMAINING_MS);
368 assertTrue(future.isCancelled());
372 public void testBuildOperation() {
373 assertSame(policyOperation, step.buildOperation());
377 public void testToString() {
378 assertNotNull(step.toString());