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