151819c4d31638a9609ef9a16f3c1470ba926d1c
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * demo
4  * ================================================================================
5  * Copyright (C) 2018-2019 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.io.UnsupportedEncodingException;
30 import java.net.URLEncoder;
31 import java.time.Instant;
32 import java.util.HashMap;
33 import java.util.LinkedList;
34 import java.util.List;
35 import java.util.Properties;
36 import java.util.UUID;
37 import org.junit.AfterClass;
38 import org.junit.BeforeClass;
39 import org.junit.Ignore;
40 import org.junit.Test;
41 import org.kie.api.runtime.KieSession;
42 import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
43 import org.onap.policy.common.endpoints.event.comm.TopicSink;
44 import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance;
45 import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
46 import org.onap.policy.controlloop.ControlLoopEventStatus;
47 import org.onap.policy.controlloop.VirtualControlLoopEvent;
48 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
49 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
50 import org.onap.policy.drools.protocol.coders.EventProtocolCoderConstants;
51 import org.onap.policy.drools.protocol.coders.EventProtocolParams;
52 import org.onap.policy.drools.protocol.coders.JsonProtocolFilter;
53 import org.onap.policy.drools.system.PolicyControllerConstants;
54 import org.onap.policy.drools.system.PolicyEngineConstants;
55 import org.onap.policy.drools.utils.logging.LoggerUtil;
56 import org.onap.policy.template.demo.SupportUtil.Pair;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 /**
61  * Verifies that event objects are cleaned up when rules are updated. This loads
62  * <b>two</b> copies of the rule set into a single policy to ensure that the two copies
63  * interact appropriately with each other's event objects.
64  */
65 public class ControlLoopEventCleanupTest {
66     private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventCleanupTest.class);
67
68     /**
69      * Number of objects per control loop, including the Params object.
70      */
71     private static int CL_OBJECTS = 7;
72
73     private static final String YAML = "src/test/resources/yaml/policy_ControlLoop_EventCleanup-test.yaml";
74
75     /**
76      * YAML to be used when the first rule set is updated.
77      */
78     private static final String YAML2 = "src/test/resources/yaml/policy_ControlLoop_EventCleanup-test2.yaml";
79
80     private static final String POLICY_VERSION = "v2.0";
81
82     private static final String POLICY_NAME = "CL_CleanupTest";
83
84     private static final String POLICY_SCOPE = "type=operational";
85
86     private static final String CONTROL_LOOP_NAME = "ControlLoop-Event-Cleanup-Test";
87
88     private static final String DROOLS_TEMPLATE = "../archetype-cl-amsterdam/src/main/resources/archetype-resources/"
89                     + "src/main/resources/__closedLoopControlName__.drl";
90
91     // values specific to the second copy of the rules
92
93     private static final String YAML_B = "src/test/resources/yaml/policy_ControlLoop_EventCleanup-test-B.yaml";
94     private static final String POLICY_NAME_B = "CL_CleanupTest_B";
95     private static final String CONTROL_LOOP_NAME_B = "ControlLoop-Event-Cleanup-Test-B";
96
97     private static final String GUARD_DISABLED = "guard.disabled";
98
99     private static String saveGuardFlag;
100
101     private static KieSession kieSession;
102     private static SupportUtil.RuleSpec[] specifications;
103
104     /**
105      * Setup the simulator.
106      */
107     @BeforeClass
108     public static void setUpSimulator() {
109         LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, "INFO");
110
111         saveGuardFlag = PolicyEngineConstants.getManager().getEnvironmentProperty(GUARD_DISABLED);
112         PolicyEngineConstants.getManager().getEnvironment().setProperty(GUARD_DISABLED, "true");
113
114         SupportUtil.setAaiProps();
115
116         PolicyEngineConstants.getManager().configure(new Properties());
117         assertTrue(PolicyEngineConstants.getManager().start());
118         Properties noopSinkProperties = new Properties();
119         noopSinkProperties.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS, "APPC-CL,POLICY-CL-MGT");
120         noopSinkProperties.put("noop.sink.topics.APPC-CL.events", "org.onap.policy.appc.Response");
121         noopSinkProperties.put("noop.sink.topics.APPC-CL.events.custom.gson",
122                         "org.onap.policy.appc.util.Serialization,gsonPretty");
123         noopSinkProperties.put("noop.sink.topics.POLICY-CL-MGT.events",
124                         "org.onap.policy.controlloop.VirtualControlLoopNotification");
125         noopSinkProperties.put("noop.sink.topics.POLICY-CL-MGT.events.custom.gson",
126                         "org.onap.policy.controlloop.util.Serialization,gsonPretty");
127         final List<TopicSink> noopTopics = TopicEndpointManager.getManager().addTopicSinks(noopSinkProperties);
128
129         EventProtocolCoderConstants.getManager().addEncoder(EventProtocolParams.builder()
130                 .groupId("junit.groupId")
131                 .artifactId("junit.artifactId")
132                 .topic("POLICY-CL-MGT")
133                 .eventClass("org.onap.policy.controlloop.VirtualControlLoopNotification")
134                 .protocolFilter(new JsonProtocolFilter())
135                 .modelClassLoaderHash(1111));
136         EventProtocolCoderConstants.getManager().addEncoder(EventProtocolParams.builder()
137                 .groupId("junit.groupId")
138                 .artifactId("junit.artifactId")
139                 .topic("APPC-CL")
140                 .eventClass("org.onap.policy.appc.Request")
141                 .protocolFilter(new JsonProtocolFilter())
142                 .modelClassLoaderHash(1111));
143
144         try {
145             SupportUtil.buildAaiSim();
146
147         } catch (Exception e) {
148             logger.error("Could not create simulator", e);
149             fail("Could not create simulator");
150         }
151
152         for (TopicSink sink : noopTopics) {
153             assertTrue(sink.start());
154         }
155
156         try {
157             specifications = new SupportUtil.RuleSpec[2];
158
159             specifications[0] = new SupportUtil.RuleSpec(DROOLS_TEMPLATE, CONTROL_LOOP_NAME, POLICY_SCOPE, POLICY_NAME,
160                             POLICY_VERSION, loadYaml(YAML));
161
162             specifications[1] = new SupportUtil.RuleSpec(DROOLS_TEMPLATE, CONTROL_LOOP_NAME_B, POLICY_SCOPE,
163                             POLICY_NAME_B, POLICY_VERSION, loadYaml(YAML_B));
164
165             kieSession = SupportUtil.buildContainer(POLICY_VERSION, specifications);
166
167         } catch (IOException e) {
168             logger.error("Could not create kieSession", e);
169             fail("Could not create kieSession");
170         }
171     }
172
173     /**
174      * Tear down.
175      */
176     @AfterClass
177     public static void tearDown() {
178         kieSession.dispose();
179
180         PolicyEngineConstants.getManager().stop();
181         HttpServletServerFactoryInstance.getServerFactory().destroy();
182         PolicyControllerConstants.getFactory().shutdown();
183         TopicEndpointManager.getManager().shutdown();
184
185         if (saveGuardFlag == null) {
186             PolicyEngineConstants.getManager().getEnvironment().remove(GUARD_DISABLED);
187
188         } else {
189             PolicyEngineConstants.getManager().getEnvironment().setProperty(GUARD_DISABLED, saveGuardFlag);
190         }
191     }
192
193     @Ignore
194     @Test
195     public void test() throws IOException {
196
197         /*
198          * Let rules create Params objects.
199          */
200         kieSession.fireAllRules();
201
202         injectEvent(CONTROL_LOOP_NAME);
203         injectEvent(CONTROL_LOOP_NAME_B);
204
205         kieSession.fireAllRules();
206         List<Object> facts = getSessionObjects();
207
208         // should have events for both control loops
209         assertEquals(2 * CL_OBJECTS, facts.size());
210         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME));
211         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME_B));
212
213         logger.info("UPDATING VERSION TO v3.0");
214         updatePolicy(YAML2, "v3.0");
215
216         /*
217          * Let rules update Params objects. The Params for the first set of rules should
218          * now be deleted and replaced with a new one, while the Params for the second set
219          * should be unchanged.
220          */
221         kieSession.fireAllRules();
222         facts = getSessionObjects();
223
224         // should only have event for second control loop + 1 Params for first control loop
225         assertEquals(CL_OBJECTS + 1, facts.size());
226         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME_B));
227
228         // add event for first control loop again
229         injectEvent(CONTROL_LOOP_NAME);
230         kieSession.fireAllRules();
231
232         logger.info("UPDATING VERSION TO v4.0");
233         updatePolicy(YAML, "v4.0");
234
235         /*
236          * Let rules update Params objects. The Params for the first set of rules should
237          * now be deleted and replaced with a new one, while the Params for the second set
238          * should be unchanged.
239          */
240         kieSession.fireAllRules();
241         facts = getSessionObjects();
242
243         // should only have event for second control loop + 1 Params for first control loop
244         assertEquals(CL_OBJECTS + 1, facts.size());
245         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME_B));
246
247         // add event for first control loop again
248         injectEvent(CONTROL_LOOP_NAME);
249         kieSession.fireAllRules();
250
251         logger.info("UPDATING VERSION TO v4.0 (i.e., unchanged)");
252         updatePolicy(YAML, "v4.0");
253
254         /*
255          * Let rules update Params objects. As the version (and YAML) are unchanged for
256          * either rule set, both Params objects should be unchanged.
257          */
258         kieSession.fireAllRules();
259         facts = getSessionObjects();
260
261         // should have events for both control loops
262         assertEquals(2 * CL_OBJECTS, facts.size());
263         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME));
264         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME_B));
265
266         /*
267          * Now we'll delete the first rule set. That won't actually have any immediate
268          * effect, so then we'll update the second rule set, which should trigger a
269          * clean-up of both.
270          */
271         SupportUtil.RuleSpec[] specs = new SupportUtil.RuleSpec[1];
272         specs[0] = specifications[1];
273
274         logger.info("UPDATING VERSION TO v5.0 - DELETED RULE SET");
275         SupportUtil.updateContainer("v5.0", specs);
276
277         specs[0] = new SupportUtil.RuleSpec(DROOLS_TEMPLATE, CONTROL_LOOP_NAME_B, POLICY_SCOPE, POLICY_NAME_B,
278                 POLICY_VERSION, loadYaml(YAML));
279
280         logger.info("UPDATING VERSION TO v6.0 - UPDATED SECOND RULE SET");
281         SupportUtil.updateContainer("v6.0", specs);
282
283         kieSession.fireAllRules();
284         facts = getSessionObjects();
285
286         // only 1 Params should remain, for second rule set, but events should be gone
287         assertEquals(1, facts.size());
288         assertTrue(facts.stream().anyMatch(obj -> obj.toString().startsWith("Params( ")));
289     }
290
291     /**
292      * Updates the policy, changing the YAML associated with the first rule set.
293      *
294      * @param yamlFile name of the YAML file
295      * @param policyVersion policy version
296      * @throws IOException if an error occurs
297      */
298     private static void updatePolicy(String yamlFile, String policyVersion) throws IOException {
299
300         specifications[0] = new SupportUtil.RuleSpec(DROOLS_TEMPLATE, CONTROL_LOOP_NAME, POLICY_SCOPE, POLICY_NAME,
301                         policyVersion, loadYaml(yamlFile));
302
303         /*
304          * Update the policy within the container.
305          */
306         SupportUtil.updateContainer(policyVersion, specifications);
307     }
308
309     /**
310      * Loads a YAML file and URL-encodes it.
311      *
312      * @param yamlFile name of the YAML file
313      * @return the contents of the specified file, URL-encoded
314      * @throws UnsupportedEncodingException if an error occurs
315      */
316     private static String loadYaml(String yamlFile) throws UnsupportedEncodingException {
317         Pair<ControlLoopPolicy, String> pair = SupportUtil.loadYaml(yamlFile);
318         assertNotNull(pair);
319         assertNotNull(pair.first);
320         assertNotNull(pair.first.getControlLoop());
321         assertNotNull(pair.first.getControlLoop().getControlLoopName());
322         assertTrue(pair.first.getControlLoop().getControlLoopName().length() > 0);
323
324         return URLEncoder.encode(pair.second, "UTF-8");
325     }
326
327     /**
328      * Gets the session objects.
329      *
330      * @return the session objects
331      */
332     private static List<Object> getSessionObjects() {
333         // sort the objects so we know the order
334         LinkedList<Object> lst = new LinkedList<>(kieSession.getObjects());
335         lst.sort((left, right) -> left.toString().compareTo(right.toString()));
336
337         lst.forEach(obj -> logger.info("obj={}", obj));
338
339         return lst;
340     }
341
342     /**
343      * Injects an ONSET event into the rule engine.
344      *
345      * @param controlLoopName the control loop name
346      */
347     private void injectEvent(String controlLoopName) {
348         VirtualControlLoopEvent event = new VirtualControlLoopEvent();
349
350         event.setClosedLoopControlName(controlLoopName);
351
352         UUID reqid = UUID.randomUUID();
353         event.setRequestId(reqid);
354
355         event.setTarget("generic-vnf.vnf-id");
356         event.setClosedLoopAlarmStart(Instant.now());
357         event.setAai(new HashMap<>());
358         event.getAai().put("generic-vnf.vnf-id", "vnf-" + reqid.toString());
359         event.getAai().put(ControlLoopEventManager.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED, "false");
360         event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
361
362         kieSession.insert(event);
363     }
364
365     /**
366      * Determines if the facts contain an event for the given control loop.
367      *
368      * @param facts session facts to be checked
369      * @param controlLoopName name of the control loop of interest
370      * @return {@code true} if the facts contain an event for the given control loop,
371      *         {@code false} otherwise
372      */
373     private boolean hasEvent(List<Object> facts, String controlLoopName) {
374         return (facts.stream().anyMatch(obj -> obj instanceof VirtualControlLoopEvent
375                         && controlLoopName.equals(((VirtualControlLoopEvent) obj).getClosedLoopControlName())));
376     }
377 }