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;
23 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNotNull;
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.Arrays;
38 import java.util.Collection;
39 import java.util.Iterator;
41 import java.util.TreeMap;
42 import java.util.function.Consumer;
43 import java.util.stream.Collectors;
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.onap.policy.common.parameters.ObjectValidationResult;
47 import org.onap.policy.common.parameters.ValidationStatus;
48 import org.onap.policy.controlloop.actorserviceprovider.impl.ActorImpl;
49 import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException;
50 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
52 public class ActorServiceTest {
53 private static final String EXPECTED_EXCEPTION = "expected exception";
54 private static final String ACTOR1 = "actor A";
55 private static final String ACTOR2 = "actor B";
56 private static final String ACTOR3 = "actor C";
57 private static final String ACTOR4 = "actor D";
64 private Map<String, Object> sub1;
65 private Map<String, Object> sub2;
66 private Map<String, Object> sub3;
67 private Map<String, Object> sub4;
68 private Map<String, Object> params;
70 private ActorService service;
74 * Initializes the fields, including a fully populated {@link #service}.
78 actor1 = spy(new ActorImpl(ACTOR1));
79 actor2 = spy(new ActorImpl(ACTOR2));
80 actor3 = spy(new ActorImpl(ACTOR3));
81 actor4 = spy(new ActorImpl(ACTOR4));
83 sub1 = Map.of("sub A", "value A");
84 sub2 = Map.of("sub B", "value B");
85 sub3 = Map.of("sub C", "value C");
86 sub4 = Map.of("sub D", "value D");
88 params = Map.of(ACTOR1, sub1, ACTOR2, sub2, ACTOR3, sub3, ACTOR4, sub4);
90 service = makeService(actor1, actor2, actor3, actor4);
94 public void testActorService_testBuildList() {
96 * make a service where actors two and four have names that are duplicates of the
101 * actor0 has a higher sequence number than actor1, so it should be discarded,
102 * even though it will be examined first
104 Actor actor0 = spy(new ActorImpl(ACTOR1) {
106 public int getSequenceNumber() {
111 actor2 = spy(new ActorImpl(ACTOR1));
112 actor4 = spy(new ActorImpl(ACTOR3));
114 service = makeService(actor0, actor1, actor2, actor3, actor4);
116 assertEquals(2, service.getActorNames().size());
118 assertSame(actor1, service.getActor(ACTOR1));
119 assertSame(actor3, service.getActor(ACTOR3));
123 public void testDoStart() {
124 service.configure(params);
126 setUpOp("testDoStart", actor -> when(actor.isConfigured()).thenReturn(false), Actor::start);
132 assertTrue(service.isAlive());
134 Iterator<Actor> iter = service.getActors().iterator();
135 verify(iter.next()).start();
136 verify(iter.next(), never()).start();
137 verify(iter.next()).start();
138 verify(iter.next()).start();
140 // no additional types of operations
141 verify(actor1).configure(any());
143 // no other types of operations
144 verify(actor1, never()).stop();
145 verify(actor1, never()).shutdown();
149 public void testDoStop() {
150 service.configure(params);
153 setUpOp("testDoStop", Actor::stop, Actor::stop);
159 assertFalse(service.isAlive());
161 Iterator<Actor> iter = service.getActors().iterator();
162 verify(iter.next()).stop();
163 verify(iter.next(), times(2)).stop();
164 verify(iter.next()).stop();
165 verify(iter.next()).stop();
167 // no additional types of operations
168 verify(actor1).configure(any());
169 verify(actor1).start();
171 // no other types of operation
172 verify(actor1, never()).shutdown();
176 public void testDoShutdown() {
177 service.configure(params);
180 setUpOp("testDoShutdown", Actor::shutdown, Actor::shutdown);
183 * Shut down the service.
186 assertFalse(service.isAlive());
188 Iterator<Actor> iter = service.getActors().iterator();
189 verify(iter.next()).shutdown();
190 verify(iter.next(), times(2)).shutdown();
191 verify(iter.next()).shutdown();
192 verify(iter.next()).shutdown();
194 // no additional types of operations
195 verify(actor1).configure(any());
196 verify(actor1).start();
198 // no other types of operation
199 verify(actor1, never()).stop();
203 * Applies an operation to the second actor, and then arranges for the third actor to
204 * throw an exception when its operation is performed.
206 * @param testName test name
207 * @param oper2 operation to apply to the second actor
208 * @param oper3 operation to apply to the third actor
210 private void setUpOp(String testName, Consumer<Actor> oper2, Consumer<Actor> oper3) {
211 Collection<Actor> actors = service.getActors();
212 assertEquals(testName, 4, actors.size());
214 Iterator<Actor> iter = actors.iterator();
216 // leave the first alone
219 // apply oper2 to the second actor
220 oper2.accept(iter.next());
222 // throw an exception in the third
223 oper3.accept(doThrow(new IllegalStateException(EXPECTED_EXCEPTION)).when(iter.next()));
225 // leave the fourth alone
230 public void testGetActor() {
231 assertSame(actor1, service.getActor(ACTOR1));
232 assertSame(actor3, service.getActor(ACTOR3));
234 assertThatIllegalArgumentException().isThrownBy(() -> service.getActor("unknown actor"));
238 public void testGetActors() {
240 assertEquals("[actor A, actor B, actor C, actor D]",
241 service.getActors().stream()
244 .collect(Collectors.toList())
250 public void testGetActorNames() {
252 assertEquals("[actor A, actor B, actor C, actor D]",
253 service.getActorNames().stream()
255 .collect(Collectors.toList())
261 public void testDoConfigure() {
262 service.configure(params);
263 assertTrue(service.isConfigured());
265 verify(actor1).configure(sub1);
266 verify(actor2).configure(sub2);
267 verify(actor3).configure(sub3);
268 verify(actor4).configure(sub4);
270 // no other types of operations
271 verify(actor1, never()).start();
272 verify(actor1, never()).stop();
273 verify(actor1, never()).shutdown();
277 * Tests doConfigure() where actors throw parameter validation and runtime exceptions.
280 public void testDoConfigureExceptions() {
281 makeValidException(actor1);
282 makeRuntimeException(actor2);
283 makeValidException(actor3);
285 service.configure(params);
286 assertTrue(service.isConfigured());
290 * Tests doConfigure(). Arranges for the following:
292 * <li>one actor is configured, but has parameters</li>
293 * <li>another actor is configured, but has no parameters</li>
294 * <li>another actor has no parameters and is not configured</li>
298 public void testDoConfigureConfigure() {
299 // need mutable parameters
300 params = new TreeMap<>(params);
302 // configure one actor
303 actor1.configure(sub1);
305 // configure another and remove its parameters
306 actor2.configure(sub2);
307 params.remove(ACTOR2);
309 // create a new, unconfigured actor
310 ActorImpl actor5 = spy(new ActorImpl("UNCONFIGURED"));
311 service = makeService(actor1, actor2, actor3, actor4, actor5);
316 service.configure(params);
317 assertTrue(service.isConfigured());
319 // this should have been configured again
320 verify(actor1, times(2)).configure(sub1);
322 // no parameters, so this should not have been configured again
323 verify(actor2).configure(sub2);
325 // these were only configured once
326 verify(actor3).configure(sub3);
327 verify(actor4).configure(sub4);
330 verify(actor5, never()).configure(any());
331 assertFalse(actor5.isConfigured());
333 // start and verify that all are started except for the last
335 verify(actor1).start();
336 verify(actor2).start();
337 verify(actor3).start();
338 verify(actor4).start();
339 verify(actor5, never()).start();
343 * Arranges for an actor to throw a validation exception when
344 * {@link Actor#configure(Map)} is invoked.
346 * @param actor actor of interest
348 private void makeValidException(Actor actor) {
349 ParameterValidationRuntimeException ex = new ParameterValidationRuntimeException(
350 new ObjectValidationResult(actor.getName(), null, ValidationStatus.INVALID, "null"));
351 doThrow(ex).when(actor).configure(any());
355 * Arranges for an actor to throw a runtime exception when
356 * {@link Actor#configure(Map)} is invoked.
358 * @param actor actor of interest
360 private void makeRuntimeException(Actor actor) {
361 IllegalStateException ex = new IllegalStateException(EXPECTED_EXCEPTION);
362 doThrow(ex).when(actor).configure(any());
366 public void testLoadActors() {
367 ActorService service = new ActorService();
368 assertFalse(service.getActors().isEmpty());
369 assertNotNull(service.getActor(DummyActor.class.getSimpleName()));
373 * Makes an actor service whose {@link ActorService#loadActors()} method returns the
376 * @param actors actors to be returned
377 * @return a new actor service
379 private ActorService makeService(Actor... actors) {
380 return new ActorService() {
382 protected Iterable<Actor> loadActors() {
383 return Arrays.asList(actors);