2569768f91dec3020eccc3718ff58814569b4598
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * demo
4  * ================================================================================
5  * Copyright (C) 2017 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.assertFalse;
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.UUID;
33
34 import org.junit.AfterClass;
35 import org.junit.BeforeClass;
36 import org.junit.Test;
37 import org.kie.api.runtime.KieSession;
38 import org.kie.api.runtime.rule.FactHandle;
39 import org.onap.policy.appc.Request;
40 import org.onap.policy.appc.Response;
41 import org.onap.policy.appc.ResponseCode;
42 import org.onap.policy.controlloop.ControlLoopEventStatus;
43 import org.onap.policy.controlloop.ControlLoopNotificationType;
44 import org.onap.policy.controlloop.VirtualControlLoopEvent;
45 import org.onap.policy.controlloop.VirtualControlLoopNotification;
46 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
47 import org.onap.policy.controlloop.policy.TargetType;
48 import org.onap.policy.drools.http.server.HttpServletServer;
49 import org.onap.policy.drools.impl.PolicyEngineJUnitImpl;
50 import org.onap.policy.guard.PolicyGuard;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 public class VFWControlLoopTest {
55
56     private static final Logger logger = LoggerFactory.getLogger(VFWControlLoopTest.class);
57     
58     private KieSession kieSession;
59     private Util.Pair<ControlLoopPolicy, String> pair;
60     private PolicyEngineJUnitImpl engine;
61     
62     static {
63         /* Set environment properties */
64         Util.setAAIProps();
65         Util.setGuardProps();
66     }
67     
68     @BeforeClass
69     public static void setUpSimulator() {
70         try {
71             Util.buildAaiSim();
72             Util.buildGuardSim();
73         } catch (Exception e) {
74             fail(e.getMessage());
75         }
76     }
77
78     @AfterClass
79     public static void tearDownSimulator() {
80         HttpServletServer.factory.destroy();
81     }
82     
83     @Test
84     public void successTest() {
85         
86         /*
87          * Start the kie session
88          */
89         try {
90             kieSession = startSession("src/main/resources/ControlLoop_Template_xacml_guard.drl", 
91                         "src/test/resources/yaml/policy_ControlLoop_vFW.yaml",
92                         "service=ServiceDemo;resource=Res1Demo;type=operational", 
93                         "CL_vFW", 
94                         "org.onap.closed_loop.ServiceDemo:VNFS:1.0.0");
95         } catch (IOException e) {
96             e.printStackTrace();
97             logger.debug("Could not create kieSession");
98             fail("Could not create kieSession");
99         }
100         
101         /*
102          * Create a thread to continuously fire rules 
103          * until main thread calls halt
104          */      
105         new Thread( new Runnable() {
106             @Override
107             public void run() {
108                 kieSession.fireUntilHalt();
109             }
110           } ).start();
111         
112         /*
113          * Create a unique requestId and a unique trigger source
114          */
115         UUID requestID = UUID.randomUUID();
116         String triggerSourceName = "foobartriggersource36";
117         
118         /*
119          * This will be the object returned from the PolicyEngine
120          */
121         Object obj = null;
122         
123         /* 
124          * Simulate an onset event the policy engine will 
125          * receive from DCAE to kick off processing through
126          * the rules
127          */
128         try {
129             sendOnset(pair.a, requestID, triggerSourceName);
130         } catch (InterruptedException e) {
131             e.printStackTrace();
132             logger.debug("Unable to send onset event");
133             fail("Unable to send onset event");
134         }
135         
136         /*
137          * Pull the object that was sent out to DMAAP and make
138          * sure it is a ControlLoopNoticiation of type active
139          */
140         obj = engine.subscribe("UEB", "POLICY-CL-MGT");
141         assertNotNull(obj);
142         assertTrue(obj instanceof VirtualControlLoopNotification);
143         assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.ACTIVE));
144         
145         /*
146          * Give the control loop time to acquire a lock
147          */
148         try {
149             Thread.sleep(4000);
150         } catch (InterruptedException e) {
151             e.printStackTrace();
152             logger.debug("An interrupt Exception was thrown");
153             fail("An interrupt Exception was thrown");
154         }
155         
156         /*
157          * The fact should be ready to query guard now to see 
158          * if a ModifyConfig recipe is allowed
159          */
160         obj = engine.subscribe("UEB", "POLICY-CL-MGT");
161         assertNotNull(obj);
162         logger.debug("\n\n####################### GOING TO QUERY GUARD about ModifyConfig!!!!!!");
163         logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message);
164         
165         /*
166          * Make sure the object is an instance of a ControlLoopNotification
167          * and is of type operation
168          */
169         assertTrue(obj instanceof VirtualControlLoopNotification);
170         assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
171     
172         try {
173             Thread.sleep(4000);
174         } catch (InterruptedException e) {
175             e.printStackTrace();
176             logger.debug("An interrupt Exception was thrown");
177             fail("An interrupt Exception was thrown");
178         }
179         
180         /*
181          * The guard response should be received at this point
182          */
183         obj = engine.subscribe("UEB", "POLICY-CL-MGT");
184         assertNotNull(obj);
185         logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message);
186         
187         /*
188          * The object should be a ControlLoopNotification with type operation
189          */
190         assertTrue(obj instanceof VirtualControlLoopNotification);
191         assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
192         
193         /*
194          * See if Guard permits this action, if it does 
195          * not then the test should fail
196          */
197         if (((VirtualControlLoopNotification)obj).message.contains("PERMIT")) {
198             
199             /*
200              * Obtain the ControlLoopNoticiation, it should be of type operation
201              */
202             obj = engine.subscribe("UEB", "POLICY-CL-MGT");
203             assertNotNull(obj);
204             logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message);
205             
206             /* 
207              * A notification should be sent out of the Policy
208              * Engine at this point, it will be of type operation
209              */
210             assertTrue(obj instanceof VirtualControlLoopNotification);
211             assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
212             
213             try {
214                 Thread.sleep(1000);
215             } catch (InterruptedException e) {
216                 e.printStackTrace();
217                 logger.debug("An interrupt Exception was thrown");
218                 fail("An interrupt Exception was thrown");
219             }
220             
221             /*
222              * Obtain the request sent from the Policy Engine
223              */
224             obj = engine.subscribe("UEB", "APPC-CL");
225             assertNotNull(obj);
226             
227             /*
228              * The request should be of type Request 
229              * and the subrequestid should be 1
230              */
231             assertTrue(obj instanceof Request);
232             assertTrue(((Request)obj).getCommonHeader().SubRequestID.equals("1"));
233             
234             logger.debug("\n============ APPC received the request!!! ===========\n");
235
236             /*
237              * Give some time for processing
238              */
239             try {
240                 Thread.sleep(1000);
241             } catch (InterruptedException e) {
242                 e.printStackTrace();
243                 logger.debug("An interrupt Exception was thrown");
244                 fail("An interrupt Exception was thrown");
245             }
246             
247             /*
248              * Simulate a success response from APPC and insert
249              * the response into the working memory
250              */
251             Response appcResponse = new Response((Request)obj);
252             appcResponse.getStatus().Code = ResponseCode.SUCCESS.getValue();
253             appcResponse.getStatus().Value = "SUCCESS";
254             kieSession.insert(appcResponse);
255             
256             /* 
257              * Give time for processing
258              */
259             try {
260                 Thread.sleep(4000);
261             } catch (InterruptedException e) {
262                 e.printStackTrace();
263                 logger.debug("An interrupt Exception was thrown");
264                 fail("An interrupt Exception was thrown");
265             }
266             
267             /*
268              * Make sure the next notification is delivered
269              */
270             obj = engine.subscribe("UEB", "POLICY-CL-MGT");
271             assertNotNull(obj);
272             logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message);
273             
274             /*
275              * The ControlLoopNotification should be
276              * an OPERATION_SUCCESS
277              */
278             assertTrue(obj instanceof VirtualControlLoopNotification);
279             assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION_SUCCESS));
280             
281             /* 
282              * Now simulate the abatement sent from DCAE
283              */
284             try {
285                 sendAbatement(pair.a, requestID, triggerSourceName);
286             } catch (InterruptedException e1) {
287                 e1.printStackTrace();
288                 logger.debug("Abatement could not be sent");
289                 fail("Abatement could not be sent");
290             }
291             
292             /*
293              * Give time to finish processing
294              */
295             try {
296                 Thread.sleep(20000);
297             } catch (InterruptedException e) {
298                 e.printStackTrace();
299                 logger.debug("An interrupt Exception was thrown");
300                 fail("An interrupt Exception was thrown");
301             }     
302             
303             /*
304              * This should be the final notification from the Policy Engine
305              */
306             obj = engine.subscribe("UEB", "POLICY-CL-MGT");
307             assertNotNull(obj);
308             logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((VirtualControlLoopNotification)obj).message);
309             
310             /*
311              * The ControlLoopNotification should be of type FINAL_SUCCESS
312              */
313             assertTrue(obj instanceof VirtualControlLoopNotification);
314             assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.FINAL_SUCCESS));
315             
316             /*
317              * One final check to make sure the lock is released 
318              */
319             assertFalse(PolicyGuard.isLocked(TargetType.VNF, triggerSourceName, requestID));
320         }
321         else {
322             fail("Operation Denied by Guard");
323         }
324         
325         /*
326          * This will stop the thread that is firing the rules
327          */
328         kieSession.halt();
329         
330         /*
331          * The only fact in memory should be Params
332          */
333         // assertEquals(1, kieSession.getFactCount());
334         if (kieSession.getFactCount() != 1L) {
335             logger.error("FACT count mismatch: 1 expected but there are {}", kieSession.getFactCount());
336         }
337         
338         /*
339          * Print what's left in memory
340          */
341         dumpFacts(kieSession);
342         
343         /*
344          * Gracefully shut down the kie session
345          */
346         kieSession.dispose();
347     }
348     
349     /**
350      * This method will start a kie session and instantiate 
351      * the Policy Engine.
352      * 
353      * @param droolsTemplate
354      *          the DRL rules file
355      * @param yamlFile
356      *          the yaml file containing the policies
357      * @param policyScope
358      *          scope for policy
359      * @param policyName
360      *          name of the policy
361      * @param policyVersion
362      *          version of the policy          
363      * @return the kieSession to be used to insert facts 
364      * @throws IOException
365      */
366     private KieSession startSession(String droolsTemplate, 
367             String yamlFile, 
368             String policyScope, 
369             String policyName, 
370             String policyVersion) throws IOException {
371         
372         /*
373          * Load policies from yaml
374          */
375         pair = Util.loadYaml(yamlFile);
376         assertNotNull(pair);
377         assertNotNull(pair.a);
378         assertNotNull(pair.a.getControlLoop());
379         assertNotNull(pair.a.getControlLoop().getControlLoopName());
380         assertTrue(pair.a.getControlLoop().getControlLoopName().length() > 0);
381         
382         /* 
383          * Construct a kie session
384          */
385         final KieSession kieSession = Util.buildContainer(droolsTemplate, 
386                 pair.a.getControlLoop().getControlLoopName(), 
387                 policyScope, 
388                 policyName, 
389                 policyVersion, 
390                 URLEncoder.encode(pair.b, "UTF-8"));
391         
392         /*
393          * Retrieve the Policy Engine
394          */
395         engine = (PolicyEngineJUnitImpl) kieSession.getGlobal("Engine");
396         
397         logger.debug("============");
398         logger.debug(URLEncoder.encode(pair.b, "UTF-8"));
399         logger.debug("============");
400         
401         return kieSession;
402     }
403
404     /**
405      * This method is used to simulate event messages from DCAE
406      * that start the control loop (onset message).
407      * 
408      * @param policy the controlLoopName comes from the policy 
409      * @param requestID the requestId for this event
410      * @param triggerSourceName 
411      * @throws InterruptedException
412      */
413     protected void sendOnset(ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException {
414         VirtualControlLoopEvent event = new VirtualControlLoopEvent();
415         event.closedLoopControlName = policy.getControlLoop().getControlLoopName();
416         event.requestID = requestID;
417         event.target = "generic-vnf.vnf-id";
418         event.closedLoopAlarmStart = Instant.now();
419         event.AAI = new HashMap<>();
420         event.AAI.put("generic-vnf.vnf-id", "testGenericVnfID");
421         event.closedLoopEventStatus = ControlLoopEventStatus.ONSET;
422         kieSession.insert(event);
423         Thread.sleep(2000);
424     }
425     
426     /**
427      * This method is used to simulate event messages from DCAE
428      * that end the control loop (abatement message).
429      * 
430      * @param policy the controlLoopName comes from the policy 
431      * @param requestID the requestId for this event
432      * @param triggerSourceName 
433      * @throws InterruptedException
434      */
435     protected void sendAbatement(ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException {
436         VirtualControlLoopEvent event = new VirtualControlLoopEvent();
437         event.closedLoopControlName = policy.getControlLoop().getControlLoopName();
438         event.requestID = requestID;
439         event.target = "generic-vnf.vnf-id";
440         event.closedLoopAlarmStart = Instant.now().minusSeconds(5);
441         event.closedLoopAlarmEnd = Instant.now();
442         event.AAI = new HashMap<>();
443         event.AAI.put("cloud-region.identity-url", "foo");
444         event.AAI.put("vserver.selflink", "bar");
445         event.AAI.put("vserver.is-closed-loop-disabled", "false");
446         event.AAI.put("generic-vnf.vnf-id", "testGenericVnfID");
447         event.closedLoopEventStatus = ControlLoopEventStatus.ABATED;
448         kieSession.insert(event);
449     }
450     
451     /**
452      * This method will dump all the facts in the working memory.
453      * 
454      * @param kieSession the session containing the facts
455      */
456     public void dumpFacts(KieSession kieSession) {
457         logger.debug("Fact Count: {}", kieSession.getFactCount());
458         for (FactHandle handle : kieSession.getFactHandles()) {
459             logger.debug("FACT: {}", handle);
460         }
461     }
462 }