Java 17 Upgrade
[policy/models.git] / models-interactions / model-actors / actorServiceProvider / src / test / java / org / onap / policy / controlloop / actorserviceprovider / impl / ActorImplTest.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.impl;
22
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;
36
37 import java.util.Iterator;
38 import java.util.Map;
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;
49
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";
57
58     private MyOper oper1;
59     private MyOper oper2;
60     private MyOper oper3;
61     private MyOper oper4;
62
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;
68
69     private ActorImpl actor;
70
71
72     /**
73      * Initializes the fields, including a fully populated {@link #actor}.
74      */
75     @Before
76     public void setUp() {
77         oper1 = spy(new MyOper(OPER1));
78         oper2 = spy(new MyOper(OPER2));
79         oper3 = spy(new MyOper(OPER3));
80         oper4 = spy(new MyOper(OPER4));
81
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");
86
87         params = Map.of(ActorParams.OPERATIONS_FIELD, Map.of(OPER1, sub1, OPER2, sub2, OPER3, sub3, OPER4, sub4));
88
89         actor = makeActor(oper1, oper2, oper3, oper4);
90     }
91
92     @Test
93     public void testActorImpl_testGetName() {
94         assertEquals(ACTOR_NAME, actor.getName());
95         assertEquals(4, actor.getOperationNames().size());
96         assertEquals(0, actor.getSequenceNumber());
97     }
98
99     @Test
100     public void testDoStart() {
101         actor.configure(params);
102         assertEquals(4, actor.getOperationNames().size());
103
104         /*
105          * arrange for second operator to be unconfigured and the third operator to throw
106          * an exception
107          */
108         Iterator<Operator> iter = actor.getOperators().iterator();
109         iter.next();
110         when(iter.next().isConfigured()).thenReturn(false);
111         when(iter.next().start()).thenThrow(new IllegalStateException(EXPECTED_EXCEPTION));
112
113         /*
114          * Start the actor.
115          */
116         actor.start();
117         assertTrue(actor.isAlive());
118
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
124         iter.next();
125         verify(iter.next()).start();
126
127         // no other types of operations
128         verify(oper1, never()).stop();
129         verify(oper1, never()).shutdown();
130     }
131
132     @Test
133     public void testDoStop() {
134         actor.configure(params);
135         actor.start();
136         assertEquals(4, actor.getOperationNames().size());
137
138         // arrange for second operator to throw an exception
139         Iterator<Operator> iter = actor.getOperators().iterator();
140         iter.next();
141         when(iter.next().stop()).thenThrow(new IllegalStateException(EXPECTED_EXCEPTION));
142
143         /*
144          * Stop the actor.
145          */
146         actor.stop();
147         assertFalse(actor.isAlive());
148
149         iter = actor.getOperators().iterator();
150         verify(iter.next()).stop();
151         // this one threw an exception
152         iter.next();
153         verify(iter.next()).stop();
154         verify(iter.next()).stop();
155
156         // no additional types of operations
157         verify(oper1).configure(any());
158         verify(oper1).start();
159
160         // no other types of operation
161         verify(oper1, never()).shutdown();
162     }
163
164     @Test
165     public void testDoShutdown() {
166         actor.configure(params);
167         actor.start();
168         assertEquals(4, actor.getOperationNames().size());
169
170         // arrange for second operator to throw an exception
171         Iterator<Operator> iter = actor.getOperators().iterator();
172         iter.next();
173         doThrow(new IllegalStateException(EXPECTED_EXCEPTION)).when(iter.next()).shutdown();
174
175         /*
176          * Stop the actor.
177          */
178         actor.shutdown();
179         assertFalse(actor.isAlive());
180
181         iter = actor.getOperators().iterator();
182         verify(iter.next()).shutdown();
183         // this one threw an exception
184         iter.next();
185         verify(iter.next()).shutdown();
186         verify(iter.next()).shutdown();
187
188         // no additional types of operations
189         verify(oper1).configure(any());
190         verify(oper1).start();
191
192         // no other types of operation
193         verify(oper1, never()).stop();
194     }
195
196     @Test
197     public void testAddOperator() {
198         // cannot add operators if already configured
199         actor.configure(params);
200         assertThatIllegalStateException().isThrownBy(() -> actor.addOperator(oper1));
201
202         /*
203          * make an actor where operators two and four have names that are duplicates of
204          * the others
205          */
206         oper2 = spy(new MyOper(OPER1));
207         oper4 = spy(new MyOper(OPER3));
208
209         actor = makeActor(oper1, oper2, oper3, oper4);
210
211         assertEquals(2, actor.getOperationNames().size());
212
213         assertSame(oper1, actor.getOperator(OPER1));
214         assertSame(oper3, actor.getOperator(OPER3));
215     }
216
217     @Test
218     public void testGetOperator() {
219         assertSame(oper1, actor.getOperator(OPER1));
220         assertSame(oper3, actor.getOperator(OPER3));
221
222         assertThatIllegalArgumentException().isThrownBy(() -> actor.getOperator("unknown name"));
223     }
224
225     @Test
226     public void testGetOperators() {
227         // @formatter:off
228         assertEquals("[add, divide, multiply, subtract]",
229                         actor.getOperators().stream()
230                             .map(Operator::getName)
231                             .sorted()
232                             .collect(Collectors.toList())
233                             .toString());
234         // @formatter:on
235     }
236
237     @Test
238     public void testGetOperationNames() {
239         // @formatter:off
240         assertEquals("[add, divide, multiply, subtract]",
241                         actor.getOperationNames().stream()
242                             .sorted()
243                             .collect(Collectors.toList())
244                             .toString());
245         // @formatter:on
246     }
247
248     @Test
249     public void testDoConfigure() {
250         actor.configure(params);
251         assertTrue(actor.isConfigured());
252
253         verify(oper1).configure(sub1);
254         verify(oper2).configure(sub2);
255         verify(oper3).configure(sub3);
256         verify(oper4).configure(sub4);
257
258         // no other types of operations
259         verify(oper1, never()).start();
260         verify(oper1, never()).stop();
261         verify(oper1, never()).shutdown();
262     }
263
264     /**
265      * Tests doConfigure() where operators throw parameter validation and runtime
266      * exceptions.
267      */
268     @Test
269     public void testDoConfigureExceptions() {
270         makeValidException(oper1);
271         makeRuntimeException(oper2);
272         makeValidException(oper3);
273
274         actor.configure(params);
275         assertTrue(actor.isConfigured());
276     }
277
278     /**
279      * Tests doConfigure(). Arranges for the following:
280      * <ul>
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>
284      * </ul>
285      */
286     @Test
287     public void testDoConfigureConfigure() {
288         // configure one operator
289         oper1.configure(sub1);
290
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));
294
295         // create a new, unconfigured actor
296         Operator oper5 = spy(new MyOper("UNCONFIGURED"));
297         actor = makeActor(oper1, oper2, oper3, oper4, oper5);
298
299         /*
300          * Configure it.
301          */
302         actor.configure(params);
303         assertTrue(actor.isConfigured());
304
305         // this should have been configured again
306         verify(oper1, times(2)).configure(sub1);
307
308         // no parameters, so this should not have been configured again
309         verify(oper2).configure(sub2);
310
311         // these were only configured once
312         verify(oper3).configure(sub3);
313         verify(oper4).configure(sub4);
314
315         // never configured
316         verify(oper5, never()).configure(any());
317         assertFalse(oper5.isConfigured());
318
319         // start and verify that all are started except for the last
320         actor.start();
321         verify(oper1).start();
322         verify(oper2).start();
323         verify(oper3).start();
324         verify(oper4).start();
325         verify(oper5, never()).start();
326     }
327
328     /**
329      * Arranges for an operator to throw a validation exception when
330      * {@link Operator#configure(Map)} is invoked.
331      *
332      * @param oper operator of interest
333      */
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());
338     }
339
340     /**
341      * Arranges for an operator to throw a runtime exception when
342      * {@link Operator#configure(Map)} is invoked.
343      *
344      * @param oper operator of interest
345      */
346     private void makeRuntimeException(Operator oper) {
347         IllegalStateException ex = new IllegalStateException(EXPECTED_EXCEPTION);
348         doThrow(ex).when(oper).configure(any());
349     }
350
351     @Test
352     public void testMakeOperatorParameters() {
353         actor.configure(params);
354
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);
360     }
361
362     /**
363      * Makes an actor with the given operators.
364      *
365      * @param operators associated operators
366      * @return a new actor
367      */
368     private ActorImpl makeActor(Operator... operators) {
369         ActorImpl actor = new ActorImpl(ACTOR_NAME);
370
371         for (Operator oper : operators) {
372             actor.addOperator(oper);
373         }
374
375         return actor;
376     }
377
378     private static class MyOper extends OperatorPartial {
379
380         public MyOper(String name) {
381             super(ACTOR_NAME, name);
382         }
383
384         @Override
385         public Operation buildOperation(ControlLoopOperationParams params) {
386             return null;
387         }
388     }
389 }