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