3b16f465bd9c1796a3918385cbdf6095841bce34
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2021, 2023 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2023 Nordix Foundation.
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  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.controlloop.eventmanager;
23
24 import static org.assertj.core.api.Assertions.assertThat;
25 import static org.assertj.core.api.Assertions.assertThatCode;
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.assertNotNull;
29 import static org.junit.jupiter.api.Assertions.assertNull;
30 import static org.junit.jupiter.api.Assertions.assertSame;
31 import static org.mockito.ArgumentMatchers.any;
32 import static org.mockito.Mockito.mock;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
35
36 import java.time.Instant;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.TreeMap;
41 import java.util.UUID;
42 import java.util.concurrent.ExecutorService;
43 import java.util.concurrent.atomic.AtomicReference;
44 import org.drools.core.WorkingMemory;
45 import org.drools.core.common.InternalFactHandle;
46 import org.junit.jupiter.api.BeforeEach;
47 import org.junit.jupiter.api.Test;
48 import org.onap.policy.common.utils.coder.Coder;
49 import org.onap.policy.common.utils.coder.CoderException;
50 import org.onap.policy.common.utils.coder.StandardYamlCoder;
51 import org.onap.policy.common.utils.resources.ResourceUtils;
52 import org.onap.policy.controlloop.ControlLoopEventStatus;
53 import org.onap.policy.controlloop.ControlLoopException;
54 import org.onap.policy.controlloop.ControlLoopTargetType;
55 import org.onap.policy.controlloop.VirtualControlLoopEvent;
56 import org.onap.policy.controlloop.VirtualControlLoopNotification;
57 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
58 import org.onap.policy.controlloop.actorserviceprovider.Operation;
59 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
60 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
61 import org.onap.policy.controlloop.actorserviceprovider.Operator;
62 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
63 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
64 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
65 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithEvent.NewEventStatus;
66 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
67 import org.onap.policy.drools.core.lock.LockCallback;
68 import org.onap.policy.drools.core.lock.LockImpl;
69 import org.onap.policy.drools.core.lock.LockState;
70 import org.onap.policy.drools.system.PolicyEngine;
71 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
72 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
73
74 class ClEventManagerWithEventTest {
75     private static final UUID REQ_ID = UUID.randomUUID();
76     private static final String CL_NAME = "my-closed-loop-name";
77     private static final String POLICY_NAME = "my-policy-name";
78     private static final String POLICY_SCOPE = "my-scope";
79     private static final String POLICY_VERSION = "1.2.3";
80     private static final String SIMPLE_ACTOR = "First";
81     private static final String SIMPLE_OPERATION = "OperationA";
82     private static final String TARGET_PROP = "my-target-property";
83     private static final String MY_TARGET = "my-target";
84     private static final String EVENT_MGR_MULTI_YAML =
85                     "../eventmanager/src/test/resources/eventManager/event-mgr-multi.yaml";
86     private static final String EVENT_MGR_SIMPLE_YAML =
87                     "../eventmanager/src/test/resources/eventManager/event-mgr-simple.yaml";
88     private static final Coder yamlCoder = new StandardYamlCoder();
89     private static final String OUTCOME_MSG = "my outcome message";
90
91     private final PolicyEngine engineMgr = mock(PolicyEngine.class);
92     private final WorkingMemory workMem = mock(WorkingMemory.class);
93     private final InternalFactHandle factHandle = mock(InternalFactHandle.class);
94     private final Operator policyOperator = mock(Operator.class);
95     private final Operation policyOperation = mock(Operation.class);
96     private final Actor policyActor = mock(Actor.class);
97     private final EventManagerServices services = mock(EventManagerServices.class);
98     private final ActorService actors = mock(ActorService.class);
99     private final OperationHistoryDataManager dataMgr = mock(OperationHistoryDataManager.class);
100     private final ExecutorService executor = mock(ExecutorService.class);
101     private final MyStep stepa = mock(MyStep.class);
102     private final MyStep stepb = mock(MyStep.class);
103
104     private List<LockImpl> locks;
105     private ToscaPolicy tosca;
106     private ControlLoopParams params;
107     private VirtualControlLoopEvent event;
108     private ClEventManagerWithEvent<MyStep> mgr;
109
110     /**
111      * Sets up.
112      */
113     @BeforeEach
114     public void setUp() throws ControlLoopException, CoderException {
115         when(services.getActorService()).thenReturn(actors);
116         when(services.getDataManager()).thenReturn(dataMgr);
117
118         when(workMem.getFactHandle(any())).thenReturn(factHandle);
119
120         event = new VirtualControlLoopEvent();
121         event.setRequestId(REQ_ID);
122         event.setTarget(TARGET_PROP);
123         event.setAai(new TreeMap<>(Map.of(TARGET_PROP, MY_TARGET)));
124         event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
125         event.setClosedLoopControlName(CL_NAME);
126         event.setTargetType(ControlLoopTargetType.VNF);
127
128         params = new ControlLoopParams();
129         params.setClosedLoopControlName(CL_NAME);
130         params.setPolicyName(POLICY_NAME);
131         params.setPolicyScope(POLICY_SCOPE);
132         params.setPolicyVersion(POLICY_VERSION);
133
134         loadPolicy(EVENT_MGR_SIMPLE_YAML);
135
136         locks = new ArrayList<>();
137
138         mgr = new MyManager(services, params, event, workMem);
139     }
140
141     @Test
142     void testConstructor() {
143         assertEquals(POLICY_NAME, mgr.getPolicyName());
144         assertSame(event, mgr.getEvent());
145
146         // valid
147         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
148
149         // invalid
150         event.setTarget("");
151         assertThatThrownBy(() -> new MyManager(services, params, event, workMem))
152                         .isInstanceOf(ControlLoopException.class);
153     }
154
155     @Test
156     void testPopulateNotification() throws Exception {
157         loadPolicy(EVENT_MGR_MULTI_YAML);
158         mgr = new MyManager(services, params, event, workMem);
159
160         // before started
161         assertNotNull(mgr.makeNotification());
162
163         mgr.start();
164
165         mgr.addToHistory(makeCompletedOutcome());
166         mgr.addToHistory(makeCompletedOutcome());
167         mgr.addToHistory(makeCompletedOutcome());
168
169         // check notification while running
170         VirtualControlLoopNotification notif = mgr.makeNotification();
171         assertThat(notif.getMessage()).contains(SIMPLE_ACTOR);
172         assertThat(notif.getHistory()).hasSize(3);
173         assertThat(notif.getAai()).isEqualTo(event.getAai());
174         assertThat(notif.getClosedLoopAlarmEnd()).isEqualTo(event.getClosedLoopAlarmEnd());
175         assertThat(notif.getClosedLoopAlarmStart()).isEqualTo(event.getClosedLoopAlarmStart());
176         assertThat(notif.getClosedLoopControlName()).isEqualTo(event.getClosedLoopControlName());
177         assertThat(notif.getClosedLoopEventClient()).isEqualTo(event.getClosedLoopEventClient());
178         assertThat(notif.getFrom()).isEqualTo("policy");
179         assertThat(notif.getTarget()).isEqualTo(event.getTarget());
180         assertThat(notif.getTargetType()).isEqualTo(event.getTargetType());
181
182         // indicate success and load the next policy - should clear the partial history
183         mgr.loadNextPolicy(OperationResult.SUCCESS);
184
185         // check notification
186         notif = mgr.makeNotification();
187         assertNull(notif.getMessage());
188         assertThat(notif.getHistory()).isEmpty();
189
190         // add outcomes and check again
191         mgr.addToHistory(makeCompletedOutcome());
192         mgr.addToHistory(makeCompletedOutcome());
193
194         notif = mgr.makeNotification();
195         assertNotNull(notif.getMessage());
196
197         // should only have history for last two outcomes
198         assertThat(notif.getHistory()).hasSize(2);
199
200         // indicate failure - should go to final state
201         mgr.loadNextPolicy(OperationResult.FAILURE);
202
203         // check notification
204         notif = mgr.makeNotification();
205         assertNull(notif.getMessage());
206
207         // should be no history
208         assertThat(notif.getHistory()).isEmpty();
209
210         // null case
211         assertThatThrownBy(() -> mgr.loadNextPolicy(null)).isInstanceOf(NullPointerException.class)
212                         .hasMessageContaining("lastResult");
213     }
214
215     @Test
216     void testStoreInDataBase() throws ControlLoopException {
217         mgr.start();
218         OperationOutcome outcome = makeOutcome();
219         mgr.addToHistory(outcome);
220
221         mgr.storeInDataBase(mgr.getPartialHistory().peekLast(), MY_TARGET);
222
223         verify(dataMgr).store(REQ_ID.toString(), event.getClosedLoopControlName(), event, MY_TARGET,
224                         mgr.getPartialHistory().peekLast().getClOperation());
225     }
226
227     @Test
228     void testMakeControlLoopResponse() {
229         final var outcome = new OperationOutcome();
230
231         var resp = mgr.makeControlLoopResponse(outcome);
232         assertNotNull(resp);
233         assertEquals("DCAE", resp.getTarget());
234         assertEquals(event.getClosedLoopControlName(), resp.getClosedLoopControlName());
235         assertEquals(event.getPolicyName(), resp.getPolicyName());
236         assertEquals(event.getPolicyVersion(), resp.getPolicyVersion());
237         assertEquals(REQ_ID, resp.getRequestId());
238         assertEquals(event.getVersion(), resp.getVersion());
239     }
240
241     @Test
242     void testOnNewEvent() {
243         var event2 = new VirtualControlLoopEvent(event);
244         assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event2));
245
246         event2.setPayload("other payload");
247         assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
248         assertEquals(NewEventStatus.SUBSEQUENT_ONSET, mgr.onNewEvent(event2));
249         assertEquals(NewEventStatus.FIRST_ONSET, mgr.onNewEvent(event));
250
251         event2.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
252         assertEquals(NewEventStatus.FIRST_ABATEMENT, mgr.onNewEvent(event2));
253
254         assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
255         assertEquals(NewEventStatus.SUBSEQUENT_ABATEMENT, mgr.onNewEvent(event2));
256
257         event2.setClosedLoopEventStatus(null);
258         assertEquals(NewEventStatus.SYNTAX_ERROR, mgr.onNewEvent(event2));
259     }
260
261     @Test
262     void testCheckEventSyntax() {
263         // initially, it's valid
264         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
265
266         event.setTarget(null);
267         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
268                         .hasMessage("No target field");
269
270         // abated supersedes previous errors - so it shouldn't throw an exception
271         event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
272         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
273
274         event.setRequestId(null);
275         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
276                         .hasMessage("No request ID");
277
278         event.setClosedLoopControlName(null);
279         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
280                         .hasMessage("No control loop name");
281     }
282
283     @Test
284     void testValidateStatus() {
285         event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
286         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
287
288         event.setClosedLoopEventStatus(ControlLoopEventStatus.ABATED);
289         assertThatCode(() -> mgr.checkEventSyntax(event)).doesNotThrowAnyException();
290
291         event.setClosedLoopEventStatus(null);
292         assertThatCode(() -> mgr.checkEventSyntax(event)).isInstanceOf(ControlLoopException.class)
293                         .hasMessage("Invalid value in closedLoopEventStatus");
294     }
295
296     private void loadPolicy(String fileName) throws CoderException {
297         var template =
298                         yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
299         tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
300
301         params.setToscaPolicy(tosca);
302     }
303
304     private OperationOutcome makeCompletedOutcome() {
305         var outcome = makeOutcome();
306         outcome.setEnd(outcome.getStart());
307
308         return outcome;
309     }
310
311     private OperationOutcome makeOutcome() {
312         var outcome = new OperationOutcome();
313         outcome.setActor(SIMPLE_ACTOR);
314         outcome.setOperation(SIMPLE_OPERATION);
315         outcome.setMessage(OUTCOME_MSG);
316         outcome.setResult(OperationResult.SUCCESS);
317         outcome.setStart(Instant.now());
318         outcome.setTarget(MY_TARGET);
319
320         return outcome;
321     }
322
323
324     private class MyManager extends ClEventManagerWithEvent<MyStep> {
325         private static final long serialVersionUID = 1L;
326
327         public MyManager(EventManagerServices services, ControlLoopParams params, VirtualControlLoopEvent event,
328                         WorkingMemory workMem) throws ControlLoopException {
329
330             super(services, params, event, workMem);
331         }
332
333         @Override
334         protected ExecutorService getBlockingExecutor() {
335             return executor;
336         }
337
338         @Override
339         protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
340             LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
341             locks.add(lock);
342             callback.lockAvailable(lock);
343         }
344
345         @Override
346         protected PolicyEngine getPolicyEngineManager() {
347             return engineMgr;
348         }
349
350         @Override
351         protected void loadPolicyStep(ControlLoopOperationParams params) {
352             getSteps().add(new MyStep(this, params, getEvent()));
353         }
354     }
355
356     private static class MyStep extends Step {
357         public MyStep(StepContext stepContext, ControlLoopOperationParams params, VirtualControlLoopEvent event) {
358             super(params, new AtomicReference<>());
359         }
360     }
361 }