adc9a2ac02d4c74a326b9dc006108b4cf45408eb
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * demo
4  * ================================================================================
5  * Copyright (C) 2017-2018 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.template.demo;
22
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assert.assertTrue;
26 import static org.junit.Assert.fail;
27
28 import java.io.IOException;
29 import java.net.URLEncoder;
30 import java.time.Instant;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Properties;
34 import java.util.UUID;
35
36 import org.junit.AfterClass;
37 import org.junit.BeforeClass;
38 import org.junit.Test;
39 import org.kie.api.runtime.KieSession;
40 import org.kie.api.runtime.rule.FactHandle;
41 import org.onap.policy.appc.Request;
42 import org.onap.policy.appc.Response;
43 import org.onap.policy.appc.ResponseCode;
44 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
45 import org.onap.policy.common.endpoints.event.comm.TopicEndpoint;
46 import org.onap.policy.common.endpoints.event.comm.TopicListener;
47 import org.onap.policy.common.endpoints.event.comm.TopicSink;
48 import org.onap.policy.common.endpoints.http.server.HttpServletServer;
49 import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
50 import org.onap.policy.controlloop.ControlLoopEventStatus;
51 import org.onap.policy.controlloop.ControlLoopNotificationType;
52 import org.onap.policy.controlloop.VirtualControlLoopEvent;
53 import org.onap.policy.controlloop.VirtualControlLoopNotification;
54 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
55 import org.onap.policy.drools.protocol.coders.EventProtocolCoder;
56 import org.onap.policy.drools.protocol.coders.JsonProtocolFilter;
57 import org.onap.policy.drools.system.PolicyController;
58 import org.onap.policy.drools.system.PolicyEngine;
59 import org.onap.policy.drools.utils.logging.LoggerUtil;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63 public class VfwControlLoopTest implements TopicListener {
64
65     private static final Logger logger = LoggerFactory.getLogger(VfwControlLoopTest.class);
66
67     private static List<? extends TopicSink> noopTopics;
68
69     private static KieSession kieSession;
70     private static Util.Pair<ControlLoopPolicy, String> pair;
71     private UUID requestId;
72
73     static {
74         /* Set environment properties */
75         Util.setAaiProps();
76         Util.setGuardProps();
77         Util.setPuProp();
78         LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, "INFO");
79     }
80
81     /**
82      * Setup the simulator.
83      */
84     @BeforeClass
85     public static void setUpSimulator() {
86         PolicyEngine.manager.configure(new Properties());
87         assertTrue(PolicyEngine.manager.start());
88         Properties noopSinkProperties = new Properties();
89         noopSinkProperties.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS, "APPC-CL,POLICY-CL-MGT");
90         noopSinkProperties.put("noop.sink.topics.APPC-CL.events", "org.onap.policy.appc.Response");
91         noopSinkProperties.put("noop.sink.topics.APPC-CL.events.custom.gson",
92                 "org.onap.policy.appc.util.Serialization,gsonPretty");
93         noopSinkProperties.put("noop.sink.topics.POLICY-CL-MGT.events",
94                 "org.onap.policy.controlloop.VirtualControlLoopNotification");
95         noopSinkProperties.put("noop.sink.topics.POLICY-CL-MGT.events.custom.gson",
96                 "org.onap.policy.controlloop.util.Serialization,gsonPretty");
97         noopTopics = TopicEndpoint.manager.addTopicSinks(noopSinkProperties);
98
99         EventProtocolCoder.manager.addEncoder("junit.groupId", "junit.artifactId", "POLICY-CL-MGT",
100                 "org.onap.policy.controlloop.VirtualControlLoopNotification", new JsonProtocolFilter(), null, null,
101                 1111);
102         EventProtocolCoder.manager.addEncoder("junit.groupId", "junit.artifactId", "APPC-CL",
103                 "org.onap.policy.appc.Request", new JsonProtocolFilter(), null, null, 1111);
104
105         try {
106             Util.buildAaiSim();
107             Util.buildGuardSim();
108         } catch (Exception e) {
109             fail(e.getMessage());
110         }
111
112         /*
113          * Start the kie session
114          */
115         try {
116             kieSession = startSession(
117                     "../archetype-cl-amsterdam/src/main/resources/archetype-resources/src/"
118                     + "main/resources/__closedLoopControlName__.drl",
119                     "src/test/resources/yaml/policy_ControlLoop_vFW.yaml",
120                     "service=ServiceDemo;resource=Res1Demo;type=operational", "CL_vFW",
121                     "org.onap.closed_loop.ServiceDemo:VNFS:1.0.0");
122         } catch (IOException e) {
123             e.printStackTrace();
124             logger.debug("Could not create kieSession");
125             fail("Could not create kieSession");
126         }
127     }
128
129     /**
130      * Tear down the simulator.
131      */
132     @AfterClass
133     public static void tearDownSimulator() {
134         /*
135          * Gracefully shut down the kie session
136          */
137         kieSession.dispose();
138
139         PolicyEngine.manager.stop();
140         HttpServletServer.factory.destroy();
141         PolicyController.factory.shutdown();
142         TopicEndpoint.manager.shutdown();
143     }
144
145     @Test
146     public void successTest() {
147
148         /*
149          * Allows the PolicyEngine to callback to this object to notify that there is an event ready
150          * to be pulled from the queue
151          */
152         for (TopicSink sink : noopTopics) {
153             assertTrue(sink.start());
154             sink.register(this);
155         }
156
157         /*
158          * Create a unique requestId
159          */
160         requestId = UUID.randomUUID();
161
162         /*
163          * Simulate an onset event the policy engine will receive from DCAE to kick off processing
164          * through the rules
165          */
166         sendEvent(pair.first, requestId, ControlLoopEventStatus.ONSET);
167
168         try {
169             kieSession.fireUntilHalt();
170             
171             // allow object clean-up
172             kieSession.fireAllRules();
173             
174         } catch (Exception e) {
175             e.printStackTrace();
176             logger.warn(e.toString());
177             fail("fail");
178         }
179
180
181         /*
182          * The only fact in memory should be Params
183          */
184         assertEquals(1, kieSession.getFactCount());
185
186         /*
187          * Print what's left in memory
188          */
189         dumpFacts(kieSession);
190     }
191
192     @Test
193     public void aaiFailTests() {
194
195         /*
196          * Allows the PolicyEngine to callback to this object to notify that there is an event ready
197          * to be pulled from the queue
198          */
199         for (TopicSink sink : noopTopics) {
200             assertTrue(sink.start());
201             sink.register(this);
202         }
203
204         /*
205          * Create a unique requestId
206          */
207         requestId = UUID.randomUUID();
208
209         /*
210          * Simulate an onset event the policy engine will receive from DCAE to kick off processing
211          * through the rules
212          */
213         sendEvent(pair.first, requestId, ControlLoopEventStatus.ONSET, "error");
214         try {
215             kieSession.fireUntilHalt();
216             
217             // allow object clean-up
218             kieSession.fireAllRules();
219             
220         } catch (Exception e) {
221             e.printStackTrace();
222             logger.warn(e.toString());
223             fail(e.getMessage());
224         }
225
226         /*
227          * The only fact in memory should be Params
228          */
229         assertEquals(1, kieSession.getFactCount());
230
231         /*
232          * Print what's left in memory
233          */
234         dumpFacts(kieSession);
235
236         /*
237          * Create a unique requestId
238          */
239         requestId = UUID.randomUUID();
240
241         /*
242          * Simulate an onset event the policy engine will receive from DCAE to kick off processing
243          * through the rules
244          */
245
246         sendEvent(pair.first, requestId, ControlLoopEventStatus.ONSET, "getFail");
247
248         try {
249             kieSession.fireUntilHalt();
250             
251             // allow object clean-up
252             kieSession.fireAllRules();
253             
254         } catch (Exception e) {
255             e.printStackTrace();
256             logger.warn(e.toString());
257             fail(e.getMessage());
258         }
259
260         /*
261          * The only fact in memory should be Params
262          */
263         assertEquals(1, kieSession.getFactCount());
264
265         /*
266          * Print what's left in memory
267          */
268         dumpFacts(kieSession);
269     }
270
271     /**
272      * This method will start a kie session and instantiate the Policy Engine.
273      * 
274      * @param droolsTemplate the DRL rules file
275      * @param yamlFile the yaml file containing the policies
276      * @param policyScope scope for policy
277      * @param policyName name of the policy
278      * @param policyVersion version of the policy
279      * @return the kieSession to be used to insert facts
280      * @throws IOException IO Exception
281      */
282     private static KieSession startSession(String droolsTemplate, String yamlFile, String policyScope,
283             String policyName, String policyVersion) throws IOException {
284
285         /*
286          * Load policies from yaml
287          */
288         pair = Util.loadYaml(yamlFile);
289         assertNotNull(pair);
290         assertNotNull(pair.first);
291         assertNotNull(pair.first.getControlLoop());
292         assertNotNull(pair.first.getControlLoop().getControlLoopName());
293         assertTrue(pair.first.getControlLoop().getControlLoopName().length() > 0);
294
295         /*
296          * Construct a kie session
297          */
298         final KieSession kieSession = Util.buildContainer(droolsTemplate, 
299                 pair.first.getControlLoop().getControlLoopName(),
300                 policyScope, policyName, policyVersion, URLEncoder.encode(pair.second, "UTF-8"));
301
302         /*
303          * Retrieve the Policy Engine
304          */
305
306         logger.debug("============");
307         logger.debug(URLEncoder.encode(pair.second, "UTF-8"));
308         logger.debug("============");
309
310         return kieSession;
311     }
312
313     /*
314      * @see org.onap.policy.drools.PolicyEngineListener#newEventNotification(java.lang.String)
315      */
316     @Override
317     public void onTopicEvent(CommInfrastructure commType, String topic, String event) {
318         /*
319          * Pull the object that was sent out to DMAAP and make sure it is a ControlLoopNoticiation
320          * of type active
321          */
322         Object obj = null;
323         if ("POLICY-CL-MGT".equals(topic)) {
324             obj = org.onap.policy.controlloop.util.Serialization.gsonJunit.fromJson(event,
325                     org.onap.policy.controlloop.VirtualControlLoopNotification.class);
326         } else if ("APPC-CL".equals(topic)) {
327             obj = org.onap.policy.appc.util.Serialization.gsonPretty.fromJson(event,
328                     org.onap.policy.appc.Request.class);
329         }
330         assertNotNull(obj);
331         if (obj instanceof VirtualControlLoopNotification) {
332             VirtualControlLoopNotification notification = (VirtualControlLoopNotification) obj;
333             String policyName = notification.getPolicyName();
334             if (policyName.endsWith("EVENT")) {
335                 logger.debug("Rule Fired: " + notification.getPolicyName());
336                 assertTrue(ControlLoopNotificationType.ACTIVE.equals(notification.getNotification()));
337             } else if (policyName.endsWith("GUARD_NOT_YET_QUERIED")) {
338                 logger.debug("Rule Fired: " + notification.getPolicyName());
339                 assertTrue(ControlLoopNotificationType.OPERATION.equals(notification.getNotification()));
340                 assertNotNull(notification.getMessage());
341                 assertTrue(notification.getMessage().startsWith("Sending guard query"));
342             } else if (policyName.endsWith("GUARD.RESPONSE")) {
343                 logger.debug("Rule Fired: " + notification.getPolicyName());
344                 assertTrue(ControlLoopNotificationType.OPERATION.equals(notification.getNotification()));
345                 assertNotNull(notification.getMessage());
346                 assertTrue(notification.getMessage().toLowerCase().endsWith("permit"));
347             } else if (policyName.endsWith("GUARD_PERMITTED")) {
348                 logger.debug("Rule Fired: " + notification.getPolicyName());
349                 assertTrue(ControlLoopNotificationType.OPERATION.equals(notification.getNotification()));
350                 assertNotNull(notification.getMessage());
351                 assertTrue(notification.getMessage().startsWith("actor=APPC"));
352             } else if (policyName.endsWith("OPERATION.TIMEOUT")) {
353                 logger.debug("Rule Fired: " + notification.getPolicyName());
354                 kieSession.halt();
355                 logger.debug("The operation timed out");
356                 fail("Operation Timed Out");
357             } else if (policyName.endsWith("APPC.RESPONSE")) {
358                 logger.debug("Rule Fired: " + notification.getPolicyName());
359                 assertTrue(ControlLoopNotificationType.OPERATION_SUCCESS.equals(notification.getNotification()));
360                 assertNotNull(notification.getMessage());
361                 assertTrue(notification.getMessage().startsWith("actor=APPC"));
362                 sendEvent(pair.first, requestId, ControlLoopEventStatus.ABATED);
363             } else if (policyName.endsWith("EVENT.MANAGER")) {
364                 logger.debug("Rule Fired: " + notification.getPolicyName());
365                 if ("error".equals(notification.getAai().get("generic-vnf.vnf-name"))) {
366                     assertEquals(ControlLoopNotificationType.FINAL_FAILURE, notification.getNotification());
367                     assertEquals("Target vnf-id could not be found", notification.getMessage());
368                 } else if ("getFail".equals(notification.getAai().get("generic-vnf.vnf-name"))) {
369                     assertEquals(ControlLoopNotificationType.FINAL_FAILURE, notification.getNotification());
370                 } else {
371                     assertTrue(ControlLoopNotificationType.FINAL_SUCCESS.equals(notification.getNotification()));
372                 }
373                 kieSession.halt();
374             } else if (policyName.endsWith("EVENT.MANAGER.TIMEOUT")) {
375                 logger.debug("Rule Fired: " + notification.getPolicyName());
376                 kieSession.halt();
377                 logger.debug("The control loop timed out");
378                 fail("Control Loop Timed Out");
379             }
380         } else if (obj instanceof Request) {
381             assertTrue(((Request) obj).getCommonHeader().getSubRequestId().equals("1"));
382             assertNotNull(((Request) obj).getPayload().get("generic-vnf.vnf-id"));
383
384             logger.debug("\n============ APPC received the request!!! ===========\n");
385
386             /*
387              * Simulate a success response from APPC and insert the response into the working memory
388              */
389             Response appcResponse = new Response((Request) obj);
390             appcResponse.getStatus().setCode(ResponseCode.SUCCESS.getValue());
391             appcResponse.getStatus().setValue("SUCCESS");
392             kieSession.insert(appcResponse);
393         }
394     }
395
396     /**
397      * This method is used to simulate event messages from DCAE that start the control loop (onset
398      * message) or end the control loop (abatement message).
399      * 
400      * @param policy the controlLoopName comes from the policy
401      * @param requestID the requestId for this event
402      * @param status could be onset or abated
403      */
404     protected void sendEvent(ControlLoopPolicy policy, UUID requestId, ControlLoopEventStatus status) {
405         VirtualControlLoopEvent event = new VirtualControlLoopEvent();
406         event.setClosedLoopControlName(policy.getControlLoop().getControlLoopName());
407         event.setRequestId(requestId);
408         event.setTarget("generic-vnf.vnf-name");
409         event.setClosedLoopAlarmStart(Instant.now());
410         event.setAai(new HashMap<>());
411         event.getAai().put("generic-vnf.vnf-name", "testGenericVnfID");
412         event.setClosedLoopEventStatus(status);
413         kieSession.insert(event);
414     }
415
416     /**
417      * This method is used to simulate event messages from DCAE that start the control loop (onset
418      * message) or end the control loop (abatement message).
419      * 
420      * @param policy the controlLoopName comes from the policy
421      * @param requestID the requestId for this event
422      * @param status could be onset or abated
423      */
424     protected void sendEvent(ControlLoopPolicy policy, UUID requestId, ControlLoopEventStatus status, String vnfId) {
425         VirtualControlLoopEvent event = new VirtualControlLoopEvent();
426         event.setClosedLoopControlName(policy.getControlLoop().getControlLoopName());
427         event.setRequestId(requestId);
428         event.setTarget("generic-vnf.vnf-name");
429         event.setClosedLoopAlarmStart(Instant.now());
430         event.setAai(new HashMap<>());
431         event.getAai().put("generic-vnf.vnf-name", vnfId);
432         event.setClosedLoopEventStatus(status);
433         kieSession.insert(event);
434     }
435
436     /**
437      * This method will dump all the facts in the working memory.
438      * 
439      * @param kieSession the session containing the facts
440      */
441     public void dumpFacts(KieSession kieSession) {
442         logger.debug("Fact Count: {}", kieSession.getFactCount());
443         for (FactHandle handle : kieSession.getFactHandles()) {
444             logger.debug("FACT: {}", handle);
445         }
446     }
447 }