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;
38 import org.junit.AfterClass;
39 import org.junit.Before;
40 import org.junit.BeforeClass;
41 import org.junit.Test;
42 import org.mockito.Mock;
43 import org.mockito.Mockito;
44 import org.mockito.MockitoAnnotations;
45 import org.onap.policy.apex.context.parameters.ContextParameterConstants;
46 import org.onap.policy.apex.context.parameters.DistributorParameters;
47 import org.onap.policy.apex.context.parameters.LockManagerParameters;
48 import org.onap.policy.apex.context.parameters.PersistorParameters;
49 import org.onap.policy.apex.context.parameters.SchemaParameters;
50 import org.onap.policy.apex.core.engine.EngineParameterConstants;
51 import org.onap.policy.apex.core.engine.EngineParameters;
52 import org.onap.policy.apex.core.engine.context.ApexInternalContext;
53 import org.onap.policy.apex.core.engine.event.EnEvent;
54 import org.onap.policy.apex.core.engine.executor.StateMachineExecutor;
55 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
56 import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
57 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
58 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
59 import org.onap.policy.apex.model.basicmodel.service.ModelService;
60 import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
61 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
62 import org.onap.policy.apex.model.enginemodel.concepts.AxEngineState;
63 import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
64 import org.onap.policy.apex.model.eventmodel.concepts.AxEvents;
65 import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
66 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
67 import org.onap.policy.apex.model.policymodel.concepts.AxState;
68 import org.onap.policy.common.parameters.ParameterService;
71 * Test the engine implementation.
73 public class ApexEngineImplTest {
74 private AxPolicyModel policyModel;
75 private AxPolicyModel incompatiblePolicyModel;
76 private AxPolicyModel policyModelWithStates;
79 StateMachineHandler smHandlerMock;
85 public static void setup() {
86 ParameterService.register(new SchemaParameters());
87 ParameterService.register(new DistributorParameters());
88 ParameterService.register(new LockManagerParameters());
89 ParameterService.register(new PersistorParameters());
90 ParameterService.register(new EngineParameters());
97 public void initializeMocking() throws ApexException {
98 MockitoAnnotations.initMocks(this);
100 Mockito.doThrow(new StateMachineException("mocked state machine exception",
101 new IOException("nexted exception"))).when(smHandlerMock).execute(Mockito.anyObject());
105 * Create policy models.
108 public void createPolicyModels() {
109 AxArtifactKey modelKey = new AxArtifactKey("PolicyModel:0.0.1");
110 policyModel = new AxPolicyModel(modelKey);
112 AxArtifactKey schemaKey = new AxArtifactKey("Schema:0.0.1");
113 AxContextSchema schema = new AxContextSchema(schemaKey, "Java", "java.lang.String");
114 policyModel.getSchemas().getSchemasMap().put(schemaKey, schema);
116 AxArtifactKey albumKey = new AxArtifactKey("Album:0.0.1");
117 AxContextAlbum album = new AxContextAlbum(albumKey, "Policy", true, schemaKey);
119 policyModel.getAlbums().getAlbumsMap().put(albumKey, album);
121 AxEvents events = new AxEvents();
122 AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
123 AxEvent event = new AxEvent(eventKey, "event.name.space", "source", "target");
124 events.getEventMap().put(eventKey, event);
125 policyModel.setEvents(events);
127 AxArtifactKey incompatibleModelKey = new AxArtifactKey("IncompatiblePolicyModel:0.0.2");
128 incompatiblePolicyModel = new AxPolicyModel(incompatibleModelKey);
130 AxArtifactKey incompatibleSchemaKey = new AxArtifactKey("IncompatibleSchema:0.0.1");
131 AxContextSchema incompatibleSchema = new AxContextSchema(incompatibleSchemaKey, "Java", "java.lang.Integer");
132 incompatiblePolicyModel.getSchemas().getSchemasMap().put(incompatibleSchemaKey, incompatibleSchema);
134 AxContextAlbum incompatibleAlbum = new AxContextAlbum(albumKey, "Policy", true, incompatibleSchemaKey);
135 incompatiblePolicyModel.getAlbums().getAlbumsMap().put(albumKey, incompatibleAlbum);
137 AxArtifactKey modelKeyStates = new AxArtifactKey("PolicyModelStates:0.0.1");
138 policyModelWithStates = new AxPolicyModel(modelKeyStates);
139 policyModelWithStates.getSchemas().getSchemasMap().put(schemaKey, schema);
140 policyModelWithStates.getAlbums().getAlbumsMap().put(albumKey, album);
141 policyModelWithStates.setEvents(events);
143 AxPolicy policy0 = new AxPolicy(new AxArtifactKey("Policy0:0.0.1"));
144 AxState state0 = new AxState(new AxReferenceKey(policy0.getKey(), "state0"));
145 state0.setTrigger(eventKey);
146 policy0.getStateMap().put(state0.getKey().getLocalName(), state0);
147 policy0.setFirstState(state0.getKey().getLocalName());
149 policyModelWithStates.getPolicies().getPolicyMap().put(policy0.getKey(), policy0);
151 AxPolicy policy1 = new AxPolicy(new AxArtifactKey("Policy1:0.0.1"));
152 AxState state1 = new AxState(new AxReferenceKey(policy1.getKey(), "state1"));
153 state1.setTrigger(eventKey);
154 policy1.getStateMap().put(state1.getKey().getLocalName(), state1);
155 policy1.setFirstState(state1.getKey().getLocalName());
157 policyModelWithStates.getPolicies().getPolicyMap().put(policy1.getKey(), policy1);
161 * Clear registrations.
164 public static void teardown() {
165 ParameterService.deregister(ContextParameterConstants.SCHEMA_GROUP_NAME);
166 ParameterService.deregister(ContextParameterConstants.DISTRIBUTOR_GROUP_NAME);
167 ParameterService.deregister(ContextParameterConstants.LOCKING_GROUP_NAME);
168 ParameterService.deregister(ContextParameterConstants.PERSISTENCE_GROUP_NAME);
169 ParameterService.deregister(EngineParameterConstants.MAIN_GROUP_NAME);
173 public void testSanity() throws ApexException {
174 AxArtifactKey engineKey = new AxArtifactKey("Engine:0.0.1");
175 ApexEngineImpl engine = (ApexEngineImpl) new ApexEngineFactory().createApexEngine(engineKey);
176 assertNotNull(engine);
177 assertEquals(engineKey, engine.getKey());
179 assertThatThrownBy(() -> engine.start()).hasMessage("start()<-Engine:0.0.1,STOPPED, cannot start engine, "
180 + "engine has not been initialized, its model is not loaded");
182 assertThatThrownBy(() -> engine.stop())
183 .hasMessage("stop()<-Engine:0.0.1,STOPPED, cannot stop engine, " + "engine is already stopped");
185 assertEquals(AxEngineState.STOPPED, engine.getState());
186 assertEquals(0, engine.getEngineContext().size());
187 assertEquals(engineKey, engine.getEngineStatus().getKey());
188 assertNull(engine.getInternalContext());
192 assertThatThrownBy(() -> engine.addEventListener(null, null))
193 .hasMessage("addEventListener()<-Engine:0.0.1,STOPPED, listenerName is null");
195 assertThatThrownBy(() -> engine.addEventListener("myListener", null))
196 .hasMessage("addEventListener()<-Engine:0.0.1,STOPPED, listener is null");
198 assertThatThrownBy(() -> engine.removeEventListener(null))
199 .hasMessage("removeEventListener()<-Engine:0.0.1,STOPPED, listenerName is null");
201 engine.addEventListener("myListener", new DummyListener());
202 engine.removeEventListener("myListener");
204 assertNull(engine.createEvent(null));
206 assertFalse(engine.handleEvent(null));
208 assertThatThrownBy(() -> engine.updateModel(null, false))
209 .hasMessage("updateModel()<-Engine:0.0.1, Apex model is not defined, it has a null value");
211 engine.updateModel(policyModel, false);
213 // Force a context exception
214 ModelService.registerModel(AxPolicyModel.class, new AxPolicyModel());
215 assertThatThrownBy(() -> engine.updateModel(incompatiblePolicyModel, false))
216 .hasMessage("updateModel()<-Engine:0.0.1, error setting the context for engine \"Engine:0.0.1\"");
218 engine.updateModel(policyModel, false);
220 assertNotNull(engine.getInternalContext());
221 assertEquals(1, engine.getEngineContext().size());
224 assertEquals(AxEngineState.READY, engine.getState());
226 assertThatThrownBy(() -> engine.start())
227 .hasMessage("start()<-Engine:0.0.1,READY, cannot start engine, engine not in state STOPPED");
229 assertThatThrownBy(() -> engine.clear())
230 .hasMessage("clear()<-Engine:0.0.1,READY, cannot clear engine, engine is not stopped");
233 assertEquals(AxEngineState.STOPPED, engine.getState());
236 assertEquals(AxEngineState.STOPPED, engine.getState());
238 assertThatThrownBy(() -> engine.start()).hasMessage("start()<-Engine:0.0.1,STOPPED, cannot start engine, "
239 + "engine has not been initialized, its model is not loaded");
241 engine.updateModel(policyModel, false);
242 assertEquals(AxEngineState.STOPPED, engine.getState());
245 assertEquals(AxEngineState.READY, engine.getState());
247 assertNull(engine.createEvent(null));
249 AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
250 EnEvent event = engine.createEvent(eventKey);
251 assertEquals(eventKey, event.getKey());
253 assertTrue(engine.handleEvent(event));
254 assertEquals(AxEngineState.READY, engine.getState());
257 assertEquals(AxEngineState.STOPPED, engine.getState());
259 engine.addEventListener("myListener", new DummyListener());
262 assertEquals(AxEngineState.READY, engine.getState());
264 assertThatThrownBy(() -> engine.updateModel(policyModel, false)).hasMessage(
265 "updateModel()<-Engine:0.0.1, cannot update model, engine should be stopped but is in state READY");
267 assertTrue(engine.handleEvent(event));
268 assertEquals(AxEngineState.READY, engine.getState());
271 assertEquals(AxEngineState.STOPPED, engine.getState());
273 engine.addEventListener("badListener", new DummyEnEventListener());
276 assertEquals(AxEngineState.READY, engine.getState());
278 assertFalse(engine.handleEvent(event));
279 assertEquals(AxEngineState.READY, engine.getState());
281 assertEquals(AxEngineState.STOPPED, engine.getState());
283 engine.removeEventListener("badListener");
284 engine.addEventListener("slowListener", new DummySlowEnEventListener());
288 public void testState() throws InterruptedException, ApexException {
289 AxArtifactKey engineKey = new AxArtifactKey("Engine:0.0.1");
290 ApexEngineImpl engine = (ApexEngineImpl) new ApexEngineFactory().createApexEngine(engineKey);
291 assertNotNull(engine);
292 assertEquals(engineKey, engine.getKey());
294 engine.updateModel(policyModel, false);
295 assertEquals(AxEngineState.STOPPED, engine.getState());
297 DummySlowEnEventListener slowListener = new DummySlowEnEventListener();
298 engine.addEventListener("slowListener", slowListener);
301 assertEquals(AxEngineState.READY, engine.getState());
303 assertEquals(AxEngineState.READY, engine.getState());
305 AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
306 EnEvent event = engine.createEvent(eventKey);
307 assertEquals(eventKey, event.getKey());
309 // 1 second is less than the 3 second wait on engine stopping
310 slowListener.setWaitTime(1000);
314 assertTrue(engine.handleEvent(event));
315 assertEquals(AxEngineState.STOPPED, engine.getState());
318 await().atLeast(50, TimeUnit.MILLISECONDS).until(() -> engine.getState().equals(AxEngineState.EXECUTING));
319 assertEquals(AxEngineState.EXECUTING, engine.getState());
321 assertFalse(engine.handleEvent(event));
322 assertNotNull(engine.createEvent(eventKey));
326 assertEquals(AxEngineState.STOPPED, engine.getState());
327 } catch (ApexException ae) {
328 fail("test should not throw an exception");
333 assertEquals(AxEngineState.READY, engine.getState());
334 } catch (ApexException ae) {
335 fail("test should not throw an exception");
338 // 4 seconds is more than the 3 second wait on engine stopping
339 slowListener.setWaitTime(4000);
343 assertTrue(engine.handleEvent(event));
344 assertEquals(AxEngineState.STOPPED, engine.getState());
348 await().atLeast(50, TimeUnit.MILLISECONDS).until(() -> engine.getState().equals(AxEngineState.EXECUTING));
349 assertEquals(AxEngineState.EXECUTING, engine.getState());
352 assertEquals(AxEngineState.STOPPED, engine.getState());
353 fail("test should throw an exception");
354 } catch (ApexException ae) {
355 assertEquals("stop()<-Engine:0.0.1,STOPPED, error stopping engine, engine stop timed out", ae.getMessage());
360 assertEquals(AxEngineState.STOPPED, engine.getState());
361 } catch (ApexException e) {
362 fail("test should not throw an exception");
367 public void testStateMachineError() throws InterruptedException, IllegalArgumentException, IllegalAccessException,
368 NoSuchFieldException, SecurityException, ApexException {
370 AxArtifactKey engineKey = new AxArtifactKey("Engine:0.0.1");
371 ApexEngineImpl engine = (ApexEngineImpl) new ApexEngineFactory().createApexEngine(engineKey);
372 assertNotNull(engine);
373 assertEquals(engineKey, engine.getKey());
375 engine.updateModel(policyModel, false);
376 assertEquals(AxEngineState.STOPPED, engine.getState());
378 final Field smHandlerField = engine.getClass().getDeclaredField("stateMachineHandler");
379 smHandlerField.setAccessible(true);
380 smHandlerField.set(engine, smHandlerMock);
383 assertEquals(AxEngineState.READY, engine.getState());
385 assertEquals(AxEngineState.READY, engine.getState());
387 AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
388 EnEvent event = engine.createEvent(eventKey);
389 assertEquals(eventKey, event.getKey());
391 assertFalse(engine.handleEvent(event));
392 assertEquals(AxEngineState.READY, engine.getState());
396 assertEquals(AxEngineState.STOPPED, engine.getState());
397 } catch (ApexException ae) {
398 fail("test should not throw an exception");
402 Mockito.doThrow(new StateMachineException("mocked state machine exception",
403 new IOException("nexted exception"))).when(smHandlerMock).start();
406 fail("test should throw an exception");
407 } catch (ApexException ae) {
408 assertEquals("updateModel()<-Engine:0.0.1, error starting the engine state machines \"Engine:0.0.1\"",
412 assertEquals(AxEngineState.STOPPED, engine.getState());
416 assertEquals(AxEngineState.STOPPED, engine.getState());
417 } catch (ApexException e) {
418 fail("test should not throw an exception");
423 public void testStateMachineHandler() throws InterruptedException, IllegalArgumentException, IllegalAccessException,
424 NoSuchFieldException, SecurityException, ApexException {
425 AxArtifactKey engineKey = new AxArtifactKey("Engine:0.0.1");
426 ApexEngineImpl engine = (ApexEngineImpl) new ApexEngineFactory().createApexEngine(engineKey);
427 assertNotNull(engine);
428 assertEquals(engineKey, engine.getKey());
430 engine.updateModel(policyModelWithStates, false);
431 assertEquals(AxEngineState.STOPPED, engine.getState());
434 assertEquals(AxEngineState.READY, engine.getState());
436 AxArtifactKey eventKey = new AxArtifactKey("Event:0.0.1");
437 EnEvent event = engine.createEvent(eventKey);
438 assertEquals(eventKey, event.getKey());
441 assertEquals(AxEngineState.STOPPED, engine.getState());
443 assertEquals(AxEngineState.STOPPED, engine.getState());
446 assertEquals(AxEngineState.READY, engine.getState());
448 assertEquals(AxEngineState.READY, engine.getState());
450 // Can't work, state is not fully defined
451 assertFalse(engine.handleEvent(event));
452 assertEquals(AxEngineState.READY, engine.getState());
454 final Field smHandlerField = engine.getClass().getDeclaredField("stateMachineHandler");
455 smHandlerField.setAccessible(true);
456 StateMachineHandler smHandler = (StateMachineHandler) smHandlerField.get(engine);
458 final Field smExecutorMapField = smHandler.getClass().getDeclaredField("stateMachineExecutorMap");
459 smExecutorMapField.setAccessible(true);
460 @SuppressWarnings("unchecked")
461 HashMap<AxEvent, StateMachineExecutor> smExMap = (HashMap<AxEvent, StateMachineExecutor>) smExecutorMapField
464 assertEquals(1, smExMap.size());
465 DummySmExecutor dummyExecutor = new DummySmExecutor(null, event.getKey());
466 smExMap.put(event.getAxEvent(), dummyExecutor);
469 ApexInternalContext internalContext = new ApexInternalContext(policyModelWithStates);
470 dummyExecutor.setContext(null, null, internalContext);
471 } catch (Exception e) {
472 // Ignore this exception, we just need to set the internal context
477 assertEquals(AxEngineState.STOPPED, engine.getState());
478 } catch (ApexException ae) {
479 fail("test should not throw an exception");
484 fail("test should throw an exception");
485 } catch (ApexException ae) {
486 assertEquals("updateModel()<-Engine:0.0.1, error starting the engine state machines \"Engine:0.0.1\"",
490 assertEquals(AxEngineState.STOPPED, engine.getState());
494 assertEquals(AxEngineState.READY, engine.getState());
495 } catch (ApexException ae) {
496 fail("test should not throw an exception");
499 // Works, Dummy executor fakes event execution
500 assertTrue(engine.handleEvent(event));
501 assertEquals(AxEngineState.READY, engine.getState());
505 assertEquals(AxEngineState.STOPPED, engine.getState());
506 } catch (ApexException ae) {
507 fail("test should not throw an exception");
512 assertEquals(AxEngineState.STOPPED, engine.getState());
513 } catch (ApexException e) {
514 fail("test should not throw an exception");