2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2024 Nordix Foundation
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.controlloop.actorserviceprovider.parameters;
24 import static org.assertj.core.api.Assertions.assertThat;
25 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertFalse;
28 import static org.junit.jupiter.api.Assertions.assertNotNull;
29 import static org.junit.jupiter.api.Assertions.assertNull;
30 import static org.junit.jupiter.api.Assertions.assertSame;
31 import static org.junit.jupiter.api.Assertions.assertTrue;
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.Mockito.doAnswer;
34 import static org.mockito.Mockito.never;
35 import static org.mockito.Mockito.times;
36 import static org.mockito.Mockito.verify;
39 import java.util.TreeMap;
40 import java.util.UUID;
41 import java.util.concurrent.CompletableFuture;
42 import java.util.concurrent.Executor;
43 import java.util.concurrent.ForkJoinPool;
44 import java.util.concurrent.atomic.AtomicInteger;
45 import java.util.function.Consumer;
46 import java.util.function.Function;
47 import org.junit.jupiter.api.BeforeEach;
48 import org.junit.jupiter.api.Test;
49 import org.junit.jupiter.api.TestInstance;
50 import org.junit.jupiter.api.extension.ExtendWith;
51 import org.mockito.Mock;
52 import org.mockito.Mockito;
53 import org.mockito.junit.jupiter.MockitoExtension;
54 import org.onap.policy.common.parameters.BeanValidationResult;
55 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
56 import org.onap.policy.controlloop.actorserviceprovider.Operation;
57 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
58 import org.onap.policy.controlloop.actorserviceprovider.Operator;
59 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams.ControlLoopOperationParamsBuilder;
60 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
62 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
63 @ExtendWith(MockitoExtension.class)
64 class ControlLoopOperationParamsTest {
65 private static final String NULL_MSG = "null";
66 private static final String EXPECTED_EXCEPTION = "expected exception";
67 private static final String ACTOR = "my-actor";
68 private static final String OPERATION = "my-operation";
69 private static final Integer RETRY = 3;
70 private static final Integer TIMEOUT = 100;
71 private static final UUID REQ_ID = UUID.randomUUID();
77 private ActorService actorService;
80 private Consumer<OperationOutcome> completer;
83 private Executor executor;
86 private CompletableFuture<OperationOutcome> operFuture;
89 private Operator operator;
92 private Operation operation;
95 private Consumer<OperationOutcome> starter;
97 private Map<String, Object> payload;
99 private ControlLoopOperationParams params;
100 private OperationOutcome outcome;
104 * Initializes mocks and sets {@link #params} to a fully-loaded set of parameters.
108 Mockito.lenient().when(actorService.getActor(ACTOR)).thenReturn(actor);
109 Mockito.lenient().when(actor.getOperator(OPERATION)).thenReturn(operator);
110 Mockito.lenient().when(operator.buildOperation(any())).thenReturn(operation);
111 Mockito.lenient().when(operation.start()).thenReturn(operFuture);
113 payload = new TreeMap<>();
115 params = ControlLoopOperationParams.builder().actorService(actorService).completeCallback(completer)
116 .requestId(REQ_ID).executor(executor).actor(ACTOR).operation(OPERATION).payload(payload)
117 .retry(RETRY).timeoutSec(TIMEOUT)
118 .startCallback(starter).build();
120 outcome = params.makeOutcome();
125 assertThatIllegalArgumentException().isThrownBy(() -> params.toBuilder().requestId(null).build().start());
127 assertSame(operFuture, params.start());
132 assertThatIllegalArgumentException().isThrownBy(() -> params.toBuilder().requestId(null).build().build());
134 assertSame(operation, params.build());
138 void testGetRequestId() {
139 assertSame(REQ_ID, params.getRequestId());
143 void testMakeOutcome() {
144 assertEquals(ACTOR, outcome.getActor());
145 assertEquals(OPERATION, outcome.getOperation());
146 assertNull(outcome.getStart());
147 assertNull(outcome.getEnd());
148 assertNull(outcome.getSubRequestId());
149 assertNotNull(outcome.getResult());
150 assertNull(outcome.getMessage());
154 void testCallbackStarted() {
155 params.callbackStarted(outcome);
156 verify(starter).accept(outcome);
158 // modify starter to throw an exception
159 AtomicInteger count = new AtomicInteger();
161 count.incrementAndGet();
162 throw new IllegalStateException(EXPECTED_EXCEPTION);
163 }).when(starter).accept(outcome);
165 params.callbackStarted(outcome);
166 verify(starter, times(2)).accept(outcome);
167 assertEquals(1, count.get());
169 // repeat with no start-callback - no additional calls expected
170 params.toBuilder().startCallback(null).build().callbackStarted(outcome);
171 verify(starter, times(2)).accept(outcome);
172 assertEquals(1, count.get());
174 // should not call complete-callback
175 verify(completer, never()).accept(any());
179 void testCallbackCompleted() {
180 params.callbackCompleted(outcome);
181 verify(completer).accept(outcome);
183 // modify completer to throw an exception
184 AtomicInteger count = new AtomicInteger();
186 count.incrementAndGet();
187 throw new IllegalStateException(EXPECTED_EXCEPTION);
188 }).when(completer).accept(outcome);
190 params.callbackCompleted(outcome);
191 verify(completer, times(2)).accept(outcome);
192 assertEquals(1, count.get());
194 // repeat with no complete-callback - no additional calls expected
195 params.toBuilder().completeCallback(null).build().callbackCompleted(outcome);
196 verify(completer, times(2)).accept(outcome);
197 assertEquals(1, count.get());
199 // should not call start-callback
200 verify(starter, never()).accept(any());
204 void testValidateFields() {
205 testValidate("actor", NULL_MSG, bldr -> bldr.actor(null));
206 testValidate("actorService", NULL_MSG, bldr -> bldr.actorService(null));
207 testValidate("executor", NULL_MSG, bldr -> bldr.executor(null));
208 testValidate("operation", NULL_MSG, bldr -> bldr.operation(null));
209 testValidate("requestId", NULL_MSG, bldr -> bldr.requestId(null));
211 // has no target entity
212 BeanValidationResult result = params.toBuilder().build().validate();
213 assertTrue(result.isValid());
216 assertTrue(params.toBuilder().build().validate().isValid());
219 assertTrue(params.toBuilder().payload(null).retry(null).timeoutSec(null).startCallback(null)
220 .completeCallback(null).build().validate().isValid());
222 // test with minimal fields
223 assertTrue(ControlLoopOperationParams.builder().actorService(actorService).requestId(REQ_ID).actor(ACTOR)
224 .operation(OPERATION).build().validate().isValid());
227 private void testValidate(String fieldName, String expected,
228 Function<ControlLoopOperationParamsBuilder, ControlLoopOperationParamsBuilder> makeInvalid) {
230 // original params should be valid
231 BeanValidationResult result = params.validate();
232 assertTrue(result.isValid(), fieldName);
234 // make invalid params
235 result = makeInvalid.apply(params.toBuilder()).build().validate();
236 assertFalse(result.isValid(), fieldName);
237 assertThat(result.getResult()).contains(fieldName).contains(expected);
241 void testBuilder_testToBuilder() {
242 assertEquals(params, params.toBuilder().build());
246 void testGetActor() {
247 assertSame(ACTOR, params.getActor());
251 void testGetActorService() {
252 assertSame(actorService, params.getActorService());
256 void testGetExecutor() {
257 assertSame(executor, params.getExecutor());
259 // should use default when unspecified
260 assertSame(ForkJoinPool.commonPool(), ControlLoopOperationParams.builder().build().getExecutor());
264 void testGetOperation() {
265 assertSame(OPERATION, params.getOperation());
269 void testGetPayload() {
270 assertSame(payload, params.getPayload());
272 // should be null when unspecified
273 assertNull(ControlLoopOperationParams.builder().build().getPayload());
277 void testGetRetry() {
278 assertSame(RETRY, params.getRetry());
280 // should be null when unspecified
281 assertNull(ControlLoopOperationParams.builder().build().getRetry());
285 void testGetTimeoutSec() {
286 assertSame(TIMEOUT, params.getTimeoutSec());
288 // should be 300 when unspecified
289 assertEquals(Integer.valueOf(300), ControlLoopOperationParams.builder().build().getTimeoutSec());
291 // null should be ok too
292 assertNull(ControlLoopOperationParams.builder().timeoutSec(null).build().getTimeoutSec());
296 void testGetStartCallback() {
297 assertSame(starter, params.getStartCallback());
301 void testGetCompleteCallback() {
302 assertSame(completer, params.getCompleteCallback());