7187ad1b5ee8456be867c131bbc90aec369c4dda
[policy/drools-pdp.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 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.drools.controller.internal;
22
23 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
24 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assert.assertSame;
29 import static org.junit.Assert.assertTrue;
30 import static org.mockito.Matchers.any;
31 import static org.mockito.Mockito.doThrow;
32 import static org.mockito.Mockito.mock;
33 import static org.mockito.Mockito.never;
34 import static org.mockito.Mockito.times;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.when;
37
38 import java.util.Arrays;
39 import java.util.Collections;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.TreeMap;
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.kie.api.KieBase;
46 import org.kie.api.definition.KiePackage;
47 import org.kie.api.definition.rule.Query;
48 import org.kie.api.runtime.KieContainer;
49 import org.kie.api.runtime.KieSession;
50 import org.kie.api.runtime.rule.FactHandle;
51 import org.kie.api.runtime.rule.QueryResults;
52 import org.kie.api.runtime.rule.QueryResultsRow;
53 import org.mockito.ArgumentCaptor;
54 import org.mockito.Mock;
55 import org.mockito.MockitoAnnotations;
56 import org.onap.policy.common.endpoints.event.comm.TopicSink;
57 import org.onap.policy.common.utils.services.OrderedServiceImpl;
58 import org.onap.policy.drools.core.PolicyContainer;
59 import org.onap.policy.drools.core.PolicySession;
60 import org.onap.policy.drools.features.DroolsControllerFeatureApi;
61 import org.onap.policy.drools.features.DroolsControllerFeatureApiConstants;
62 import org.onap.policy.drools.protocol.coders.EventProtocolCoder;
63 import org.onap.policy.drools.protocol.coders.EventProtocolCoderConstants;
64 import org.onap.policy.drools.protocol.coders.EventProtocolParams;
65 import org.onap.policy.drools.protocol.coders.JsonProtocolFilter;
66 import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration;
67 import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomGsonCoder;
68 import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.PotentialCoderFilter;
69
70 public class MavenDroolsController2Test {
71     private static final int FACT1_OBJECT = 1000;
72     private static final int FACT3_OBJECT = 1001;
73
74     private static final long FACT_COUNT = 200L;
75
76     private static final String EXPECTED_EXCEPTION = "expected exception";
77     private static final RuntimeException RUNTIME_EX = new RuntimeException(EXPECTED_EXCEPTION);
78     private static final IllegalArgumentException ARG_EX = new IllegalArgumentException(EXPECTED_EXCEPTION);
79
80     private static final String UNKNOWN_CLASS = "unknown class";
81
82     private static final String GROUP = "my-group";
83     private static final String ARTIFACT = "my-artifact";
84     private static final String VERSION = "my-version";
85
86     private static final String GROUP2 = "my-groupB";
87     private static final String ARTIFACT2 = "my-artifactB";
88     private static final String VERSION2 = "my-versionB";
89
90     private static final String TOPIC = "my-topic";
91     private static final String TOPIC2 = "my-topic";
92
93     private static final ClassLoader CLASS_LOADER = MavenDroolsController2Test.class.getClassLoader();
94     private static final int CLASS_LOADER_HASHCODE = CLASS_LOADER.hashCode();
95
96     private static final String SESSION1 = "session-A";
97     private static final String SESSION2 = "session-B";
98     private static final String FULL_SESSION1 = "full-A";
99     private static final String FULL_SESSION2 = "full-B";
100
101     private static final String EVENT_TEXT = "my-event-text";
102     private static final Object EVENT = new Object();
103
104     private static final String QUERY = "my-query";
105     private static final String QUERY2 = "my-query-B";
106     private static final String ENTITY = "my-entity";
107     private static final Object PARM1 = "parmA";
108     private static final Object PARM2 = "parmB";
109
110     @Mock
111     private EventProtocolCoder coderMgr;
112     @Mock
113     private DroolsControllerFeatureApi prov1;
114     @Mock
115     private DroolsControllerFeatureApi prov2;
116     @Mock
117     private OrderedServiceImpl<DroolsControllerFeatureApi> droolsProviders;
118     @Mock
119     private TopicCoderFilterConfiguration decoder1;
120     @Mock
121     private TopicCoderFilterConfiguration decoder2;
122     @Mock
123     private TopicCoderFilterConfiguration encoder1;
124     @Mock
125     private TopicCoderFilterConfiguration encoder2;
126     @Mock
127     private PolicyContainer container;
128     @Mock
129     private CustomGsonCoder gson1;
130     @Mock
131     private CustomGsonCoder gson2;
132     @Mock
133     private PotentialCoderFilter filter1a;
134     @Mock
135     private JsonProtocolFilter jsonFilter1a;
136     @Mock
137     private PotentialCoderFilter filter1b;
138     @Mock
139     private JsonProtocolFilter jsonFilter1b;
140     @Mock
141     private PotentialCoderFilter filter2;
142     @Mock
143     private JsonProtocolFilter jsonFilter2;
144     @Mock
145     private PolicySession sess1;
146     @Mock
147     private PolicySession sess2;
148     @Mock
149     private KieSession kieSess;
150     @Mock
151     private KieSession kieSess2;
152     @Mock
153     private TopicSink sink;
154     @Mock
155     private FactHandle fact1;
156     @Mock
157     private FactHandle fact2;
158     @Mock
159     private FactHandle fact3;
160     @Mock
161     private FactHandle factex;
162     @Mock
163     private KieBase kieBase;
164     @Mock
165     private KiePackage pkg1;
166     @Mock
167     private KiePackage pkg2;
168     @Mock
169     private Query query1;
170     @Mock
171     private Query query2;
172     @Mock
173     private Query query3;
174     @Mock
175     private QueryResults queryResults;
176     @Mock
177     private QueryResultsRow row1;
178     @Mock
179     private QueryResultsRow row2;
180
181     private List<TopicCoderFilterConfiguration> decoders;
182     private List<TopicCoderFilterConfiguration> encoders;
183
184     private MavenDroolsController drools;
185
186     /**
187      * Initializes objects, including the drools controller.
188      */
189     @Before
190     public void setUp() {
191         MockitoAnnotations.initMocks(this);
192
193         when(droolsProviders.getList()).thenReturn(Arrays.asList(prov1, prov2));
194
195         when(coderMgr.isDecodingSupported(GROUP, ARTIFACT, TOPIC)).thenReturn(true);
196         when(coderMgr.decode(GROUP, ARTIFACT, TOPIC, EVENT_TEXT)).thenReturn(EVENT);
197
198         when(kieSess.getFactCount()).thenReturn(FACT_COUNT);
199         when(kieSess.getFactHandles()).thenReturn(Arrays.asList(fact1, fact2, factex, fact3));
200         when(kieSess.getFactHandles(any())).thenReturn(Arrays.asList(fact1, fact3));
201         when(kieSess.getKieBase()).thenReturn(kieBase);
202         when(kieSess.getQueryResults(QUERY, PARM1, PARM2)).thenReturn(queryResults);
203
204         when(kieSess.getObject(fact1)).thenReturn(FACT1_OBJECT);
205         when(kieSess.getObject(fact2)).thenReturn("");
206         when(kieSess.getObject(fact3)).thenReturn(FACT3_OBJECT);
207         when(kieSess.getObject(factex)).thenThrow(RUNTIME_EX);
208
209         when(kieSess2.getFactHandles()).thenReturn(Collections.emptyList());
210
211         when(kieBase.getKiePackages()).thenReturn(Arrays.asList(pkg1, pkg2));
212
213         when(pkg1.getQueries()).thenReturn(Arrays.asList(query3));
214         when(pkg2.getQueries()).thenReturn(Arrays.asList(query2, query1));
215
216         when(query1.getName()).thenReturn(QUERY);
217         when(query2.getName()).thenReturn(QUERY2);
218
219         when(queryResults.iterator()).thenReturn(Arrays.asList(row1, row2).iterator());
220
221         when(row1.get(ENTITY)).thenReturn(FACT1_OBJECT);
222         when(row2.get(ENTITY)).thenReturn(FACT3_OBJECT);
223
224         when(row1.getFactHandle(ENTITY)).thenReturn(fact1);
225         when(row2.getFactHandle(ENTITY)).thenReturn(fact3);
226
227         when(sess1.getKieSession()).thenReturn(kieSess);
228         when(sess2.getKieSession()).thenReturn(kieSess2);
229
230         when(sess1.getName()).thenReturn(SESSION1);
231         when(sess2.getName()).thenReturn(SESSION2);
232
233         when(sess1.getFullName()).thenReturn(FULL_SESSION1);
234         when(sess2.getFullName()).thenReturn(FULL_SESSION2);
235
236         when(container.getClassLoader()).thenReturn(CLASS_LOADER);
237         when(container.getPolicySessions()).thenReturn(Arrays.asList(sess1, sess2));
238         when(container.insertAll(EVENT)).thenReturn(true);
239
240         when(decoder1.getTopic()).thenReturn(TOPIC);
241         when(decoder2.getTopic()).thenReturn(TOPIC2);
242
243         when(encoder1.getTopic()).thenReturn(TOPIC);
244         when(encoder2.getTopic()).thenReturn(TOPIC2);
245
246         decoders = Arrays.asList(decoder1, decoder2);
247         encoders = Arrays.asList(encoder1, encoder2);
248
249         when(decoder1.getCustomGsonCoder()).thenReturn(gson1);
250         when(encoder2.getCustomGsonCoder()).thenReturn(gson2);
251
252         when(filter1a.getCodedClass()).thenReturn(Object.class.getName());
253         when(filter1a.getFilter()).thenReturn(jsonFilter1a);
254
255         when(filter1b.getCodedClass()).thenReturn(String.class.getName());
256         when(filter1b.getFilter()).thenReturn(jsonFilter1b);
257
258         when(filter2.getCodedClass()).thenReturn(Integer.class.getName());
259         when(filter2.getFilter()).thenReturn(jsonFilter2);
260
261         when(decoder1.getCoderFilters()).thenReturn(Arrays.asList(filter1a, filter1b));
262         when(decoder2.getCoderFilters()).thenReturn(Collections.emptyList());
263
264         when(encoder1.getCoderFilters()).thenReturn(Collections.emptyList());
265         when(encoder2.getCoderFilters()).thenReturn(Arrays.asList(filter2));
266
267         when(sink.getTopic()).thenReturn(TOPIC);
268         when(sink.send(EVENT_TEXT)).thenReturn(true);
269
270         drools = new MyDrools(GROUP, ARTIFACT, VERSION, null, null);
271
272         when(coderMgr.encode(TOPIC, EVENT, drools)).thenReturn(EVENT_TEXT);
273     }
274
275     @Test
276     public void testMavenDroolsController_InvalidArgs() {
277         assertThatIllegalArgumentException().isThrownBy(() -> new MyDrools(null, ARTIFACT, VERSION, null, null))
278                         .withMessageContaining("group");
279         assertThatIllegalArgumentException().isThrownBy(() -> new MyDrools("", ARTIFACT, VERSION, null, null))
280                         .withMessageContaining("group");
281
282         assertThatIllegalArgumentException().isThrownBy(() -> new MyDrools(GROUP, null, VERSION, null, null))
283                         .withMessageContaining("artifact");
284         assertThatIllegalArgumentException().isThrownBy(() -> new MyDrools(GROUP, "", VERSION, null, null))
285                         .withMessageContaining("artifact");
286
287         assertThatIllegalArgumentException().isThrownBy(() -> new MyDrools(GROUP, ARTIFACT, null, null, null))
288                         .withMessageContaining("version");
289         assertThatIllegalArgumentException().isThrownBy(() -> new MyDrools(GROUP, ARTIFACT, "", null, null))
290                         .withMessageContaining("version");
291     }
292
293     @Test
294     public void testUpdateToVersion() {
295         // add coders
296         drools.updateToVersion(GROUP, ARTIFACT, VERSION2, decoders, encoders);
297
298         verify(container).updateToVersion(VERSION2);
299
300         // nothing removed the first time
301         verify(coderMgr, never()).removeDecoders(GROUP, ARTIFACT, TOPIC2);
302         verify(coderMgr, never()).removeEncoders(GROUP, ARTIFACT, TOPIC);
303
304         verify(coderMgr, times(2)).addDecoder(any());
305         verify(coderMgr, times(1)).addEncoder(any());
306
307         // remove coders
308         when(container.getVersion()).thenReturn(VERSION2);
309         drools.updateToVersion(GROUP, ARTIFACT, VERSION, null, null);
310
311         verify(container).updateToVersion(VERSION);
312
313         verify(coderMgr, times(2)).removeDecoders(GROUP, ARTIFACT, TOPIC2);
314         verify(coderMgr, times(2)).removeEncoders(GROUP, ARTIFACT, TOPIC);
315
316         // not added again
317         verify(coderMgr, times(2)).addDecoder(any());
318         verify(coderMgr, times(1)).addEncoder(any());
319     }
320
321     @Test
322     public void testUpdateToVersion_Unchanged() {
323         drools.updateToVersion(GROUP, ARTIFACT, VERSION, decoders, encoders);
324
325         verify(coderMgr, never()).addDecoder(any());
326         verify(coderMgr, never()).addEncoder(any());
327     }
328
329     @Test
330     public void testUpdateToVersion_InvalidArgs() {
331         assertThatIllegalArgumentException()
332                         .isThrownBy(() -> drools.updateToVersion(null, ARTIFACT, VERSION, null, null))
333                         .withMessageContaining("group");
334         assertThatIllegalArgumentException().isThrownBy(() -> drools.updateToVersion("", ARTIFACT, VERSION, null, null))
335                         .withMessageContaining("group");
336
337         assertThatIllegalArgumentException().isThrownBy(() -> drools.updateToVersion(GROUP, null, VERSION, null, null))
338                         .withMessageContaining("artifact");
339         assertThatIllegalArgumentException().isThrownBy(() -> drools.updateToVersion(GROUP, "", VERSION, null, null))
340                         .withMessageContaining("artifact");
341
342         assertThatIllegalArgumentException().isThrownBy(() -> drools.updateToVersion(GROUP, ARTIFACT, null, null, null))
343                         .withMessageContaining("version");
344         assertThatIllegalArgumentException().isThrownBy(() -> drools.updateToVersion(GROUP, ARTIFACT, "", null, null))
345                         .withMessageContaining("version");
346
347         assertThatIllegalArgumentException()
348                         .isThrownBy(() -> drools.updateToVersion("no-group-id", ARTIFACT, VERSION, null, null))
349                         .withMessageContaining("BRAINLESS");
350
351         assertThatIllegalArgumentException()
352                         .isThrownBy(() -> drools.updateToVersion(GROUP, "no-artifact-id", VERSION, null, null))
353                         .withMessageContaining("BRAINLESS");
354
355         assertThatIllegalArgumentException()
356                         .isThrownBy(() -> drools.updateToVersion(GROUP, ARTIFACT, "no-version", null, null))
357                         .withMessageContaining("BRAINLESS");
358
359         assertThatIllegalArgumentException()
360                         .isThrownBy(() -> drools.updateToVersion(GROUP2, ARTIFACT, VERSION, null, null))
361                         .withMessageContaining("coordinates must be identical");
362
363         assertThatIllegalArgumentException()
364                         .isThrownBy(() -> drools.updateToVersion(GROUP, ARTIFACT2, VERSION, null, null))
365                         .withMessageContaining("coordinates must be identical");
366     }
367
368     @Test
369     public void testInitCoders_NullCoders() {
370         // already constructed with null coders
371         verify(coderMgr, never()).addDecoder(any());
372         verify(coderMgr, never()).addEncoder(any());
373     }
374
375     @Test
376     public void testInitCoders_NullOrEmptyFilters() {
377         when(decoder1.getCoderFilters()).thenReturn(Collections.emptyList());
378         when(decoder2.getCoderFilters()).thenReturn(null);
379
380         when(encoder1.getCoderFilters()).thenReturn(null);
381         when(encoder2.getCoderFilters()).thenReturn(Collections.emptyList());
382
383         drools = new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders);
384
385         verify(coderMgr, never()).addDecoder(any());
386         verify(coderMgr, never()).addEncoder(any());
387     }
388
389     @Test
390     public void testInitCoders_GsonClass() {
391         when(gson1.getClassContainer()).thenReturn("");
392         when(gson2.getClassContainer()).thenReturn(Long.class.getName());
393
394         drools = new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders);
395
396         // all should be added
397         verify(coderMgr, times(2)).addDecoder(any());
398         verify(coderMgr, times(1)).addEncoder(any());
399     }
400
401     @Test
402     public void testInitCoders_InvalidGsonClass() {
403         when(gson1.getClassContainer()).thenReturn(UNKNOWN_CLASS);
404
405         assertThatIllegalArgumentException()
406                         .isThrownBy(() -> new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders))
407                         .withMessageContaining("cannot be retrieved");
408     }
409
410     @Test
411     public void testInitCoders_InvalidFilterClass() {
412         when(filter2.getCodedClass()).thenReturn(UNKNOWN_CLASS);
413
414         assertThatIllegalArgumentException()
415                         .isThrownBy(() -> new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders))
416                         .withMessageContaining("cannot be retrieved");
417     }
418
419     @Test
420     public void testInitCoders_Filters() {
421
422         drools = new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders);
423
424         ArgumentCaptor<EventProtocolParams> dec = ArgumentCaptor.forClass(EventProtocolParams.class);
425         verify(coderMgr, times(2)).addDecoder(dec.capture());
426
427         ArgumentCaptor<EventProtocolParams> enc = ArgumentCaptor.forClass(EventProtocolParams.class);
428         verify(coderMgr, times(1)).addEncoder(enc.capture());
429
430         // validate parameters
431         EventProtocolParams params = dec.getAllValues().get(0);
432         assertEquals(ARTIFACT, params.getArtifactId());
433         assertEquals(gson1, params.getCustomCoder());
434         assertEquals(Object.class.getName(), params.getEventClass());
435         assertEquals(GROUP, params.getGroupId());
436         assertEquals(CLASS_LOADER_HASHCODE, params.getModelClassLoaderHash());
437         assertEquals(jsonFilter1a, params.getProtocolFilter());
438         assertEquals(TOPIC, params.getTopic());
439
440         params = dec.getAllValues().get(1);
441         assertEquals(ARTIFACT, params.getArtifactId());
442         assertEquals(gson1, params.getCustomCoder());
443         assertEquals(String.class.getName(), params.getEventClass());
444         assertEquals(GROUP, params.getGroupId());
445         assertEquals(CLASS_LOADER_HASHCODE, params.getModelClassLoaderHash());
446         assertEquals(jsonFilter1b, params.getProtocolFilter());
447         assertEquals(TOPIC, params.getTopic());
448
449         params = enc.getAllValues().get(0);
450         assertEquals(ARTIFACT, params.getArtifactId());
451         assertEquals(gson2, params.getCustomCoder());
452         assertEquals(Integer.class.getName(), params.getEventClass());
453         assertEquals(GROUP, params.getGroupId());
454         assertEquals(CLASS_LOADER_HASHCODE, params.getModelClassLoaderHash());
455         assertEquals(jsonFilter2, params.getProtocolFilter());
456         assertEquals(TOPIC, params.getTopic());
457     }
458
459     @Test
460     public void testOwnsCoder() {
461         int hc = CLASS_LOADER_HASHCODE;
462
463         // wrong hash code
464         assertFalse(drools.ownsCoder(String.class, hc + 1));
465
466         // correct hash code
467         assertTrue(drools.ownsCoder(String.class, hc));
468
469         // unknown class
470         drools = new MyDrools(GROUP, ARTIFACT, VERSION, null, null) {
471             @Override
472             protected boolean isClass(String className) {
473                 return false;
474             }
475         };
476         assertFalse(drools.ownsCoder(String.class, hc));
477     }
478
479     @Test
480     public void testStart_testStop_testIsAlive() {
481         drools = new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders);
482
483         when(container.start()).thenReturn(true);
484         when(container.stop()).thenReturn(true);
485
486         assertFalse(drools.isAlive());
487
488         // start it
489         assertTrue(drools.start());
490         verify(container).start();
491         assertTrue(drools.isAlive());
492
493         // repeat - no changes
494         assertTrue(drools.start());
495         verify(container).start();
496         assertTrue(drools.isAlive());
497
498         // stop it
499         assertTrue(drools.stop());
500         verify(container).stop();
501         assertFalse(drools.isAlive());
502
503         // repeat - no changes
504         assertTrue(drools.stop());
505         verify(container).stop();
506         assertFalse(drools.isAlive());
507
508         // now check with container returning false - should still be invoked
509         when(container.start()).thenReturn(false);
510         when(container.stop()).thenReturn(false);
511         assertFalse(drools.start());
512         assertTrue(drools.isAlive());
513         assertFalse(drools.stop());
514         assertFalse(drools.isAlive());
515         verify(container, times(2)).start();
516         verify(container, times(2)).stop();
517
518         // coders should still be intact
519         verify(coderMgr, never()).removeDecoders(any(), any(), any());
520         verify(coderMgr, never()).removeEncoders(any(), any(), any());
521
522         verify(container, never()).shutdown();
523         verify(container, never()).destroy();
524     }
525
526     @Test
527     public void testShutdown() {
528         drools = new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders);
529
530         // start it
531         drools.start();
532
533         // shut down
534         drools.shutdown();
535
536         verify(container).stop();
537         assertFalse(drools.isAlive());
538
539         // coders should have been removed
540         verify(coderMgr, times(2)).removeDecoders(any(), any(), any());
541         verify(coderMgr, times(2)).removeEncoders(any(), any(), any());
542
543         verify(container).shutdown();
544         verify(container, never()).destroy();
545     }
546
547     @Test
548     public void testShutdown_Ex() {
549         drools = new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders);
550
551         // start it
552         drools.start();
553
554         when(container.stop()).thenThrow(RUNTIME_EX);
555
556         // shut down
557         drools.shutdown();
558
559         assertFalse(drools.isAlive());
560
561         verify(container).shutdown();
562         verify(container, never()).destroy();
563     }
564
565     @Test
566     public void testHalt() {
567         drools = new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders);
568
569         // start it
570         drools.start();
571
572         // halt
573         drools.halt();
574
575         verify(container).stop();
576         assertFalse(drools.isAlive());
577
578         // coders should have been removed
579         verify(coderMgr, times(2)).removeDecoders(any(), any(), any());
580         verify(coderMgr, times(2)).removeEncoders(any(), any(), any());
581
582         verify(container).destroy();
583     }
584
585     @Test
586     public void testHalt_Ex() {
587         drools = new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders);
588
589         // start it
590         drools.start();
591
592         when(container.stop()).thenThrow(RUNTIME_EX);
593
594         // halt
595         drools.halt();
596
597         assertFalse(drools.isAlive());
598
599         verify(container).destroy();
600     }
601
602     @Test
603     public void testRemoveCoders_Ex() {
604         drools = new MyDrools(GROUP, ARTIFACT, VERSION, decoders, encoders) {
605             @Override
606             protected void removeDecoders() {
607                 throw ARG_EX;
608             }
609
610             @Override
611             protected void removeEncoders() {
612                 throw ARG_EX;
613             }
614         };
615
616         drools.updateToVersion(GROUP, ARTIFACT, VERSION2, null, null);
617     }
618
619     @Test
620     public void testOfferStringString() {
621         drools.start();
622         assertTrue(drools.offer(TOPIC, EVENT_TEXT));
623
624         verify(container).insertAll(EVENT);
625     }
626
627     @Test
628     public void testOfferStringString_NoDecode() {
629         when(coderMgr.isDecodingSupported(GROUP, ARTIFACT, TOPIC)).thenReturn(false);
630
631         drools.start();
632         assertTrue(drools.offer(TOPIC, EVENT_TEXT));
633
634         verify(container, never()).insertAll(EVENT);
635     }
636
637     @Test
638     public void testOfferStringString_DecodeUnsupported() {
639         when(coderMgr.decode(GROUP, ARTIFACT, TOPIC, EVENT_TEXT))
640                         .thenThrow(new UnsupportedOperationException(EXPECTED_EXCEPTION));
641
642         drools.start();
643         assertTrue(drools.offer(TOPIC, EVENT_TEXT));
644
645         verify(container, never()).insertAll(EVENT);
646     }
647
648     @Test
649     public void testOfferStringString_DecodeEx() {
650         when(coderMgr.decode(GROUP, ARTIFACT, TOPIC, EVENT_TEXT)).thenThrow(RUNTIME_EX);
651
652         drools.start();
653         assertTrue(drools.offer(TOPIC, EVENT_TEXT));
654
655         verify(container, never()).insertAll(EVENT);
656     }
657
658     @Test
659     public void testOfferStringString_Ignored() {
660         drools.start();
661
662         drools.lock();
663         assertTrue(drools.offer(TOPIC, EVENT_TEXT));
664         assertEquals(0, drools.getRecentSourceEvents().length);
665         drools.unlock();
666
667         drools.stop();
668         assertTrue(drools.offer(TOPIC, EVENT_TEXT));
669         assertEquals(0, drools.getRecentSourceEvents().length);
670         drools.start();
671
672         // no sessions
673         when(container.getPolicySessions()).thenReturn(Collections.emptyList());
674         assertTrue(drools.offer(TOPIC, EVENT_TEXT));
675         assertEquals(0, drools.getRecentSourceEvents().length);
676     }
677
678     @Test
679     public void testOfferT() {
680         drools.start();
681         assertTrue(drools.offer(EVENT));
682         assertEquals(1, drools.getRecentSourceEvents().length);
683         assertEquals(EVENT, drools.getRecentSourceEvents()[0]);
684         verify(container).insertAll(EVENT);
685
686         verify(prov1).beforeInsert(drools, EVENT);
687         verify(prov2).beforeInsert(drools, EVENT);
688
689         verify(prov1).afterInsert(drools, EVENT, true);
690         verify(prov2).afterInsert(drools, EVENT, true);
691     }
692
693     @Test
694     public void testOfferT_Ex() {
695         when(prov1.beforeInsert(drools, EVENT)).thenThrow(RUNTIME_EX);
696         when(prov1.afterInsert(drools, EVENT, true)).thenThrow(RUNTIME_EX);
697
698         drools.start();
699         assertTrue(drools.offer(EVENT));
700         assertEquals(1, drools.getRecentSourceEvents().length);
701         assertEquals(EVENT, drools.getRecentSourceEvents()[0]);
702         verify(container).insertAll(EVENT);
703
704         // should still invoke prov2
705         verify(prov2).beforeInsert(drools, EVENT);
706
707         verify(prov2).afterInsert(drools, EVENT, true);
708     }
709
710     @Test
711     public void testOfferT_NotInserted() {
712         when(container.insertAll(EVENT)).thenReturn(false);
713
714         drools.start();
715         assertTrue(drools.offer(EVENT));
716         assertEquals(1, drools.getRecentSourceEvents().length);
717         assertEquals(EVENT, drools.getRecentSourceEvents()[0]);
718         verify(container).insertAll(EVENT);
719
720         verify(prov1).beforeInsert(drools, EVENT);
721         verify(prov2).beforeInsert(drools, EVENT);
722
723         verify(prov1).afterInsert(drools, EVENT, false);
724         verify(prov2).afterInsert(drools, EVENT, false);
725     }
726
727     @Test
728     public void testOfferT_BeforeInsertIntercept() {
729         drools.start();
730         when(prov1.beforeInsert(drools, EVENT)).thenReturn(true);
731
732         assertTrue(drools.offer(EVENT));
733         assertEquals(1, drools.getRecentSourceEvents().length);
734         assertEquals(EVENT, drools.getRecentSourceEvents()[0]);
735         verify(container, never()).insertAll(EVENT);
736
737         verify(prov1).beforeInsert(drools, EVENT);
738
739         // nothing else invoked
740         verify(prov2, never()).beforeInsert(drools, EVENT);
741         verify(prov1, never()).afterInsert(drools, EVENT, true);
742         verify(prov2, never()).afterInsert(drools, EVENT, true);
743     }
744
745     @Test
746     public void testOfferT_AfterInsertIntercept() {
747         drools.start();
748
749         when(prov1.afterInsert(drools, EVENT, true)).thenReturn(true);
750
751         assertTrue(drools.offer(EVENT));
752         assertEquals(1, drools.getRecentSourceEvents().length);
753         assertEquals(EVENT, drools.getRecentSourceEvents()[0]);
754         verify(container).insertAll(EVENT);
755
756         verify(prov1).beforeInsert(drools, EVENT);
757         verify(prov2).beforeInsert(drools, EVENT);
758
759         verify(prov1).afterInsert(drools, EVENT, true);
760
761         // prov2 is never called
762         verify(prov2, never()).afterInsert(drools, EVENT, true);
763     }
764
765     @Test
766     public void testOfferT_Ignored() {
767         drools.start();
768
769         drools.lock();
770         assertTrue(drools.offer(EVENT));
771         assertEquals(0, drools.getRecentSourceEvents().length);
772         drools.unlock();
773
774         drools.stop();
775         assertTrue(drools.offer(EVENT));
776         assertEquals(0, drools.getRecentSourceEvents().length);
777         drools.start();
778
779         // no sessions
780         when(container.getPolicySessions()).thenReturn(Collections.emptyList());
781         assertTrue(drools.offer(EVENT));
782         assertEquals(0, drools.getRecentSourceEvents().length);
783     }
784
785     @Test
786     public void testDeliver() {
787         drools.start();
788         assertTrue(drools.deliver(sink, EVENT));
789         assertEquals(1, drools.getRecentSinkEvents().length);
790         assertEquals(EVENT_TEXT, drools.getRecentSinkEvents()[0]);
791
792         verify(sink).send(EVENT_TEXT);
793
794         verify(prov1).beforeDeliver(drools, sink, EVENT);
795         verify(prov2).beforeDeliver(drools, sink, EVENT);
796
797         verify(prov1).afterDeliver(drools, sink, EVENT, EVENT_TEXT, true);
798         verify(prov2).afterDeliver(drools, sink, EVENT, EVENT_TEXT, true);
799     }
800
801     @Test
802     public void testDeliver_InvalidArgs() {
803         drools.start();
804
805         assertThatIllegalArgumentException().isThrownBy(() -> drools.deliver(null, EVENT))
806                         .withMessageContaining("sink");
807
808         assertThatIllegalArgumentException().isThrownBy(() -> drools.deliver(sink, null))
809                         .withMessageContaining("event");
810
811         drools.lock();
812         assertThatIllegalStateException().isThrownBy(() -> drools.deliver(sink, EVENT)).withMessageContaining("locked");
813         drools.unlock();
814
815         drools.stop();
816         assertThatIllegalStateException().isThrownBy(() -> drools.deliver(sink, EVENT))
817                         .withMessageContaining("stopped");
818         drools.start();
819
820         assertEquals(0, drools.getRecentSinkEvents().length);
821     }
822
823     @Test
824     public void testDeliver_BeforeIntercept() {
825         when(prov1.beforeDeliver(drools, sink, EVENT)).thenReturn(true);
826
827         drools.start();
828         assertTrue(drools.deliver(sink, EVENT));
829         assertEquals(0, drools.getRecentSinkEvents().length);
830
831         verify(prov1).beforeDeliver(drools, sink, EVENT);
832
833         // nothing else should have been invoked
834         verify(sink, never()).send(EVENT_TEXT);
835         verify(prov2, never()).beforeDeliver(drools, sink, EVENT);
836         verify(prov1, never()).afterDeliver(drools, sink, EVENT, EVENT_TEXT, true);
837         verify(prov2, never()).afterDeliver(drools, sink, EVENT, EVENT_TEXT, true);
838     }
839
840     @Test
841     public void testDeliver_AfterIntercept() {
842         when(prov1.afterDeliver(drools, sink, EVENT, EVENT_TEXT, true)).thenReturn(true);
843
844         drools.start();
845         assertTrue(drools.deliver(sink, EVENT));
846         assertEquals(1, drools.getRecentSinkEvents().length);
847         assertEquals(EVENT_TEXT, drools.getRecentSinkEvents()[0]);
848
849         verify(prov1).beforeDeliver(drools, sink, EVENT);
850         verify(prov2).beforeDeliver(drools, sink, EVENT);
851
852         verify(sink).send(EVENT_TEXT);
853
854         verify(prov1).afterDeliver(drools, sink, EVENT, EVENT_TEXT, true);
855
856         // nothing else should have been invoked
857         verify(prov2, never()).afterDeliver(drools, sink, EVENT, EVENT_TEXT, true);
858     }
859
860     @Test
861     public void testDeliver_InterceptEx() {
862         when(prov1.beforeDeliver(drools, sink, EVENT)).thenThrow(RUNTIME_EX);
863         when(prov1.afterDeliver(drools, sink, EVENT, EVENT_TEXT, true)).thenThrow(RUNTIME_EX);
864
865         drools.start();
866         assertTrue(drools.deliver(sink, EVENT));
867
868         verify(sink).send(EVENT_TEXT);
869
870         // should still invoke prov2
871         verify(prov2).beforeDeliver(drools, sink, EVENT);
872         verify(prov2).afterDeliver(drools, sink, EVENT, EVENT_TEXT, true);
873     }
874
875     @Test
876     public void testGetXxx() {
877         assertEquals(VERSION, drools.getVersion());
878         assertEquals(ARTIFACT, drools.getArtifactId());
879         assertEquals(GROUP, drools.getGroupId());
880         assertEquals(CLASS_LOADER_HASHCODE, drools.getModelClassLoaderHash());
881         assertSame(container, drools.getContainer());
882         assertEquals(Arrays.asList(sess1, sess2), drools.getSessions());
883
884         // test junit methods - need a controller with fewer overrides
885         drools = new MavenDroolsController(GROUP, ARTIFACT, VERSION, null, null) {
886             @Override
887             protected PolicyContainer makePolicyContainer(String groupId, String artifactId, String version) {
888                 return container;
889             }
890         };
891
892         assertSame(EventProtocolCoderConstants.getManager(), drools.getCoderManager());
893         assertSame(DroolsControllerFeatureApiConstants.getProviders(), drools.getDroolsProviders());
894     }
895
896     @Test
897     public void testLock_testUnlock_testIsLocked() {
898         assertFalse(drools.isLocked());
899
900         assertTrue(drools.lock());
901         assertTrue(drools.isLocked());
902
903         assertTrue(drools.unlock());
904         assertFalse(drools.isLocked());
905
906         // repeat
907         assertTrue(drools.lock());
908         assertTrue(drools.isLocked());
909
910         assertTrue(drools.unlock());
911         assertFalse(drools.isLocked());
912     }
913
914     @Test
915     public void testGetSessionNames_testGetCanonicalSessionNames() {
916         assertEquals("[session-A, session-B]", drools.getSessionNames(true).toString());
917         assertEquals("[full-A, full-B]", drools.getSessionNames(false).toString());
918
919         assertEquals("[session-A, session-B]", drools.getSessionNames().toString());
920
921         assertEquals("[full-A, full-B]", drools.getCanonicalSessionNames().toString());
922
923         // exception case
924         when(container.getPolicySessions()).thenThrow(RUNTIME_EX);
925         assertEquals("[expected exception]", drools.getSessionNames().toString());
926     }
927
928     @Test
929     public void testGetBaseDomainNames() {
930         KieContainer kiecont = mock(KieContainer.class);
931         when(kiecont.getKieBaseNames()).thenReturn(Arrays.asList("kieA", "kieB"));
932         when(container.getKieContainer()).thenReturn(kiecont);
933
934         assertEquals("[kieA, kieB]", drools.getBaseDomainNames().toString());
935     }
936
937     @Test
938     public void testGetSession() {
939         assertThatIllegalArgumentException().isThrownBy(() -> drools.getSession(null))
940                         .withMessageContaining("must be provided");
941
942         assertThatIllegalArgumentException().isThrownBy(() -> drools.getSession(""))
943                         .withMessageContaining("must be provided");
944
945         assertSame(sess1, drools.getSession(SESSION1));
946         assertSame(sess1, drools.getSession(FULL_SESSION1));
947
948         assertSame(sess2, drools.getSession(SESSION2));
949
950         assertThatIllegalArgumentException().isThrownBy(() -> drools.getSession("unknown session"))
951                         .withMessageContaining("Invalid Session Name");
952     }
953
954     @Test
955     public void testFactClassNames() {
956         // copy to a sorted map so the order remains unchanged
957         Map<String, Integer> map = new TreeMap<>(drools.factClassNames(SESSION1));
958         assertEquals("{java.lang.Integer=2, java.lang.String=1}", map.toString());
959
960         assertThatIllegalArgumentException().isThrownBy(() -> drools.factClassNames(null))
961                         .withMessageContaining("Invalid Session Name");
962
963         assertThatIllegalArgumentException().isThrownBy(() -> drools.factClassNames(""))
964                         .withMessageContaining("Invalid Session Name");
965     }
966
967     @Test
968     public void testFactCount() {
969         assertEquals(FACT_COUNT, drools.factCount(SESSION1));
970
971         assertThatIllegalArgumentException().isThrownBy(() -> drools.factCount(null))
972                         .withMessageContaining("Invalid Session Name");
973
974         assertThatIllegalArgumentException().isThrownBy(() -> drools.factCount(""))
975                         .withMessageContaining("Invalid Session Name");
976     }
977
978     @Test
979     public void testFactsStringStringBoolean() {
980         assertEquals("[1000, 1001]", drools.facts(SESSION1, Integer.class.getName(), false).toString());
981         verify(kieSess, never()).delete(fact1);
982         verify(kieSess, never()).delete(fact2);
983         verify(kieSess, never()).delete(fact3);
984         verify(kieSess, never()).delete(factex);
985
986         // now delete - but should only delete 1 & 3
987         assertEquals("[1000, 1001]", drools.facts(SESSION1, Integer.class.getName(), true).toString());
988         verify(kieSess).delete(fact1);
989         verify(kieSess, never()).delete(fact2);
990         verify(kieSess).delete(fact3);
991         verify(kieSess, never()).delete(factex);
992
993         assertThatIllegalArgumentException().isThrownBy(() -> drools.facts(null, Integer.class.getName(), false))
994                         .withMessageContaining("Invalid Session Name");
995
996         assertThatIllegalArgumentException().isThrownBy(() -> drools.facts("", Integer.class.getName(), false))
997                         .withMessageContaining("Invalid Session Name");
998
999         assertThatIllegalArgumentException().isThrownBy(() -> drools.facts(SESSION1, null, false))
1000                         .withMessageContaining("Invalid Class Name");
1001
1002         assertThatIllegalArgumentException().isThrownBy(() -> drools.facts(SESSION1, "", false))
1003                         .withMessageContaining("Invalid Class Name");
1004
1005         assertThatIllegalArgumentException().isThrownBy(() -> drools.facts(SESSION1, UNKNOWN_CLASS, false))
1006                         .withMessageContaining("classloader");
1007     }
1008
1009     @Test
1010     public void testFactsStringStringBoolean_DeleteEx() {
1011         doThrow(RUNTIME_EX).when(kieSess).delete(fact1);
1012
1013         assertEquals("[1000, 1001]", drools.facts(SESSION1, Integer.class.getName(), true).toString());
1014
1015         // should still have deleted #3
1016         verify(kieSess).delete(fact3);
1017     }
1018
1019     @Test
1020     public void testFactsStringClassOfT() {
1021         assertEquals("[1000, 1001]", drools.facts(SESSION1, Integer.class).toString());
1022     }
1023
1024     @Test
1025     public void testFactQuery() {
1026         assertEquals("[1000, 1001]", drools.factQuery(SESSION1, QUERY, ENTITY, false, PARM1, PARM2).toString());
1027
1028         verify(kieSess, never()).delete(fact1);
1029         verify(kieSess, never()).delete(fact3);
1030
1031         assertThatIllegalArgumentException()
1032                         .isThrownBy(() -> drools.factQuery(null, QUERY, ENTITY, false, PARM1, PARM2))
1033                         .withMessageContaining("Invalid Session Name");
1034
1035         assertThatIllegalArgumentException().isThrownBy(() -> drools.factQuery("", QUERY, ENTITY, false, PARM1, PARM2))
1036                         .withMessageContaining("Invalid Session Name");
1037
1038         assertThatIllegalArgumentException()
1039                         .isThrownBy(() -> drools.factQuery(SESSION1, null, ENTITY, false, PARM1, PARM2))
1040                         .withMessageContaining("Invalid Query Name");
1041
1042         assertThatIllegalArgumentException()
1043                         .isThrownBy(() -> drools.factQuery(SESSION1, "", ENTITY, false, PARM1, PARM2))
1044                         .withMessageContaining("Invalid Query Name");
1045
1046         assertThatIllegalArgumentException()
1047                         .isThrownBy(() -> drools.factQuery(SESSION1, QUERY, null, false, PARM1, PARM2))
1048                         .withMessageContaining("Invalid Queried Entity");
1049
1050         assertThatIllegalArgumentException()
1051                         .isThrownBy(() -> drools.factQuery(SESSION1, QUERY, "", false, PARM1, PARM2))
1052                         .withMessageContaining("Invalid Queried Entity");
1053
1054         assertThatIllegalArgumentException().isThrownBy(
1055             () -> drools.factQuery(SESSION1, QUERY + "-unknown-query", ENTITY, false, PARM1, PARM2))
1056             .withMessageContaining("Invalid Query Name");
1057     }
1058
1059     @Test
1060     public void testFactQuery_Delete() {
1061         doThrow(RUNTIME_EX).when(kieSess).delete(fact1);
1062
1063         assertEquals("[1000, 1001]", drools.factQuery(SESSION1, QUERY, ENTITY, true, PARM1, PARM2).toString());
1064
1065         // should still delete fact #3
1066         verify(kieSess).delete(fact3);
1067     }
1068
1069     @Test
1070     public void testDeleteStringT() {
1071         assertTrue(drools.delete(SESSION1, FACT3_OBJECT));
1072
1073         verify(kieSess, never()).delete(fact1);
1074         verify(kieSess).delete(fact3);
1075
1076         // not found
1077         assertFalse(drools.delete(SESSION1, "hello"));
1078
1079         // repeat, but generate exception while getting the first object
1080         when(kieSess.getObject(fact1)).thenThrow(RUNTIME_EX);
1081         assertTrue(drools.delete(SESSION1, FACT3_OBJECT));
1082
1083         verify(kieSess, never()).delete(fact1);
1084
1085         // should still delete fact #3
1086         verify(kieSess, times(2)).delete(fact3);
1087     }
1088
1089     @Test
1090     public void testDeleteT() {
1091         assertTrue(drools.delete(FACT3_OBJECT));
1092
1093         verify(kieSess).delete(fact3);
1094     }
1095
1096     @Test
1097     public void testDeleteStringClassOfT() {
1098         assertTrue(drools.delete(SESSION1, Integer.class));
1099
1100         verify(kieSess).delete(fact1);
1101         verify(kieSess).delete(fact3);
1102     }
1103
1104     @Test
1105     public void testDeleteStringClassOfT_Ex() {
1106         doThrow(RUNTIME_EX).when(kieSess).delete(fact1);
1107
1108         assertFalse(drools.delete(SESSION1, Integer.class));
1109
1110         // should still delete fact #3
1111         verify(kieSess).delete(fact3);
1112     }
1113
1114     @Test
1115     public void testDeleteClassOfT() {
1116         assertTrue(drools.delete(Integer.class));
1117
1118         verify(kieSess).delete(fact1);
1119         verify(kieSess).delete(fact3);
1120     }
1121
1122     @Test
1123     public void testFetchModelClass() {
1124         assertSame(Long.class, drools.fetchModelClass(Long.class.getName()));
1125     }
1126
1127     @Test
1128     public void testIsBrained() {
1129         assertTrue(drools.isBrained());
1130     }
1131
1132     @Test
1133     public void testToString() {
1134         assertNotNull(drools.toString());
1135     }
1136
1137     private class MyDrools extends MavenDroolsController {
1138
1139         public MyDrools(String groupId, String artifactId, String version,
1140                         List<TopicCoderFilterConfiguration> decoderConfigurations,
1141                         List<TopicCoderFilterConfiguration> encoderConfigurations) {
1142
1143             super(groupId, artifactId, version, decoderConfigurations, encoderConfigurations);
1144         }
1145
1146         @Override
1147         protected EventProtocolCoder getCoderManager() {
1148             return coderMgr;
1149         }
1150
1151         @Override
1152         protected OrderedServiceImpl<DroolsControllerFeatureApi> getDroolsProviders() {
1153             return droolsProviders;
1154         }
1155
1156         @Override
1157         protected PolicyContainer makePolicyContainer(String groupId, String artifactId, String version) {
1158             when(container.getGroupId()).thenReturn(groupId);
1159             when(container.getArtifactId()).thenReturn(artifactId);
1160             when(container.getVersion()).thenReturn(version);
1161
1162             return container;
1163         }
1164     }
1165 }