2  * ============LICENSE_START=======================================================
 
   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
 
  11  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  21 package org.onap.policy.template.demo;
 
  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;
 
  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.JsonProtocolFilter;
 
  51 import org.onap.policy.drools.system.PolicyController;
 
  52 import org.onap.policy.drools.system.PolicyEngine;
 
  53 import org.onap.policy.drools.utils.logging.LoggerUtil;
 
  54 import org.onap.policy.template.demo.Util.Pair;
 
  55 import org.slf4j.Logger;
 
  56 import org.slf4j.LoggerFactory;
 
  59  * Verifies that event objects are cleaned up when rules are updated. This loads
 
  60  * <b>two</b> copies of the rule set into a single policy to ensure that the two copies
 
  61  * interact appropriately with each other's event objects.
 
  63 public class ControlLoopEventCleanupTest {
 
  64     private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventCleanupTest.class);
 
  67      * Number of objects per control loop, including the Params object.
 
  69     private static int CL_OBJECTS = 7;
 
  71     private static final String YAML = "src/test/resources/yaml/policy_ControlLoop_EventCleanup-test.yaml";
 
  74      * YAML to be used when the first rule set is updated.
 
  76     private static final String YAML2 = "src/test/resources/yaml/policy_ControlLoop_EventCleanup-test2.yaml";
 
  78     private static final String POLICY_VERSION = "v2.0";
 
  80     private static final String POLICY_NAME = "CL_CleanupTest";
 
  82     private static final String POLICY_SCOPE = "type=operational";
 
  84     private static final String CONTROL_LOOP_NAME = "ControlLoop-Event-Cleanup-Test";
 
  86     private static final String DROOLS_TEMPLATE = "../archetype-cl-amsterdam/src/main/resources/archetype-resources/"
 
  87                     + "src/main/resources/__closedLoopControlName__.drl";
 
  89     // values specific to the second copy of the rules
 
  91     private static final String YAML_B = "src/test/resources/yaml/policy_ControlLoop_EventCleanup-test-B.yaml";
 
  92     private static final String POLICY_NAME_B = "CL_CleanupTest_B";
 
  93     private static final String CONTROL_LOOP_NAME_B = "ControlLoop-Event-Cleanup-Test-B";
 
  95     private static final String GUARD_DISABLED = "guard.disabled";
 
  97     private static String saveGuardFlag;
 
  99     private static KieSession kieSession;
 
 100     private static Util.RuleSpec[] specifications;
 
 103      * Setup the simulator.
 
 106     public static void setUpSimulator() {
 
 107         LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, "INFO");
 
 109         saveGuardFlag = PolicyEngine.manager.getEnvironmentProperty(GUARD_DISABLED);
 
 110         PolicyEngine.manager.getEnvironment().setProperty(GUARD_DISABLED, "true");
 
 114         PolicyEngine.manager.configure(new Properties());
 
 115         assertTrue(PolicyEngine.manager.start());
 
 116         Properties noopSinkProperties = new Properties();
 
 117         noopSinkProperties.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS, "APPC-CL,POLICY-CL-MGT");
 
 118         noopSinkProperties.put("noop.sink.topics.APPC-CL.events", "org.onap.policy.appc.Response");
 
 119         noopSinkProperties.put("noop.sink.topics.APPC-CL.events.custom.gson",
 
 120                         "org.onap.policy.appc.util.Serialization,gsonPretty");
 
 121         noopSinkProperties.put("noop.sink.topics.POLICY-CL-MGT.events",
 
 122                         "org.onap.policy.controlloop.VirtualControlLoopNotification");
 
 123         noopSinkProperties.put("noop.sink.topics.POLICY-CL-MGT.events.custom.gson",
 
 124                         "org.onap.policy.controlloop.util.Serialization,gsonPretty");
 
 125         final List<TopicSink> noopTopics = TopicEndpoint.manager.addTopicSinks(noopSinkProperties);
 
 127         EventProtocolCoder.manager.addEncoder("junit.groupId", "junit.artifactId", "POLICY-CL-MGT",
 
 128                         "org.onap.policy.controlloop.VirtualControlLoopNotification", new JsonProtocolFilter(), null,
 
 130         EventProtocolCoder.manager.addEncoder("junit.groupId", "junit.artifactId", "APPC-CL",
 
 131                         "org.onap.policy.appc.Request", new JsonProtocolFilter(), null, null, 1111);
 
 136         } catch (Exception e) {
 
 137             logger.error("Could not create simulator", e);
 
 138             fail("Could not create simulator");
 
 141         for (TopicSink sink : noopTopics) {
 
 142             assertTrue(sink.start());
 
 146             specifications = new Util.RuleSpec[2];
 
 148             specifications[0] = new Util.RuleSpec(DROOLS_TEMPLATE, CONTROL_LOOP_NAME, POLICY_SCOPE, POLICY_NAME,
 
 149                             POLICY_VERSION, loadYaml(YAML));
 
 151             specifications[1] = new Util.RuleSpec(DROOLS_TEMPLATE, CONTROL_LOOP_NAME_B, POLICY_SCOPE, POLICY_NAME_B,
 
 152                             POLICY_VERSION, loadYaml(YAML_B));
 
 154             kieSession = Util.buildContainer(POLICY_VERSION, specifications);
 
 156         } catch (IOException e) {
 
 157             logger.error("Could not create kieSession", e);
 
 158             fail("Could not create kieSession");
 
 166     public static void tearDown() {
 
 167         kieSession.dispose();
 
 169         PolicyEngine.manager.stop();
 
 170         HttpServletServer.factory.destroy();
 
 171         PolicyController.factory.shutdown();
 
 172         TopicEndpoint.manager.shutdown();
 
 174         if (saveGuardFlag == null) {
 
 175             PolicyEngine.manager.getEnvironment().remove(GUARD_DISABLED);
 
 178             PolicyEngine.manager.getEnvironment().setProperty(GUARD_DISABLED, saveGuardFlag);
 
 183     public void test() throws IOException {
 
 186          * Let rules create Params objects.
 
 188         kieSession.fireAllRules();
 
 190         injectEvent(CONTROL_LOOP_NAME);
 
 191         injectEvent(CONTROL_LOOP_NAME_B);
 
 193         kieSession.fireAllRules();
 
 194         List<Object> facts = getSessionObjects();
 
 196         // should have events for both control loops
 
 197         assertEquals(2 * CL_OBJECTS, facts.size());
 
 198         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME));
 
 199         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME_B));
 
 201         logger.info("UPDATING VERSION TO v3.0");
 
 202         updatePolicy(YAML2, "v3.0");
 
 205          * Let rules update Params objects. The Params for the first set of rules should
 
 206          * now be deleted and replaced with a new one, while the Params for the second set
 
 207          * should be unchanged.
 
 209         kieSession.fireAllRules();
 
 210         facts = getSessionObjects();
 
 212         // should only have event for second control loop + 1 Params for first control loop
 
 213         assertEquals(CL_OBJECTS + 1, facts.size());
 
 214         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME_B));
 
 216         // add event for first control loop again
 
 217         injectEvent(CONTROL_LOOP_NAME);
 
 218         kieSession.fireAllRules();
 
 220         logger.info("UPDATING VERSION TO v4.0");
 
 221         updatePolicy(YAML, "v4.0");
 
 224          * Let rules update Params objects. The Params for the first set of rules should
 
 225          * now be deleted and replaced with a new one, while the Params for the second set
 
 226          * should be unchanged.
 
 228         kieSession.fireAllRules();
 
 229         facts = getSessionObjects();
 
 231         // should only have event for second control loop + 1 Params for first control loop
 
 232         assertEquals(CL_OBJECTS + 1, facts.size());
 
 233         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME_B));
 
 235         // add event for first control loop again
 
 236         injectEvent(CONTROL_LOOP_NAME);
 
 237         kieSession.fireAllRules();
 
 239         logger.info("UPDATING VERSION TO v4.0 (i.e., unchanged)");
 
 240         updatePolicy(YAML, "v4.0");
 
 243          * Let rules update Params objects. As the version (and YAML) are unchanged for
 
 244          * either rule set, both Params objects should be unchanged.
 
 246         kieSession.fireAllRules();
 
 247         facts = getSessionObjects();
 
 249         // should have events for both control loops
 
 250         assertEquals(2 * CL_OBJECTS, facts.size());
 
 251         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME));
 
 252         assertTrue(hasEvent(facts, CONTROL_LOOP_NAME_B));
 
 255          * Now we'll delete the first rule set. That won't actually have any immediate
 
 256          * effect, so then we'll update the second rule set, which should trigger a
 
 259         Util.RuleSpec[] specs = new Util.RuleSpec[1];
 
 260         specs[0] = specifications[1];
 
 262         logger.info("UPDATING VERSION TO v5.0 - DELETED RULE SET");
 
 263         Util.updateContainer("v5.0", specs);
 
 265         specs[0] = new Util.RuleSpec(DROOLS_TEMPLATE, CONTROL_LOOP_NAME_B, POLICY_SCOPE, POLICY_NAME_B, POLICY_VERSION,
 
 268         logger.info("UPDATING VERSION TO v6.0 - UPDATED SECOND RULE SET");
 
 269         Util.updateContainer("v6.0", specs);
 
 271         kieSession.fireAllRules();
 
 272         facts = getSessionObjects();
 
 274         // only 1 Params should remain, for second rule set, but events should be gone
 
 275         assertEquals(1, facts.size());
 
 276         assertTrue(facts.stream().anyMatch(obj -> obj.toString().startsWith("Params( ")));
 
 280      * Updates the policy, changing the YAML associated with the first rule set.
 
 282      * @param yamlFile name of the YAML file
 
 283      * @param policyVersion policy version
 
 284      * @throws IOException if an error occurs
 
 286     private static void updatePolicy(String yamlFile, String policyVersion) throws IOException {
 
 288         specifications[0] = new Util.RuleSpec(DROOLS_TEMPLATE, CONTROL_LOOP_NAME, POLICY_SCOPE, POLICY_NAME,
 
 289                         policyVersion, loadYaml(yamlFile));
 
 292          * Update the policy within the container.
 
 294         Util.updateContainer(policyVersion, specifications);
 
 298      * Loads a YAML file and URL-encodes it.
 
 300      * @param yamlFile name of the YAML file
 
 301      * @return the contents of the specified file, URL-encoded
 
 302      * @throws UnsupportedEncodingException if an error occurs
 
 304     private static String loadYaml(String yamlFile) throws UnsupportedEncodingException {
 
 305         Pair<ControlLoopPolicy, String> pair = Util.loadYaml(yamlFile);
 
 307         assertNotNull(pair.first);
 
 308         assertNotNull(pair.first.getControlLoop());
 
 309         assertNotNull(pair.first.getControlLoop().getControlLoopName());
 
 310         assertTrue(pair.first.getControlLoop().getControlLoopName().length() > 0);
 
 312         return URLEncoder.encode(pair.second, "UTF-8");
 
 316      * Gets the session objects.
 
 318      * @return the session objects
 
 320     private static List<Object> getSessionObjects() {
 
 321         // sort the objects so we know the order
 
 322         LinkedList<Object> lst = new LinkedList<>(kieSession.getObjects());
 
 323         lst.sort((left, right) -> left.toString().compareTo(right.toString()));
 
 325         lst.forEach(obj -> logger.info("obj={}", obj));
 
 331      * Injects an ONSET event into the rule engine.
 
 333      * @param controlLoopName the control loop name
 
 335     private void injectEvent(String controlLoopName) {
 
 336         VirtualControlLoopEvent event = new VirtualControlLoopEvent();
 
 338         event.setClosedLoopControlName(controlLoopName);
 
 340         UUID reqid = UUID.randomUUID();
 
 341         event.setRequestId(reqid);
 
 343         event.setTarget("generic-vnf.vnf-id");
 
 344         event.setClosedLoopAlarmStart(Instant.now());
 
 345         event.setAai(new HashMap<>());
 
 346         event.getAai().put("generic-vnf.vnf-id", "vnf-" + reqid.toString());
 
 347         event.getAai().put(ControlLoopEventManager.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED, "false");
 
 348         event.setClosedLoopEventStatus(ControlLoopEventStatus.ONSET);
 
 350         kieSession.insert(event);
 
 354      * Determines if the facts contain an event for the given control loop.
 
 356      * @param facts session facts to be checked
 
 357      * @param controlLoopName name of the control loop of interest
 
 358      * @return {@code true} if the facts contain an event for the given control loop,
 
 359      *         {@code false} otherwise
 
 361     private boolean hasEvent(List<Object> facts, String controlLoopName) {
 
 362         return (facts.stream().anyMatch(obj -> obj instanceof VirtualControlLoopEvent
 
 363                         && controlLoopName.equals(((VirtualControlLoopEvent) obj).getClosedLoopControlName())));