2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2018 Ericsson. All rights reserved.
4 * Modifications Copyright (C) 2020-2022, 2024 Nordix Foundation.
5 * Modifications Copyright (C) 2020-2022 Bell Canada. All rights reserved.
6 * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
20 * SPDX-License-Identifier: Apache-2.0
21 * ============LICENSE_END=========================================================
24 package org.onap.policy.apex.service.engine.runtime.impl;
26 import static org.assertj.core.api.Assertions.assertThatThrownBy;
27 import static org.junit.jupiter.api.Assertions.assertEquals;
28 import static org.junit.jupiter.api.Assertions.assertFalse;
29 import static org.junit.jupiter.api.Assertions.assertNull;
30 import static org.junit.jupiter.api.Assertions.assertTrue;
31 import static org.junit.jupiter.api.Assertions.fail;
33 import java.io.ByteArrayInputStream;
34 import java.io.IOException;
35 import org.jetbrains.annotations.NotNull;
36 import org.junit.jupiter.api.AfterAll;
37 import org.junit.jupiter.api.BeforeAll;
38 import org.junit.jupiter.api.Test;
39 import org.onap.policy.apex.context.parameters.ContextParameterConstants;
40 import org.onap.policy.apex.context.parameters.ContextParameters;
41 import org.onap.policy.apex.context.parameters.DistributorParameters;
42 import org.onap.policy.apex.context.parameters.LockManagerParameters;
43 import org.onap.policy.apex.context.parameters.PersistorParameters;
44 import org.onap.policy.apex.context.parameters.SchemaParameters;
45 import org.onap.policy.apex.core.engine.EngineParameterConstants;
46 import org.onap.policy.apex.core.engine.EngineParameters;
47 import org.onap.policy.apex.core.engine.ExecutorParameters;
48 import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
49 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
50 import org.onap.policy.apex.model.basicmodel.handling.ApexModelException;
51 import org.onap.policy.apex.model.basicmodel.handling.ApexModelReader;
52 import org.onap.policy.apex.model.basicmodel.service.ModelService;
53 import org.onap.policy.apex.model.enginemodel.concepts.AxEngineState;
54 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
55 import org.onap.policy.apex.service.engine.event.ApexEvent;
56 import org.onap.policy.apex.service.parameters.engineservice.EngineServiceParameters;
57 import org.onap.policy.common.parameters.ParameterService;
58 import org.onap.policy.common.utils.resources.TextFileUtils;
61 * Test the engine service implementation.
63 class EngineServiceImplTest {
65 private static String simpleModelString;
66 private static String differentModelString;
67 private static AxPolicyModel simpleModel;
70 * Read the models into strings.
72 * @throws IOException on model reading errors
73 * @throws ApexModelException on model reading exceptions
76 static void readSimpleModel() throws IOException, ApexModelException {
77 simpleModelString = TextFileUtils.getTextFileAsString("src/test/resources/policymodels/SmallModel.json");
79 differentModelString =
80 TextFileUtils.getTextFileAsString("src/test/resources/policymodels/SmallModelDifferent.json");
82 final ApexModelReader<AxPolicyModel> modelReader = new ApexModelReader<>(AxPolicyModel.class);
83 simpleModel = modelReader.read(new ByteArrayInputStream(simpleModelString.getBytes()));
87 * Initialize default parameters.
90 static void initializeDefaultParameters() {
91 ParameterService.clear();
92 final SchemaParameters schemaParameters = new SchemaParameters();
93 schemaParameters.setName(ContextParameterConstants.SCHEMA_GROUP_NAME);
94 ParameterService.register(schemaParameters);
96 final ContextParameters contextParameters = new ContextParameters();
97 contextParameters.setName(ContextParameterConstants.MAIN_GROUP_NAME);
98 ParameterService.register(contextParameters);
100 final DistributorParameters distributorParameters = new DistributorParameters();
101 distributorParameters.setName(ContextParameterConstants.DISTRIBUTOR_GROUP_NAME);
102 ParameterService.register(distributorParameters);
104 final LockManagerParameters lockManagerParameters = new LockManagerParameters();
105 lockManagerParameters.setName(ContextParameterConstants.LOCKING_GROUP_NAME);
106 ParameterService.register(lockManagerParameters);
108 final PersistorParameters persistorParameters = new PersistorParameters();
109 persistorParameters.setName(ContextParameterConstants.PERSISTENCE_GROUP_NAME);
110 ParameterService.register(persistorParameters);
112 final EngineParameters engineParameters = new EngineParameters();
113 engineParameters.setName(EngineParameterConstants.MAIN_GROUP_NAME);
114 ExecutorParameters jsExecutorParameters = getExecutorParameters("JAVASCRIPT");
115 engineParameters.getExecutorParameterMap().put("JAVASCRIPT", jsExecutorParameters);
116 getExecutorParameters("MVEL");
117 engineParameters.getExecutorParameterMap().put("MVEL", jsExecutorParameters);
118 ParameterService.register(engineParameters);
121 private static @NotNull ExecutorParameters getExecutorParameters(String lang) {
122 ExecutorParameters jsExecutorParameters = new ExecutorParameters();
123 jsExecutorParameters.setName(lang);
125 .setTaskSelectionExecutorPluginClass("org.onap.policy.apex.service.engine.runtime.impl.DummyTse");
126 jsExecutorParameters.setTaskExecutorPluginClass("org.onap.policy.apex.service.engine.runtime.impl.DummyTe");
128 .setStateFinalizerExecutorPluginClass("org.onap.policy.apex.service.engine.runtime.impl.DummySfe");
129 return jsExecutorParameters;
133 * Teardown default parameters.
136 static void teardownDefaultParameters() {
137 ParameterService.deregister(ContextParameterConstants.SCHEMA_GROUP_NAME);
138 ParameterService.deregister(ContextParameterConstants.DISTRIBUTOR_GROUP_NAME);
139 ParameterService.deregister(ContextParameterConstants.LOCKING_GROUP_NAME);
140 ParameterService.deregister(ContextParameterConstants.PERSISTENCE_GROUP_NAME);
141 ParameterService.deregister(ContextParameterConstants.MAIN_GROUP_NAME);
142 ParameterService.deregister(EngineParameterConstants.MAIN_GROUP_NAME);
143 ModelService.clear();
146 private EngineServiceParameters makeConfig() {
147 EngineServiceParameters config = new EngineServiceParameters();
148 config.setInstanceCount(0);
150 config.setEngineKey(new AxArtifactKey("Engine", "0.0.1"));
151 config.setInstanceCount(1);
152 config.setPolicyModel("policyModelContent");
157 void testEngineServiceImplSanity() throws ApexException {
158 assertThatThrownBy(() -> EngineServiceImpl.create(null)).isInstanceOf(ApexException.class)
159 .hasMessage("Engine service configuration parameters are null");
161 EngineServiceParameters invalidConfig = new EngineServiceParameters();
162 invalidConfig.setInstanceCount(0);
163 assertThatThrownBy(() -> EngineServiceImpl.create(invalidConfig)).isInstanceOf(ApexException.class)
164 .hasMessageContaining("Invalid engine service configuration parameters");
166 EngineServiceParameters config = makeConfig();
167 EngineServiceImpl esImpl = EngineServiceImpl.create(config);
168 assertEquals("Engine:0.0.1", esImpl.getKey().getId());
170 esImpl.registerActionListener(null, null);
171 esImpl.registerActionListener("DummyListener", null);
172 esImpl.registerActionListener(null, new DummyApexEventListener());
174 esImpl.registerActionListener("DummyListener", new DummyApexEventListener());
175 assertThatThrownBy(() -> esImpl.deregisterActionListener(null))
176 .hasMessage("removeEventListener()<-Engine-0:0.0.1,STOPPED, listenerName is null");
178 esImpl.deregisterActionListener("DummyListener");
180 assertEquals(esImpl, esImpl.getEngineServiceEventInterface());
181 assertEquals(1, esImpl.getEngineKeys().size());
183 assertNull(esImpl.getApexModelKey());
185 assertThatThrownBy(() -> esImpl.getRuntimeInfo(null)).isInstanceOf(ApexException.class)
186 .hasMessage("engine key must be specified and may not be null");
188 assertThatThrownBy(() -> esImpl.getRuntimeInfo(new AxArtifactKey("DummyKey", "0.0.1")))
189 .isInstanceOf(ApexException.class).hasMessage("engine with key DummyKey:0.0.1 not found in engine service");
191 String runtimeInfo = esImpl.getRuntimeInfo(esImpl.getEngineKeys().iterator().next());
192 assertEquals("{\n \"TimeStamp\":", runtimeInfo.substring(0, 16));
194 assertEquals(AxEngineState.STOPPED, esImpl.getState());
196 assertThatThrownBy(() -> esImpl.getStatus(null)).isInstanceOf(ApexException.class)
197 .hasMessage("engine key must be specified and may not be null");
198 assertThatThrownBy(() -> esImpl.getStatus(new AxArtifactKey("DummyKey", "0.0.1")))
199 .isInstanceOf(ApexException.class).hasMessage("engine with key DummyKey:0.0.1 not found in engine service");
201 String status = esImpl.getStatus(esImpl.getEngineKeys().iterator().next());
202 assertTrue(status.contains("\"timestamp\":"));
204 assertFalse(esImpl.isStarted());
205 assertFalse(esImpl.isStarted(null));
206 assertFalse(esImpl.isStarted(new AxArtifactKey("DummyKey", "0.0.1")));
207 assertFalse(esImpl.isStarted(esImpl.getEngineKeys().iterator().next()));
208 assertTrue(esImpl.isStopped());
209 assertTrue(esImpl.isStopped(null));
210 assertTrue(esImpl.isStopped(new AxArtifactKey("DummyKey", "0.0.1")));
211 assertTrue(esImpl.isStopped(esImpl.getEngineKeys().iterator().next()));
215 void testEngineServiceExceptions() throws ApexException {
216 EngineServiceParameters config = makeConfig();
217 EngineServiceImpl esImpl = EngineServiceImpl.create(config);
218 assertThatThrownBy(() -> esImpl.start(null)).isInstanceOf(ApexException.class)
219 .hasMessage("engine key must be specified and may not be null");
221 assertThatThrownBy(() -> esImpl.start(new AxArtifactKey("DummyKey", "0.0.1"))).isInstanceOf(ApexException.class)
222 .hasMessage("engine with key DummyKey:0.0.1 not found in engine service");
224 assertThatThrownBy(() -> esImpl.start(esImpl.getEngineKeys().iterator().next()))
225 .isInstanceOf(ApexException.class).hasMessage("start()<-Engine-0:0.0.1,STOPPED, cannot start engine, "
226 + "engine has not been initialized, its model is not loaded");
228 assertThatThrownBy(esImpl::startAll).isInstanceOf(ApexException.class)
229 .hasMessage("start()<-Engine-0:0.0.1,STOPPED, cannot start engine, "
230 + "engine has not been initialized, its model is not loaded");
232 assertThatThrownBy(() -> esImpl.stop(null)).isInstanceOf(ApexException.class)
233 .hasMessage("engine key must be specified and may not be null");
235 assertThatThrownBy(() -> esImpl.stop(new AxArtifactKey("DummyKey", "0.0.1"))).isInstanceOf(ApexException.class)
236 .hasMessage("engine with key DummyKey:0.0.1 not found in engine service");
238 esImpl.stop(esImpl.getEngineKeys().iterator().next());
241 esImpl.sendEvent(null);
242 esImpl.sendEvent(new ApexEvent("SomeEvent", "0.0.1", "the.event.namespace", "EventSource", "EventTarget", ""));
244 esImpl.startPeriodicEvents(100000);
246 assertThatThrownBy(() -> esImpl.startPeriodicEvents(100000)).isInstanceOf(ApexException.class)
247 .hasMessage("Periodic event generation already running on engine Engine:0.0.1, ApexPeriodicEventGenerator "
248 + "[period=100000, firstEventTime=0, lastEventTime=0, eventCount=0]");
250 esImpl.stopPeriodicEvents();
252 assertThatThrownBy(esImpl::stopPeriodicEvents).isInstanceOf(ApexException.class)
253 .hasMessage("Periodic event generation not running on engine Engine:0.0.1");
255 assertThatThrownBy(() -> esImpl.clear(null)).isInstanceOf(ApexException.class)
256 .hasMessage("engine key must be specified and may not be null");
258 assertThatThrownBy(() -> esImpl.clear(new AxArtifactKey("DummyKey", "0.0.1"))).isInstanceOf(ApexException.class)
259 .hasMessage("engine with key DummyKey:0.0.1 not found in engine service");
260 esImpl.clear(esImpl.getEngineKeys().iterator().next());
263 assertThatThrownBy(() -> esImpl.updateModel(null, (String) null, true)).isInstanceOf(ApexException.class)
264 .hasMessage("engine key must be specified and may not be null");
266 assertThatThrownBy(() -> esImpl.updateModel(new AxArtifactKey("DummyKey", "0.0.1"), (String) null, true))
267 .isInstanceOf(ApexException.class)
268 .hasMessage("model for updating engine service with key DummyKey:0.0.1 is empty");
270 assertThatThrownBy(() -> esImpl.updateModel(new AxArtifactKey("DummyKey", "0.0.1"), "", true))
271 .isInstanceOf(ApexException.class)
272 .hasMessage("model for updating engine service with key DummyKey:0.0.1 is empty");
275 () -> esImpl.updateModel(new AxArtifactKey("DummyKey", "0.0.1"), "I am not an Apex model", true))
276 .isInstanceOf(ApexException.class)
277 .hasMessage("failed to unmarshal the apex model on engine service DummyKey:0.0.1");
279 assertThatThrownBy(() -> esImpl.updateModel(new AxArtifactKey("DummyKey", "0.0.1"), simpleModelString, true))
280 .isInstanceOf(ApexException.class)
281 .hasMessage("engine service key DummyKey:0.0.1 does not match the keyEngine:0.0.1 of this engine service");
283 assertThatThrownBy(() -> esImpl.updateModel(null, simpleModelString, true)).isInstanceOf(ApexException.class)
284 .hasMessage("engine key must be specified and may not be null");
286 assertThatThrownBy(() -> esImpl.updateModel(null, (AxPolicyModel) null, true)).isInstanceOf(ApexException.class)
287 .hasMessage("engine key must be specified and may not be null");
289 assertThatThrownBy(() -> esImpl.updateModel(new AxArtifactKey("DummyKey", "0.0.1"), (AxPolicyModel) null, true))
290 .isInstanceOf(ApexException.class)
291 .hasMessage("model for updating on engine service with key DummyKey:0.0.1 is null");
293 assertThatThrownBy(() -> esImpl.updateModel(new AxArtifactKey("DummyKey", "0.0.1"), simpleModel, true))
294 .isInstanceOf(ApexException.class)
295 .hasMessage("engine service key DummyKey:0.0.1 does not match the keyEngine:0.0.1 of this engine service");
299 void testApexImplModelWIthModel() throws ApexException {
300 EngineServiceParameters config = makeConfig();
301 EngineServiceImpl esImpl = EngineServiceImpl.create(config);
302 assertEquals("Engine:0.0.1", esImpl.getKey().getId());
305 esImpl.updateModel(config.getEngineKey(), simpleModelString, false);
306 } catch (ApexException apEx) {
307 fail("test should not throw an exception");
311 esImpl.updateModel(config.getEngineKey(), differentModelString, false);
312 fail("test should throw an exception");
313 } catch (ApexException apEx) {
314 assertEquals("apex model update failed, supplied model with key \"SmallModelDifferent:0.0.1\" is not a "
315 + "compatible model update " + "from the existing engine model with key \"SmallModel:0.0.1\"",
320 esImpl.updateModel(config.getEngineKey(), differentModelString, true);
321 } catch (ApexException apEx) {
322 fail("test should not throw an exception");
326 esImpl.updateModel(config.getEngineKey(), simpleModelString, true);
327 } catch (ApexException apEx) {
328 fail("test should not throw an exception");
331 String runtimeInfo = esImpl.getRuntimeInfo(esImpl.getEngineKeys().iterator().next());
332 assertEquals("{\n \"TimeStamp\":", runtimeInfo.substring(0, 16));
334 assertEquals(AxEngineState.EXECUTING, esImpl.getState());
336 String status = esImpl.getStatus(esImpl.getEngineKeys().iterator().next());
337 assertTrue(status.contains("\"timestamp\":"));
338 assertTrue(esImpl.isStarted());
339 assertTrue(esImpl.isStarted(esImpl.getEngineKeys().iterator().next()));
340 assertFalse(esImpl.isStopped());
341 assertFalse(esImpl.isStopped(esImpl.getEngineKeys().iterator().next()));
344 esImpl.start(esImpl.getEngineKeys().iterator().next());
345 fail("test should throw an exception");
346 } catch (ApexException apEx) {
347 assertEquals("apex engine for engine key Engine-0:0.0.1 is already running with state READY",
353 fail("test should throw an exception");
354 } catch (ApexException apEx) {
355 assertEquals("apex engine for engine key Engine-0:0.0.1 is already running with state READY",
360 esImpl.stop(esImpl.getEngineKeys().iterator().next());
361 } catch (ApexException apEx) {
362 fail("test should not throw an exception");
366 esImpl.start(esImpl.getEngineKeys().iterator().next());
367 } catch (ApexException apEx) {
368 fail("test should not throw an exception");
373 } catch (ApexException apEx) {
374 fail("test should not throw an exception");
379 } catch (ApexException apEx) {
380 fail("test should not throw an exception");
384 esImpl.sendEvent(new ApexEvent("SomeEvent", "0.0.1", "the.event.namespace", "EventSource", "EventTarget",
386 } catch (ApexException apEx) {
387 fail("test should not throw an exception");
390 assertPeriodicEvents(esImpl);
393 private static void assertPeriodicEvents(EngineServiceImpl esImpl) throws ApexException {
394 esImpl.startPeriodicEvents(100000);
397 esImpl.stopPeriodicEvents();
399 esImpl.startPeriodicEvents(100000);
401 esImpl.startPeriodicEvents(100000);
402 fail("test should throw an exception");
403 } catch (ApexException apEx) {
404 assertEquals("Periodic event generation already running on engine Engine:0.0.1, ApexPeriodicEventGenerator "
405 + "[period=100000, firstEventTime=0, lastEventTime=0, eventCount=0]", apEx.getMessage());
408 esImpl.stopPeriodicEvents();
410 esImpl.stopPeriodicEvents();
411 fail("test should throw an exception");
412 } catch (ApexException apEx) {
413 assertEquals("Periodic event generation not running on engine Engine:0.0.1", apEx.getMessage());
417 esImpl.clear(esImpl.getEngineKeys().iterator().next());
418 } catch (ApexException apEx) {
419 fail("test should not throw an exception");
424 } catch (ApexException apEx) {
425 fail("test should not throw an exception");