a6aa9d9dd653ee37898bd75b30d5b1862f4e24bc
[policy/drools-pdp.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2018-2021 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.system.internal;
22
23 import static org.assertj.core.api.Assertions.assertThatCode;
24 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
25 import static org.assertj.core.api.Assertions.assertThatThrownBy;
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertFalse;
28 import static org.junit.Assert.assertNotNull;
29 import static org.junit.Assert.assertTrue;
30 import static org.mockito.ArgumentMatchers.any;
31 import static org.mockito.Mockito.mock;
32 import static org.mockito.Mockito.never;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.verify;
35 import static org.mockito.Mockito.when;
36
37 import java.util.Arrays;
38 import java.util.List;
39 import java.util.Properties;
40 import java.util.function.BiConsumer;
41 import java.util.function.Consumer;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
45 import org.onap.policy.common.endpoints.event.comm.TopicEndpoint;
46 import org.onap.policy.common.endpoints.event.comm.TopicSink;
47 import org.onap.policy.common.endpoints.event.comm.TopicSource;
48 import org.onap.policy.common.utils.gson.GsonTestUtils;
49 import org.onap.policy.drools.controller.DroolsController;
50 import org.onap.policy.drools.controller.DroolsControllerFactory;
51 import org.onap.policy.drools.features.PolicyControllerFeatureApi;
52 import org.onap.policy.drools.persistence.SystemPersistence;
53 import org.onap.policy.drools.protocol.configuration.DroolsConfiguration;
54 import org.onap.policy.drools.system.GsonMgmtTestBuilder;
55
56 public class AggregatedPolicyControllerTest {
57
58     private static final String AGG_NAME = "agg-name";
59     private static final String SINK_TOPIC1 = "sink-a";
60     private static final String SINK_TOPIC2 = "sink-b";
61     private static final String SOURCE_TOPIC1 = "source-a";
62     private static final String SOURCE_TOPIC2 = "source-b";
63
64     private static final String EXPECTED = "expected exception";
65
66     private static final String MY_EVENT = "my-event";
67
68     private static final String ARTIFACT1 = "artifact-a";
69     private static final String GROUP1 = "group-a";
70     private static final String VERSION1 = "version-a";
71
72     private static final String ARTIFACT2 = "artifact-b";
73     private static final String GROUP2 = "group-b";
74     private static final String VERSION2 = "version-b";
75
76     private Properties properties;
77     private TopicEndpoint endpointMgr;
78     private List<TopicSource> sources;
79     private TopicSource source1;
80     private TopicSource source2;
81     private List<TopicSink> sinks;
82     private TopicSink sink1;
83     private TopicSink sink2;
84     private SystemPersistence persist;
85     private DroolsControllerFactory droolsFactory;
86     private DroolsController drools;
87     private DroolsConfiguration config;
88     private List<PolicyControllerFeatureApi> providers;
89     private PolicyControllerFeatureApi prov1;
90     private PolicyControllerFeatureApi prov2;
91     private AggregatedPolicyController apc;
92
93     /**
94      * Initializes the object to be tested.
95      */
96     @Before
97     public void setUp() {
98         properties = new Properties();
99
100         source1 = mock(TopicSource.class);
101         source2 = mock(TopicSource.class);
102         when(source1.getTopic()).thenReturn(SOURCE_TOPIC1);
103         when(source2.getTopic()).thenReturn(SOURCE_TOPIC2);
104
105         sink1 = mock(TopicSink.class);
106         sink2 = mock(TopicSink.class);
107         when(sink1.getTopic()).thenReturn(SINK_TOPIC1);
108         when(sink2.getTopic()).thenReturn(SINK_TOPIC2);
109
110         sources = Arrays.asList(source1, source2);
111         sinks = Arrays.asList(sink1, sink2);
112
113         endpointMgr = mock(TopicEndpoint.class);
114         when(endpointMgr.addTopicSources(any(Properties.class))).thenReturn(sources);
115         when(endpointMgr.addTopicSinks(any(Properties.class))).thenReturn(sinks);
116
117         persist = mock(SystemPersistence.class);
118
119         drools = mock(DroolsController.class);
120         when(drools.start()).thenReturn(true);
121         when(drools.stop()).thenReturn(true);
122         when(drools.offer(any(), any())).thenReturn(true);
123         when(drools.deliver(any(), any())).thenReturn(true);
124         when(drools.lock()).thenReturn(true);
125         when(drools.unlock()).thenReturn(true);
126         when(drools.getArtifactId()).thenReturn(ARTIFACT1);
127         when(drools.getGroupId()).thenReturn(GROUP1);
128         when(drools.getVersion()).thenReturn(VERSION1);
129
130         config = mock(DroolsConfiguration.class);
131         when(config.getArtifactId()).thenReturn(ARTIFACT2);
132         when(config.getGroupId()).thenReturn(GROUP2);
133         when(config.getVersion()).thenReturn(VERSION2);
134
135         droolsFactory = mock(DroolsControllerFactory.class);
136         when(droolsFactory.build(any(), any(), any())).thenReturn(drools);
137
138         prov1 = mock(PolicyControllerFeatureApi.class);
139         prov2 = mock(PolicyControllerFeatureApi.class);
140
141         providers = Arrays.asList(prov1, prov2);
142
143         apc = new AggregatedPolicyControllerImpl(AGG_NAME, properties);
144     }
145
146     @Test
147     public void testFactory() {
148         apc = new AggregatedPolicyController(AGG_NAME, properties);
149         assertNotNull(apc.getDroolsFactory());
150         assertNotNull(apc.getEndpointManager());
151         assertNotNull(apc.getProviders());
152         assertNotNull(apc.getPersistenceManager());
153     }
154
155     @Test
156     public void testAggregatedPolicyController_() {
157         verify(persist).storeController(AGG_NAME, properties);
158     }
159
160     @Test(expected = IllegalArgumentException.class)
161     public void testInitDrools_Ex() {
162         new AggregatedPolicyControllerImpl(AGG_NAME, properties) {
163             @Override
164             protected DroolsControllerFactory getDroolsFactory() {
165                 throw new RuntimeException(EXPECTED);
166             }
167         };
168     }
169
170     @Test(expected = IllegalArgumentException.class)
171     public void testInitDrools_Error() {
172         new AggregatedPolicyControllerImpl(AGG_NAME, properties) {
173             @Override
174             protected DroolsControllerFactory getDroolsFactory() {
175                 throw new LinkageError(EXPECTED);
176             }
177         };
178     }
179
180     @Test
181     public void testUpdateDrools_ConfigVariations() {
182
183         // config should return same values as current controller
184         when(config.getArtifactId()).thenReturn(ARTIFACT1.toUpperCase());
185         when(config.getGroupId()).thenReturn(GROUP1.toUpperCase());
186         when(config.getVersion()).thenReturn(VERSION1.toUpperCase());
187
188         assertTrue(apc.updateDrools(config));
189
190         // number of times store should have been called
191         int count = 0;
192
193         // invoked once during construction, but shouldn't be invoked during update
194         verify(persist, times(++count)).storeController(any(), any());
195
196
197         // different artifact
198         when(config.getArtifactId()).thenReturn(ARTIFACT2);
199
200         assertTrue(apc.updateDrools(config));
201
202         // should be invoked during update
203         verify(persist, times(++count)).storeController(any(), any());
204
205
206         // different group
207         when(config.getArtifactId()).thenReturn(ARTIFACT1);
208         when(config.getGroupId()).thenReturn(GROUP2);
209
210         assertTrue(apc.updateDrools(config));
211
212         // should be invoked during update
213         verify(persist, times(++count)).storeController(any(), any());
214
215
216         // different version
217         when(config.getGroupId()).thenReturn(GROUP1);
218         when(config.getVersion()).thenReturn(VERSION2);
219
220         assertTrue(apc.updateDrools(config));
221
222         // should be invoked during update
223         verify(persist, times(++count)).storeController(any(), any());
224
225
226         /*
227          * Exception case.
228          */
229         when(drools.lock()).thenThrow(new IllegalArgumentException(EXPECTED));
230         when(drools.unlock()).thenThrow(new IllegalArgumentException(EXPECTED));
231
232         assertFalse(apc.updateDrools(config));
233     }
234
235     @Test
236     public void testUpdateDrools_LockVariations() {
237         // not locked
238         apc.updateDrools(config);
239         verify(drools, never()).lock();
240         verify(drools).unlock();
241
242         // locked
243         setUp();
244         apc.lock();
245         apc.updateDrools(config);
246         verify(drools, times(2)).lock();
247         verify(drools, never()).unlock();
248     }
249
250     @Test
251     public void testUpdateDrools_AliveVariations() {
252         // not started
253         apc.updateDrools(config);
254         verify(drools, never()).start();
255         verify(drools).stop();
256
257         // started
258         setUp();
259         apc.start();
260         apc.updateDrools(config);
261         verify(drools, times(2)).start();
262         verify(drools, never()).stop();
263     }
264
265     @Test
266     public void testSerialize() {
267         GsonTestUtils gson = new GsonMgmtTestBuilder().addDroolsControllerMock().addTopicSinkMock().addTopicSourceMock()
268                         .build();
269         assertThatCode(() -> gson.compareGson(apc, AggregatedPolicyControllerTest.class)).doesNotThrowAnyException();
270     }
271
272     @Test
273     public void testGetName() {
274         assertEquals(AGG_NAME, apc.getName());
275     }
276
277     @Test
278     public void testStart() {
279         // arrange for first provider to throw exceptions
280         when(prov1.beforeStart(any())).thenThrow(new RuntimeException(EXPECTED));
281         when(prov1.afterStart(any())).thenThrow(new RuntimeException(EXPECTED));
282
283         // arrange for first sink to throw exception
284         when(sink1.start()).thenThrow(new RuntimeException(EXPECTED));
285
286         // start it
287         assertTrue(apc.start());
288
289         assertTrue(apc.isAlive());
290
291         verify(prov1).beforeStart(apc);
292         verify(prov2).beforeStart(apc);
293
294         verify(source1).register(apc);
295         verify(source2).register(apc);
296
297         verify(sink1).start();
298         verify(sink2).start();
299
300         verify(prov1).afterStart(apc);
301         verify(prov2).afterStart(apc);
302
303         checkBeforeAfter(
304             (prov, flag) -> when(prov.beforeStart(apc)).thenReturn(flag),
305             (prov, flag) -> when(prov.afterStart(apc)).thenReturn(flag),
306             () -> apc.start(),
307             prov -> verify(prov).beforeStart(apc),
308             () -> verify(source1).register(apc),
309             prov -> verify(prov).afterStart(apc));
310     }
311
312     @Test
313     public void testStart_AlreadyStarted() {
314         apc.start();
315
316         // re-start it
317         assertTrue(apc.start());
318
319         assertTrue(apc.isAlive());
320
321         // these should now have been called twice
322         verify(prov1, times(2)).beforeStart(apc);
323         verify(prov2, times(2)).beforeStart(apc);
324
325         // these should still only have been called once
326         verify(source1).register(apc);
327         verify(sink1).start();
328         verify(prov1).afterStart(apc);
329     }
330
331     @Test
332     public void testStart_Locked() {
333         apc.lock();
334
335         // start it
336         assertThatIllegalStateException().isThrownBy(() -> apc.start());
337
338         assertFalse(apc.isAlive());
339
340         // should call beforeStart(), but stop after that
341         verify(prov1).beforeStart(apc);
342         verify(prov2).beforeStart(apc);
343
344         verify(source1, never()).register(apc);
345         verify(sink1, never()).start();
346         verify(prov1, never()).afterStart(apc);
347     }
348
349     @Test
350     public void testStop() {
351         // arrange for first provider to throw exceptions
352         when(prov1.beforeStop(any())).thenThrow(new RuntimeException(EXPECTED));
353         when(prov1.afterStop(any())).thenThrow(new RuntimeException(EXPECTED));
354
355         // start it
356         apc.start();
357
358         // now stop it
359         assertTrue(apc.stop());
360
361         assertFalse(apc.isAlive());
362
363         verify(prov1).beforeStop(apc);
364         verify(prov2).beforeStop(apc);
365
366         verify(source1).unregister(apc);
367         verify(source2).unregister(apc);
368
369         verify(prov1).afterStop(apc);
370         verify(prov2).afterStop(apc);
371
372         // ensure no shutdown operations were called
373         verify(prov1, never()).beforeShutdown(apc);
374         verify(droolsFactory, never()).shutdown(drools);
375         verify(prov2, never()).afterShutdown(apc);
376
377         checkBeforeAfter(
378             (prov, flag) -> when(prov.beforeStop(apc)).thenReturn(flag),
379             (prov, flag) -> when(prov.afterStop(apc)).thenReturn(flag),
380             () -> {
381                 apc.start();
382                 apc.stop();
383             },
384             prov -> verify(prov).beforeStop(apc),
385             () -> verify(source1).unregister(apc),
386             prov -> verify(prov).afterStop(apc));
387     }
388
389     @Test
390     public void testStop_AlreadyStopped() {
391         apc.start();
392         apc.stop();
393
394         // now re-stop it
395         assertTrue(apc.stop());
396
397         // called again
398         verify(prov1, times(2)).beforeStop(apc);
399         verify(prov2, times(2)).beforeStop(apc);
400
401         // should NOT be called again
402         verify(source1).unregister(apc);
403         verify(prov1).afterStop(apc);
404     }
405
406     @Test
407     public void testShutdown() {
408         // arrange for first provider to throw exceptions
409         when(prov1.beforeShutdown(any())).thenThrow(new RuntimeException(EXPECTED));
410         when(prov1.afterShutdown(any())).thenThrow(new RuntimeException(EXPECTED));
411
412         // start it
413         apc.start();
414
415         // now shut it down
416         apc.shutdown();
417
418         verify(prov1).beforeShutdown(apc);
419         verify(prov2).beforeShutdown(apc);
420
421         assertFalse(apc.isAlive());
422
423         verify(prov1).afterStop(apc);
424         verify(prov2).afterStop(apc);
425
426         verify(droolsFactory).shutdown(drools);
427
428         verify(prov1).afterShutdown(apc);
429         verify(prov2).afterShutdown(apc);
430
431         // ensure no halt operation was called
432         verify(prov1, never()).beforeHalt(apc);
433
434         checkBeforeAfter(
435             (prov, flag) -> when(prov.beforeShutdown(apc)).thenReturn(flag),
436             (prov, flag) -> when(prov.afterShutdown(apc)).thenReturn(flag),
437             () -> {
438                 apc.start();
439                 apc.shutdown();
440             },
441             prov -> verify(prov).beforeShutdown(apc),
442             () -> verify(source1).unregister(apc),
443             prov -> verify(prov).afterShutdown(apc));
444     }
445
446     @Test
447     public void testHalt() {
448         // arrange for first provider to throw exceptions
449         when(prov1.beforeHalt(any())).thenThrow(new RuntimeException(EXPECTED));
450         when(prov1.afterHalt(any())).thenThrow(new RuntimeException(EXPECTED));
451
452         // start it
453         apc.start();
454
455         // now halt it
456         apc.halt();
457
458         verify(prov1).beforeHalt(apc);
459         verify(prov2).beforeHalt(apc);
460
461         assertFalse(apc.isAlive());
462
463         verify(prov1).beforeStop(apc);
464         verify(prov2).beforeStop(apc);
465
466         verify(droolsFactory).destroy(drools);
467         verify(persist).deleteController(AGG_NAME);
468
469         verify(prov1).afterHalt(apc);
470         verify(prov2).afterHalt(apc);
471
472         // ensure no shutdown operation was called
473         verify(prov1, never()).beforeShutdown(apc);
474
475         checkBeforeAfter(
476             (prov, flag) -> when(prov.beforeHalt(apc)).thenReturn(flag),
477             (prov, flag) -> when(prov.afterHalt(apc)).thenReturn(flag),
478             () -> {
479                 apc.start();
480                 apc.halt();
481             },
482             prov -> verify(prov).beforeHalt(apc),
483             () -> verify(source1).unregister(apc),
484             prov -> verify(prov).afterHalt(apc));
485     }
486
487     @Test
488     public void testOnTopicEvent() {
489         // arrange for first provider to throw exceptions
490         when(prov1.beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT))
491                         .thenThrow(new RuntimeException(EXPECTED));
492         when(prov1.afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true))
493                         .thenThrow(new RuntimeException(EXPECTED));
494
495         // start it
496         apc.start();
497
498         // now offer it
499         apc.onTopicEvent(CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
500
501         verify(prov1).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
502         verify(prov2).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
503
504         verify(drools).offer(SOURCE_TOPIC1, MY_EVENT);
505
506         verify(prov1).afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true);
507         verify(prov2).afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true);
508
509         checkBeforeAfter(
510             (prov, flag) -> when(prov.beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT))
511                             .thenReturn(flag),
512             (prov, flag) -> when(
513                             prov.afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true))
514                                             .thenReturn(flag),
515             () -> {
516                 apc.start();
517                 apc.onTopicEvent(CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
518             },
519             prov -> verify(prov).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT),
520             () -> verify(drools).offer(SOURCE_TOPIC1, MY_EVENT),
521             prov -> verify(prov).afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true));
522     }
523
524     @Test
525     public void testOnTopicEvent_Locked() {
526         // start it
527         apc.start();
528
529         apc.lock();
530
531         // now offer it
532         apc.onTopicEvent(CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
533
534         verify(prov1, never()).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
535         verify(prov2, never()).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
536
537         // never gets this far
538         verify(drools, never()).offer(SOURCE_TOPIC1, MY_EVENT);
539         verify(prov1, never()).afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true);
540     }
541
542     @Test
543     public void testOnTopicEvent_NotStarted() {
544
545         // offer it
546         apc.onTopicEvent(CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
547
548         verify(prov1, never()).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
549         verify(prov2, never()).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
550
551         // never gets this far
552         verify(drools, never()).offer(SOURCE_TOPIC1, MY_EVENT);
553         verify(prov1, never()).afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true);
554     }
555
556     @Test
557     public void testDeliver_testInitSinks() {
558         // arrange for first provider to throw exceptions
559         when(prov1.beforeDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT))
560                         .thenThrow(new RuntimeException(EXPECTED));
561         when(prov1.afterDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT, true))
562                         .thenThrow(new RuntimeException(EXPECTED));
563
564         // start it
565         apc.start();
566
567         // now offer it
568         assertTrue(apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT));
569
570         verify(prov1).beforeDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT);
571         verify(prov2).beforeDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT);
572
573         verify(drools).deliver(sink1, MY_EVENT);
574         verify(drools, never()).deliver(sink2, MY_EVENT);
575
576         verify(prov1).afterDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT, true);
577         verify(prov2).afterDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT, true);
578
579         // offer to the other topic
580         assertTrue(apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC2, MY_EVENT));
581
582         // now both topics should show one message delivered
583         verify(drools).deliver(sink1, MY_EVENT);
584         verify(drools).deliver(sink2, MY_EVENT);
585
586         checkBeforeAfter(
587             (prov, flag) -> when(prov.beforeDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT))
588                             .thenReturn(flag),
589             (prov, flag) -> when(
590                             prov.afterDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT, true))
591                                             .thenReturn(flag),
592             () -> {
593                 apc.start();
594                 apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT);
595             },
596             prov -> verify(prov).beforeDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT),
597             () -> verify(drools).deliver(sink1, MY_EVENT),
598             prov -> verify(prov).afterDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT, true));
599     }
600
601     @Test(expected = IllegalArgumentException.class)
602     public void testDeliver_NullTopic() {
603         validateDeliverFailure(null, MY_EVENT);
604     }
605
606     @Test(expected = IllegalArgumentException.class)
607     public void testDeliver_EmptyTopic() {
608         validateDeliverFailure("", MY_EVENT);
609     }
610
611     @Test(expected = IllegalArgumentException.class)
612     public void testDeliver_NullEvent() {
613         validateDeliverFailure(SINK_TOPIC1, null);
614     }
615
616     @Test(expected = IllegalStateException.class)
617     public void testDeliver_NotStarted() {
618         // do NOT start
619         apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT);
620     }
621
622     @Test(expected = IllegalStateException.class)
623     public void testDeliver_Locked() {
624         apc.start();
625         apc.lock();
626         apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT);
627     }
628
629     @Test(expected = IllegalArgumentException.class)
630     public void testDeliver_UnknownTopic() {
631         apc.start();
632         apc.deliver(CommInfrastructure.NOOP, "unknown-topic", MY_EVENT);
633     }
634
635     @Test
636     public void testIsAlive() {
637         assertFalse(apc.isAlive());
638
639         apc.start();
640         assertTrue(apc.isAlive());
641
642         apc.stop();
643         assertFalse(apc.isAlive());
644     }
645
646     @Test
647     public void testLock() {
648         // arrange for first provider to throw exceptions
649         when(prov1.beforeLock(any())).thenThrow(new RuntimeException(EXPECTED));
650         when(prov1.afterLock(any())).thenThrow(new RuntimeException(EXPECTED));
651
652         // start it
653         apc.start();
654
655         // now lock it
656         assertTrue(apc.lock());
657
658         verify(prov1).beforeLock(apc);
659         verify(prov2).beforeLock(apc);
660
661         assertTrue(apc.isLocked());
662
663         verify(drools).lock();
664
665         verify(prov1).afterLock(apc);
666         verify(prov2).afterLock(apc);
667
668         checkBeforeAfter(
669             (prov, flag) -> when(prov.beforeLock(apc)).thenReturn(flag),
670             (prov, flag) -> when(prov.afterLock(apc)).thenReturn(flag),
671             () -> {
672                 apc.start();
673                 apc.lock();
674             },
675             prov -> verify(prov).beforeLock(apc),
676             () -> verify(drools).lock(),
677             prov -> verify(prov).afterLock(apc));
678     }
679
680     @Test
681     public void testLock_AlreadyLocked() {
682         apc.start();
683         apc.lock();
684
685         // now re-lock it
686         assertTrue(apc.lock());
687
688         // these should be invoked a second time
689         verify(prov1, times(2)).beforeLock(apc);
690         verify(prov2, times(2)).beforeLock(apc);
691
692         assertTrue(apc.isLocked());
693
694         // these shouldn't be invoked a second time
695         verify(drools).lock();
696         verify(prov1).afterLock(apc);
697     }
698
699     @Test
700     public void testUnlock() {
701         // arrange for first provider to throw exceptions
702         when(prov1.beforeUnlock(any())).thenThrow(new RuntimeException(EXPECTED));
703         when(prov1.afterUnlock(any())).thenThrow(new RuntimeException(EXPECTED));
704
705         // start it
706         apc.start();
707         apc.lock();
708
709         // now unlock it
710         assertTrue(apc.unlock());
711
712         verify(prov1).beforeUnlock(apc);
713         verify(prov2).beforeUnlock(apc);
714
715         assertFalse(apc.isLocked());
716
717         verify(drools).unlock();
718
719         verify(prov1).afterUnlock(apc);
720         verify(prov2).afterUnlock(apc);
721
722         checkBeforeAfter(
723             (prov, flag) -> when(prov.beforeUnlock(apc)).thenReturn(flag),
724             (prov, flag) -> when(prov.afterUnlock(apc)).thenReturn(flag),
725             () -> {
726                 apc.start();
727                 apc.lock();
728                 apc.unlock();
729             },
730             prov -> verify(prov).beforeUnlock(apc),
731             () -> verify(drools).unlock(),
732             prov -> verify(prov).afterUnlock(apc));
733     }
734
735     @Test
736     public void testUnlock_NotLocked() {
737         apc.start();
738
739         // now unlock it
740         assertTrue(apc.unlock());
741
742         verify(prov1).beforeUnlock(apc);
743         verify(prov2).beforeUnlock(apc);
744
745         assertFalse(apc.isLocked());
746
747         // these shouldn't be invoked
748         verify(drools, never()).unlock();
749         verify(prov1, never()).afterLock(apc);
750     }
751
752     @Test
753     public void testIsLocked() {
754         assertFalse(apc.isLocked());
755
756         apc.lock();
757         assertTrue(apc.isLocked());
758
759         apc.unlock();
760         assertFalse(apc.isLocked());
761     }
762
763     @Test
764     public void testGetTopicSources() {
765         assertEquals(sources, apc.getTopicSources());
766     }
767
768     @Test
769     public void testGetTopicSinks() {
770         assertEquals(sinks, apc.getTopicSinks());
771     }
772
773     @Test
774     public void testGetDrools() {
775         assertEquals(drools, apc.getDrools());
776     }
777
778     @Test
779     public void testGetProperties() {
780         assertEquals(properties, apc.getProperties());
781     }
782
783     @Test
784     public void testToString() {
785         assertTrue(apc.toString().startsWith("AggregatedPolicyController("));
786     }
787
788     private void validateDeliverFailure(String topic, String event) {
789         apc.start();
790         apc.deliver(CommInfrastructure.NOOP, topic, event);
791     }
792
793     /**
794      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries
795      * combinations where beforeXxx and afterXxx return {@code true} and {@code false}.
796      *
797      * @param setBefore function to set the return value of a provider's beforeXxx method
798      * @param setAfter function to set the return value of a provider's afterXxx method
799      * @param action invokes the operation
800      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
801      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
802      *        and the afterXxx loop was invoked
803      * @param verifyAfter verifies that a provider's afterXxx method was invoked
804      */
805     private void checkBeforeAfter(BiConsumer<PolicyControllerFeatureApi, Boolean> setBefore,
806                     BiConsumer<PolicyControllerFeatureApi, Boolean> setAfter, Runnable action,
807                     Consumer<PolicyControllerFeatureApi> verifyBefore, Runnable verifyMiddle,
808                     Consumer<PolicyControllerFeatureApi> verifyAfter) {
809
810         checkBeforeAfter_FalseFalse(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
811         checkBeforeAfter_FalseTrue(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
812         checkBeforeAfter_TrueFalse(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
813
814         // don't need to test true-true, as it's behavior is a subset of true-false
815     }
816
817     /**
818      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
819      * case where both the beforeXxx and afterXxx methods return {@code false}.
820      *
821      * @param setBefore function to set the return value of a provider's beforeXxx method
822      * @param setAfter function to set the return value of a provider's afterXxx method
823      * @param action invokes the operation
824      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
825      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
826      *        and the afterXxx loop was invoked
827      * @param verifyAfter verifies that a provider's afterXxx method was invoked
828      */
829     private void checkBeforeAfter_FalseFalse(BiConsumer<PolicyControllerFeatureApi, Boolean> setBefore,
830                     BiConsumer<PolicyControllerFeatureApi, Boolean> setAfter, Runnable action,
831                     Consumer<PolicyControllerFeatureApi> verifyBefore, Runnable verifyMiddle,
832                     Consumer<PolicyControllerFeatureApi> verifyAfter) {
833
834         setUp();
835
836         // configure for the test
837         setBefore.accept(prov1, false);
838         setBefore.accept(prov2, false);
839
840         setAfter.accept(prov1, false);
841         setAfter.accept(prov2, false);
842
843         // run the action
844         action.run();
845
846         // verify that various methods were invoked
847         verifyBefore.accept(prov1);
848         verifyBefore.accept(prov2);
849
850         verifyMiddle.run();
851
852         verifyAfter.accept(prov1);
853         verifyAfter.accept(prov2);
854     }
855
856     /**
857      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
858      * case where the first provider's afterXxx returns {@code true}, while the others
859      * return {@code false}.
860      *
861      * @param setBefore function to set the return value of a provider's beforeXxx method
862      * @param setAfter function to set the return value of a provider's afterXxx method
863      * @param action invokes the operation
864      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
865      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
866      *        and the afterXxx loop was invoked
867      * @param verifyAfter verifies that a provider's afterXxx method was invoked
868      */
869     private void checkBeforeAfter_FalseTrue(BiConsumer<PolicyControllerFeatureApi, Boolean> setBefore,
870                     BiConsumer<PolicyControllerFeatureApi, Boolean> setAfter, Runnable action,
871                     Consumer<PolicyControllerFeatureApi> verifyBefore, Runnable verifyMiddle,
872                     Consumer<PolicyControllerFeatureApi> verifyAfter) {
873
874         setUp();
875
876         // configure for the test
877         setBefore.accept(prov1, false);
878         setBefore.accept(prov2, false);
879
880         setAfter.accept(prov1, true);
881         setAfter.accept(prov2, false);
882
883         // run the action
884         action.run();
885
886         // verify that various methods were invoked
887         verifyBefore.accept(prov1);
888         verifyBefore.accept(prov2);
889
890         verifyMiddle.run();
891
892         verifyAfter.accept(prov1);
893         assertThatThrownBy(() -> verifyAfter.accept(prov2)).isInstanceOf(AssertionError.class);
894     }
895
896     /**
897      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
898      * case where the first provider's beforeXxx returns {@code true}, while the others
899      * return {@code false}.
900      *
901      * @param setBefore function to set the return value of a provider's beforeXxx method
902      * @param setAfter function to set the return value of a provider's afterXxx method
903      * @param action invokes the operation
904      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
905      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
906      *        and the afterXxx loop was invoked
907      * @param verifyAfter verifies that a provider's afterXxx method was invoked
908      */
909     private void checkBeforeAfter_TrueFalse(BiConsumer<PolicyControllerFeatureApi, Boolean> setBefore,
910                     BiConsumer<PolicyControllerFeatureApi, Boolean> setAfter, Runnable action,
911                     Consumer<PolicyControllerFeatureApi> verifyBefore, Runnable verifyMiddle,
912                     Consumer<PolicyControllerFeatureApi> verifyAfter) {
913
914         setUp();
915
916         // configure for the test
917         setBefore.accept(prov1, true);
918         setBefore.accept(prov2, false);
919
920         setAfter.accept(prov1, false);
921         setAfter.accept(prov2, false);
922
923         // run the action
924         action.run();
925
926         // verify that various methods were invoked
927         verifyBefore.accept(prov1);
928
929         // remaining methods should not have been invoked
930         assertThatThrownBy(() -> verifyBefore.accept(prov2)).isInstanceOf(AssertionError.class);
931
932         assertThatThrownBy(verifyMiddle::run).isInstanceOf(AssertionError.class);
933
934         assertThatThrownBy(() -> verifyAfter.accept(prov1)).isInstanceOf(AssertionError.class);
935         assertThatThrownBy(() -> verifyAfter.accept(prov2)).isInstanceOf(AssertionError.class);
936     }
937
938     /**
939      * Controller with overrides.
940      */
941     private class AggregatedPolicyControllerImpl extends AggregatedPolicyController {
942
943         public AggregatedPolicyControllerImpl(String name, Properties properties) {
944             super(name, properties);
945         }
946
947         @Override
948         protected SystemPersistence getPersistenceManager() {
949             return persist;
950         }
951
952         @Override
953         protected TopicEndpoint getEndpointManager() {
954             return endpointMgr;
955         }
956
957         @Override
958         protected DroolsControllerFactory getDroolsFactory() {
959             return droolsFactory;
960         }
961
962         @Override
963         protected List<PolicyControllerFeatureApi> getProviders() {
964             return providers;
965         }
966     }
967 }