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.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;
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";
74 private Operator policyOperator;
76 private Operation policyOperation;
78 private Actor policyActor;
80 private ActorService actors;
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;
99 MockitoAnnotations.initMocks(this);
101 future = new CompletableFuture<>();
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);
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);
120 event.setTarget(ControlLoopOperationManager2.VSERVER_VSERVER_NAME);
121 event.setAai(new TreeMap<>(Map.of(ControlLoopOperationManager2.VSERVER_VSERVER_NAME, MY_TARGET)));
123 context = new ControlLoopEventContext(event);
125 starts = new LinkedBlockingQueue<>();
126 completions = new LinkedBlockingQueue<>();
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();
134 startTime = new AtomicReference<>();
136 step = new Step(params, startTime);
140 public void testConstructor() {
141 assertTrue(step.isPolicyStep());
142 assertSame(params, step.getParams());
143 assertNull(step.getParentStep());
145 // check that it recorded the startTime by starting and checking it
147 step.start(REMAINING_MS);
149 assertNotNull(startTime.get());
151 // try with null start time
152 assertThatThrownBy(() -> new Step(params, null)).isInstanceOf(NullPointerException.class)
153 .hasMessageContaining("startTime");
157 public void testConstructorWithOtherStep_testInitStartTime_testGetStartTimeRef() {
158 Step step2 = new Step(step, "actorB", "operB");
159 assertFalse(step2.isPolicyStep());
160 assertSame(step, step2.getParentStep());
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());
172 when(actors.getActor(params2.getActor())).thenReturn(policyActor);
173 when(policyActor.getOperator(params2.getOperation())).thenReturn(policyOperator);
175 assertNull(step2.getStartTime());
177 // check that it recorded the startTime by starting and checking it
179 step2.start(REMAINING_MS);
181 Instant instant = startTime.get();
182 assertNotNull(instant);
183 assertSame(instant, step2.getStartTime());
185 // launch the original step, too, so we can test the other branch of
188 step.start(REMAINING_MS);
190 assertSame(instant, startTime.get());
191 assertSame(instant, step.getStartTime());
195 public void testGetActorName_testGetOperationName() {
196 assertEquals(POLICY_ACTOR, step.getActorName());
197 assertEquals(POLICY_OPERATION, step.getOperationName());
201 public void testIsInitialized_testInit_testGetOperation() {
202 assertFalse(step.isInitialized());
204 // verify it's unchanged
205 assertFalse(step.isInitialized());
207 assertNull(step.getOperation());
211 assertSame(policyOperation, step.getOperation());
212 assertTrue(step.isInitialized());
214 // repeat - should be unchanged
216 assertSame(policyOperation, step.getOperation());
217 assertTrue(step.isInitialized());
219 // repeat without init - should be unchanged
220 assertSame(policyOperation, step.getOperation());
221 assertTrue(step.isInitialized());
225 public void testStart() {
226 assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
227 .withMessage("step has not been initialized");
229 // initialize it, by calling getOperation(), and then try again
231 assertTrue(step.start(REMAINING_MS));
233 assertNotNull(startTime.get());
235 // should fail if we try again
236 assertThatIllegalStateException().isThrownBy(() -> step.start(REMAINING_MS))
237 .withMessage("step is already running");
241 * Tests start() when the operation.start() throws an exception.
244 public void testStartException() {
245 when(policyOperation.start()).thenThrow(new RuntimeException());
248 assertTrue(step.start(REMAINING_MS));
250 // exception should be immediate
251 OperationOutcome outcome = completions.poll();
252 assertNotNull(outcome);
254 assertNotEquals(OperationResult.SUCCESS, outcome.getResult());
255 assertEquals(POLICY_ACTOR, outcome.getActor());
256 assertTrue(outcome.isFinalOutcome());
260 * Tests start() when the operation throws an asynchronous exception.
263 public void testStartAsyncException() {
265 step.start(REMAINING_MS);
267 future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION));
269 // exception should be immediate
270 OperationOutcome outcome = completions.poll();
271 assertNotNull(outcome);
273 assertNotEquals(OperationResult.SUCCESS, outcome.getResult());
274 assertEquals(POLICY_ACTOR, outcome.getActor());
275 assertTrue(outcome.isFinalOutcome());
279 * Tests handleException() when the exception is a CancellationException.
282 public void testHandleExceptionCancellationException() {
284 step.start(REMAINING_MS);
286 future.completeExceptionally(new CancellationException(EXPECTED_EXCEPTION));
288 // should not have generated an outcome
289 assertNull(completions.peek());
293 public void testHandleExceptionCauseCancellationException() {
295 step.start(REMAINING_MS);
297 future.completeExceptionally(new RuntimeException(EXPECTED_EXCEPTION, new CancellationException()));
299 // should not have generated an outcome
300 assertNull(completions.peek());
304 public void testHandleException() {
305 when(policyOperation.start()).thenThrow(new RuntimeException());
309 assertTrue(step.start(REMAINING_MS));
311 // exception should be immediate
312 OperationOutcome outcome = completions.poll();
313 assertNotNull(outcome);
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());
325 public void testHandleTimeout() throws InterruptedException {
328 long tstart = System.currentTimeMillis();
330 // give it a short timeout
333 OperationOutcome outcome = completions.poll(5, TimeUnit.SECONDS);
334 assertNotNull(outcome);
336 // should not have timed out before 100ms
337 assertTrue(tstart + 100 <= System.currentTimeMillis());
339 // must wait for the future to complete before checking that it was cancelled
340 assertThatThrownBy(() -> future.get(5, TimeUnit.SECONDS)).isInstanceOf(Exception.class);
342 // verify that the future was cancelled
343 assertTrue(future.isCancelled());
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());
355 public void testCancel() {
356 // should have no effect
361 step.start(REMAINING_MS);
364 assertTrue(future.isCancelled());
368 public void testBuildOperation() {
369 assertSame(policyOperation, step.buildOperation());
373 public void testToString() {
374 assertNotNull(step.toString());