Changes for checkstyle 8.32
[policy/apex-pdp.git] / core / core-engine / src / test / java / org / onap / policy / apex / core / engine / engine / impl / ApexEngineImplTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019-2020 Nordix Foundation.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.apex.core.engine.engine.impl;
23
24 import static org.assertj.core.api.Assertions.assertThatThrownBy;
25 import static org.awaitility.Awaitility.await;
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertFalse;
28 import static org.junit.Assert.assertNotNull;
29 import static org.junit.Assert.assertNull;
30 import static org.junit.Assert.assertTrue;
31 import static org.junit.Assert.fail;
32
33 import java.io.IOException;
34 import java.lang.reflect.Field;
35 import java.util.HashMap;
36 import java.util.concurrent.TimeUnit;
37 import org.junit.AfterClass;
38 import org.junit.Before;
39 import org.junit.BeforeClass;
40 import org.junit.Test;
41 import org.mockito.Mock;
42 import org.mockito.Mockito;
43 import org.mockito.MockitoAnnotations;
44 import org.onap.policy.apex.context.parameters.ContextParameterConstants;
45 import org.onap.policy.apex.context.parameters.DistributorParameters;
46 import org.onap.policy.apex.context.parameters.LockManagerParameters;
47 import org.onap.policy.apex.context.parameters.PersistorParameters;
48 import org.onap.policy.apex.context.parameters.SchemaParameters;
49 import org.onap.policy.apex.core.engine.EngineParameterConstants;
50 import org.onap.policy.apex.core.engine.EngineParameters;
51 import org.onap.policy.apex.core.engine.context.ApexInternalContext;
52 import org.onap.policy.apex.core.engine.event.EnEvent;
53 import org.onap.policy.apex.core.engine.executor.StateMachineExecutor;
54 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
55 import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
56 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
57 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
58 import org.onap.policy.apex.model.basicmodel.service.ModelService;
59 import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
60 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
61 import org.onap.policy.apex.model.enginemodel.concepts.AxEngineState;
62 import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
63 import org.onap.policy.apex.model.eventmodel.concepts.AxEvents;
64 import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
65 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
66 import org.onap.policy.apex.model.policymodel.concepts.AxState;
67 import org.onap.policy.common.parameters.ParameterService;
68
69 /**
70  * Test the engine implementation.
71  */
72 public class ApexEngineImplTest {
73     private AxPolicyModel policyModel;
74     private AxPolicyModel incompatiblePolicyModel;
75     private AxPolicyModel policyModelWithStates;
76
77     @Mock
78     StateMachineHandler smHandlerMock;
79
80     /**
81      * Set up services.
82      */
83     @BeforeClass
84     public static void setup() {
85         ParameterService.register(new SchemaParameters());
86         ParameterService.register(new DistributorParameters());
87         ParameterService.register(new LockManagerParameters());
88         ParameterService.register(new PersistorParameters());
89         ParameterService.register(new EngineParameters());
90     }
91
92     /**
93      * Set up mocking.
94      */
95     @Before
96     public void initializeMocking() throws ApexException {
97         MockitoAnnotations.initMocks(this);
98
99         Mockito.doThrow(new StateMachineException("mocked state machine exception",
100                         new IOException("nexted exception"))).when(smHandlerMock).execute(Mockito.anyObject());
101     }
102
103     /**
104      * Create policy models.
105      */
106     @Before
107     public void createPolicyModels() {
108         AxArtifactKey modelKey = new AxArtifactKey("PolicyModel:0.0.1");
109         policyModel = new AxPolicyModel(modelKey);
110
111         AxArtifactKey schemaKey = new AxArtifactKey("Schema:0.0.1");
112         AxContextSchema schema = new AxContextSchema(schemaKey, "Java", "java.lang.String");
113         policyModel.getSchemas().getSchemasMap().put(schemaKey, schema);
114
115         AxArtifactKey albumKey = new AxArtifactKey("Album:0.0.1");
116         AxContextAlbum album = new AxContextAlbum(albumKey, "Policy", true, schemaKey);
117
118         policyModel.getAlbums().getAlbumsMap().put(albumKey, album);
119
120         AxEvents events = new AxEvents();
121         AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
122         AxEvent event = new AxEvent(eventKey, "event.name.space", "source", "target");
123         events.getEventMap().put(eventKey, event);
124         policyModel.setEvents(events);
125
126         AxArtifactKey incompatibleModelKey = new AxArtifactKey("IncompatiblePolicyModel:0.0.2");
127         incompatiblePolicyModel = new AxPolicyModel(incompatibleModelKey);
128
129         AxArtifactKey incompatibleSchemaKey = new AxArtifactKey("IncompatibleSchema:0.0.1");
130         AxContextSchema incompatibleSchema = new AxContextSchema(incompatibleSchemaKey, "Java", "java.lang.Integer");
131         incompatiblePolicyModel.getSchemas().getSchemasMap().put(incompatibleSchemaKey, incompatibleSchema);
132
133         AxContextAlbum incompatibleAlbum = new AxContextAlbum(albumKey, "Policy", true, incompatibleSchemaKey);
134         incompatiblePolicyModel.getAlbums().getAlbumsMap().put(albumKey, incompatibleAlbum);
135
136         AxArtifactKey modelKeyStates = new AxArtifactKey("PolicyModelStates:0.0.1");
137         policyModelWithStates = new AxPolicyModel(modelKeyStates);
138         policyModelWithStates.getSchemas().getSchemasMap().put(schemaKey, schema);
139         policyModelWithStates.getAlbums().getAlbumsMap().put(albumKey, album);
140         policyModelWithStates.setEvents(events);
141
142         AxPolicy policy0 = new AxPolicy(new AxArtifactKey("Policy0:0.0.1"));
143         AxState state0 = new AxState(new AxReferenceKey(policy0.getKey(), "state0"));
144         state0.setTrigger(eventKey);
145         policy0.getStateMap().put(state0.getKey().getLocalName(), state0);
146         policy0.setFirstState(state0.getKey().getLocalName());
147
148         policyModelWithStates.getPolicies().getPolicyMap().put(policy0.getKey(), policy0);
149
150         AxPolicy policy1 = new AxPolicy(new AxArtifactKey("Policy1:0.0.1"));
151         AxState state1 = new AxState(new AxReferenceKey(policy1.getKey(), "state1"));
152         state1.setTrigger(eventKey);
153         policy1.getStateMap().put(state1.getKey().getLocalName(), state1);
154         policy1.setFirstState(state1.getKey().getLocalName());
155
156         policyModelWithStates.getPolicies().getPolicyMap().put(policy1.getKey(), policy1);
157     }
158
159     /**
160      * Clear registrations.
161      */
162     @AfterClass
163     public static void teardown() {
164         ParameterService.deregister(ContextParameterConstants.SCHEMA_GROUP_NAME);
165         ParameterService.deregister(ContextParameterConstants.DISTRIBUTOR_GROUP_NAME);
166         ParameterService.deregister(ContextParameterConstants.LOCKING_GROUP_NAME);
167         ParameterService.deregister(ContextParameterConstants.PERSISTENCE_GROUP_NAME);
168         ParameterService.deregister(EngineParameterConstants.MAIN_GROUP_NAME);
169     }
170
171     @Test
172     public void testSanity() throws ApexException {
173         AxArtifactKey engineKey = new AxArtifactKey("Engine:0.0.1");
174         ApexEngineImpl engine = (ApexEngineImpl) new ApexEngineFactory().createApexEngine(engineKey);
175         assertNotNull(engine);
176         assertEquals(engineKey, engine.getKey());
177
178         assertThatThrownBy(() -> engine.start()).hasMessage("start()<-Engine:0.0.1,STOPPED,  cannot start engine, "
179                             + "engine has not been initialized, its model is not loaded");
180
181         assertThatThrownBy(() -> engine.stop())
182             .hasMessage("stop()<-Engine:0.0.1,STOPPED, cannot stop engine, " + "engine is already stopped");
183
184         assertEquals(AxEngineState.STOPPED, engine.getState());
185         assertEquals(0, engine.getEngineContext().size());
186         assertEquals(engineKey, engine.getEngineStatus().getKey());
187         assertNull(engine.getInternalContext());
188
189         engine.clear();
190
191         assertThatThrownBy(() -> engine.addEventListener(null, null))
192             .hasMessage("addEventListener()<-Engine:0.0.1,STOPPED, listenerName is null");
193
194         assertThatThrownBy(() -> engine.addEventListener("myListener", null))
195             .hasMessage("addEventListener()<-Engine:0.0.1,STOPPED, listener is null");
196
197         assertThatThrownBy(() -> engine.removeEventListener(null))
198             .hasMessage("removeEventListener()<-Engine:0.0.1,STOPPED, listenerName is null");
199
200         engine.addEventListener("myListener", new DummyListener());
201         engine.removeEventListener("myListener");
202
203         assertNull(engine.createEvent(null));
204
205         assertFalse(engine.handleEvent(null));
206
207         assertThatThrownBy(() -> engine.updateModel(null, false))
208             .hasMessage("updateModel()<-Engine:0.0.1, Apex model is not defined, it has a null value");
209
210         engine.updateModel(policyModel, false);
211
212         // Force a context exception
213         ModelService.registerModel(AxPolicyModel.class, new AxPolicyModel());
214         assertThatThrownBy(() -> engine.updateModel(incompatiblePolicyModel, false))
215             .hasMessage("updateModel()<-Engine:0.0.1, error setting the context for engine \"Engine:0.0.1\"");
216
217         engine.updateModel(policyModel, false);
218
219         assertNotNull(engine.getInternalContext());
220         assertEquals(1, engine.getEngineContext().size());
221
222         engine.start();
223         assertEquals(AxEngineState.READY, engine.getState());
224
225         assertThatThrownBy(() -> engine.start())
226             .hasMessage("start()<-Engine:0.0.1,READY, cannot start engine, engine not in state STOPPED");
227
228         assertThatThrownBy(() -> engine.clear())
229             .hasMessage("clear()<-Engine:0.0.1,READY, cannot clear engine, engine is not stopped");
230
231         engine.stop();
232         assertEquals(AxEngineState.STOPPED, engine.getState());
233
234         engine.clear();
235         assertEquals(AxEngineState.STOPPED, engine.getState());
236
237         assertThatThrownBy(() -> engine.start()).hasMessage("start()<-Engine:0.0.1,STOPPED,  cannot start engine, "
238             + "engine has not been initialized, its model is not loaded");
239
240         engine.updateModel(policyModel, false);
241         assertEquals(AxEngineState.STOPPED, engine.getState());
242
243         engine.start();
244         assertEquals(AxEngineState.READY, engine.getState());
245
246         assertNull(engine.createEvent(null));
247
248         AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
249         EnEvent event = engine.createEvent(eventKey);
250         assertEquals(eventKey, event.getKey());
251
252         assertTrue(engine.handleEvent(event));
253         assertEquals(AxEngineState.READY, engine.getState());
254
255         engine.stop();
256         assertEquals(AxEngineState.STOPPED, engine.getState());
257
258         engine.addEventListener("myListener", new DummyListener());
259
260         engine.start();
261         assertEquals(AxEngineState.READY, engine.getState());
262
263         assertThatThrownBy(() -> engine.updateModel(policyModel, false)).hasMessage(
264             "updateModel()<-Engine:0.0.1, cannot update model, engine should be stopped but is in state READY");
265
266         assertTrue(engine.handleEvent(event));
267         assertEquals(AxEngineState.READY, engine.getState());
268
269         engine.stop();
270         assertEquals(AxEngineState.STOPPED, engine.getState());
271
272         engine.addEventListener("badListener", new DummyEnEventListener());
273
274         engine.start();
275         assertEquals(AxEngineState.READY, engine.getState());
276
277         assertFalse(engine.handleEvent(event));
278         assertEquals(AxEngineState.READY, engine.getState());
279         engine.stop();
280         assertEquals(AxEngineState.STOPPED, engine.getState());
281
282         engine.removeEventListener("badListener");
283         engine.addEventListener("slowListener", new DummySlowEnEventListener());
284     }
285
286     @Test
287     public void testState() throws InterruptedException, ApexException {
288         AxArtifactKey engineKey = new AxArtifactKey("Engine:0.0.1");
289         ApexEngineImpl engine = (ApexEngineImpl) new ApexEngineFactory().createApexEngine(engineKey);
290         assertNotNull(engine);
291         assertEquals(engineKey, engine.getKey());
292
293         engine.updateModel(policyModel, false);
294         assertEquals(AxEngineState.STOPPED, engine.getState());
295
296         DummySlowEnEventListener slowListener = new DummySlowEnEventListener();
297         engine.addEventListener("slowListener", slowListener);
298
299         engine.start();
300         assertEquals(AxEngineState.READY, engine.getState());
301
302         assertEquals(AxEngineState.READY, engine.getState());
303
304         AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
305         EnEvent event = engine.createEvent(eventKey);
306         assertEquals(eventKey, event.getKey());
307
308         // 1 second is less than the 3 second wait on engine stopping
309         slowListener.setWaitTime(1000);
310         (new Thread() {
311             @Override
312             public void run() {
313                 assertTrue(engine.handleEvent(event));
314                 assertEquals(AxEngineState.STOPPED, engine.getState());
315             }
316         }).start();
317         await().atLeast(50, TimeUnit.MILLISECONDS).until(() -> engine.getState().equals(AxEngineState.EXECUTING));
318         assertEquals(AxEngineState.EXECUTING, engine.getState());
319
320         assertFalse(engine.handleEvent(event));
321         assertNotNull(engine.createEvent(eventKey));
322
323         try {
324             engine.stop();
325             assertEquals(AxEngineState.STOPPED, engine.getState());
326         } catch (ApexException ae) {
327             fail("test should not throw an exception");
328         }
329
330         try {
331             engine.start();
332             assertEquals(AxEngineState.READY, engine.getState());
333         } catch (ApexException ae) {
334             fail("test should not throw an exception");
335         }
336
337         // 4 seconds is more than the 3 second wait on engine stopping
338         slowListener.setWaitTime(4000);
339         (new Thread() {
340             @Override
341             public void run() {
342                 assertTrue(engine.handleEvent(event));
343                 assertEquals(AxEngineState.STOPPED, engine.getState());
344             }
345         }).start();
346
347         await().atLeast(50, TimeUnit.MILLISECONDS).until(() -> engine.getState().equals(AxEngineState.EXECUTING));
348         assertEquals(AxEngineState.EXECUTING, engine.getState());
349         try {
350             engine.stop();
351             assertEquals(AxEngineState.STOPPED, engine.getState());
352             fail("test should throw an exception");
353         } catch (ApexException ae) {
354             assertEquals("stop()<-Engine:0.0.1,STOPPED, error stopping engine, engine stop timed out", ae.getMessage());
355         }
356
357         try {
358             engine.clear();
359             assertEquals(AxEngineState.STOPPED, engine.getState());
360         } catch (ApexException e) {
361             fail("test should not throw an exception");
362         }
363     }
364
365     @Test
366     public void testStateMachineError() throws InterruptedException, IllegalArgumentException, IllegalAccessException,
367                     NoSuchFieldException, SecurityException, ApexException {
368
369         AxArtifactKey engineKey = new AxArtifactKey("Engine:0.0.1");
370         ApexEngineImpl engine = (ApexEngineImpl) new ApexEngineFactory().createApexEngine(engineKey);
371         assertNotNull(engine);
372         assertEquals(engineKey, engine.getKey());
373
374         engine.updateModel(policyModel, false);
375         assertEquals(AxEngineState.STOPPED, engine.getState());
376
377         final Field smHandlerField = engine.getClass().getDeclaredField("stateMachineHandler");
378         smHandlerField.setAccessible(true);
379         smHandlerField.set(engine, smHandlerMock);
380
381         engine.start();
382         assertEquals(AxEngineState.READY, engine.getState());
383
384         assertEquals(AxEngineState.READY, engine.getState());
385
386         AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
387         EnEvent event = engine.createEvent(eventKey);
388         assertEquals(eventKey, event.getKey());
389
390         assertFalse(engine.handleEvent(event));
391         assertEquals(AxEngineState.READY, engine.getState());
392
393         try {
394             engine.stop();
395             assertEquals(AxEngineState.STOPPED, engine.getState());
396         } catch (ApexException ae) {
397             fail("test should not throw an exception");
398         }
399
400         try {
401             Mockito.doThrow(new StateMachineException("mocked state machine exception",
402                             new IOException("nexted exception"))).when(smHandlerMock).start();
403
404             engine.start();
405             fail("test should throw an exception");
406         } catch (ApexException ae) {
407             assertEquals("updateModel()<-Engine:0.0.1, error starting the engine state machines \"Engine:0.0.1\"",
408                             ae.getMessage());
409         }
410
411         assertEquals(AxEngineState.STOPPED, engine.getState());
412
413         try {
414             engine.clear();
415             assertEquals(AxEngineState.STOPPED, engine.getState());
416         } catch (ApexException e) {
417             fail("test should not throw an exception");
418         }
419     }
420
421     @Test
422     public void testStateMachineHandler() throws InterruptedException, IllegalArgumentException, IllegalAccessException,
423                     NoSuchFieldException, SecurityException, ApexException {
424         AxArtifactKey engineKey = new AxArtifactKey("Engine:0.0.1");
425         ApexEngineImpl engine = (ApexEngineImpl) new ApexEngineFactory().createApexEngine(engineKey);
426         assertNotNull(engine);
427         assertEquals(engineKey, engine.getKey());
428
429         engine.updateModel(policyModelWithStates, false);
430         assertEquals(AxEngineState.STOPPED, engine.getState());
431
432         engine.start();
433         assertEquals(AxEngineState.READY, engine.getState());
434
435         AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
436         EnEvent event = engine.createEvent(eventKey);
437         assertEquals(eventKey, event.getKey());
438
439         engine.stop();
440         assertEquals(AxEngineState.STOPPED, engine.getState());
441
442         assertEquals(AxEngineState.STOPPED, engine.getState());
443
444         engine.start();
445         assertEquals(AxEngineState.READY, engine.getState());
446
447         assertEquals(AxEngineState.READY, engine.getState());
448
449         // Can't work, state is not fully defined
450         assertFalse(engine.handleEvent(event));
451         assertEquals(AxEngineState.READY, engine.getState());
452
453         final Field smHandlerField = engine.getClass().getDeclaredField("stateMachineHandler");
454         smHandlerField.setAccessible(true);
455         StateMachineHandler smHandler = (StateMachineHandler) smHandlerField.get(engine);
456
457         final Field smExecutorMapField = smHandler.getClass().getDeclaredField("stateMachineExecutorMap");
458         smExecutorMapField.setAccessible(true);
459         @SuppressWarnings("unchecked")
460         HashMap<AxEvent, StateMachineExecutor> smExMap = (HashMap<AxEvent, StateMachineExecutor>) smExecutorMapField
461                         .get(smHandler);
462
463         assertEquals(1, smExMap.size());
464         DummySmExecutor dummyExecutor = new DummySmExecutor(null, event.getKey());
465         smExMap.put(event.getAxEvent(), dummyExecutor);
466         
467         try {
468             ApexInternalContext internalContext = new ApexInternalContext(policyModelWithStates);
469             dummyExecutor.setContext(null, null, internalContext);
470         } catch (Exception e) {
471             // Ignore this exception, we just need to set the internal context
472         }
473
474         try {
475             engine.stop();
476             assertEquals(AxEngineState.STOPPED, engine.getState());
477         } catch (ApexException ae) {
478             fail("test should not throw an exception");
479         }
480         
481         try {
482             engine.start();
483             fail("test should throw an exception");
484         } catch (ApexException ae) {
485             assertEquals("updateModel()<-Engine:0.0.1, error starting the engine state machines \"Engine:0.0.1\"",
486                             ae.getMessage());
487         }
488
489         assertEquals(AxEngineState.STOPPED, engine.getState());
490
491         try {
492             engine.start();
493             assertEquals(AxEngineState.READY, engine.getState());
494         } catch (ApexException ae) {
495             fail("test should not throw an exception");
496         }
497
498         // Works, Dummy executor fakes event execution
499         assertTrue(engine.handleEvent(event));
500         assertEquals(AxEngineState.READY, engine.getState());
501
502         try {
503             engine.stop();
504             assertEquals(AxEngineState.STOPPED, engine.getState());
505         } catch (ApexException ae) {
506             fail("test should not throw an exception");
507         }
508
509         try {
510             engine.clear();
511             assertEquals(AxEngineState.STOPPED, engine.getState());
512         } catch (ApexException e) {
513             fail("test should not throw an exception");
514         }
515     }
516 }