2  * ============LICENSE_START=======================================================
 
   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
 
  11  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  21 package org.onap.policy.drools.system.internal;
 
  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;
 
  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 import org.onap.policy.drools.system.GsonMgmtTestBuilder;
 
  54 public class AggregatedPolicyControllerTest {
 
  56     private static final String AGG_NAME = "agg-name";
 
  57     private static final String SINK_TOPIC1 = "sink-a";
 
  58     private static final String SINK_TOPIC2 = "sink-b";
 
  59     private static final String SOURCE_TOPIC1 = "source-a";
 
  60     private static final String SOURCE_TOPIC2 = "source-b";
 
  62     private static final String EXPECTED = "expected exception";
 
  64     private static final String MY_EVENT = "my-event";
 
  66     private static final String ARTIFACT1 = "artifact-a";
 
  67     private static final String GROUP1 = "group-a";
 
  68     private static final String VERSION1 = "version-a";
 
  70     private static final String ARTIFACT2 = "artifact-b";
 
  71     private static final String GROUP2 = "group-b";
 
  72     private static final String VERSION2 = "version-b";
 
  74     private Properties properties;
 
  75     private TopicEndpoint endpointMgr;
 
  76     private List<TopicSource> sources;
 
  77     private TopicSource source1;
 
  78     private TopicSource source2;
 
  79     private List<TopicSink> sinks;
 
  80     private TopicSink sink1;
 
  81     private TopicSink sink2;
 
  82     private SystemPersistence persist;
 
  83     private DroolsControllerFactory droolsFactory;
 
  84     private DroolsController drools;
 
  85     private DroolsConfiguration config;
 
  86     private List<PolicyControllerFeatureApi> providers;
 
  87     private PolicyControllerFeatureApi prov1;
 
  88     private PolicyControllerFeatureApi prov2;
 
  89     private AggregatedPolicyController apc;
 
  92      * Initializes the object to be tested.
 
  96         properties = new Properties();
 
  98         source1 = mock(TopicSource.class);
 
  99         source2 = mock(TopicSource.class);
 
 100         when(source1.getTopic()).thenReturn(SOURCE_TOPIC1);
 
 101         when(source2.getTopic()).thenReturn(SOURCE_TOPIC2);
 
 103         sink1 = mock(TopicSink.class);
 
 104         sink2 = mock(TopicSink.class);
 
 105         when(sink1.getTopic()).thenReturn(SINK_TOPIC1);
 
 106         when(sink2.getTopic()).thenReturn(SINK_TOPIC2);
 
 108         sources = Arrays.asList(source1, source2);
 
 109         sinks = Arrays.asList(sink1, sink2);
 
 111         endpointMgr = mock(TopicEndpoint.class);
 
 112         when(endpointMgr.addTopicSources(any())).thenReturn(sources);
 
 113         when(endpointMgr.addTopicSinks(any())).thenReturn(sinks);
 
 115         persist = mock(SystemPersistence.class);
 
 117         drools = mock(DroolsController.class);
 
 118         when(drools.start()).thenReturn(true);
 
 119         when(drools.stop()).thenReturn(true);
 
 120         when(drools.offer(any(), any())).thenReturn(true);
 
 121         when(drools.deliver(any(), any())).thenReturn(true);
 
 122         when(drools.lock()).thenReturn(true);
 
 123         when(drools.unlock()).thenReturn(true);
 
 124         when(drools.getArtifactId()).thenReturn(ARTIFACT1);
 
 125         when(drools.getGroupId()).thenReturn(GROUP1);
 
 126         when(drools.getVersion()).thenReturn(VERSION1);
 
 128         config = mock(DroolsConfiguration.class);
 
 129         when(config.getArtifactId()).thenReturn(ARTIFACT2);
 
 130         when(config.getGroupId()).thenReturn(GROUP2);
 
 131         when(config.getVersion()).thenReturn(VERSION2);
 
 133         droolsFactory = mock(DroolsControllerFactory.class);
 
 134         when(droolsFactory.build(any(), any(), any())).thenReturn(drools);
 
 136         prov1 = mock(PolicyControllerFeatureApi.class);
 
 137         prov2 = mock(PolicyControllerFeatureApi.class);
 
 139         providers = Arrays.asList(prov1, prov2);
 
 141         apc = new AggregatedPolicyControllerImpl(AGG_NAME, properties);
 
 145     public void testFactory() {
 
 146         apc = new AggregatedPolicyController(AGG_NAME, properties);
 
 147         assertNotNull(apc.getDroolsFactory());
 
 148         assertNotNull(apc.getEndpointManager());
 
 149         assertNotNull(apc.getProviders());
 
 150         assertNotNull(apc.getPersistenceManager());
 
 154     public void testAggregatedPolicyController_() {
 
 155         verify(persist).storeController(AGG_NAME, properties);
 
 158     @Test(expected = IllegalArgumentException.class)
 
 159     public void testInitDrools_Ex() {
 
 160         new AggregatedPolicyControllerImpl(AGG_NAME, properties) {
 
 162             protected DroolsControllerFactory getDroolsFactory() {
 
 163                 throw new RuntimeException(EXPECTED);
 
 168     @Test(expected = IllegalArgumentException.class)
 
 169     public void testInitDrools_Error() {
 
 170         new AggregatedPolicyControllerImpl(AGG_NAME, properties) {
 
 172             protected DroolsControllerFactory getDroolsFactory() {
 
 173                 throw new LinkageError(EXPECTED);
 
 179     public void testUpdateDrools_ConfigVariations() {
 
 181         // config should return same values as current controller
 
 182         when(config.getArtifactId()).thenReturn(ARTIFACT1.toUpperCase());
 
 183         when(config.getGroupId()).thenReturn(GROUP1.toUpperCase());
 
 184         when(config.getVersion()).thenReturn(VERSION1.toUpperCase());
 
 186         assertTrue(apc.updateDrools(config));
 
 188         // number of times store should have been called
 
 191         // invoked once during construction, but shouldn't be invoked during update
 
 192         verify(persist, times(++count)).storeController(any(), any());
 
 195         // different artifact
 
 196         when(config.getArtifactId()).thenReturn(ARTIFACT2);
 
 198         assertTrue(apc.updateDrools(config));
 
 200         // should be invoked during update
 
 201         verify(persist, times(++count)).storeController(any(), any());
 
 205         when(config.getArtifactId()).thenReturn(ARTIFACT1);
 
 206         when(config.getGroupId()).thenReturn(GROUP2);
 
 208         assertTrue(apc.updateDrools(config));
 
 210         // should be invoked during update
 
 211         verify(persist, times(++count)).storeController(any(), any());
 
 215         when(config.getGroupId()).thenReturn(GROUP1);
 
 216         when(config.getVersion()).thenReturn(VERSION2);
 
 218         assertTrue(apc.updateDrools(config));
 
 220         // should be invoked during update
 
 221         verify(persist, times(++count)).storeController(any(), any());
 
 227         when(drools.lock()).thenThrow(new IllegalArgumentException(EXPECTED));
 
 228         when(drools.unlock()).thenThrow(new IllegalArgumentException(EXPECTED));
 
 230         assertFalse(apc.updateDrools(config));
 
 234     public void testUpdateDrools_LockVariations() {
 
 236         apc.updateDrools(config);
 
 237         verify(drools, never()).lock();
 
 238         verify(drools).unlock();
 
 243         apc.updateDrools(config);
 
 244         verify(drools, times(2)).lock();
 
 245         verify(drools, never()).unlock();
 
 249     public void testUpdateDrools_AliveVariations() {
 
 251         apc.updateDrools(config);
 
 252         verify(drools, never()).start();
 
 253         verify(drools).stop();
 
 258         apc.updateDrools(config);
 
 259         verify(drools, times(2)).start();
 
 260         verify(drools, never()).stop();
 
 264     public void testSerialize() {
 
 265         new GsonMgmtTestBuilder().addDroolsControllerMock().addTopicSinkMock().addTopicSourceMock().build()
 
 266                         .compareGson(apc, AggregatedPolicyControllerTest.class);
 
 270     public void testGetName() {
 
 271         assertEquals(AGG_NAME, apc.getName());
 
 275     public void testStart() {
 
 276         // arrange for first provider to throw exceptions
 
 277         when(prov1.beforeStart(any())).thenThrow(new RuntimeException(EXPECTED));
 
 278         when(prov1.afterStart(any())).thenThrow(new RuntimeException(EXPECTED));
 
 280         // arrange for first sink to throw exception
 
 281         when(sink1.start()).thenThrow(new RuntimeException(EXPECTED));
 
 284         assertTrue(apc.start());
 
 286         assertTrue(apc.isAlive());
 
 288         verify(prov1).beforeStart(apc);
 
 289         verify(prov2).beforeStart(apc);
 
 291         verify(source1).register(apc);
 
 292         verify(source2).register(apc);
 
 294         verify(sink1).start();
 
 295         verify(sink2).start();
 
 297         verify(prov1).afterStart(apc);
 
 298         verify(prov2).afterStart(apc);
 
 301             (prov, flag) -> when(prov.beforeStart(apc)).thenReturn(flag),
 
 302             (prov, flag) -> when(prov.afterStart(apc)).thenReturn(flag),
 
 304             prov -> verify(prov).beforeStart(apc),
 
 305             () -> verify(source1).register(apc),
 
 306             prov -> verify(prov).afterStart(apc));
 
 310     public void testStart_AlreadyStarted() {
 
 314         assertTrue(apc.start());
 
 316         assertTrue(apc.isAlive());
 
 318         // these should now have been called twice
 
 319         verify(prov1, times(2)).beforeStart(apc);
 
 320         verify(prov2, times(2)).beforeStart(apc);
 
 322         // these should still only have been called once
 
 323         verify(source1).register(apc);
 
 324         verify(sink1).start();
 
 325         verify(prov1).afterStart(apc);
 
 329     public void testStart_Locked() {
 
 333         assertThatIllegalStateException().isThrownBy(() -> apc.start());
 
 335         assertFalse(apc.isAlive());
 
 337         // should call beforeStart(), but stop after that
 
 338         verify(prov1).beforeStart(apc);
 
 339         verify(prov2).beforeStart(apc);
 
 341         verify(source1, never()).register(apc);
 
 342         verify(sink1, never()).start();
 
 343         verify(prov1, never()).afterStart(apc);
 
 347     public void testStop() {
 
 348         // arrange for first provider to throw exceptions
 
 349         when(prov1.beforeStop(any())).thenThrow(new RuntimeException(EXPECTED));
 
 350         when(prov1.afterStop(any())).thenThrow(new RuntimeException(EXPECTED));
 
 356         assertTrue(apc.stop());
 
 358         assertFalse(apc.isAlive());
 
 360         verify(prov1).beforeStop(apc);
 
 361         verify(prov2).beforeStop(apc);
 
 363         verify(source1).unregister(apc);
 
 364         verify(source2).unregister(apc);
 
 366         verify(prov1).afterStop(apc);
 
 367         verify(prov2).afterStop(apc);
 
 369         // ensure no shutdown operations were called
 
 370         verify(prov1, never()).beforeShutdown(apc);
 
 371         verify(droolsFactory, never()).shutdown(drools);
 
 372         verify(prov2, never()).afterShutdown(apc);
 
 375             (prov, flag) -> when(prov.beforeStop(apc)).thenReturn(flag),
 
 376             (prov, flag) -> when(prov.afterStop(apc)).thenReturn(flag),
 
 381             prov -> verify(prov).beforeStop(apc),
 
 382             () -> verify(source1).unregister(apc),
 
 383             prov -> verify(prov).afterStop(apc));
 
 387     public void testStop_AlreadyStopped() {
 
 392         assertTrue(apc.stop());
 
 395         verify(prov1, times(2)).beforeStop(apc);
 
 396         verify(prov2, times(2)).beforeStop(apc);
 
 398         // should NOT be called again
 
 399         verify(source1).unregister(apc);
 
 400         verify(prov1).afterStop(apc);
 
 404     public void testShutdown() {
 
 405         // arrange for first provider to throw exceptions
 
 406         when(prov1.beforeShutdown(any())).thenThrow(new RuntimeException(EXPECTED));
 
 407         when(prov1.afterShutdown(any())).thenThrow(new RuntimeException(EXPECTED));
 
 415         verify(prov1).beforeShutdown(apc);
 
 416         verify(prov2).beforeShutdown(apc);
 
 418         assertFalse(apc.isAlive());
 
 420         verify(prov1).afterStop(apc);
 
 421         verify(prov2).afterStop(apc);
 
 423         verify(droolsFactory).shutdown(drools);
 
 425         verify(prov1).afterShutdown(apc);
 
 426         verify(prov2).afterShutdown(apc);
 
 428         // ensure no halt operation was called
 
 429         verify(prov1, never()).beforeHalt(apc);
 
 432             (prov, flag) -> when(prov.beforeShutdown(apc)).thenReturn(flag),
 
 433             (prov, flag) -> when(prov.afterShutdown(apc)).thenReturn(flag),
 
 438             prov -> verify(prov).beforeShutdown(apc),
 
 439             () -> verify(source1).unregister(apc),
 
 440             prov -> verify(prov).afterShutdown(apc));
 
 444     public void testHalt() {
 
 445         // arrange for first provider to throw exceptions
 
 446         when(prov1.beforeHalt(any())).thenThrow(new RuntimeException(EXPECTED));
 
 447         when(prov1.afterHalt(any())).thenThrow(new RuntimeException(EXPECTED));
 
 455         verify(prov1).beforeHalt(apc);
 
 456         verify(prov2).beforeHalt(apc);
 
 458         assertFalse(apc.isAlive());
 
 460         verify(prov1).beforeStop(apc);
 
 461         verify(prov2).beforeStop(apc);
 
 463         verify(droolsFactory).destroy(drools);
 
 464         verify(persist).deleteController(AGG_NAME);
 
 466         verify(prov1).afterHalt(apc);
 
 467         verify(prov2).afterHalt(apc);
 
 469         // ensure no shutdown operation was called
 
 470         verify(prov1, never()).beforeShutdown(apc);
 
 473             (prov, flag) -> when(prov.beforeHalt(apc)).thenReturn(flag),
 
 474             (prov, flag) -> when(prov.afterHalt(apc)).thenReturn(flag),
 
 479             prov -> verify(prov).beforeHalt(apc),
 
 480             () -> verify(source1).unregister(apc),
 
 481             prov -> verify(prov).afterHalt(apc));
 
 485     public void testOnTopicEvent() {
 
 486         // arrange for first provider to throw exceptions
 
 487         when(prov1.beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT))
 
 488                         .thenThrow(new RuntimeException(EXPECTED));
 
 489         when(prov1.afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true))
 
 490                         .thenThrow(new RuntimeException(EXPECTED));
 
 496         apc.onTopicEvent(CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
 
 498         verify(prov1).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
 
 499         verify(prov2).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
 
 501         verify(drools).offer(SOURCE_TOPIC1, MY_EVENT);
 
 503         verify(prov1).afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true);
 
 504         verify(prov2).afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true);
 
 507             (prov, flag) -> when(prov.beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT))
 
 509             (prov, flag) -> when(
 
 510                             prov.afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true))
 
 514                 apc.onTopicEvent(CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
 
 516             prov -> verify(prov).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT),
 
 517             () -> verify(drools).offer(SOURCE_TOPIC1, MY_EVENT),
 
 518             prov -> verify(prov).afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true));
 
 522     public void testOnTopicEvent_Locked() {
 
 529         apc.onTopicEvent(CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
 
 531         verify(prov1, never()).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
 
 532         verify(prov2, never()).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
 
 534         // never gets this far
 
 535         verify(drools, never()).offer(SOURCE_TOPIC1, MY_EVENT);
 
 536         verify(prov1, never()).afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true);
 
 540     public void testOnTopicEvent_NotStarted() {
 
 543         apc.onTopicEvent(CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
 
 545         verify(prov1, never()).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
 
 546         verify(prov2, never()).beforeOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT);
 
 548         // never gets this far
 
 549         verify(drools, never()).offer(SOURCE_TOPIC1, MY_EVENT);
 
 550         verify(prov1, never()).afterOffer(apc, CommInfrastructure.NOOP, SOURCE_TOPIC1, MY_EVENT, true);
 
 554     public void testDeliver_testInitSinks() {
 
 555         // arrange for first provider to throw exceptions
 
 556         when(prov1.beforeDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT))
 
 557                         .thenThrow(new RuntimeException(EXPECTED));
 
 558         when(prov1.afterDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT, true))
 
 559                         .thenThrow(new RuntimeException(EXPECTED));
 
 565         assertTrue(apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT));
 
 567         verify(prov1).beforeDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT);
 
 568         verify(prov2).beforeDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT);
 
 570         verify(drools).deliver(sink1, MY_EVENT);
 
 571         verify(drools, never()).deliver(sink2, MY_EVENT);
 
 573         verify(prov1).afterDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT, true);
 
 574         verify(prov2).afterDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT, true);
 
 576         // offer to the other topic
 
 577         assertTrue(apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC2, MY_EVENT));
 
 579         // now both topics should show one message delivered
 
 580         verify(drools).deliver(sink1, MY_EVENT);
 
 581         verify(drools).deliver(sink2, MY_EVENT);
 
 584             (prov, flag) -> when(prov.beforeDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT))
 
 586             (prov, flag) -> when(
 
 587                             prov.afterDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT, true))
 
 591                 apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT);
 
 593             prov -> verify(prov).beforeDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT),
 
 594             () -> verify(drools).deliver(sink1, MY_EVENT),
 
 595             prov -> verify(prov).afterDeliver(apc, CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT, true));
 
 598     @Test(expected = IllegalArgumentException.class)
 
 599     public void testDeliver_NullTopic() {
 
 601         apc.deliver(CommInfrastructure.NOOP, null, MY_EVENT);
 
 604     @Test(expected = IllegalArgumentException.class)
 
 605     public void testDeliver_EmptyTopic() {
 
 607         apc.deliver(CommInfrastructure.NOOP, "", MY_EVENT);
 
 610     @Test(expected = IllegalArgumentException.class)
 
 611     public void testDeliver_NullEvent() {
 
 613         apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC1, null);
 
 616     @Test(expected = IllegalStateException.class)
 
 617     public void testDeliver_NotStarted() {
 
 619         apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT);
 
 622     @Test(expected = IllegalStateException.class)
 
 623     public void testDeliver_Locked() {
 
 626         apc.deliver(CommInfrastructure.NOOP, SINK_TOPIC1, MY_EVENT);
 
 629     @Test(expected = IllegalArgumentException.class)
 
 630     public void testDeliver_UnknownTopic() {
 
 632         apc.deliver(CommInfrastructure.NOOP, "unknown-topic", MY_EVENT);
 
 636     public void testIsAlive() {
 
 637         assertFalse(apc.isAlive());
 
 640         assertTrue(apc.isAlive());
 
 643         assertFalse(apc.isAlive());
 
 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));
 
 656         assertTrue(apc.lock());
 
 658         verify(prov1).beforeLock(apc);
 
 659         verify(prov2).beforeLock(apc);
 
 661         assertTrue(apc.isLocked());
 
 663         verify(drools).lock();
 
 665         verify(prov1).afterLock(apc);
 
 666         verify(prov2).afterLock(apc);
 
 669             (prov, flag) -> when(prov.beforeLock(apc)).thenReturn(flag),
 
 670             (prov, flag) -> when(prov.afterLock(apc)).thenReturn(flag),
 
 675             prov -> verify(prov).beforeLock(apc),
 
 676             () -> verify(drools).lock(),
 
 677             prov -> verify(prov).afterLock(apc));
 
 681     public void testLock_AlreadyLocked() {
 
 686         assertTrue(apc.lock());
 
 688         // these should be invoked a second time
 
 689         verify(prov1, times(2)).beforeLock(apc);
 
 690         verify(prov2, times(2)).beforeLock(apc);
 
 692         assertTrue(apc.isLocked());
 
 694         // these shouldn't be invoked a second time
 
 695         verify(drools).lock();
 
 696         verify(prov1).afterLock(apc);
 
 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));
 
 710         assertTrue(apc.unlock());
 
 712         verify(prov1).beforeUnlock(apc);
 
 713         verify(prov2).beforeUnlock(apc);
 
 715         assertFalse(apc.isLocked());
 
 717         verify(drools).unlock();
 
 719         verify(prov1).afterUnlock(apc);
 
 720         verify(prov2).afterUnlock(apc);
 
 723             (prov, flag) -> when(prov.beforeUnlock(apc)).thenReturn(flag),
 
 724             (prov, flag) -> when(prov.afterUnlock(apc)).thenReturn(flag),
 
 730             prov -> verify(prov).beforeUnlock(apc),
 
 731             () -> verify(drools).unlock(),
 
 732             prov -> verify(prov).afterUnlock(apc));
 
 736     public void testUnlock_NotLocked() {
 
 740         assertTrue(apc.unlock());
 
 742         verify(prov1).beforeUnlock(apc);
 
 743         verify(prov2).beforeUnlock(apc);
 
 745         assertFalse(apc.isLocked());
 
 747         // these shouldn't be invoked
 
 748         verify(drools, never()).unlock();
 
 749         verify(prov1, never()).afterLock(apc);
 
 753     public void testIsLocked() {
 
 754         assertFalse(apc.isLocked());
 
 757         assertTrue(apc.isLocked());
 
 760         assertFalse(apc.isLocked());
 
 764     public void testGetTopicSources() {
 
 765         assertEquals(sources, apc.getTopicSources());
 
 769     public void testGetTopicSinks() {
 
 770         assertEquals(sinks, apc.getTopicSinks());
 
 774     public void testGetDrools() {
 
 775         assertEquals(drools, apc.getDrools());
 
 779     public void testGetProperties() {
 
 780         assertEquals(properties, apc.getProperties());
 
 784     public void testToString() {
 
 785         assertTrue(apc.toString().startsWith("AggregatedPolicyController ["));
 
 789      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries
 
 790      * combinations where beforeXxx and afterXxx return {@code true} and {@code false}.
 
 792      * @param setBefore function to set the return value of a provider's beforeXxx method
 
 793      * @param setAfter function to set the return value of a provider's afterXxx method
 
 794      * @param action invokes the operation
 
 795      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
 
 796      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
 
 797      *        and the afterXxx loop was invoked
 
 798      * @param verifyAfter verifies that a provider's afterXxx method was invoked
 
 800     private void checkBeforeAfter(BiConsumer<PolicyControllerFeatureApi, Boolean> setBefore,
 
 801                     BiConsumer<PolicyControllerFeatureApi, Boolean> setAfter, Runnable action,
 
 802                     Consumer<PolicyControllerFeatureApi> verifyBefore, Runnable verifyMiddle,
 
 803                     Consumer<PolicyControllerFeatureApi> verifyAfter) {
 
 805         checkBeforeAfter_FalseFalse(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
 
 806         checkBeforeAfter_FalseTrue(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
 
 807         checkBeforeAfter_TrueFalse(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
 
 809         // don't need to test true-true, as it's behavior is a subset of true-false
 
 813      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
 
 814      * case where both the beforeXxx and afterXxx methods return {@code false}.
 
 816      * @param setBefore function to set the return value of a provider's beforeXxx method
 
 817      * @param setAfter function to set the return value of a provider's afterXxx method
 
 818      * @param action invokes the operation
 
 819      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
 
 820      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
 
 821      *        and the afterXxx loop was invoked
 
 822      * @param verifyAfter verifies that a provider's afterXxx method was invoked
 
 824     private void checkBeforeAfter_FalseFalse(BiConsumer<PolicyControllerFeatureApi, Boolean> setBefore,
 
 825                     BiConsumer<PolicyControllerFeatureApi, Boolean> setAfter, Runnable action,
 
 826                     Consumer<PolicyControllerFeatureApi> verifyBefore, Runnable verifyMiddle,
 
 827                     Consumer<PolicyControllerFeatureApi> verifyAfter) {
 
 831         // configure for the test
 
 832         setBefore.accept(prov1, false);
 
 833         setBefore.accept(prov2, false);
 
 835         setAfter.accept(prov1, false);
 
 836         setAfter.accept(prov2, false);
 
 841         // verify that various methods were invoked
 
 842         verifyBefore.accept(prov1);
 
 843         verifyBefore.accept(prov2);
 
 847         verifyAfter.accept(prov1);
 
 848         verifyAfter.accept(prov2);
 
 852      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
 
 853      * case where the first provider's afterXxx returns {@code true}, while the others
 
 854      * return {@code false}.
 
 856      * @param setBefore function to set the return value of a provider's beforeXxx method
 
 857      * @param setAfter function to set the return value of a provider's afterXxx method
 
 858      * @param action invokes the operation
 
 859      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
 
 860      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
 
 861      *        and the afterXxx loop was invoked
 
 862      * @param verifyAfter verifies that a provider's afterXxx method was invoked
 
 864     private void checkBeforeAfter_FalseTrue(BiConsumer<PolicyControllerFeatureApi, Boolean> setBefore,
 
 865                     BiConsumer<PolicyControllerFeatureApi, Boolean> setAfter, Runnable action,
 
 866                     Consumer<PolicyControllerFeatureApi> verifyBefore, Runnable verifyMiddle,
 
 867                     Consumer<PolicyControllerFeatureApi> verifyAfter) {
 
 871         // configure for the test
 
 872         setBefore.accept(prov1, false);
 
 873         setBefore.accept(prov2, false);
 
 875         setAfter.accept(prov1, true);
 
 876         setAfter.accept(prov2, false);
 
 881         // verify that various methods were invoked
 
 882         verifyBefore.accept(prov1);
 
 883         verifyBefore.accept(prov2);
 
 887         verifyAfter.accept(prov1);
 
 888         assertThatThrownBy(() -> verifyAfter.accept(prov2)).isInstanceOf(AssertionError.class);
 
 892      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
 
 893      * case where the first provider's beforeXxx returns {@code true}, while the others
 
 894      * return {@code false}.
 
 896      * @param setBefore function to set the return value of a provider's beforeXxx method
 
 897      * @param setAfter function to set the return value of a provider's afterXxx method
 
 898      * @param action invokes the operation
 
 899      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
 
 900      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
 
 901      *        and the afterXxx loop was invoked
 
 902      * @param verifyAfter verifies that a provider's afterXxx method was invoked
 
 904     private void checkBeforeAfter_TrueFalse(BiConsumer<PolicyControllerFeatureApi, Boolean> setBefore,
 
 905                     BiConsumer<PolicyControllerFeatureApi, Boolean> setAfter, Runnable action,
 
 906                     Consumer<PolicyControllerFeatureApi> verifyBefore, Runnable verifyMiddle,
 
 907                     Consumer<PolicyControllerFeatureApi> verifyAfter) {
 
 911         // configure for the test
 
 912         setBefore.accept(prov1, true);
 
 913         setBefore.accept(prov2, false);
 
 915         setAfter.accept(prov1, false);
 
 916         setAfter.accept(prov2, false);
 
 921         // verify that various methods were invoked
 
 922         verifyBefore.accept(prov1);
 
 924         // remaining methods should not have been invoked
 
 925         assertThatThrownBy(() -> verifyBefore.accept(prov2)).isInstanceOf(AssertionError.class);
 
 927         assertThatThrownBy(() -> verifyMiddle.run()).isInstanceOf(AssertionError.class);
 
 929         assertThatThrownBy(() -> verifyAfter.accept(prov1)).isInstanceOf(AssertionError.class);
 
 930         assertThatThrownBy(() -> verifyAfter.accept(prov2)).isInstanceOf(AssertionError.class);
 
 934      * Controller with overrides.
 
 936     private class AggregatedPolicyControllerImpl extends AggregatedPolicyController {
 
 938         public AggregatedPolicyControllerImpl(String name, Properties properties) {
 
 939             super(name, properties);
 
 943         protected SystemPersistence getPersistenceManager() {
 
 948         protected TopicEndpoint getEndpointManager() {
 
 953         protected DroolsControllerFactory getDroolsFactory() {
 
 954             return droolsFactory;
 
 958         protected List<PolicyControllerFeatureApi> getProviders() {