5d91bd2b3d2b3379635ef30c3793b937e973a4fa
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2020 Nordix Foundation.
5  *  Modifications Copyright (C) 2021 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.core.engine.executor;
25
26 import static org.assertj.core.api.Assertions.assertThatThrownBy;
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertNotNull;
29 import static org.junit.Assert.assertNull;
30 import static org.junit.Assert.assertTrue;
31
32 import java.util.Collection;
33 import java.util.LinkedHashMap;
34 import java.util.Map;
35 import org.junit.After;
36 import org.junit.Before;
37 import org.junit.Test;
38 import org.mockito.Mock;
39 import org.mockito.Mockito;
40 import org.mockito.MockitoAnnotations;
41 import org.onap.policy.apex.context.ContextException;
42 import org.onap.policy.apex.context.parameters.SchemaParameters;
43 import org.onap.policy.apex.core.engine.ExecutorParameters;
44 import org.onap.policy.apex.core.engine.context.ApexInternalContext;
45 import org.onap.policy.apex.core.engine.event.EnEvent;
46 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
47 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
48 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
49 import org.onap.policy.apex.model.basicmodel.service.ModelService;
50 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
51 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchemas;
52 import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
53 import org.onap.policy.apex.model.eventmodel.concepts.AxEvents;
54 import org.onap.policy.apex.model.eventmodel.concepts.AxField;
55 import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
56 import org.onap.policy.apex.model.policymodel.concepts.AxState;
57 import org.onap.policy.apex.model.policymodel.concepts.AxStateFinalizerLogic;
58 import org.onap.policy.apex.model.policymodel.concepts.AxStateOutput;
59 import org.onap.policy.apex.model.policymodel.concepts.AxStateTaskOutputType;
60 import org.onap.policy.apex.model.policymodel.concepts.AxStateTaskReference;
61 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
62 import org.onap.policy.apex.model.policymodel.concepts.AxTasks;
63 import org.onap.policy.common.parameters.ParameterService;
64
65 /**
66  * Test task executor.
67  */
68 public class StateMachineExecutorTest {
69     @Mock
70     private ApexInternalContext internalContextMock;
71
72     @Mock
73     private Executor<EnEvent, Collection<EnEvent>, AxPolicy, ApexInternalContext> nextExecutorMock;
74
75     @Mock
76     private ExecutorFactory executorFactoryMock;
77
78     @Mock
79     private EnEvent incomingEventMock;
80
81     private AxPolicy axPolicy = new AxPolicy();
82
83     private DummyTaskSelectExecutor dummyTsle;
84
85     private DummyStateFinalizerExecutor dummySfle;
86
87     /**
88      * Set up mocking.
89      */
90     @Before
91     public void startMocking() {
92         MockitoAnnotations.initMocks(this);
93
94         axPolicy.setKey(new AxArtifactKey("Policy:0.0.1"));
95
96         AxReferenceKey state0Key = new AxReferenceKey(axPolicy.getKey(), "state0");
97         AxState state0 = new AxState(state0Key);
98
99         AxReferenceKey state1Key = new AxReferenceKey(axPolicy.getKey(), "state1");
100         AxState state1 = new AxState(state1Key);
101
102         axPolicy.getStateMap().put("State0", state0);
103         axPolicy.getStateMap().put("State1", state1);
104         axPolicy.setFirstState("state0");
105
106         AxArtifactKey event0Key = new AxArtifactKey("Event0:0.0.1");
107         AxEvent event0 = new AxEvent(event0Key, "a.name.space", "source", "target");
108         AxArtifactKey event1Key = new AxArtifactKey("Event1:0.0.1");
109         AxEvent event1 = new AxEvent(event1Key, "a.name.space", "source", "target");
110         AxArtifactKey event2Key = new AxArtifactKey("Event2:0.0.1");
111         AxEvent event2 = new AxEvent(event2Key, "a.name.space", "source", "target");
112         AxEvents events = new AxEvents();
113         events.getEventMap().put(event0Key, event0);
114         events.getEventMap().put(event1Key, event1);
115         events.getEventMap().put(event2Key, event2);
116         ModelService.registerModel(AxEvents.class, events);
117
118         AxReferenceKey fieldKey = new AxReferenceKey("Event1:0.0.1:event:Field0");
119         AxArtifactKey stringSchemaKey = new AxArtifactKey("StringSchema:0.0.1");
120         AxContextSchema stringSchema = new AxContextSchema(stringSchemaKey, "Java", "java.lang.String");
121         AxContextSchemas schemas = new AxContextSchemas();
122         schemas.getSchemasMap().put(stringSchemaKey, stringSchema);
123         ModelService.registerModel(AxContextSchemas.class, schemas);
124
125         AxField event1Field0Definition = new AxField(fieldKey, stringSchemaKey);
126         event1.getParameterMap().put("Event1Field0", event1Field0Definition);
127
128         event0.getParameterMap().put("Event1Field0", event1Field0Definition);
129         event0.getParameterMap().put("UnusedField", event1Field0Definition);
130
131         Mockito.doReturn(event0Key).when(incomingEventMock).getKey();
132         Mockito.doReturn(event0).when(incomingEventMock).getAxEvent();
133
134         state0.setTrigger(event0Key);
135         state1.setTrigger(event1Key);
136
137         AxArtifactKey task0Key = new AxArtifactKey("task0:0.0.1");
138         AxTask task0 = new AxTask(task0Key);
139
140         AxArtifactKey task1Key = new AxArtifactKey("task1:0.0.1");
141         AxTask task1 = new AxTask(task1Key);
142
143         AxTasks tasks = new AxTasks();
144         tasks.getTaskMap().put(task0Key, task0);
145         tasks.getTaskMap().put(task1Key, task1);
146         ModelService.registerModel(AxTasks.class, tasks);
147
148         ParameterService.register(new SchemaParameters());
149
150         AxReferenceKey stateOutput0Key = new AxReferenceKey("Policy:0.0.1:state0:stateOutput0");
151         AxStateOutput stateOutput0 = new AxStateOutput(stateOutput0Key, event1Key, state1.getKey());
152
153         state0.getStateOutputs().put(stateOutput0Key.getLocalName(), stateOutput0);
154
155         AxReferenceKey stateOutput1Key = new AxReferenceKey("Policy:0.0.1:state0:stateOutput1");
156         AxStateOutput stateOutput1 = new AxStateOutput(stateOutput1Key, event2Key, AxReferenceKey.getNullKey());
157
158         state1.getStateOutputs().put(stateOutput1Key.getLocalName(), stateOutput1);
159
160         AxReferenceKey str0Key = new AxReferenceKey("Policy:0.0.1:state0:str0");
161         AxStateTaskReference str0 = new AxStateTaskReference(str0Key, AxStateTaskOutputType.DIRECT, stateOutput0Key);
162         state0.getTaskReferences().put(task0Key, str0);
163
164         AxReferenceKey sflKey = new AxReferenceKey("Policy:0.0.1:state1:sfl");
165         AxStateFinalizerLogic sfl = new AxStateFinalizerLogic(sflKey, "Java", "State fianlizer logic");
166         state1.getStateFinalizerLogicMap().put("sfl", sfl);
167
168         AxReferenceKey str1Key = new AxReferenceKey("Policy:0.0.1:state1:str1");
169         AxStateTaskReference str1 = new AxStateTaskReference(str1Key, AxStateTaskOutputType.LOGIC, sflKey);
170         state1.getTaskReferences().put(task1Key, str1);
171
172         Mockito.doReturn(new DummyTaskExecutor(true)).when(executorFactoryMock).getTaskExecutor(Mockito.anyObject(),
173             Mockito.anyObject(), Mockito.anyObject());
174
175         dummyTsle = new DummyTaskSelectExecutor(true);
176         Mockito.doReturn(dummyTsle).when(executorFactoryMock).getTaskSelectionExecutor(Mockito.anyObject(),
177             Mockito.anyObject(), Mockito.anyObject());
178
179         dummySfle = new DummyStateFinalizerExecutor(true);
180         Mockito.doReturn(dummySfle).when(executorFactoryMock).getStateFinalizerExecutor(Mockito.anyObject(),
181             Mockito.anyObject(), Mockito.anyObject());
182     }
183
184     @After
185     public void cleardown() {
186         ParameterService.clear();
187         ModelService.clear();
188     }
189
190     @Test
191     public void testStateMachineExecutor() throws StateMachineException, ContextException {
192         StateMachineExecutor executor =
193             new StateMachineExecutor(executorFactoryMock, new AxArtifactKey("OwnerKey:0.0.1"));
194
195         assertThatThrownBy(() -> executor.execute(0, null, incomingEventMock))
196             .hasMessage("no states defined on state machine");
197         executor.setContext(null, axPolicy, internalContextMock);
198         assertEquals("Policy:0.0.1", executor.getKey().getId());
199         assertNull(executor.getParent());
200         assertEquals(internalContextMock, executor.getContext());
201         assertNull(executor.getNext());
202         assertNull(executor.getIncoming());
203         assertTrue(executor.getOutgoing().isEmpty());
204         assertEquals(axPolicy, executor.getSubject());
205
206         executor.setParameters(new ExecutorParameters());
207         executor.setNext(nextExecutorMock);
208         assertEquals(nextExecutorMock, executor.getNext());
209         executor.setNext(null);
210         assertNull(executor.getNext());
211
212         assertThatThrownBy(() -> executor.executePre(0, null, null))
213             .hasMessage("execution pre work not implemented on class");
214         assertThatThrownBy(() -> executor.executePost(false))
215             .hasMessage("execution post work not implemented on class");
216         assertThatThrownBy(executor::prepare)
217             .isInstanceOf(NullPointerException.class);
218         axPolicy.setFirstState("BadState");
219         executor.setContext(null, axPolicy, internalContextMock);
220         assertThatThrownBy(() -> executor.execute(0, null, incomingEventMock))
221             .hasMessage("first state not defined on state machine");
222         axPolicy.setFirstState("state0");
223         executor.setContext(null, axPolicy, internalContextMock);
224         executor.execute(0, null, incomingEventMock);
225
226         DummyTaskSelectExecutor.setTaskNo(0);
227         executor.execute(0, null, incomingEventMock);
228
229         AxReferenceKey badStateKey = new AxReferenceKey("Policy:0.0.1:PName:BadState");
230         axPolicy.getStateMap().get("State1").getStateOutputs().get("stateOutput1").setNextState(badStateKey);
231         DummyTaskSelectExecutor.setTaskNo(0);
232         assertThatThrownBy(() -> executor.execute(0, null, incomingEventMock))
233             .hasMessage("state execution failed, next state \"Policy:0.0.1:PName:BadState\" not found");
234         axPolicy.getStateMap().get("State1").getStateOutputs().get("stateOutput1")
235             .setNextState(AxReferenceKey.getNullKey());
236         DummyTaskSelectExecutor.setTaskNo(0);
237         executor.execute(0, null, incomingEventMock);
238
239         axPolicy.getStateMap().get("State1").setTrigger(new AxArtifactKey("BadTrigger:0.0.1"));
240         DummyTaskSelectExecutor.setTaskNo(0);
241         assertThatThrownBy(() -> executor.execute(0, null, incomingEventMock))
242             .hasMessage("incoming event \"Event1:0.0.1\" does not match trigger \"BadTrigger:0.0.1\" "
243                 + "of state \"Policy:0.0.1:NULL:state1\"");
244         axPolicy.getStateMap().get("State1").setTrigger(new AxArtifactKey("Event1:0.0.1"));
245         DummyTaskSelectExecutor.setTaskNo(0);
246         executor.execute(0, null, incomingEventMock);
247
248         AxStateFinalizerLogic savedSfl = axPolicy.getStateMap().get("State1").getStateFinalizerLogicMap().get("sfl");
249         axPolicy.getStateMap().get("State1").getStateFinalizerLogicMap().put("sfl", null);
250         assertThatThrownBy(() -> executor.setContext(null, axPolicy, internalContextMock))
251             .hasMessage("state finalizer logic on task reference "
252                 + "\"AxStateTaskReference:(stateKey=AxReferenceKey:(parentKeyName=Policy,"
253                 + "parentKeyVersion=0.0.1,parentLocalName=state1,localName=str1),"
254                 + "outputType=LOGIC,output=AxReferenceKey:(parentKeyName=Policy,parentKeyVersion=0.0.1,"
255                 + "parentLocalName=state1,localName=sfl))\" on state \"Policy:0.0.1:NULL:state1\" " + "does not exist");
256         axPolicy.getStateMap().get("State1").getStateFinalizerLogicMap().put("sfl", savedSfl);
257         executor.setContext(null, axPolicy, internalContextMock);
258
259         DummyTaskSelectExecutor.setTaskNo(0);
260         executor.execute(0, null, incomingEventMock);
261
262         AxArtifactKey task1Key = new AxArtifactKey("task1:0.0.1");
263         axPolicy.getStateMap().get("State1").getTaskReferences().get(task1Key)
264             .setStateTaskOutputType(AxStateTaskOutputType.UNDEFINED);
265         assertThatThrownBy(() -> executor.setContext(null, axPolicy, internalContextMock))
266             .hasMessage("invalid state output type on task reference \"AxStateTaskReference:(stateKey"
267                 + "=AxReferenceKey:(parentKeyName=Policy,parentKeyVersion=0.0.1,parentLocalName=state1,localName=str1),"
268                 + "outputType=UNDEFINED,output=AxReferenceKey:(parentKeyName=Policy,"
269                 + "parentKeyVersion=0.0.1,parentLocalName=state1,localName=sfl))\" "
270                 + "on state \"Policy:0.0.1:NULL:state1\"");
271         axPolicy.getStateMap().get("State1").getTaskReferences().get(task1Key)
272             .setStateTaskOutputType(AxStateTaskOutputType.LOGIC);
273         executor.setContext(null, axPolicy, internalContextMock);
274
275         DummyTaskSelectExecutor.setTaskNo(0);
276         executor.execute(0, null, incomingEventMock);
277
278         DummyTaskSelectExecutor.setTaskNo(0);
279         dummySfle.setReturnBad(true);
280         assertThatThrownBy(() -> executor.execute(0, null, incomingEventMock))
281             .hasMessage("State execution of state \"Policy:0.0.1:NULL:state1\" on task \"task1:0.0.1\""
282                 + " failed: state output definition for state output \"stateOutputBad\" not found for "
283                 + "state \"Policy:0.0.1:NULL:state1\"");
284         DummyTaskSelectExecutor.setTaskNo(0);
285         dummySfle.setReturnBad(false);
286         executor.execute(0, null, incomingEventMock);
287
288         assertThatThrownBy(executor::cleanUp)
289             .hasMessage("cleanUp() not implemented on class");
290     }
291
292     @Test
293     public void testStateOutput() throws StateMachineException {
294         final StateOutput output =
295             new StateOutput(axPolicy.getStateMap().get("State0").getStateOutputs().get("stateOutput0"));
296         assertNotNull(output);
297
298         assertEquals("stateOutput0", output.getStateOutputDefinition().getKey().getLocalName());
299
300         assertThatThrownBy(() -> output.setEventFields(null, null))
301             .hasMessage("incomingFieldDefinitionMap may not be null");
302         Map<String, AxEvent> incomingFieldDefinitionMap = new LinkedHashMap<>();
303         assertThatThrownBy(() -> output.setEventFields(incomingFieldDefinitionMap, null))
304             .hasMessage("eventFieldMaps may not be null");
305         Map<String, Map<String, Object>> eventFieldMaps = new LinkedHashMap<>();
306         output.setEventFields(incomingFieldDefinitionMap, eventFieldMaps);
307         AxEvent event = new AxEvent(new AxArtifactKey("Event1", "0.0.1"));
308         event.setParameterMap(Map.of("key", new AxField()));
309         incomingFieldDefinitionMap.put("Event1", event);
310         eventFieldMaps.put("Event1", Map.of("key2", "value"));
311         assertThatThrownBy(() -> output.setEventFields(incomingFieldDefinitionMap, eventFieldMaps))
312             .hasMessage("field definitions and values do not match for event Event1:0.0.1\n[key]\n[key2]");
313
314         eventFieldMaps.put("Event1", Map.of("key", "value"));
315         assertThatThrownBy(() -> output.setEventFields(incomingFieldDefinitionMap, eventFieldMaps))
316             .hasMessage("field \"key\" does not exist on event \"Event1:0.0.1\"");
317
318         incomingFieldDefinitionMap.clear();
319         eventFieldMaps.clear();
320         AxArtifactKey stringSchemaKey = new AxArtifactKey("StringSchema:0.0.1");
321         AxReferenceKey fieldKey = new AxReferenceKey("Event1:0.0.1:event:Field0");
322         AxField event1Field0Definition = new AxField(fieldKey, stringSchemaKey);
323         event.setParameterMap(Map.of("Event1Field0", event1Field0Definition));
324         incomingFieldDefinitionMap.put("Event1", event);
325         eventFieldMaps.put("Event1", Map.of("Event1Field0", "Value"));
326         output.setEventFields(incomingFieldDefinitionMap, eventFieldMaps);
327
328         StateOutput outputCopy = new StateOutput(axPolicy.getStateMap().get("State0")
329                 .getStateOutputs().get("stateOutput0"));
330
331         EnEvent incomingEvent = new EnEvent(new AxArtifactKey("Event0:0.0.1"));
332         outputCopy.copyUnsetFields(incomingEvent);
333         incomingEvent.put("Event1Field0", "Hello");
334         outputCopy.copyUnsetFields(incomingEvent);
335     }
336 }