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