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