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