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.actorserviceprovider.impl;
23 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
24 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertSame;
28 import static org.junit.Assert.assertTrue;
29 import static org.mockito.ArgumentMatchers.any;
30 import static org.mockito.Mockito.doThrow;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.spy;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.verify;
35 import static org.mockito.Mockito.when;
37 import java.util.Iterator;
39 import java.util.stream.Collectors;
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.onap.policy.common.parameters.ObjectValidationResult;
43 import org.onap.policy.common.parameters.ValidationStatus;
44 import org.onap.policy.controlloop.actorserviceprovider.Operation;
45 import org.onap.policy.controlloop.actorserviceprovider.Operator;
46 import org.onap.policy.controlloop.actorserviceprovider.parameters.ActorParams;
47 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
48 import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException;
50 public class ActorImplTest {
51 private static final String EXPECTED_EXCEPTION = "expected exception";
52 private static final String ACTOR_NAME = "my-actor";
53 private static final String OPER1 = "add";
54 private static final String OPER2 = "subtract";
55 private static final String OPER3 = "multiply";
56 private static final String OPER4 = "divide";
63 private Map<String, Object> sub1;
64 private Map<String, Object> sub2;
65 private Map<String, Object> sub3;
66 private Map<String, Object> sub4;
67 private Map<String, Object> params;
69 private ActorImpl actor;
73 * Initializes the fields, including a fully populated {@link #actor}.
77 oper1 = spy(new MyOper(OPER1));
78 oper2 = spy(new MyOper(OPER2));
79 oper3 = spy(new MyOper(OPER3));
80 oper4 = spy(new MyOper(OPER4));
82 sub1 = Map.of("sub A", "value A");
83 sub2 = Map.of("sub B", "value B");
84 sub3 = Map.of("sub C", "value C");
85 sub4 = Map.of("sub D", "value D");
87 params = Map.of(ActorParams.OPERATIONS_FIELD, Map.of(OPER1, sub1, OPER2, sub2, OPER3, sub3, OPER4, sub4));
89 actor = makeActor(oper1, oper2, oper3, oper4);
93 public void testActorImpl_testGetName() {
94 assertEquals(ACTOR_NAME, actor.getName());
95 assertEquals(4, actor.getOperationNames().size());
96 assertEquals(0, actor.getSequenceNumber());
100 public void testDoStart() {
101 actor.configure(params);
102 assertEquals(4, actor.getOperationNames().size());
105 * arrange for second operator to be unconfigured and the third operator to throw
108 Iterator<Operator> iter = actor.getOperators().iterator();
110 when(iter.next().isConfigured()).thenReturn(false);
111 when(iter.next().start()).thenThrow(new IllegalStateException(EXPECTED_EXCEPTION));
117 assertTrue(actor.isAlive());
119 iter = actor.getOperators().iterator();
120 verify(iter.next()).start();
121 // this one isn't configured, so shouldn't attempt to start it
122 verify(iter.next(), never()).start();
123 // this one threw an exception
125 verify(iter.next()).start();
127 // no other types of operations
128 verify(oper1, never()).stop();
129 verify(oper1, never()).shutdown();
133 public void testDoStop() {
134 actor.configure(params);
136 assertEquals(4, actor.getOperationNames().size());
138 // arrange for second operator to throw an exception
139 Iterator<Operator> iter = actor.getOperators().iterator();
141 when(iter.next().stop()).thenThrow(new IllegalStateException(EXPECTED_EXCEPTION));
147 assertFalse(actor.isAlive());
149 iter = actor.getOperators().iterator();
150 verify(iter.next()).stop();
151 // this one threw an exception
153 verify(iter.next()).stop();
154 verify(iter.next()).stop();
156 // no additional types of operations
157 verify(oper1).configure(any());
158 verify(oper1).start();
160 // no other types of operation
161 verify(oper1, never()).shutdown();
165 public void testDoShutdown() {
166 actor.configure(params);
168 assertEquals(4, actor.getOperationNames().size());
170 // arrange for second operator to throw an exception
171 Iterator<Operator> iter = actor.getOperators().iterator();
173 doThrow(new IllegalStateException(EXPECTED_EXCEPTION)).when(iter.next()).shutdown();
179 assertFalse(actor.isAlive());
181 iter = actor.getOperators().iterator();
182 verify(iter.next()).shutdown();
183 // this one threw an exception
185 verify(iter.next()).shutdown();
186 verify(iter.next()).shutdown();
188 // no additional types of operations
189 verify(oper1).configure(any());
190 verify(oper1).start();
192 // no other types of operation
193 verify(oper1, never()).stop();
197 public void testAddOperator() {
198 // cannot add operators if already configured
199 actor.configure(params);
200 assertThatIllegalStateException().isThrownBy(() -> actor.addOperator(oper1));
203 * make an actor where operators two and four have names that are duplicates of
206 oper2 = spy(new MyOper(OPER1));
207 oper4 = spy(new MyOper(OPER3));
209 actor = makeActor(oper1, oper2, oper3, oper4);
211 assertEquals(2, actor.getOperationNames().size());
213 assertSame(oper1, actor.getOperator(OPER1));
214 assertSame(oper3, actor.getOperator(OPER3));
218 public void testGetOperator() {
219 assertSame(oper1, actor.getOperator(OPER1));
220 assertSame(oper3, actor.getOperator(OPER3));
222 assertThatIllegalArgumentException().isThrownBy(() -> actor.getOperator("unknown name"));
226 public void testGetOperators() {
228 assertEquals("[add, divide, multiply, subtract]",
229 actor.getOperators().stream()
230 .map(Operator::getName)
232 .collect(Collectors.toList())
238 public void testGetOperationNames() {
240 assertEquals("[add, divide, multiply, subtract]",
241 actor.getOperationNames().stream()
243 .collect(Collectors.toList())
249 public void testDoConfigure() {
250 actor.configure(params);
251 assertTrue(actor.isConfigured());
253 verify(oper1).configure(sub1);
254 verify(oper2).configure(sub2);
255 verify(oper3).configure(sub3);
256 verify(oper4).configure(sub4);
258 // no other types of operations
259 verify(oper1, never()).start();
260 verify(oper1, never()).stop();
261 verify(oper1, never()).shutdown();
265 * Tests doConfigure() where operators throw parameter validation and runtime
269 public void testDoConfigureExceptions() {
270 makeValidException(oper1);
271 makeRuntimeException(oper2);
272 makeValidException(oper3);
274 actor.configure(params);
275 assertTrue(actor.isConfigured());
279 * Tests doConfigure(). Arranges for the following:
281 * <li>one operator is configured, but has parameters</li>
282 * <li>another operator is configured, but has no parameters</li>
283 * <li>another operator has no parameters and is not configured</li>
287 public void testDoConfigureConfigure() {
288 // configure one operator
289 oper1.configure(sub1);
291 // configure another and remove its parameters
292 oper2.configure(sub2);
293 params = Map.of(ActorParams.OPERATIONS_FIELD, Map.of(OPER1, sub1, OPER3, sub3, OPER4, sub4));
295 // create a new, unconfigured actor
296 Operator oper5 = spy(new MyOper("UNCONFIGURED"));
297 actor = makeActor(oper1, oper2, oper3, oper4, oper5);
302 actor.configure(params);
303 assertTrue(actor.isConfigured());
305 // this should have been configured again
306 verify(oper1, times(2)).configure(sub1);
308 // no parameters, so this should not have been configured again
309 verify(oper2).configure(sub2);
311 // these were only configured once
312 verify(oper3).configure(sub3);
313 verify(oper4).configure(sub4);
316 verify(oper5, never()).configure(any());
317 assertFalse(oper5.isConfigured());
319 // start and verify that all are started except for the last
321 verify(oper1).start();
322 verify(oper2).start();
323 verify(oper3).start();
324 verify(oper4).start();
325 verify(oper5, never()).start();
329 * Arranges for an operator to throw a validation exception when
330 * {@link Operator#configure(Map)} is invoked.
332 * @param oper operator of interest
334 private void makeValidException(Operator oper) {
335 ParameterValidationRuntimeException ex = new ParameterValidationRuntimeException(
336 new ObjectValidationResult(actor.getName(), null, ValidationStatus.INVALID, "null"));
337 doThrow(ex).when(oper).configure(any());
341 * Arranges for an operator to throw a runtime exception when
342 * {@link Operator#configure(Map)} is invoked.
344 * @param oper operator of interest
346 private void makeRuntimeException(Operator oper) {
347 IllegalStateException ex = new IllegalStateException(EXPECTED_EXCEPTION);
348 doThrow(ex).when(oper).configure(any());
352 public void testMakeOperatorParameters() {
353 actor.configure(params);
355 // each operator should have received its own parameters
356 verify(oper1).configure(sub1);
357 verify(oper2).configure(sub2);
358 verify(oper3).configure(sub3);
359 verify(oper4).configure(sub4);
363 * Makes an actor with the given operators.
365 * @param operators associated operators
366 * @return a new actor
368 private ActorImpl makeActor(Operator... operators) {
369 ActorImpl actor = new ActorImpl(ACTOR_NAME);
371 for (Operator oper : operators) {
372 actor.addOperator(oper);
378 private static class MyOper extends OperatorPartial {
380 public MyOper(String name) {
381 super(ACTOR_NAME, name);
385 public Operation buildOperation(ControlLoopOperationParams params) {