caba093ce2c492b83af03ee7bf84c1abdc58098a
[policy/apex-pdp.git] /
1 /*-
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
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  * SPDX-License-Identifier: Apache-2.0
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.policy.apex.service.engine.runtime.impl;
25
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;
32
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;
59
60 /**
61  * Test the engine service implementation.
62  */
63 class EngineServiceImplTest {
64
65     private static String simpleModelString;
66     private static String differentModelString;
67     private static AxPolicyModel simpleModel;
68
69     /**
70      * Read the models into strings.
71      *
72      * @throws IOException on model reading errors
73      * @throws ApexModelException on model reading exceptions
74      */
75     @BeforeAll
76     static void readSimpleModel() throws IOException, ApexModelException {
77         simpleModelString = TextFileUtils.getTextFileAsString("src/test/resources/policymodels/SmallModel.json");
78
79         differentModelString =
80             TextFileUtils.getTextFileAsString("src/test/resources/policymodels/SmallModelDifferent.json");
81
82         final ApexModelReader<AxPolicyModel> modelReader = new ApexModelReader<>(AxPolicyModel.class);
83         simpleModel = modelReader.read(new ByteArrayInputStream(simpleModelString.getBytes()));
84     }
85
86     /**
87      * Initialize default parameters.
88      */
89     @BeforeAll
90     static void initializeDefaultParameters() {
91         ParameterService.clear();
92         final SchemaParameters schemaParameters = new SchemaParameters();
93         schemaParameters.setName(ContextParameterConstants.SCHEMA_GROUP_NAME);
94         ParameterService.register(schemaParameters);
95
96         final ContextParameters contextParameters = new ContextParameters();
97         contextParameters.setName(ContextParameterConstants.MAIN_GROUP_NAME);
98         ParameterService.register(contextParameters);
99
100         final DistributorParameters distributorParameters = new DistributorParameters();
101         distributorParameters.setName(ContextParameterConstants.DISTRIBUTOR_GROUP_NAME);
102         ParameterService.register(distributorParameters);
103
104         final LockManagerParameters lockManagerParameters = new LockManagerParameters();
105         lockManagerParameters.setName(ContextParameterConstants.LOCKING_GROUP_NAME);
106         ParameterService.register(lockManagerParameters);
107
108         final PersistorParameters persistorParameters = new PersistorParameters();
109         persistorParameters.setName(ContextParameterConstants.PERSISTENCE_GROUP_NAME);
110         ParameterService.register(persistorParameters);
111
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);
119     }
120
121     private static @NotNull ExecutorParameters getExecutorParameters(String lang) {
122         ExecutorParameters jsExecutorParameters = new ExecutorParameters();
123         jsExecutorParameters.setName(lang);
124         jsExecutorParameters
125             .setTaskSelectionExecutorPluginClass("org.onap.policy.apex.service.engine.runtime.impl.DummyTse");
126         jsExecutorParameters.setTaskExecutorPluginClass("org.onap.policy.apex.service.engine.runtime.impl.DummyTe");
127         jsExecutorParameters
128             .setStateFinalizerExecutorPluginClass("org.onap.policy.apex.service.engine.runtime.impl.DummySfe");
129         return jsExecutorParameters;
130     }
131
132     /**
133      * Teardown default parameters.
134      */
135     @AfterAll
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();
144     }
145
146     private EngineServiceParameters makeConfig() {
147         EngineServiceParameters config = new EngineServiceParameters();
148         config.setInstanceCount(0);
149         config.setId(123);
150         config.setEngineKey(new AxArtifactKey("Engine", "0.0.1"));
151         config.setInstanceCount(1);
152         config.setPolicyModel("policyModelContent");
153         return config;
154     }
155
156     @Test
157     void testEngineServiceImplSanity() throws ApexException {
158         assertThatThrownBy(() -> EngineServiceImpl.create(null)).isInstanceOf(ApexException.class)
159             .hasMessage("Engine service configuration parameters are null");
160
161         EngineServiceParameters invalidConfig = new EngineServiceParameters();
162         invalidConfig.setInstanceCount(0);
163         assertThatThrownBy(() -> EngineServiceImpl.create(invalidConfig)).isInstanceOf(ApexException.class)
164             .hasMessageContaining("Invalid engine service configuration parameters");
165
166         EngineServiceParameters config = makeConfig();
167         EngineServiceImpl esImpl = EngineServiceImpl.create(config);
168         assertEquals("Engine:0.0.1", esImpl.getKey().getId());
169
170         esImpl.registerActionListener(null, null);
171         esImpl.registerActionListener("DummyListener", null);
172         esImpl.registerActionListener(null, new DummyApexEventListener());
173
174         esImpl.registerActionListener("DummyListener", new DummyApexEventListener());
175         assertThatThrownBy(() -> esImpl.deregisterActionListener(null))
176             .hasMessage("removeEventListener()<-Engine-0:0.0.1,STOPPED, listenerName is null");
177
178         esImpl.deregisterActionListener("DummyListener");
179
180         assertEquals(esImpl, esImpl.getEngineServiceEventInterface());
181         assertEquals(1, esImpl.getEngineKeys().size());
182
183         assertNull(esImpl.getApexModelKey());
184
185         assertThatThrownBy(() -> esImpl.getRuntimeInfo(null)).isInstanceOf(ApexException.class)
186             .hasMessage("engine key must be specified and may not be null");
187
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");
190
191         String runtimeInfo = esImpl.getRuntimeInfo(esImpl.getEngineKeys().iterator().next());
192         assertEquals("{\n  \"TimeStamp\":", runtimeInfo.substring(0, 16));
193
194         assertEquals(AxEngineState.STOPPED, esImpl.getState());
195
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");
200
201         String status = esImpl.getStatus(esImpl.getEngineKeys().iterator().next());
202         assertTrue(status.contains("\"timestamp\":"));
203
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()));
212     }
213
214     @Test
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");
220
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");
223
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");
227
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");
231
232         assertThatThrownBy(() -> esImpl.stop(null)).isInstanceOf(ApexException.class)
233             .hasMessage("engine key must be specified and may not be null");
234
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");
237
238         esImpl.stop(esImpl.getEngineKeys().iterator().next());
239
240         esImpl.stop();
241         esImpl.sendEvent(null);
242         esImpl.sendEvent(new ApexEvent("SomeEvent", "0.0.1", "the.event.namespace", "EventSource", "EventTarget", ""));
243
244         esImpl.startPeriodicEvents(100000);
245
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]");
249
250         esImpl.stopPeriodicEvents();
251
252         assertThatThrownBy(esImpl::stopPeriodicEvents).isInstanceOf(ApexException.class)
253             .hasMessage("Periodic event generation not running on engine Engine:0.0.1");
254
255         assertThatThrownBy(() -> esImpl.clear(null)).isInstanceOf(ApexException.class)
256             .hasMessage("engine key must be specified and may not be null");
257
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());
261         esImpl.clear();
262
263         assertThatThrownBy(() -> esImpl.updateModel(null, (String) null, true)).isInstanceOf(ApexException.class)
264             .hasMessage("engine key must be specified and may not be null");
265
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");
269
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");
273
274         assertThatThrownBy(
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");
278
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");
282
283         assertThatThrownBy(() -> esImpl.updateModel(null, simpleModelString, true)).isInstanceOf(ApexException.class)
284             .hasMessage("engine key must be specified and may not be null");
285
286         assertThatThrownBy(() -> esImpl.updateModel(null, (AxPolicyModel) null, true)).isInstanceOf(ApexException.class)
287             .hasMessage("engine key must be specified and may not be null");
288
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");
292
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");
296     }
297
298     @Test
299     void testApexImplModelWIthModel() throws ApexException {
300         EngineServiceParameters config = makeConfig();
301         EngineServiceImpl esImpl = EngineServiceImpl.create(config);
302         assertEquals("Engine:0.0.1", esImpl.getKey().getId());
303
304         try {
305             esImpl.updateModel(config.getEngineKey(), simpleModelString, false);
306         } catch (ApexException apEx) {
307             fail("test should not throw an exception");
308         }
309
310         try {
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\"",
316                     apEx.getMessage());
317         }
318
319         try {
320             esImpl.updateModel(config.getEngineKey(), differentModelString, true);
321         } catch (ApexException apEx) {
322             fail("test should not throw an exception");
323         }
324
325         try {
326             esImpl.updateModel(config.getEngineKey(), simpleModelString, true);
327         } catch (ApexException apEx) {
328             fail("test should not throw an exception");
329         }
330
331         String runtimeInfo = esImpl.getRuntimeInfo(esImpl.getEngineKeys().iterator().next());
332         assertEquals("{\n  \"TimeStamp\":", runtimeInfo.substring(0, 16));
333
334         assertEquals(AxEngineState.EXECUTING, esImpl.getState());
335
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()));
342
343         try {
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",
348                     apEx.getMessage());
349         }
350
351         try {
352             esImpl.startAll();
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",
356                     apEx.getMessage());
357         }
358
359         try {
360             esImpl.stop(esImpl.getEngineKeys().iterator().next());
361         } catch (ApexException apEx) {
362             fail("test should not throw an exception");
363         }
364
365         try {
366             esImpl.start(esImpl.getEngineKeys().iterator().next());
367         } catch (ApexException apEx) {
368             fail("test should not throw an exception");
369         }
370
371         try {
372             esImpl.stop();
373         } catch (ApexException apEx) {
374             fail("test should not throw an exception");
375         }
376
377         try {
378             esImpl.startAll();
379         } catch (ApexException apEx) {
380             fail("test should not throw an exception");
381         }
382
383         try {
384             esImpl.sendEvent(new ApexEvent("SomeEvent", "0.0.1", "the.event.namespace", "EventSource", "EventTarget",
385                     ""));
386         } catch (ApexException apEx) {
387             fail("test should not throw an exception");
388         }
389
390         assertPeriodicEvents(esImpl);
391     }
392
393     private static void assertPeriodicEvents(EngineServiceImpl esImpl) throws ApexException {
394         esImpl.startPeriodicEvents(100000);
395         esImpl.stop();
396         esImpl.startAll();
397         esImpl.stopPeriodicEvents();
398
399         esImpl.startPeriodicEvents(100000);
400         try {
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());
406         }
407
408         esImpl.stopPeriodicEvents();
409         try {
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());
414         }
415
416         try {
417             esImpl.clear(esImpl.getEngineKeys().iterator().next());
418         } catch (ApexException apEx) {
419             fail("test should not throw an exception");
420         }
421
422         try {
423             esImpl.clear();
424         } catch (ApexException apEx) {
425             fail("test should not throw an exception");
426         }
427     }
428 }