2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2020 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.controlloop.common.rules.test;
23 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertSame;
27 import static org.junit.Assert.assertTrue;
28 import static org.mockito.ArgumentMatchers.any;
29 import static org.mockito.ArgumentMatchers.eq;
30 import static org.mockito.Mockito.doAnswer;
31 import static org.mockito.Mockito.mock;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.when;
36 import java.util.LinkedList;
37 import java.util.List;
38 import java.util.Properties;
39 import java.util.stream.Collectors;
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.kie.api.definition.rule.Rule;
43 import org.kie.api.event.rule.AfterMatchFiredEvent;
44 import org.kie.api.event.rule.AgendaEventListener;
45 import org.kie.api.event.rule.BeforeMatchFiredEvent;
46 import org.kie.api.event.rule.MatchCancelledEvent;
47 import org.kie.api.event.rule.MatchCreatedEvent;
48 import org.kie.api.event.rule.ObjectDeletedEvent;
49 import org.kie.api.event.rule.ObjectInsertedEvent;
50 import org.kie.api.event.rule.ObjectUpdatedEvent;
51 import org.kie.api.event.rule.RuleRuntimeEventListener;
52 import org.kie.api.runtime.KieSession;
53 import org.kie.api.runtime.rule.Match;
54 import org.mockito.Mock;
55 import org.mockito.MockitoAnnotations;
56 import org.onap.policy.controlloop.ControlLoopEvent;
57 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
58 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager2;
59 import org.onap.policy.drools.controller.DroolsController;
60 import org.onap.policy.drools.persistence.SystemPersistence;
61 import org.onap.policy.drools.system.PolicyController;
62 import org.onap.policy.drools.system.PolicyControllerFactory;
63 import org.onap.policy.drools.system.PolicyEngine;
64 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
66 public class RulesTest {
67 private static final String CONTROLLER_NAME = "rulesTest";
68 private static final String POLICY_FILE = "src/test/resources/tosca-policy.json";
69 private static final String MY_POLICY = "operational.restart";
70 private static final String RESOURCE_DIR = "src/test/resources";
71 private static final String MY_RULE_NAME = "my-rule-name";
72 private static final String MY_TEXT = "my text";
75 private PolicyEngine engine;
77 private SystemPersistence repo;
79 private PolicyController controller;
81 private KieSession kieSession;
83 private PolicyControllerFactory controllerFactory;
85 private DroolsController drools;
87 private List<Object> facts;
88 private List<RuleRuntimeEventListener> ruleListeners;
89 private List<AgendaEventListener> agendaListeners;
90 private Properties properties;
91 private boolean installed;
100 MockitoAnnotations.initMocks(this);
102 facts = new LinkedList<>();
103 ruleListeners = new LinkedList<>();
104 agendaListeners = new LinkedList<>();
106 properties = new Properties();
108 when(engine.createPolicyController(any(), any())).thenReturn(controller);
109 when(repo.getControllerProperties(CONTROLLER_NAME)).thenReturn(properties);
110 when(controller.getDrools()).thenReturn(drools);
112 when(drools.facts(eq(CONTROLLER_NAME), any())).thenAnswer(args -> {
113 Class<?> clazz = args.getArgument(1);
114 return facts.stream().filter(obj -> obj.getClass() == clazz).collect(Collectors.toList());
117 // notify listeners when objects are added to drools
118 when(drools.offer(any())).thenAnswer(args -> {
119 Object object = args.getArgument(0);
120 notifyInserted(object);
122 if (!(object instanceof ToscaPolicy)) {
126 // "insert" Params objects associated with the policy (i.e., mimic the rules)
127 ToscaPolicy policy = (ToscaPolicy) object;
128 ControlLoopParams params = new ControlLoopParams();
129 params.setToscaPolicy(policy);
130 notifyInserted(params);
135 when(drools.delete(any())).thenAnswer(args -> {
136 Class<?> clazz = args.getArgument(0);
137 facts.removeIf(obj -> obj.getClass() == clazz);
141 // handle rule listener registration and deregistration with the kieSession
143 ruleListeners.add(args.getArgument(0));
145 }).when(kieSession).addEventListener(any(RuleRuntimeEventListener.class));
148 ruleListeners.remove(args.getArgument(0));
150 }).when(kieSession).removeEventListener(any(RuleRuntimeEventListener.class));
152 // handle agenda listener registration and deregistration with the kieSession
154 agendaListeners.add(args.getArgument(0));
156 }).when(kieSession).addEventListener(any(AgendaEventListener.class));
159 agendaListeners.remove(args.getArgument(0));
161 }).when(kieSession).removeEventListener(any(AgendaEventListener.class));
163 rules = new MyRules();
165 rules.configure(RESOURCE_DIR);
170 public void testRules() {
171 assertEquals(CONTROLLER_NAME, rules.getControllerName());
173 assertSame(engine, rules.getPdpd());
174 assertSame(repo, rules.getPdpdRepo());
175 assertSame(controller, rules.getController());
179 public void testStart() throws Exception {
180 verify(repo).setConfigurationDir("src/test/resources/config");
181 assertTrue(installed);
182 verify(engine).configure(any(Properties.class));
183 verify(engine).createPolicyController(CONTROLLER_NAME, properties);
184 verify(engine).start();
186 verify(kieSession).addEventListener(any(RuleRuntimeEventListener.class));
187 verify(kieSession).addEventListener(any(AgendaEventListener.class));
191 public void testDestroy() {
194 verify(controllerFactory).shutdown(CONTROLLER_NAME);
195 verify(engine).stop();
199 public void testResetFacts() {
202 verify(drools).delete(ToscaPolicy.class);
203 verify(drools).delete(ControlLoopParams.class);
204 verify(drools).delete(ControlLoopEventManager2.class);
205 verify(drools).delete(ControlLoopEvent.class);
209 public void testSetupPolicyFromTemplate_testGetPolicyFromTemplate() {
210 rules.setupPolicyFromTemplate("tosca-template.json", MY_POLICY);
212 assertThatIllegalArgumentException()
213 .isThrownBy(() -> rules.setupPolicyFromTemplate("missing-file.json", "a-policy"));
217 public void testSetupPolicyFromFile_testGetPolicyFromFile_testSetupPolicy() {
218 assertNotNull(rules.setupPolicyFromFile(POLICY_FILE));
220 assertThatIllegalArgumentException().isThrownBy(() -> rules.setupPolicyFromFile("missing-file.json"));
224 public void testRuleListenerLogger() {
225 Rule rule = mock(Rule.class);
226 when(rule.getName()).thenReturn(MY_RULE_NAME);
228 // insertions - with and without rule name
229 ObjectInsertedEvent insert = mock(ObjectInsertedEvent.class);
230 when(insert.getObject()).thenReturn(MY_TEXT);
231 ruleListeners.forEach(listener -> listener.objectInserted(insert));
232 when(insert.getRule()).thenReturn(rule);
233 ruleListeners.forEach(listener -> listener.objectInserted(insert));
235 // updates - with and without rule name
236 ObjectUpdatedEvent update = mock(ObjectUpdatedEvent.class);
237 when(update.getObject()).thenReturn(MY_TEXT);
238 ruleListeners.forEach(listener -> listener.objectUpdated(update));
239 when(update.getRule()).thenReturn(rule);
240 ruleListeners.forEach(listener -> listener.objectUpdated(update));
242 // deletions - with and without rule name
243 ObjectDeletedEvent delete = mock(ObjectDeletedEvent.class);
244 when(delete.getOldObject()).thenReturn(MY_TEXT);
245 ruleListeners.forEach(listener -> listener.objectDeleted(delete));
246 when(delete.getRule()).thenReturn(rule);
247 ruleListeners.forEach(listener -> listener.objectDeleted(delete));
251 public void testAgendaListenerLogger() {
252 Rule rule = mock(Rule.class);
253 when(rule.getName()).thenReturn(MY_RULE_NAME);
255 Match match = mock(Match.class);
256 when(match.getRule()).thenReturn(rule);
259 MatchCreatedEvent create = mock(MatchCreatedEvent.class);
260 when(create.getMatch()).thenReturn(match);
261 agendaListeners.forEach(listener -> listener.matchCreated(create));
264 MatchCancelledEvent cancel = mock(MatchCancelledEvent.class);
265 when(cancel.getMatch()).thenReturn(match);
266 agendaListeners.forEach(listener -> listener.matchCancelled(cancel));
269 BeforeMatchFiredEvent before = mock(BeforeMatchFiredEvent.class);
270 when(before.getMatch()).thenReturn(match);
271 agendaListeners.forEach(listener -> listener.beforeMatchFired(before));
274 AfterMatchFiredEvent after = mock(AfterMatchFiredEvent.class);
275 when(after.getMatch()).thenReturn(match);
276 agendaListeners.forEach(listener -> listener.afterMatchFired(after));
280 public void testMakePdpd_testMakePdpdRepo() {
281 // need rules that makes real objects
282 rules = new Rules(CONTROLLER_NAME);
284 assertNotNull(rules.getPdpd());
285 assertNotNull(rules.getPdpdRepo());
288 protected void notifyInserted(Object object) {
289 // add it to our list
292 // increase code coverage by adding random objects
293 ObjectInsertedEvent event0 = mock(ObjectInsertedEvent.class);
294 when(event0.getObject()).thenReturn(new Object());
295 ruleListeners.forEach(listener -> listener.objectInserted(event0));
297 // increase code coverage by adding a random object
298 ObjectInsertedEvent event = mock(ObjectInsertedEvent.class);
299 when(event.getObject()).thenReturn(object);
301 if (object instanceof ToscaPolicy) {
302 // increase code coverage by associating it with a random rule
303 Rule rule = mock(Rule.class);
304 when(rule.getName()).thenReturn(MY_RULE_NAME);
305 when(event.getRule()).thenReturn(rule);
308 ruleListeners.forEach(listener -> listener.objectInserted(event));
311 private class MyRules extends Rules {
313 super(CONTROLLER_NAME);
317 protected PolicyEngine makeEngine() {
322 protected SystemPersistence makePdpdRepo() {
327 protected KieSession getKieSession() {
332 protected PolicyControllerFactory getControllerFactory() {
333 return controllerFactory;
337 protected void installArtifact(File kmoduleFile, File pomFile, String resourceDir, List<File> ruleFiles) {