851a79129460fce0315fd145696d28aede1cdeff
[policy/models.git] / models-interactions / model-actors / actorServiceProvider / src / test / java / org / onap / policy / controlloop / actorserviceprovider / ActorServiceTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.policy.controlloop.actorserviceprovider;
22
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;
36
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.Iterator;
40 import java.util.Map;
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;
51
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";
58
59     private Actor actor1;
60     private Actor actor2;
61     private Actor actor3;
62     private Actor actor4;
63
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;
69
70     private ActorService service;
71
72
73     /**
74      * Initializes the fields, including a fully populated {@link #service}.
75      */
76     @Before
77     public void setUp() {
78         actor1 = spy(new ActorImpl(ACTOR1));
79         actor2 = spy(new ActorImpl(ACTOR2));
80         actor3 = spy(new ActorImpl(ACTOR3));
81         actor4 = spy(new ActorImpl(ACTOR4));
82
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");
87
88         params = Map.of(ACTOR1, sub1, ACTOR2, sub2, ACTOR3, sub3, ACTOR4, sub4);
89
90         service = makeService(actor1, actor2, actor3, actor4);
91     }
92
93     @Test
94     public void testActorService() {
95         /*
96          * make a service where actors two and four have names that are duplicates of the
97          * others
98          */
99         actor2 = spy(new ActorImpl(ACTOR1));
100         actor4 = spy(new ActorImpl(ACTOR3));
101
102         service = makeService(actor1, actor2, actor3, actor4);
103
104         assertEquals(2, service.getActorNames().size());
105
106         assertSame(actor1, service.getActor(ACTOR1));
107         assertSame(actor3, service.getActor(ACTOR3));
108     }
109
110     @Test
111     public void testDoStart() {
112         service.configure(params);
113
114         setUpOp("testDoStart", actor -> when(actor.isConfigured()).thenReturn(false), Actor::start);
115
116         /*
117          * Start the service.
118          */
119         service.start();
120         assertTrue(service.isAlive());
121
122         Iterator<Actor> iter = service.getActors().iterator();
123         verify(iter.next()).start();
124         verify(iter.next(), never()).start();
125         verify(iter.next()).start();
126         verify(iter.next()).start();
127
128         // no additional types of operations
129         verify(actor1).configure(any());
130
131         // no other types of operations
132         verify(actor1, never()).stop();
133         verify(actor1, never()).shutdown();
134     }
135
136     @Test
137     public void testDoStop() {
138         service.configure(params);
139         service.start();
140
141         setUpOp("testDoStop", Actor::stop, Actor::stop);
142
143         /*
144          * Stop the service.
145          */
146         service.stop();
147         assertFalse(service.isAlive());
148
149         Iterator<Actor> iter = service.getActors().iterator();
150         verify(iter.next()).stop();
151         verify(iter.next(), times(2)).stop();
152         verify(iter.next()).stop();
153         verify(iter.next()).stop();
154
155         // no additional types of operations
156         verify(actor1).configure(any());
157         verify(actor1).start();
158
159         // no other types of operation
160         verify(actor1, never()).shutdown();
161     }
162
163     @Test
164     public void testDoShutdown() {
165         service.configure(params);
166         service.start();
167
168         setUpOp("testDoShutdown", Actor::shutdown, Actor::shutdown);
169
170         /*
171          * Shut down the service.
172          */
173         service.shutdown();
174         assertFalse(service.isAlive());
175
176         Iterator<Actor> iter = service.getActors().iterator();
177         verify(iter.next()).shutdown();
178         verify(iter.next(), times(2)).shutdown();
179         verify(iter.next()).shutdown();
180         verify(iter.next()).shutdown();
181
182         // no additional types of operations
183         verify(actor1).configure(any());
184         verify(actor1).start();
185
186         // no other types of operation
187         verify(actor1, never()).stop();
188     }
189
190     /**
191      * Applies an operation to the second actor, and then arranges for the third actor to
192      * throw an exception when its operation is performed.
193      *
194      * @param testName test name
195      * @param oper2 operation to apply to the second actor
196      * @param oper3 operation to apply to the third actor
197      */
198     private void setUpOp(String testName, Consumer<Actor> oper2, Consumer<Actor> oper3) {
199         Collection<Actor> actors = service.getActors();
200         assertEquals(testName, 4, actors.size());
201
202         Iterator<Actor> iter = actors.iterator();
203
204         // leave the first alone
205         iter.next();
206
207         // apply oper2 to the second actor
208         oper2.accept(iter.next());
209
210         // throw an exception in the third
211         oper3.accept(doThrow(new IllegalStateException(EXPECTED_EXCEPTION)).when(iter.next()));
212
213         // leave the fourth alone
214         iter.next();
215     }
216
217     @Test
218     public void testGetInstance() {
219         service = ActorService.getInstance();
220         assertNotNull(service);
221
222         assertSame(service, ActorService.getInstance());
223     }
224
225     @Test
226     public void testGetActor() {
227         assertSame(actor1, service.getActor(ACTOR1));
228         assertSame(actor3, service.getActor(ACTOR3));
229
230         assertThatIllegalArgumentException().isThrownBy(() -> service.getActor("unknown actor"));
231     }
232
233     @Test
234     public void testGetActors() {
235         // @formatter:off
236         assertEquals("[actor A, actor B, actor C, actor D]",
237                         service.getActors().stream()
238                             .map(Actor::getName)
239                             .sorted()
240                             .collect(Collectors.toList())
241                             .toString());
242         // @formatter:on
243     }
244
245     @Test
246     public void testGetActorNames() {
247         // @formatter:off
248         assertEquals("[actor A, actor B, actor C, actor D]",
249                         service.getActorNames().stream()
250                             .sorted()
251                             .collect(Collectors.toList())
252                             .toString());
253         // @formatter:on
254     }
255
256     @Test
257     public void testDoConfigure() {
258         service.configure(params);
259         assertTrue(service.isConfigured());
260
261         verify(actor1).configure(sub1);
262         verify(actor2).configure(sub2);
263         verify(actor3).configure(sub3);
264         verify(actor4).configure(sub4);
265
266         // no other types of operations
267         verify(actor1, never()).start();
268         verify(actor1, never()).stop();
269         verify(actor1, never()).shutdown();
270     }
271
272     /**
273      * Tests doConfigure() where actors throw parameter validation and runtime exceptions.
274      */
275     @Test
276     public void testDoConfigureExceptions() {
277         makeValidException(actor1);
278         makeRuntimeException(actor2);
279         makeValidException(actor3);
280
281         service.configure(params);
282         assertTrue(service.isConfigured());
283     }
284
285     /**
286      * Tests doConfigure(). Arranges for the following:
287      * <ul>
288      * <li>one actor is configured, but has parameters</li>
289      * <li>another actor is configured, but has no parameters</li>
290      * <li>another actor has no parameters and is not configured</li>
291      * </ul>
292      */
293     @Test
294     public void testDoConfigureConfigure() {
295         // need mutable parameters
296         params = new TreeMap<>(params);
297
298         // configure one actor
299         actor1.configure(sub1);
300
301         // configure another and remove its parameters
302         actor2.configure(sub2);
303         params.remove(ACTOR2);
304
305         // create a new, unconfigured actor
306         ActorImpl actor5 = spy(new ActorImpl("UNCONFIGURED"));
307         service = makeService(actor1, actor2, actor3, actor4, actor5);
308
309         /*
310          * Configure it.
311          */
312         service.configure(params);
313         assertTrue(service.isConfigured());
314
315         // this should have been configured again
316         verify(actor1, times(2)).configure(sub1);
317
318         // no parameters, so this should not have been configured again
319         verify(actor2).configure(sub2);
320
321         // these were only configured once
322         verify(actor3).configure(sub3);
323         verify(actor4).configure(sub4);
324
325         // never configured
326         verify(actor5, never()).configure(any());
327         assertFalse(actor5.isConfigured());
328
329         // start and verify that all are started except for the last
330         service.start();
331         verify(actor1).start();
332         verify(actor2).start();
333         verify(actor3).start();
334         verify(actor4).start();
335         verify(actor5, never()).start();
336     }
337
338     /**
339      * Arranges for an actor to throw a validation exception when
340      * {@link Actor#configure(Map)} is invoked.
341      *
342      * @param actor actor of interest
343      */
344     private void makeValidException(Actor actor) {
345         ParameterValidationRuntimeException ex = new ParameterValidationRuntimeException(
346                         new ObjectValidationResult(actor.getName(), null, ValidationStatus.INVALID, "null"));
347         doThrow(ex).when(actor).configure(any());
348     }
349
350     /**
351      * Arranges for an actor to throw a runtime exception when
352      * {@link Actor#configure(Map)} is invoked.
353      *
354      * @param actor actor of interest
355      */
356     private void makeRuntimeException(Actor actor) {
357         IllegalStateException ex = new IllegalStateException(EXPECTED_EXCEPTION);
358         doThrow(ex).when(actor).configure(any());
359     }
360
361     @Test
362     public void testLoadActors() {
363         assertFalse(ActorService.getInstance().getActors().isEmpty());
364         assertNotNull(ActorService.getInstance().getActor("DummyActor"));
365     }
366
367     /**
368      * Makes an actor service whose {@link ActorService#loadActors()} method returns the
369      * given actors.
370      *
371      * @param actors actors to be returned
372      * @return a new actor service
373      */
374     private ActorService makeService(Actor... actors) {
375         return new ActorService() {
376             @Override
377             protected Iterable<Actor> loadActors() {
378                 return Arrays.asList(actors);
379             }
380         };
381     }
382 }