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