28cb977fc09ac504d7a36f9f59b534bc4ce83d0c
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
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
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.controlloop.common.rules.test;
22
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;
34
35 import java.io.File;
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;
65
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";
73
74     @Mock
75     private PolicyEngine engine;
76     @Mock
77     private SystemPersistence repo;
78     @Mock
79     private PolicyController controller;
80     @Mock
81     private KieSession kieSession;
82     @Mock
83     private PolicyControllerFactory controllerFactory;
84     @Mock
85     private DroolsController drools;
86
87     private List<Object> facts;
88     private List<RuleRuntimeEventListener> ruleListeners;
89     private List<AgendaEventListener> agendaListeners;
90     private Properties properties;
91     private boolean installed;
92
93     private Rules rules;
94
95     /**
96      * Sets up.
97      */
98     @Before
99     public void setUp() {
100         MockitoAnnotations.initMocks(this);
101
102         facts = new LinkedList<>();
103         ruleListeners = new LinkedList<>();
104         agendaListeners = new LinkedList<>();
105         installed = false;
106         properties = new Properties();
107
108         when(engine.createPolicyController(any(), any())).thenReturn(controller);
109         when(repo.getControllerProperties(CONTROLLER_NAME)).thenReturn(properties);
110         when(controller.getDrools()).thenReturn(drools);
111
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());
115         });
116
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);
121
122             if (!(object instanceof ToscaPolicy)) {
123                 return true;
124             }
125
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);
131
132             return true;
133         });
134
135         when(drools.delete(any())).thenAnswer(args -> {
136             Class<?> clazz = args.getArgument(0);
137             facts.removeIf(obj -> obj.getClass() == clazz);
138             return null;
139         });
140
141         // handle rule listener registration and deregistration with the kieSession
142         doAnswer(args -> {
143             ruleListeners.add(args.getArgument(0));
144             return null;
145         }).when(kieSession).addEventListener(any(RuleRuntimeEventListener.class));
146
147         doAnswer(args -> {
148             ruleListeners.remove(args.getArgument(0));
149             return null;
150         }).when(kieSession).removeEventListener(any(RuleRuntimeEventListener.class));
151
152         // handle agenda listener registration and deregistration with the kieSession
153         doAnswer(args -> {
154             agendaListeners.add(args.getArgument(0));
155             return null;
156         }).when(kieSession).addEventListener(any(AgendaEventListener.class));
157
158         doAnswer(args -> {
159             agendaListeners.remove(args.getArgument(0));
160             return null;
161         }).when(kieSession).removeEventListener(any(AgendaEventListener.class));
162
163         rules = new MyRules();
164
165         rules.configure(RESOURCE_DIR);
166         rules.start();
167     }
168
169     @Test
170     public void testRules() {
171         assertEquals(CONTROLLER_NAME, rules.getControllerName());
172
173         assertSame(engine, rules.getPdpd());
174         assertSame(repo, rules.getPdpdRepo());
175         assertSame(controller, rules.getController());
176     }
177
178     @Test
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();
185
186         verify(kieSession).addEventListener(any(RuleRuntimeEventListener.class));
187         verify(kieSession).addEventListener(any(AgendaEventListener.class));
188     }
189
190     @Test
191     public void testDestroy() {
192         rules.destroy();
193
194         verify(controllerFactory).shutdown(CONTROLLER_NAME);
195         verify(engine).stop();
196     }
197
198     @Test
199     public void testResetFacts() {
200         rules.resetFacts();
201
202         verify(drools).delete(ToscaPolicy.class);
203         verify(drools).delete(ControlLoopParams.class);
204         verify(drools).delete(ControlLoopEventManager2.class);
205         verify(drools).delete(ControlLoopEvent.class);
206     }
207
208     @Test
209     public void testSetupPolicyFromTemplate_testGetPolicyFromTemplate() {
210         rules.setupPolicyFromTemplate("tosca-template.json", MY_POLICY);
211
212         assertThatIllegalArgumentException()
213                         .isThrownBy(() -> rules.setupPolicyFromTemplate("missing-file.json", "a-policy"));
214     }
215
216     @Test
217     public void testSetupPolicyFromFile_testGetPolicyFromFile_testSetupPolicy() {
218         assertNotNull(rules.setupPolicyFromFile(POLICY_FILE));
219
220         assertThatIllegalArgumentException().isThrownBy(() -> rules.setupPolicyFromFile("missing-file.json"));
221     }
222
223     @Test
224     public void testRuleListenerLogger() {
225         Rule rule = mock(Rule.class);
226         when(rule.getName()).thenReturn(MY_RULE_NAME);
227
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));
234
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));
241
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));
248     }
249
250     @Test
251     public void testAgendaListenerLogger() {
252         Rule rule = mock(Rule.class);
253         when(rule.getName()).thenReturn(MY_RULE_NAME);
254
255         Match match = mock(Match.class);
256         when(match.getRule()).thenReturn(rule);
257
258         // create
259         MatchCreatedEvent create = mock(MatchCreatedEvent.class);
260         when(create.getMatch()).thenReturn(match);
261         agendaListeners.forEach(listener -> listener.matchCreated(create));
262
263         // cancel
264         MatchCancelledEvent cancel = mock(MatchCancelledEvent.class);
265         when(cancel.getMatch()).thenReturn(match);
266         agendaListeners.forEach(listener -> listener.matchCancelled(cancel));
267
268         // before-fire
269         BeforeMatchFiredEvent before = mock(BeforeMatchFiredEvent.class);
270         when(before.getMatch()).thenReturn(match);
271         agendaListeners.forEach(listener -> listener.beforeMatchFired(before));
272
273         // after-fire
274         AfterMatchFiredEvent after = mock(AfterMatchFiredEvent.class);
275         when(after.getMatch()).thenReturn(match);
276         agendaListeners.forEach(listener -> listener.afterMatchFired(after));
277     }
278
279     @Test
280     public void testMakePdpd_testMakePdpdRepo() {
281         // need rules that makes real objects
282         rules = new Rules(CONTROLLER_NAME);
283
284         assertNotNull(rules.getPdpd());
285         assertNotNull(rules.getPdpdRepo());
286     }
287
288     protected void notifyInserted(Object object) {
289         // add it to our list
290         facts.add(object);
291
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));
296
297         // increase code coverage by adding a random object
298         ObjectInsertedEvent event = mock(ObjectInsertedEvent.class);
299         when(event.getObject()).thenReturn(object);
300
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);
306         }
307
308         ruleListeners.forEach(listener -> listener.objectInserted(event));
309     }
310
311     private class MyRules extends Rules {
312         public MyRules() {
313             super(CONTROLLER_NAME);
314         }
315
316         @Override
317         protected PolicyEngine makeEngine() {
318             return engine;
319         }
320
321         @Override
322         protected SystemPersistence makePdpdRepo() {
323             return repo;
324         }
325
326         @Override
327         protected KieSession getKieSession() {
328             return kieSession;
329         }
330
331         @Override
332         protected PolicyControllerFactory getControllerFactory() {
333             return controllerFactory;
334         }
335
336         @Override
337         protected void installArtifact(File kmoduleFile, File pomFile, String resourceDir, List<File> ruleFiles) {
338             installed = true;
339         }
340     }
341 }