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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.apex.core.engine.engine.impl;
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;
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;
70 * Test the engine implementation.
72 public class ApexEngineImplTest {
73 private AxPolicyModel policyModel;
74 private AxPolicyModel incompatiblePolicyModel;
75 private AxPolicyModel policyModelWithStates;
78 StateMachineHandler smHandlerMock;
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());
96 public void initializeMocking() throws ApexException {
97 MockitoAnnotations.initMocks(this);
99 Mockito.doThrow(new StateMachineException("mocked state machine exception",
100 new IOException("nexted exception"))).when(smHandlerMock).execute(Mockito.anyObject());
104 * Create policy models.
107 public void createPolicyModels() {
108 AxArtifactKey modelKey = new AxArtifactKey("PolicyModel:0.0.1");
109 policyModel = new AxPolicyModel(modelKey);
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);
115 AxArtifactKey albumKey = new AxArtifactKey("Album:0.0.1");
116 AxContextAlbum album = new AxContextAlbum(albumKey, "Policy", true, schemaKey);
118 policyModel.getAlbums().getAlbumsMap().put(albumKey, album);
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);
126 AxArtifactKey incompatibleModelKey = new AxArtifactKey("IncompatiblePolicyModel:0.0.2");
127 incompatiblePolicyModel = new AxPolicyModel(incompatibleModelKey);
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);
133 AxContextAlbum incompatibleAlbum = new AxContextAlbum(albumKey, "Policy", true, incompatibleSchemaKey);
134 incompatiblePolicyModel.getAlbums().getAlbumsMap().put(albumKey, incompatibleAlbum);
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);
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());
148 policyModelWithStates.getPolicies().getPolicyMap().put(policy0.getKey(), policy0);
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());
156 policyModelWithStates.getPolicies().getPolicyMap().put(policy1.getKey(), policy1);
160 * Clear registrations.
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);
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());
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");
181 assertThatThrownBy(() -> engine.stop())
182 .hasMessage("stop()<-Engine:0.0.1,STOPPED, cannot stop engine, " + "engine is already stopped");
184 assertEquals(AxEngineState.STOPPED, engine.getState());
185 assertEquals(0, engine.getEngineContext().size());
186 assertEquals(engineKey, engine.getEngineStatus().getKey());
187 assertNull(engine.getInternalContext());
191 assertThatThrownBy(() -> engine.addEventListener(null, null))
192 .hasMessage("addEventListener()<-Engine:0.0.1,STOPPED, listenerName is null");
194 assertThatThrownBy(() -> engine.addEventListener("myListener", null))
195 .hasMessage("addEventListener()<-Engine:0.0.1,STOPPED, listener is null");
197 assertThatThrownBy(() -> engine.removeEventListener(null))
198 .hasMessage("removeEventListener()<-Engine:0.0.1,STOPPED, listenerName is null");
200 engine.addEventListener("myListener", new DummyListener());
201 engine.removeEventListener("myListener");
203 assertNull(engine.createEvent(null));
205 assertFalse(engine.handleEvent(null));
207 assertThatThrownBy(() -> engine.updateModel(null, false))
208 .hasMessage("updateModel()<-Engine:0.0.1, Apex model is not defined, it has a null value");
210 engine.updateModel(policyModel, false);
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\"");
217 engine.updateModel(policyModel, false);
219 assertNotNull(engine.getInternalContext());
220 assertEquals(1, engine.getEngineContext().size());
223 assertEquals(AxEngineState.READY, engine.getState());
225 assertThatThrownBy(() -> engine.start())
226 .hasMessage("start()<-Engine:0.0.1,READY, cannot start engine, engine not in state STOPPED");
228 assertThatThrownBy(() -> engine.clear())
229 .hasMessage("clear()<-Engine:0.0.1,READY, cannot clear engine, engine is not stopped");
232 assertEquals(AxEngineState.STOPPED, engine.getState());
235 assertEquals(AxEngineState.STOPPED, engine.getState());
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");
240 engine.updateModel(policyModel, false);
241 assertEquals(AxEngineState.STOPPED, engine.getState());
244 assertEquals(AxEngineState.READY, engine.getState());
246 assertNull(engine.createEvent(null));
248 AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
249 EnEvent event = engine.createEvent(eventKey);
250 assertEquals(eventKey, event.getKey());
252 assertTrue(engine.handleEvent(event));
253 assertEquals(AxEngineState.READY, engine.getState());
256 assertEquals(AxEngineState.STOPPED, engine.getState());
258 engine.addEventListener("myListener", new DummyListener());
261 assertEquals(AxEngineState.READY, engine.getState());
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");
266 assertTrue(engine.handleEvent(event));
267 assertEquals(AxEngineState.READY, engine.getState());
270 assertEquals(AxEngineState.STOPPED, engine.getState());
272 engine.addEventListener("badListener", new DummyEnEventListener());
275 assertEquals(AxEngineState.READY, engine.getState());
277 assertFalse(engine.handleEvent(event));
278 assertEquals(AxEngineState.READY, engine.getState());
280 assertEquals(AxEngineState.STOPPED, engine.getState());
282 engine.removeEventListener("badListener");
283 engine.addEventListener("slowListener", new DummySlowEnEventListener());
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());
293 engine.updateModel(policyModel, false);
294 assertEquals(AxEngineState.STOPPED, engine.getState());
296 DummySlowEnEventListener slowListener = new DummySlowEnEventListener();
297 engine.addEventListener("slowListener", slowListener);
300 assertEquals(AxEngineState.READY, engine.getState());
302 assertEquals(AxEngineState.READY, engine.getState());
304 AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
305 EnEvent event = engine.createEvent(eventKey);
306 assertEquals(eventKey, event.getKey());
308 // 1 second is less than the 3 second wait on engine stopping
309 slowListener.setWaitTime(1000);
313 assertTrue(engine.handleEvent(event));
314 assertEquals(AxEngineState.STOPPED, engine.getState());
317 await().atLeast(50, TimeUnit.MILLISECONDS).until(() -> engine.getState().equals(AxEngineState.EXECUTING));
318 assertEquals(AxEngineState.EXECUTING, engine.getState());
320 assertFalse(engine.handleEvent(event));
321 assertNotNull(engine.createEvent(eventKey));
325 assertEquals(AxEngineState.STOPPED, engine.getState());
326 } catch (ApexException ae) {
327 fail("test should not throw an exception");
332 assertEquals(AxEngineState.READY, engine.getState());
333 } catch (ApexException ae) {
334 fail("test should not throw an exception");
337 // 4 seconds is more than the 3 second wait on engine stopping
338 slowListener.setWaitTime(4000);
342 assertTrue(engine.handleEvent(event));
343 assertEquals(AxEngineState.STOPPED, engine.getState());
347 await().atLeast(50, TimeUnit.MILLISECONDS).until(() -> engine.getState().equals(AxEngineState.EXECUTING));
348 assertEquals(AxEngineState.EXECUTING, engine.getState());
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());
359 assertEquals(AxEngineState.STOPPED, engine.getState());
360 } catch (ApexException e) {
361 fail("test should not throw an exception");
366 public void testStateMachineError() throws InterruptedException, IllegalArgumentException, IllegalAccessException,
367 NoSuchFieldException, SecurityException, ApexException {
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());
374 engine.updateModel(policyModel, false);
375 assertEquals(AxEngineState.STOPPED, engine.getState());
377 final Field smHandlerField = engine.getClass().getDeclaredField("stateMachineHandler");
378 smHandlerField.setAccessible(true);
379 smHandlerField.set(engine, smHandlerMock);
382 assertEquals(AxEngineState.READY, engine.getState());
384 assertEquals(AxEngineState.READY, engine.getState());
386 AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
387 EnEvent event = engine.createEvent(eventKey);
388 assertEquals(eventKey, event.getKey());
390 assertFalse(engine.handleEvent(event));
391 assertEquals(AxEngineState.READY, engine.getState());
395 assertEquals(AxEngineState.STOPPED, engine.getState());
396 } catch (ApexException ae) {
397 fail("test should not throw an exception");
401 Mockito.doThrow(new StateMachineException("mocked state machine exception",
402 new IOException("nexted exception"))).when(smHandlerMock).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\"",
411 assertEquals(AxEngineState.STOPPED, engine.getState());
415 assertEquals(AxEngineState.STOPPED, engine.getState());
416 } catch (ApexException e) {
417 fail("test should not throw an exception");
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());
429 engine.updateModel(policyModelWithStates, false);
430 assertEquals(AxEngineState.STOPPED, engine.getState());
433 assertEquals(AxEngineState.READY, engine.getState());
435 AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
436 EnEvent event = engine.createEvent(eventKey);
437 assertEquals(eventKey, event.getKey());
440 assertEquals(AxEngineState.STOPPED, engine.getState());
442 assertEquals(AxEngineState.STOPPED, engine.getState());
445 assertEquals(AxEngineState.READY, engine.getState());
447 assertEquals(AxEngineState.READY, engine.getState());
449 // Can't work, state is not fully defined
450 assertFalse(engine.handleEvent(event));
451 assertEquals(AxEngineState.READY, engine.getState());
453 final Field smHandlerField = engine.getClass().getDeclaredField("stateMachineHandler");
454 smHandlerField.setAccessible(true);
455 StateMachineHandler smHandler = (StateMachineHandler) smHandlerField.get(engine);
457 final Field smExecutorMapField = smHandler.getClass().getDeclaredField("stateMachineExecutorMap");
458 smExecutorMapField.setAccessible(true);
459 @SuppressWarnings("unchecked")
460 HashMap<AxEvent, StateMachineExecutor> smExMap = (HashMap<AxEvent, StateMachineExecutor>) smExecutorMapField
463 assertEquals(1, smExMap.size());
464 DummySmExecutor dummyExecutor = new DummySmExecutor(null, event.getKey());
465 smExMap.put(event.getAxEvent(), dummyExecutor);
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
476 assertEquals(AxEngineState.STOPPED, engine.getState());
477 } catch (ApexException ae) {
478 fail("test should not throw an exception");
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\"",
489 assertEquals(AxEngineState.STOPPED, engine.getState());
493 assertEquals(AxEngineState.READY, engine.getState());
494 } catch (ApexException ae) {
495 fail("test should not throw an exception");
498 // Works, Dummy executor fakes event execution
499 assertTrue(engine.handleEvent(event));
500 assertEquals(AxEngineState.READY, engine.getState());
504 assertEquals(AxEngineState.STOPPED, engine.getState());
505 } catch (ApexException ae) {
506 fail("test should not throw an exception");
511 assertEquals(AxEngineState.STOPPED, engine.getState());
512 } catch (ApexException e) {
513 fail("test should not throw an exception");