Removing deprecated DMAAP library
[policy/drools-pdp.git] / policy-management / src / test / java / org / onap / policy / drools / system / PolicyEngineManagerTest.java
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2018-2022 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2023-2024 Nordix Foundation.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.drools.system;
23
24 import static org.assertj.core.api.Assertions.assertThatCode;
25 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
26 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
27 import static org.assertj.core.api.Assertions.assertThatThrownBy;
28 import static org.junit.jupiter.api.Assertions.assertEquals;
29 import static org.junit.jupiter.api.Assertions.assertFalse;
30 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
31 import static org.junit.jupiter.api.Assertions.assertNotNull;
32 import static org.junit.jupiter.api.Assertions.assertNull;
33 import static org.junit.jupiter.api.Assertions.assertSame;
34 import static org.junit.jupiter.api.Assertions.assertTrue;
35 import static org.mockito.ArgumentMatchers.any;
36 import static org.mockito.ArgumentMatchers.anyLong;
37 import static org.mockito.Mockito.doThrow;
38 import static org.mockito.Mockito.mock;
39 import static org.mockito.Mockito.never;
40 import static org.mockito.Mockito.spy;
41 import static org.mockito.Mockito.times;
42 import static org.mockito.Mockito.verify;
43 import static org.mockito.Mockito.when;
44
45 import io.prometheus.client.CollectorRegistry;
46 import io.prometheus.client.Summary;
47 import java.util.Arrays;
48 import java.util.Collections;
49 import java.util.List;
50 import java.util.Properties;
51 import java.util.concurrent.ScheduledExecutorService;
52 import java.util.function.BiConsumer;
53 import java.util.function.Consumer;
54 import org.junit.jupiter.api.AfterEach;
55 import org.junit.jupiter.api.BeforeEach;
56 import org.junit.jupiter.api.Test;
57 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
58 import org.onap.policy.common.endpoints.event.comm.TopicEndpoint;
59 import org.onap.policy.common.endpoints.event.comm.TopicSink;
60 import org.onap.policy.common.endpoints.event.comm.TopicSource;
61 import org.onap.policy.common.endpoints.http.client.HttpClient;
62 import org.onap.policy.common.endpoints.http.client.HttpClientFactory;
63 import org.onap.policy.common.endpoints.http.server.HttpServletServer;
64 import org.onap.policy.common.endpoints.http.server.HttpServletServerFactory;
65 import org.onap.policy.common.utils.gson.GsonTestUtils;
66 import org.onap.policy.drools.controller.DroolsController;
67 import org.onap.policy.drools.core.lock.Lock;
68 import org.onap.policy.drools.core.lock.LockCallback;
69 import org.onap.policy.drools.core.lock.PolicyResourceLockManager;
70 import org.onap.policy.drools.features.PolicyControllerFeatureApi;
71 import org.onap.policy.drools.features.PolicyEngineFeatureApi;
72 import org.onap.policy.drools.metrics.Metric;
73 import org.onap.policy.drools.persistence.SystemPersistence;
74 import org.onap.policy.drools.properties.DroolsPropertyConstants;
75 import org.onap.policy.drools.protocol.coders.EventProtocolCoder;
76 import org.onap.policy.drools.protocol.configuration.ControllerConfiguration;
77 import org.onap.policy.drools.protocol.configuration.DroolsConfiguration;
78 import org.onap.policy.drools.protocol.configuration.PdpdConfiguration;
79 import org.onap.policy.drools.stats.PolicyStatsManager;
80 import org.onap.policy.drools.system.internal.SimpleLockManager;
81 import org.onap.policy.drools.system.internal.SimpleLockProperties;
82 import org.onap.policy.models.pdp.enums.PdpResponseStatus;
83
84 class PolicyEngineManagerTest {
85     private static final String EXPECTED = "expected exception";
86
87     private static final String NOOP_STR = CommInfrastructure.NOOP.name();
88     private static final String MY_NAME = "my-name";
89     private static final String CONTROLLER1 = "controller-a";
90     private static final String CONTROLLER2 = "controller-b";
91     private static final String CONTROLLER3 = "controller-c";
92     private static final String CONTROLLER4 = "controller-d";
93     private static final String FEATURE1 = "feature-a";
94     private static final String FEATURE2 = "feature-b";
95     private static final String MY_TOPIC = "my-topic";
96     private static final String MESSAGE = "my-message";
97     private static final String MY_OWNER = "my-owner";
98     private static final String MY_RESOURCE = "my-resource";
99     private static final String POLICY = "policy";
100     private static final String CONTROLLOOP = "controlloop";
101
102     private static final Object MY_EVENT = new Object();
103
104     private static final GsonTestUtils gson = new GsonMgmtTestBuilder().addTopicSourceMock().addTopicSinkMock()
105                     .addHttpServletServerMock().build();
106
107     private Properties properties;
108     private PolicyEngineFeatureApi prov1;
109     private PolicyEngineFeatureApi prov2;
110     private List<PolicyEngineFeatureApi> providers;
111     private PolicyControllerFeatureApi contProv1;
112     private PolicyControllerFeatureApi contProv2;
113     private List<PolicyControllerFeatureApi> contProviders;
114     private String[] globalInitArgs;
115     private TopicSource source1;
116     private TopicSource source2;
117     private List<TopicSource> sources;
118     private TopicSink sink1;
119     private TopicSink sink2;
120     private List<TopicSink> sinks;
121     private HttpServletServer server1;
122     private HttpServletServer server2;
123     private List<HttpServletServer> servers;
124     private HttpServletServerFactory serverFactory;
125     private HttpClientFactory clientFactory;
126     private HttpClient client1;
127     private HttpClient client2;
128     private TopicEndpoint endpoint;
129     private PolicyController controller;
130     private PolicyController controller2;
131     private PolicyController controller3;
132     private PolicyController controller4;
133     private List<PolicyController> controllers;
134     private PolicyControllerFactory controllerFactory;
135     private boolean jmxStarted;
136     private boolean jmxStopped;
137     private long threadSleepMs;
138     private int threadExitCode;
139     private boolean threadStarted;
140     private boolean threadInterrupted;
141     private Thread shutdownThread;
142     private boolean shouldInterrupt;
143     private EventProtocolCoder coder;
144     private SystemPersistence persist;
145     private PolicyEngine engine;
146     private DroolsConfiguration drools3;
147     private DroolsConfiguration drools4;
148     private ControllerConfiguration config3;
149     private ControllerConfiguration config4;
150     private PdpdConfiguration pdpConfig;
151     private String pdpConfigJson;
152     private PolicyEngineManager mgr;
153     private ScheduledExecutorService exsvc;
154     private PolicyResourceLockManager lockmgr;
155     private PolicyStatsManager statsManager;
156
157     /**
158      * Initializes the object to be tested.
159      *
160      * @throws Exception if an error occurs
161      */
162     @BeforeEach
163     public void setUp() throws Exception {
164         CollectorRegistry.defaultRegistry.clear();
165         properties = new Properties();
166         prov1 = mock(PolicyEngineFeatureApi.class);
167         prov2 = mock(PolicyEngineFeatureApi.class);
168         providers = Arrays.asList(prov1, prov2);
169         contProv1 = mock(PolicyControllerFeatureApi.class);
170         contProv2 = mock(PolicyControllerFeatureApi.class);
171         contProviders = Arrays.asList(contProv1, contProv2);
172         globalInitArgs = null;
173         source1 = mock(TopicSource.class);
174         source2 = mock(TopicSource.class);
175         sources = Arrays.asList(source1, source2);
176         sink1 = mock(TopicSink.class);
177         sink2 = mock(TopicSink.class);
178         sinks = Arrays.asList(sink1, sink2);
179         server1 = mock(HttpServletServer.class);
180         server2 = mock(HttpServletServer.class);
181         servers = Arrays.asList(server1, server2);
182         serverFactory = mock(HttpServletServerFactory.class);
183         client1 = mock(HttpClient.class);
184         client2 = mock(HttpClient.class);
185         clientFactory = mock(HttpClientFactory.class);
186         endpoint = mock(TopicEndpoint.class);
187         controller = mock(PolicyController.class);
188         controller2 = mock(PolicyController.class);
189         controller3 = mock(PolicyController.class);
190         controller4 = mock(PolicyController.class);
191         // do NOT include controller3 or controller4 in the list
192         controllers = Arrays.asList(controller, controller2);
193         controllerFactory = mock(PolicyControllerFactory.class);
194         jmxStarted = false;
195         jmxStopped = false;
196         threadSleepMs = -1;
197         threadExitCode = -1;
198         threadStarted = false;
199         threadInterrupted = false;
200         shutdownThread = null;
201         shouldInterrupt = false;
202         coder = mock(EventProtocolCoder.class);
203         persist = mock(SystemPersistence.class);
204         engine = mock(PolicyEngine.class);
205         drools3 = new DroolsConfiguration();
206         drools4 = new DroolsConfiguration();
207         config3 = new ControllerConfiguration();
208         config4 = new ControllerConfiguration();
209         pdpConfig = new PdpdConfiguration();
210         exsvc = mock(ScheduledExecutorService.class);
211         lockmgr = mock(PolicyResourceLockManager.class);
212         statsManager = new PolicyStatsManager();
213         statsManager.getGroupStat().setBirthTime(0L);
214
215         when(lockmgr.start()).thenReturn(true);
216         when(lockmgr.stop()).thenReturn(true);
217         when(lockmgr.lock()).thenReturn(true);
218         when(lockmgr.unlock()).thenReturn(true);
219
220         when(prov2.beforeCreateLockManager(any(), any())).thenReturn(lockmgr);
221
222         when(prov1.getName()).thenReturn(FEATURE1);
223         when(prov2.getName()).thenReturn(FEATURE2);
224
225         when(controllerFactory.build(any(), any())).thenReturn(controller);
226         when(controllerFactory.inventory()).thenReturn(controllers);
227         when(controllerFactory.get(CONTROLLER1)).thenReturn(controller);
228         when(controllerFactory.get(CONTROLLER2)).thenReturn(controller2);
229         // do NOT return controller3 or controller4
230
231         when(server1.getPort()).thenReturn(1001);
232         when(server1.waitedStart(anyLong())).thenReturn(true);
233         when(server1.stop()).thenReturn(true);
234
235         when(server2.getPort()).thenReturn(1002);
236         when(server2.waitedStart(anyLong())).thenReturn(true);
237         when(server2.stop()).thenReturn(true);
238
239         when(serverFactory.build(any())).thenReturn(servers);
240
241         when(client1.getPort()).thenReturn(2001);
242         when(client1.start()).thenReturn(true);
243         when(client1.stop()).thenReturn(true);
244
245         when(client2.getPort()).thenReturn(2002);
246         when(client2.start()).thenReturn(true);
247         when(client2.stop()).thenReturn(true);
248
249         when(clientFactory.inventory()).thenReturn(List.of(client1, client2));
250
251         when(source1.getTopic()).thenReturn("source1-topic");
252         when(source1.start()).thenReturn(true);
253         when(source1.stop()).thenReturn(true);
254
255         when(source2.getTopic()).thenReturn("source2-topic");
256         when(source2.start()).thenReturn(true);
257         when(source2.stop()).thenReturn(true);
258
259         when(sink1.getTopic()).thenReturn("sink1-topic");
260         when(sink1.start()).thenReturn(true);
261         when(sink1.stop()).thenReturn(true);
262         when(sink1.send(any())).thenReturn(true);
263         when(sink1.getTopicCommInfrastructure()).thenReturn(CommInfrastructure.NOOP);
264
265         when(sink2.getTopic()).thenReturn("sink2-topic");
266         when(sink2.start()).thenReturn(true);
267         when(sink2.stop()).thenReturn(true);
268
269         when(controller.getName()).thenReturn(CONTROLLER1);
270         when(controller.start()).thenReturn(true);
271         when(controller.stop()).thenReturn(true);
272         when(controller.lock()).thenReturn(true);
273         when(controller.unlock()).thenReturn(true);
274
275         when(controller2.getName()).thenReturn(CONTROLLER2);
276         when(controller2.start()).thenReturn(true);
277         when(controller2.stop()).thenReturn(true);
278         when(controller2.lock()).thenReturn(true);
279         when(controller2.unlock()).thenReturn(true);
280
281         when(controller3.getName()).thenReturn(CONTROLLER3);
282         when(controller3.start()).thenReturn(true);
283         when(controller3.stop()).thenReturn(true);
284         when(controller3.lock()).thenReturn(true);
285         when(controller3.unlock()).thenReturn(true);
286
287         when(controller4.getName()).thenReturn(CONTROLLER4);
288         when(controller4.start()).thenReturn(true);
289         when(controller4.stop()).thenReturn(true);
290         when(controller4.lock()).thenReturn(true);
291         when(controller4.unlock()).thenReturn(true);
292
293         when(endpoint.addTopicSources(any(Properties.class))).thenReturn(sources);
294         when(endpoint.addTopicSinks(any(Properties.class))).thenReturn(sinks);
295         when(endpoint.start()).thenReturn(true);
296         when(endpoint.stop()).thenReturn(true);
297         when(endpoint.lock()).thenReturn(true);
298         when(endpoint.unlock()).thenReturn(true);
299         when(endpoint.getTopicSink(CommInfrastructure.NOOP, MY_TOPIC)).thenReturn(sink1);
300         when(endpoint.getTopicSinks(MY_TOPIC)).thenReturn(Collections.singletonList(sink1));
301
302         when(coder.encode(any(), any())).thenReturn(MESSAGE);
303
304         when(persist.getControllerProperties(CONTROLLER3)).thenReturn(properties);
305         when(persist.getControllerProperties(CONTROLLER4)).thenReturn(properties);
306
307         when(engine.createPolicyController(CONTROLLER3, properties)).thenReturn(controller3);
308         when(engine.createPolicyController(CONTROLLER4, properties)).thenReturn(controller4);
309         when(engine.getStats()).thenReturn(statsManager);
310
311         config3.setName(CONTROLLER3);
312         config3.setOperation(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_CREATE);
313         config3.setDrools(drools3);
314
315         config4.setName(CONTROLLER4);
316         config4.setOperation(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UPDATE);
317         config4.setDrools(drools4);
318
319         pdpConfig.getControllers().add(config3);
320         pdpConfig.getControllers().add(config4);
321         pdpConfig.setEntity(PdpdConfiguration.CONFIG_ENTITY_CONTROLLER);
322
323         pdpConfigJson = gson.gsonEncode(pdpConfig);
324
325         mgr = new PolicyEngineManagerImpl();
326     }
327
328     @AfterEach
329     public void tearDown() {
330         CollectorRegistry.defaultRegistry.clear();
331     }
332
333     @Test
334     void testSerialize() {
335         mgr.setHostName("foo");
336         mgr.setClusterName("bar");
337         mgr.configure(properties);
338         assertThatCode(() -> gson.compareGson(mgr, PolicyEngineManagerTest.class)).doesNotThrowAnyException();
339     }
340
341     @Test
342     void testFactory() {
343         mgr = new PolicyEngineManager();
344
345         assertNotNull(mgr.getEngineProviders());
346         assertNotNull(mgr.getControllerProviders());
347         assertNotNull(mgr.getTopicEndpointManager());
348         assertNotNull(mgr.getServletFactory());
349         assertNotNull(mgr.getControllerFactory());
350         assertNotNull(mgr.makeShutdownThread());
351         assertNotNull(mgr.getProtocolCoder());
352         assertNotNull(mgr.getPersistenceManager());
353         assertNotNull(mgr.getPolicyEngine());
354     }
355
356     @Test
357     void testBoot() throws Exception {
358         String[] args = {"boot-a", "boot-b"};
359
360         // arrange for first provider to throw exceptions
361         when(prov1.beforeBoot(mgr, args)).thenThrow(new RuntimeException(EXPECTED));
362         when(prov1.afterBoot(mgr)).thenThrow(new RuntimeException(EXPECTED));
363
364         mgr.boot(args);
365
366         verify(prov1).beforeBoot(mgr, args);
367         verify(prov2).beforeBoot(mgr, args);
368
369         assertSame(globalInitArgs, args);
370
371         verify(prov1).afterBoot(mgr);
372         verify(prov2).afterBoot(mgr);
373
374         // global init throws exception - still calls afterBoot
375         setUp();
376         mgr = new PolicyEngineManagerImpl() {
377             @Override
378             protected void globalInitContainer(String[] cliArgs) {
379                 throw new RuntimeException(EXPECTED);
380             }
381         };
382         mgr.boot(args);
383         verify(prov2).afterBoot(mgr);
384
385         // other tests
386         checkBeforeAfter(
387             (prov, flag) -> when(prov.beforeBoot(mgr, args)).thenReturn(flag),
388             (prov, flag) -> when(prov.afterBoot(mgr)).thenReturn(flag),
389             () -> mgr.boot(args),
390             prov -> verify(prov).beforeBoot(mgr, args),
391             () -> assertSame(globalInitArgs, args),
392             prov -> verify(prov).afterBoot(mgr));
393     }
394
395     @Test
396     void testSetEnvironment_testGetEnvironment_testGetEnvironmentProperty_setEnvironmentProperty() {
397         Properties props1 = new Properties();
398         props1.put("prop1-a", "value1-a");
399         props1.put("prop1-b", "value1-b");
400
401         mgr.setEnvironment(props1);
402
403         Properties env = mgr.getEnvironment();
404         assertEquals(props1, env);
405
406         // add more properties
407         Properties props2 = new Properties();
408         String propKey = "prop2-a";
409         props2.put(propKey, "value2-a");
410         props2.put("prop2-b", "value2-b");
411
412         mgr.setEnvironment(props2);
413
414         assertSame(mgr.getEnvironment(), env);
415
416         // new env should have a union of the properties
417         props1.putAll(props2);
418         assertEquals(props1, env);
419
420         assertEquals("value2-a", mgr.getEnvironmentProperty(propKey));
421
422         String newValue = "new-value";
423         mgr.setEnvironmentProperty(propKey, newValue);
424         assertEquals(newValue, mgr.getEnvironmentProperty(propKey));
425
426         props1.setProperty(propKey, newValue);
427         assertEquals(props1, env);
428
429         assertNotNull(mgr.getEnvironmentProperty("PATH"));
430         assertNull(mgr.getEnvironmentProperty("unknown-env-property"));
431
432         System.setProperty("propS-a", "valueS-a");
433         assertEquals("valueS-a", mgr.getEnvironmentProperty("propS-a"));
434
435         Properties props3 = new Properties();
436         props3.put("prop3-a", "${env:HOME}");
437         mgr.setEnvironment(props3);
438         assertEquals(System.getenv("HOME"), mgr.getEnvironmentProperty("prop3-a"));
439         assertEquals("valueS-a", mgr.getEnvironmentProperty("propS-a"));
440         assertEquals(newValue, mgr.getEnvironmentProperty(propKey));
441     }
442
443     @Test
444     void testDefaultTelemetryConfig() {
445         Properties config = mgr.defaultTelemetryConfig();
446         assertNotNull(config);
447         assertFalse(config.isEmpty());
448     }
449
450     @Test
451     void testGetPdpName() {
452         properties.setProperty(PolicyEngineManager.CLUSTER_NAME_PROP, "east1");
453         mgr.configure(properties);
454
455         var pdpName = mgr.getPdpName();
456         assertEquals("east1", extractCluster(pdpName));
457         assertEquals(mgr.getClusterName(), extractCluster(pdpName));
458         assertEquals(mgr.getHostName(), extractHostname(pdpName));
459
460         mgr.setHostName("foo");
461         mgr.setClusterName("bar");
462         mgr.setPdpName("foo.bar");
463
464         pdpName = mgr.getPdpName();
465         assertEquals("bar", extractCluster(pdpName));
466         assertEquals(mgr.getClusterName(), extractCluster(pdpName));
467         assertEquals("foo", extractHostname(pdpName));
468         assertEquals(mgr.getHostName(), extractHostname(pdpName));
469     }
470
471     private String extractCluster(String name) {
472         return name.substring(name.lastIndexOf(".") + 1);
473     }
474
475     private String extractHostname(String name) {
476         return name.substring(0, name.lastIndexOf("."));
477     }
478
479     /**
480      * Tests that makeExecutorService() uses the value from the thread
481      * property.
482      */
483     @Test
484     void testMakeExecutorServicePropertyProvided() {
485         PolicyEngineManager mgrspy = spy(mgr);
486
487         properties.setProperty(PolicyEngineManager.EXECUTOR_THREAD_PROP, "3");
488         mgrspy.configure(properties);
489         assertSame(exsvc, mgrspy.getExecutorService());
490         verify(mgrspy).makeScheduledExecutor(3);
491     }
492
493     /**
494      * Tests that makeExecutorService() uses the default thread count when no thread
495      * property is provided.
496      */
497     @Test
498     void testMakeExecutorServiceNoProperty() {
499         PolicyEngineManager mgrspy = spy(mgr);
500
501         mgrspy.configure(properties);
502         assertSame(exsvc, mgrspy.getExecutorService());
503         verify(mgrspy).makeScheduledExecutor(PolicyEngineManager.DEFAULT_EXECUTOR_THREADS);
504     }
505
506     /**
507      * Tests that makeExecutorService() uses the default thread count when the thread
508      * property is invalid.
509      */
510     @Test
511     void testMakeExecutorServiceInvalidProperty() {
512         PolicyEngineManager mgrspy = spy(mgr);
513
514         properties.setProperty(PolicyEngineManager.EXECUTOR_THREAD_PROP, "abc");
515         mgrspy.configure(properties);
516         assertSame(exsvc, mgrspy.getExecutorService());
517         verify(mgrspy).makeScheduledExecutor(PolicyEngineManager.DEFAULT_EXECUTOR_THREADS);
518     }
519
520     /**
521      * Tests createLockManager() when beforeCreateLock throws an exception and returns a
522      * manager.
523      */
524     @Test
525     void testCreateLockManagerHaveProvider() {
526         // first provider throws an exception
527         when(prov1.beforeCreateLockManager(any(), any())).thenThrow(new RuntimeException(EXPECTED));
528
529         mgr.configure(properties);
530         assertSame(lockmgr, mgr.getLockManager());
531     }
532
533     /**
534      * Tests createLockManager() when SimpleLockManager throws an exception.
535      */
536     @Test
537     void testCreateLockManagerSimpleEx() {
538         when(prov2.beforeCreateLockManager(any(), any())).thenReturn(null);
539
540         // invalid property for SimpleLockManager
541         properties.setProperty(SimpleLockProperties.EXPIRE_CHECK_SEC, "abc");
542         mgr.configure(properties);
543
544         // should create a manager using default properties
545         assertInstanceOf(SimpleLockManager.class, mgr.getLockManager());
546     }
547
548     /**
549      * Tests createLockManager() when SimpleLockManager is returned.
550      */
551     @Test
552     void testCreateLockManagerSimple() {
553         when(prov2.beforeCreateLockManager(any(), any())).thenReturn(null);
554
555         mgr.configure(properties);
556         assertInstanceOf(SimpleLockManager.class, mgr.getLockManager());
557     }
558
559     @Test
560     void testConfigureProperties() throws Exception {
561         // arrange for first provider to throw exceptions
562         when(prov1.beforeConfigure(mgr, properties)).thenThrow(new RuntimeException(EXPECTED));
563         when(prov1.afterConfigure(mgr)).thenThrow(new RuntimeException(EXPECTED));
564
565         mgr.configure(properties);
566
567         verify(prov1).beforeConfigure(mgr, properties);
568         verify(prov2).beforeConfigure(mgr, properties);
569
570         assertSame(properties, mgr.getProperties());
571
572         assertEquals(sources, mgr.getSources());
573         assertEquals(sinks, mgr.getSinks());
574         assertEquals(servers, mgr.getHttpServers());
575
576         verify(source1).register(mgr);
577         verify(source2).register(mgr);
578
579         verify(prov1).afterConfigure(mgr);
580         verify(prov2).afterConfigure(mgr);
581
582         // middle stuff throws exception - still calls afterXxx
583         setUp();
584         when(endpoint.addTopicSources(properties)).thenThrow(new IllegalArgumentException(EXPECTED));
585         when(endpoint.addTopicSinks(properties)).thenThrow(new IllegalArgumentException(EXPECTED));
586         when(serverFactory.build(properties)).thenThrow(new IllegalArgumentException(EXPECTED));
587         when(clientFactory.build(properties)).thenThrow(new IllegalArgumentException(EXPECTED));
588         mgr.configure(properties);
589         verify(prov2).afterConfigure(mgr);
590
591         // null properties - nothing should be invoked
592         setUp();
593         Properties nullProps = null;
594         assertThatIllegalArgumentException().isThrownBy(() -> mgr.configure(nullProps));
595         verify(prov1, never()).beforeConfigure(mgr, properties);
596         verify(prov1, never()).afterConfigure(mgr);
597
598         // other tests
599         checkBeforeAfter(
600             (prov, flag) -> when(prov.beforeConfigure(mgr, properties)).thenReturn(flag),
601             (prov, flag) -> when(prov.afterConfigure(mgr)).thenReturn(flag),
602             () -> mgr.configure(properties),
603             prov -> verify(prov).beforeConfigure(mgr, properties),
604             () -> assertSame(properties, mgr.getProperties()),
605             prov -> verify(prov).afterConfigure(mgr));
606     }
607
608     @Test
609     void testConfigurePdpdConfiguration() throws Exception {
610         mgr.configure(properties);
611         assertTrue(mgr.configure(pdpConfig));
612
613         verify(controllerFactory).patch(controller3, drools3);
614         verify(controllerFactory).patch(controller4, drools4);
615
616         // invalid params
617         PdpdConfiguration nullConfig = null;
618         assertThatIllegalArgumentException().isThrownBy(() -> mgr.configure(nullConfig));
619
620         pdpConfig.setEntity("unknown-entity");
621         assertThatIllegalArgumentException().isThrownBy(() -> mgr.configure(pdpConfig));
622
623         // source list of size 1
624         setUp();
625         when(endpoint.addTopicSources(any(Properties.class))).thenReturn(Collections.singletonList(source1));
626         mgr.configure(properties);
627         assertTrue(mgr.configure(pdpConfig));
628
629         verify(controllerFactory).patch(controller3, drools3);
630         verify(controllerFactory).patch(controller4, drools4);
631     }
632
633     @Test
634     void testCreatePolicyController() throws Exception {
635         assertEquals(controller, mgr.createPolicyController(MY_NAME, properties));
636
637         verify(contProv1).beforeCreate(MY_NAME, properties);
638         verify(contProv2).beforeCreate(MY_NAME, properties);
639         verify(controller, never()).lock();
640         verify(contProv1).afterCreate(controller);
641         verify(contProv2).afterCreate(controller);
642
643         // first provider throws exceptions - same result
644         setUp();
645         when(contProv1.beforeCreate(MY_NAME, properties)).thenThrow(new RuntimeException(EXPECTED));
646         when(contProv1.afterCreate(controller)).thenThrow(new RuntimeException(EXPECTED));
647         assertEquals(controller, mgr.createPolicyController(MY_NAME, properties));
648
649         verify(contProv1).beforeCreate(MY_NAME, properties);
650         verify(contProv2).beforeCreate(MY_NAME, properties);
651         verify(controller, never()).lock();
652         verify(contProv1).afterCreate(controller);
653         verify(contProv2).afterCreate(controller);
654
655         // locked - same result, but engine locked
656         setUp();
657         mgr.lock();
658         assertEquals(controller, mgr.createPolicyController(MY_NAME, properties));
659         verify(contProv1).beforeCreate(MY_NAME, properties);
660         verify(controller, times(2)).lock();
661         verify(contProv2).afterCreate(controller);
662
663         // empty name in properties - same result
664         setUp();
665         properties.setProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME, "");
666         assertEquals(controller, mgr.createPolicyController(MY_NAME, properties));
667         verify(contProv1).beforeCreate(MY_NAME, properties);
668
669         // matching name in properties - same result
670         setUp();
671         properties.setProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME, MY_NAME);
672         assertEquals(controller, mgr.createPolicyController(MY_NAME, properties));
673         verify(contProv1).beforeCreate(MY_NAME, properties);
674
675         // mismatching name in properties - nothing should happen besides exception
676         setUp();
677         properties.setProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME, "mistmatched-name");
678         assertThatIllegalStateException().isThrownBy(() -> mgr.createPolicyController(MY_NAME, properties));
679         verify(contProv1, never()).beforeCreate(MY_NAME, properties);
680
681         // first provider generates controller - stops after first provider
682         setUp();
683         when(contProv1.beforeCreate(MY_NAME, properties)).thenReturn(controller2);
684         assertEquals(controller2, mgr.createPolicyController(MY_NAME, properties));
685         verify(contProv1).beforeCreate(MY_NAME, properties);
686         verify(contProv2, never()).beforeCreate(MY_NAME, properties);
687         verify(controller, never()).lock();
688         verify(contProv1, never()).afterCreate(controller);
689         verify(contProv2, never()).afterCreate(controller);
690
691         // first provider returns true - stops after first provider afterXxx
692         setUp();
693         when(contProv1.afterCreate(controller)).thenReturn(true);
694         assertEquals(controller, mgr.createPolicyController(MY_NAME, properties));
695         verify(contProv1).beforeCreate(MY_NAME, properties);
696         verify(contProv2).beforeCreate(MY_NAME, properties);
697         verify(contProv1).afterCreate(controller);
698         verify(contProv2, never()).afterCreate(controller);
699     }
700
701     @Test
702     void testUpdatePolicyControllers() throws Exception {
703         assertEquals(Arrays.asList(controller3, controller4), mgr.updatePolicyControllers(pdpConfig.getControllers()));
704
705         // controller3 was CREATE
706         verify(controllerFactory).patch(controller3, drools3);
707         verify(controller3, never()).lock();
708         verify(controller3, never()).unlock();
709
710         // controller4 was UPDATE
711         verify(controllerFactory).patch(controller4, drools4);
712         verify(controller4, never()).lock();
713         verify(controller4).unlock();
714
715         // invalid args
716         assertTrue(mgr.updatePolicyControllers(null).isEmpty());
717         assertTrue(mgr.updatePolicyControllers(Collections.emptyList()).isEmpty());
718
719         // force exception in the first controller with invalid operation
720         setUp();
721         config3.setOperation("unknown-operation");
722         assertEquals(Collections.singletonList(controller4), mgr.updatePolicyControllers(pdpConfig.getControllers()));
723
724         // controller3 should NOT have been done
725         verify(controllerFactory, never()).patch(controller3, drools3);
726
727         // controller4 should still be done
728         verify(controllerFactory).patch(controller4, drools4);
729         verify(controller4, never()).lock();
730         verify(controller4).unlock();
731     }
732
733     @Test
734     void testUpdatePolicyController() throws Exception {
735         assertEquals(controller3, mgr.updatePolicyController(config3));
736         verify(engine).createPolicyController(CONTROLLER3, properties);
737
738         // invalid parameters
739         assertThatIllegalArgumentException().isThrownBy(() -> mgr.updatePolicyController(null));
740
741         // invalid name
742         setUp();
743         config3.setName(null);
744         assertThatIllegalArgumentException().isThrownBy(() -> mgr.updatePolicyController(config3));
745
746         config3.setName("");
747         assertThatIllegalArgumentException().isThrownBy(() -> mgr.updatePolicyController(config3));
748
749         // invalid operation
750         setUp();
751         config3.setOperation(null);
752         assertThatIllegalArgumentException().isThrownBy(() -> mgr.updatePolicyController(config3));
753
754         config3.setOperation("");
755         assertThatIllegalArgumentException().isThrownBy(() -> mgr.updatePolicyController(config3));
756
757         config3.setOperation(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_LOCK);
758         assertThatIllegalArgumentException().isThrownBy(() -> mgr.updatePolicyController(config3));
759
760         config3.setOperation(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UNLOCK);
761         assertThatIllegalArgumentException().isThrownBy(() -> mgr.updatePolicyController(config3));
762
763         // exception from get() - should create controller
764         setUp();
765         when(controllerFactory.get(CONTROLLER3)).thenThrow(new IllegalArgumentException(EXPECTED));
766         assertEquals(controller3, mgr.updatePolicyController(config3));
767         verify(engine).createPolicyController(CONTROLLER3, properties);
768
769         // null properties
770         setUp();
771         when(persist.getControllerProperties(CONTROLLER3)).thenReturn(null);
772         assertThatIllegalArgumentException().isThrownBy(() -> mgr.updatePolicyController(config3));
773
774         // throw linkage error
775         setUp();
776         when(persist.getControllerProperties(CONTROLLER3)).thenThrow(new LinkageError(EXPECTED));
777         assertThatIllegalStateException().isThrownBy(() -> mgr.updatePolicyController(config3));
778
779         /*
780          * For remaining tests, the factory will return the controller instead of creating
781          * one.
782          */
783         setUp();
784         when(controllerFactory.get(CONTROLLER3)).thenReturn(controller3);
785
786         assertEquals(controller3, mgr.updatePolicyController(config3));
787
788         // should NOT have created a new controller
789         verify(engine, never()).createPolicyController(any(), any());
790
791         int countPatch = 0;
792         int countLock = 0;
793         int countUnlock = 0;
794
795         // check different operations
796
797         // CREATE only invokes patch() (note: mgr.update() has already been called)
798         verify(controllerFactory, times(++countPatch)).patch(controller3, drools3);
799         verify(controller3, times(countLock)).lock();
800         verify(controller3, times(countUnlock)).unlock();
801
802         // UPDATE invokes unlock() and patch()
803         config3.setOperation(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UPDATE);
804         assertEquals(controller3, mgr.updatePolicyController(config3));
805         verify(controllerFactory, times(++countPatch)).patch(controller3, drools3);
806         verify(controller3, times(countLock)).lock();
807         verify(controller3, times(++countUnlock)).unlock();
808
809         // LOCK invokes lock()
810         config3.setOperation(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_LOCK);
811         assertEquals(controller3, mgr.updatePolicyController(config3));
812         verify(controllerFactory, times(countPatch)).patch(controller3, drools3);
813         verify(controller3, times(++countLock)).lock();
814         verify(controller3, times(countUnlock)).unlock();
815
816         // UNLOCK invokes unlock()
817         config3.setOperation(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UNLOCK);
818         assertEquals(controller3, mgr.updatePolicyController(config3));
819         verify(controllerFactory, times(countPatch)).patch(controller3, drools3);
820         verify(controller3, times(countLock)).lock();
821         verify(controller3, times(++countUnlock)).unlock();
822
823         // invalid operation
824         config3.setOperation("invalid-operation");
825         assertThatIllegalArgumentException().isThrownBy(() -> mgr.updatePolicyController(config3));
826     }
827
828     @Test
829     void testStart() throws Throwable {
830         // normal success case
831         testStart(true, () -> {
832             // arrange for first provider, server, source, and sink to throw exceptions
833             when(prov1.beforeStart(mgr)).thenThrow(new RuntimeException(EXPECTED));
834             when(prov1.afterStart(mgr)).thenThrow(new RuntimeException(EXPECTED));
835             when(server1.waitedStart(anyLong())).thenThrow(new RuntimeException(EXPECTED));
836             when(client1.start()).thenThrow(new RuntimeException(EXPECTED));
837             when(source1.start()).thenThrow(new RuntimeException(EXPECTED));
838             when(sink1.start()).thenThrow(new RuntimeException(EXPECTED));
839         });
840
841         // lock manager fails to start - still does everything
842         testStart(false, () -> when(lockmgr.start()).thenReturn(false));
843
844         //  lock manager throws an exception - still does everything
845         testStart(false, () -> when(lockmgr.start()).thenThrow(new RuntimeException(EXPECTED)));
846
847         // servlet wait fails - still does everything
848         testStart(false, () -> when(server1.waitedStart(anyLong())).thenReturn(false));
849
850         // client fails - still does everything
851         testStart(false, () -> when(client1.start()).thenReturn(false));
852
853         // topic source is not started with start
854         testStart(true, () -> when(source1.start()).thenReturn(false));
855
856         // topic sink is not started with start
857         testStart(true, () -> when(sink1.start()).thenReturn(false));
858
859         // controller fails to start - still does everything
860         testStart(false, () -> when(controller.start()).thenReturn(false));
861
862         // controller throws an exception - still does everything
863         testStart(false, () -> when(controller.start()).thenThrow(new RuntimeException(EXPECTED)));
864
865         // endpoint manager fails to start - still does everything
866         testStart(false, () -> when(endpoint.start()).thenReturn(false));
867
868         // endpoint manager throws an exception - still does everything AND succeeds
869         testStart(true, () -> when(endpoint.start()).thenThrow(new IllegalStateException(EXPECTED)));
870
871         // locked - nothing other than beforeXxx methods should be invoked
872         setUp();
873         mgr.configure(properties);
874         mgr.lock();
875         assertThatIllegalStateException().isThrownBy(() -> mgr.start());
876         verify(prov2).beforeStart(mgr);
877         verify(server2, never()).waitedStart(anyLong());
878         verify(source2, never()).start();
879         verify(sink1, never()).start();
880         verify(controller, never()).start();
881         verify(endpoint, never()).start();
882         assertFalse(jmxStarted);
883         verify(prov1, never()).afterStart(mgr);
884
885         // other tests
886         checkBeforeAfter(
887             (prov, flag) -> when(prov.beforeStart(mgr)).thenReturn(flag),
888             (prov, flag) -> when(prov.afterStart(mgr)).thenReturn(flag),
889             () -> {
890                 mgr.configure(properties);
891                 assertTrue(mgr.start());
892             },
893             prov -> verify(prov).beforeStart(mgr),
894             () -> assertTrue(jmxStarted),
895             prov -> verify(prov).afterStart(mgr));
896     }
897
898     /**
899      * Tests the start() method, after setting some option.
900      *
901      * @param expectedResult what start() is expected to return
902      * @param setOption function that sets an option
903      * @throws Throwable if an error occurs during setup
904      */
905     private void testStart(boolean expectedResult, RunnableWithEx setOption) throws Throwable {
906         setUp();
907         setOption.run();
908
909         mgr.configure(properties);
910         assertEquals(expectedResult, mgr.start());
911
912         verify(prov1).beforeStart(mgr);
913         verify(prov2).beforeStart(mgr);
914
915         verify(server1).waitedStart(anyLong());
916         verify(server2).waitedStart(anyLong());
917
918         verify(client1).start();
919         verify(client2).start();
920
921         verify(source1, never()).start();
922         verify(source2, never()).start();
923
924         verify(sink1, never()).start();
925         verify(sink2, never()).start();
926
927         verify(controller).start();
928         verify(controller2).start();
929
930         verify(endpoint).start();
931
932         assertTrue(jmxStarted);
933
934         verify(prov1).afterStart(mgr);
935         verify(prov2).afterStart(mgr);
936     }
937
938     @Test
939     void testStop() throws Throwable {
940         // normal success case
941         testStop(true, () -> {
942             // arrange for first provider, server, source, and sink to throw exceptions
943             when(prov1.beforeStop(mgr)).thenThrow(new RuntimeException(EXPECTED));
944             when(prov1.afterStop(mgr)).thenThrow(new RuntimeException(EXPECTED));
945             when(server1.stop()).thenThrow(new RuntimeException(EXPECTED));
946             when(client1.stop()).thenThrow(new RuntimeException(EXPECTED));
947             when(source1.stop()).thenThrow(new RuntimeException(EXPECTED));
948             when(sink1.stop()).thenThrow(new RuntimeException(EXPECTED));
949         });
950
951         // not alive - shouldn't run anything besides beforeStop()
952         setUp();
953         mgr.configure(properties);
954         assertTrue(mgr.stop());
955         verify(prov1).beforeStop(mgr);
956         verify(prov2).beforeStop(mgr);
957         verify(controller, never()).stop();
958         verify(source1, never()).stop();
959         verify(sink1, never()).stop();
960         verify(endpoint, never()).stop();
961         verify(server1, never()).stop();
962         verify(client1, never()).stop();
963         verify(prov1, never()).afterStop(mgr);
964         verify(prov2, never()).afterStop(mgr);
965
966         // controller fails to stop - still does everything
967         testStop(false, () -> when(controller.stop()).thenReturn(false));
968
969         // controller throws an exception - still does everything
970         testStop(false, () -> when(controller.stop()).thenThrow(new RuntimeException(EXPECTED)));
971
972         // topic source fails to stop - still does everything
973         testStop(false, () -> when(source1.stop()).thenReturn(false));
974
975         // topic sink fails to stop - still does everything
976         testStop(false, () -> when(sink1.stop()).thenReturn(false));
977
978         // endpoint manager fails to stop - still does everything
979         testStop(false, () -> when(endpoint.stop()).thenReturn(false));
980
981         // servlet fails to stop - still does everything
982         testStop(false, () -> when(server1.stop()).thenReturn(false));
983
984         // client fails to stop - still does everything
985         testStop(false, () -> when(client1.stop()).thenReturn(false));
986
987         // lock manager fails to stop - still does everything
988         testStop(false, () -> when(lockmgr.stop()).thenReturn(false));
989
990         // lock manager throws an exception - still does everything
991         testStop(false, () -> when(lockmgr.stop()).thenThrow(new RuntimeException(EXPECTED)));
992
993         // other tests
994         checkBeforeAfter(
995             (prov, flag) -> when(prov.beforeStop(mgr)).thenReturn(flag),
996             (prov, flag) -> when(prov.afterStop(mgr)).thenReturn(flag),
997             () -> {
998                 mgr.configure(properties);
999                 mgr.start();
1000                 assertTrue(mgr.stop());
1001             },
1002             prov -> verify(prov).beforeStop(mgr),
1003             () -> verify(endpoint).stop(),
1004             prov -> verify(prov).afterStop(mgr));
1005     }
1006
1007     /**
1008      * Tests the stop() method, after setting some option.
1009      *
1010      * @param expectedResult what stop() is expected to return
1011      * @param setOption function that sets an option
1012      * @throws Throwable if an error occurs during setup
1013      */
1014     private void testStop(boolean expectedResult, RunnableWithEx setOption) throws Throwable {
1015         setUp();
1016         setOption.run();
1017
1018         mgr.configure(properties);
1019         mgr.start();
1020         assertEquals(expectedResult, mgr.stop());
1021
1022         verify(prov1).beforeStop(mgr);
1023         verify(prov2).beforeStop(mgr);
1024
1025         verify(controller).stop();
1026         verify(controller2).stop();
1027
1028         verify(source1).stop();
1029         verify(source2).stop();
1030
1031         verify(sink1).stop();
1032         verify(sink2).stop();
1033
1034         verify(endpoint).stop();
1035
1036         verify(server1).stop();
1037         verify(server2).stop();
1038
1039         verify(client1).stop();
1040         verify(client2).stop();
1041
1042         verify(prov1).afterStop(mgr);
1043         verify(prov2).afterStop(mgr);
1044     }
1045
1046     @Test
1047     void testShutdown() throws Throwable {
1048         // normal success case
1049         testShutdown(() -> {
1050             // arrange for first provider, source, and sink to throw exceptions
1051             when(prov1.beforeShutdown(mgr)).thenThrow(new RuntimeException(EXPECTED));
1052             when(prov1.afterShutdown(mgr)).thenThrow(new RuntimeException(EXPECTED));
1053             doThrow(new RuntimeException(EXPECTED)).when(source1).shutdown();
1054             doThrow(new RuntimeException(EXPECTED)).when(sink1).shutdown();
1055         });
1056
1057         assertNotNull(shutdownThread);
1058         assertTrue(threadStarted);
1059         assertTrue(threadInterrupted);
1060
1061
1062         // lock manager throws an exception - still does everything
1063         testShutdown(() -> doThrow(new RuntimeException(EXPECTED)).when(lockmgr).shutdown());
1064
1065         // other tests
1066         checkBeforeAfter(
1067             (prov, flag) -> when(prov.beforeShutdown(mgr)).thenReturn(flag),
1068             (prov, flag) -> when(prov.afterShutdown(mgr)).thenReturn(flag),
1069             () -> {
1070                 mgr.configure(properties);
1071                 mgr.start();
1072                 mgr.shutdown();
1073             },
1074             prov -> verify(prov).beforeShutdown(mgr),
1075             () -> assertTrue(jmxStopped),
1076             prov -> verify(prov).afterShutdown(mgr));
1077     }
1078
1079     /**
1080      * Tests the shutdown() method, after setting some option.
1081      *
1082      * @param setOption function that sets an option
1083      * @throws Throwable if an error occurs during setup
1084      */
1085     private void testShutdown(RunnableWithEx setOption) throws Throwable {
1086         setUp();
1087         setOption.run();
1088
1089         mgr.configure(properties);
1090         mgr.start();
1091         mgr.shutdown();
1092
1093         verify(prov1).beforeShutdown(mgr);
1094         verify(prov2).beforeShutdown(mgr);
1095
1096         verify(source1).shutdown();
1097         verify(source2).shutdown();
1098
1099         verify(sink1).shutdown();
1100         verify(sink2).shutdown();
1101
1102         verify(controllerFactory).shutdown();
1103         verify(endpoint).shutdown();
1104         verify(serverFactory).destroy();
1105         verify(clientFactory).destroy();
1106
1107         assertTrue(jmxStopped);
1108
1109         verify(prov1).afterShutdown(mgr);
1110         verify(prov2).afterShutdown(mgr);
1111
1112         verify(exsvc).shutdownNow();
1113     }
1114
1115     @Test
1116     void testShutdownThreadRun() throws Throwable {
1117         // arrange for first server to throw exceptions
1118         testShutdownThreadRun(() -> doThrow(new RuntimeException(EXPECTED)).when(server1).shutdown());
1119
1120         // sleep throws an exception
1121         testShutdownThreadRun(() -> shouldInterrupt = true);
1122     }
1123
1124     /**
1125      * Tests the ShutdownThread.run() method, after setting some option.
1126      *
1127      * @param setOption function that sets an option
1128      * @throws Throwable if an error occurs during setup
1129      */
1130     private void testShutdownThreadRun(RunnableWithEx setOption) throws Throwable {
1131         setUp();
1132         setOption.run();
1133
1134         mgr.configure(properties);
1135         mgr.start();
1136         mgr.shutdown();
1137
1138         assertNotNull(shutdownThread);
1139
1140         shutdownThread.run();
1141
1142         assertTrue(threadSleepMs >= 0);
1143         assertEquals(0, threadExitCode);
1144
1145         verify(server1).shutdown();
1146         verify(server2).shutdown();
1147
1148         verify(clientFactory).destroy();
1149     }
1150
1151     @Test
1152     void testIsAlive() {
1153         mgr.configure(properties);
1154         assertFalse(mgr.isAlive());
1155
1156         mgr.start();
1157         assertTrue(mgr.isAlive());
1158
1159         mgr.stop();
1160         assertFalse(mgr.isAlive());
1161     }
1162
1163     @Test
1164     void testLock() throws Throwable {
1165         // normal success case
1166         testLock(true, () -> {
1167             // arrange for first provider to throw exceptions
1168             when(prov1.beforeLock(mgr)).thenThrow(new RuntimeException(EXPECTED));
1169             when(prov1.afterLock(mgr)).thenThrow(new RuntimeException(EXPECTED));
1170         });
1171
1172         // already locked - shouldn't run anything besides beforeLock()
1173         setUp();
1174         mgr.configure(properties);
1175         mgr.lock();
1176         assertTrue(mgr.lock());
1177         verify(prov1, times(2)).beforeLock(mgr);
1178         verify(prov2, times(2)).beforeLock(mgr);
1179         verify(controller).lock();
1180         verify(controller2).lock();
1181         verify(endpoint).lock();
1182         verify(prov1).afterLock(mgr);
1183         verify(prov2).afterLock(mgr);
1184
1185         // controller fails to lock - still does everything
1186         testLock(false, () -> when(controller.lock()).thenReturn(false));
1187
1188         // controller throws an exception - still does everything
1189         testLock(false, () -> when(controller.lock()).thenThrow(new RuntimeException(EXPECTED)));
1190
1191         // endpoint manager fails to lock - still does everything
1192         testLock(false, () -> when(endpoint.lock()).thenReturn(false));
1193
1194         // lock manager fails to lock - still does everything
1195         testLock(false, () -> when(lockmgr.lock()).thenReturn(false));
1196
1197         // lock manager throws an exception - still does everything
1198         testLock(false, () -> when(lockmgr.lock()).thenThrow(new RuntimeException(EXPECTED)));
1199
1200         // other tests
1201         checkBeforeAfter(
1202             (prov, flag) -> when(prov.beforeLock(mgr)).thenReturn(flag),
1203             (prov, flag) -> when(prov.afterLock(mgr)).thenReturn(flag),
1204             () -> {
1205                 mgr.configure(properties);
1206                 mgr.start();
1207                 assertTrue(mgr.lock());
1208             },
1209             prov -> verify(prov).beforeLock(mgr),
1210             () -> verify(endpoint).lock(),
1211             prov -> verify(prov).afterLock(mgr));
1212     }
1213
1214     /**
1215      * Tests the lock() method, after setting some option.
1216      *
1217      * @param expectedResult what lock() is expected to return
1218      * @param setOption function that sets an option
1219      * @throws Throwable if an error occurs during setup
1220      */
1221     private void testLock(boolean expectedResult, RunnableWithEx setOption) throws Throwable {
1222         setUp();
1223         setOption.run();
1224
1225         mgr.configure(properties);
1226         assertEquals(expectedResult, mgr.lock());
1227
1228         verify(prov1).beforeLock(mgr);
1229         verify(prov2).beforeLock(mgr);
1230
1231         verify(controller).lock();
1232         verify(controller2).lock();
1233
1234         verify(endpoint).lock();
1235
1236         verify(prov1).afterLock(mgr);
1237         verify(prov2).afterLock(mgr);
1238     }
1239
1240     @Test
1241     void testUnlock() throws Throwable {
1242         // normal success case
1243         testUnlock(true, () -> {
1244             // arrange for first provider to throw exceptions
1245             when(prov1.beforeUnlock(mgr)).thenThrow(new RuntimeException(EXPECTED));
1246             when(prov1.afterUnlock(mgr)).thenThrow(new RuntimeException(EXPECTED));
1247         });
1248
1249         // not locked - shouldn't run anything besides beforeUnlock()
1250         setUp();
1251         mgr.configure(properties);
1252         assertTrue(mgr.unlock());
1253         verify(prov1).beforeUnlock(mgr);
1254         verify(prov2).beforeUnlock(mgr);
1255         verify(controller, never()).unlock();
1256         verify(controller2, never()).unlock();
1257         verify(endpoint, never()).unlock();
1258         verify(prov1, never()).afterUnlock(mgr);
1259         verify(prov2, never()).afterUnlock(mgr);
1260
1261         // controller fails to unlock - still does everything
1262         testUnlock(false, () -> when(controller.unlock()).thenReturn(false));
1263
1264         // controller throws an exception - still does everything
1265         testUnlock(false, () -> when(controller.unlock()).thenThrow(new RuntimeException(EXPECTED)));
1266
1267         // endpoint manager fails to unlock - still does everything
1268         testUnlock(false, () -> when(endpoint.unlock()).thenReturn(false));
1269
1270         // lock manager fails to lock - still does everything
1271         testUnlock(false, () -> when(lockmgr.unlock()).thenReturn(false));
1272
1273         // lock manager throws an exception - still does everything
1274         testUnlock(false, () -> when(lockmgr.unlock()).thenThrow(new RuntimeException(EXPECTED)));
1275
1276         // other tests
1277         checkBeforeAfter(
1278             (prov, flag) -> when(prov.beforeUnlock(mgr)).thenReturn(flag),
1279             (prov, flag) -> when(prov.afterUnlock(mgr)).thenReturn(flag),
1280             () -> {
1281                 mgr.configure(properties);
1282                 mgr.lock();
1283                 assertTrue(mgr.unlock());
1284             },
1285             prov -> verify(prov).beforeUnlock(mgr),
1286             () -> verify(endpoint).unlock(),
1287             prov -> verify(prov).afterUnlock(mgr));
1288     }
1289
1290     /**
1291      * Tests the unlock() method, after setting some option.
1292      *
1293      * @param expectedResult what unlock() is expected to return
1294      * @param setOption function that sets an option
1295      * @throws Throwable if an error occurs during setup
1296      */
1297     private void testUnlock(boolean expectedResult, RunnableWithEx setOption) throws Throwable {
1298         setUp();
1299         setOption.run();
1300
1301         mgr.configure(properties);
1302         mgr.lock();
1303         assertEquals(expectedResult, mgr.unlock());
1304
1305         verify(prov1).beforeUnlock(mgr);
1306         verify(prov2).beforeUnlock(mgr);
1307
1308         verify(controller).unlock();
1309         verify(controller2).unlock();
1310
1311         verify(endpoint).unlock();
1312
1313         verify(prov1).afterUnlock(mgr);
1314         verify(prov2).afterUnlock(mgr);
1315     }
1316
1317     @Test
1318     void testIsLocked() {
1319         mgr.configure(properties);
1320         assertFalse(mgr.isLocked());
1321
1322         mgr.lock();
1323         assertTrue(mgr.isLocked());
1324
1325         mgr.unlock();
1326         assertFalse(mgr.isLocked());
1327     }
1328
1329     @Test
1330     void testRemovePolicyControllerString() {
1331         mgr.removePolicyController(MY_NAME);
1332
1333         verify(controllerFactory).destroy(MY_NAME);
1334     }
1335
1336     @Test
1337     void testRemovePolicyControllerPolicyController() {
1338         mgr.removePolicyController(controller);
1339
1340         verify(controllerFactory).destroy(controller);
1341     }
1342
1343     @Test
1344     void testGetPolicyControllers() {
1345         assertEquals(controllers, mgr.getPolicyControllers());
1346     }
1347
1348     @Test
1349     void testGetPolicyControllerIds() {
1350         assertEquals(Arrays.asList(CONTROLLER1, CONTROLLER2), mgr.getPolicyControllerIds());
1351     }
1352
1353     @Test
1354     void testGetProperties() {
1355         properties.setProperty("prop-x", "value-x");
1356         properties.setProperty("prop-y", "value-y");
1357
1358         mgr.configure(properties);
1359         assertEquals(properties, mgr.getProperties());
1360     }
1361
1362     @Test
1363     void testGetSources() {
1364         mgr.configure(properties);
1365         assertEquals(sources, mgr.getSources());
1366     }
1367
1368     @Test
1369     void testGetSinks() {
1370         mgr.configure(properties);
1371         assertEquals(sinks, mgr.getSinks());
1372     }
1373
1374     @Test
1375     void testGetHttpServers() {
1376         mgr.configure(properties);
1377         assertEquals(servers, mgr.getHttpServers());
1378     }
1379
1380     @Test
1381     void testGetFeatures() {
1382         assertEquals(Arrays.asList(FEATURE1, FEATURE2), mgr.getFeatures());
1383     }
1384
1385     @Test
1386     void testGetFeatureProviders() {
1387         assertEquals(providers, mgr.getFeatureProviders());
1388     }
1389
1390     @Test
1391     void testGetFeatureProvider() {
1392         assertEquals(prov1, mgr.getFeatureProvider(FEATURE1));
1393         assertEquals(prov2, mgr.getFeatureProvider(FEATURE2));
1394
1395         // null feature
1396         assertThatIllegalArgumentException().isThrownBy(() -> mgr.getFeatureProvider(null));
1397
1398         // empty feature
1399         assertThatIllegalArgumentException().isThrownBy(() -> mgr.getFeatureProvider(""));
1400
1401         // unknown feature
1402         assertThatIllegalArgumentException().isThrownBy(() -> mgr.getFeatureProvider("unknown-feature"));
1403     }
1404
1405     @Test
1406     void testTransaction() {
1407         mgr.metric(CONTROLLER1, POLICY, new Metric());
1408         assertEquals(0, mgr.getStats().getGroupStat().getPolicyExecutedCount());
1409         assertEquals(0, mgr.getStats().getSubgroupStats().size());
1410
1411         Metric metric = new Metric();
1412         mgr.transaction(CONTROLLER1, CONTROLLOOP, metric);
1413         assertEquals(1, mgr.getStats().getGroupStat().getPolicyExecutedCount());
1414         assertEquals(1, mgr.getStats().getSubgroupStats().size());
1415         assertEquals(1, mgr.getStats().getSubgroupStats().get(CONTROLLOOP).getPolicyExecutedFailCount());
1416
1417         Summary.Child.Value summary =
1418                 PolicyEngineManagerImpl.transLatencySecsSummary
1419                         .labels(CONTROLLER1, CONTROLLOOP, POLICY, PdpResponseStatus.FAIL.name()).get();
1420
1421         assertEquals(0, summary.count, 0.0);
1422         assertEquals(0, summary.sum, 0.0);
1423
1424         metric.setServiceInstanceId(POLICY);
1425         metric.setElapsedTime(5000L);
1426         metric.setSuccess(false);
1427         mgr.transaction(CONTROLLER1, CONTROLLOOP, metric);
1428
1429         summary =
1430                 PolicyEngineManagerImpl.transLatencySecsSummary
1431                         .labels(CONTROLLER1, CONTROLLOOP, POLICY, PdpResponseStatus.FAIL.name()).get();
1432
1433         assertEquals(1, summary.count, 0.0);
1434         assertEquals(5, summary.sum, 0.0);
1435     }
1436
1437     @Test
1438     void testOnTopicEvent() {
1439         mgr.onTopicEvent(CommInfrastructure.NOOP, MY_TOPIC, pdpConfigJson);
1440
1441         verify(controllerFactory).patch(controller3, drools3);
1442         verify(controllerFactory).patch(controller4, drools4);
1443
1444         // null json - no additional patches
1445         mgr.onTopicEvent(CommInfrastructure.NOOP, MY_TOPIC, null);
1446
1447         verify(controllerFactory).patch(controller3, drools3);
1448         verify(controllerFactory).patch(controller4, drools4);
1449     }
1450
1451     @Test
1452     void testDeliverStringObject() throws Exception {
1453         mgr.configure(properties);
1454         mgr.start();
1455
1456         assertTrue(mgr.deliver(MY_TOPIC, MY_EVENT));
1457
1458         verify(sink1).send(MESSAGE);
1459
1460         // invalid parameters
1461         String nullStr = null;
1462         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(nullStr, MY_EVENT));
1463         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver("", MY_EVENT));
1464
1465         Object nullObj = null;
1466         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(MY_TOPIC, nullObj));
1467
1468         // locked
1469         mgr.lock();
1470         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(MY_TOPIC, MY_EVENT));
1471         mgr.unlock();
1472
1473         // not running
1474         mgr.stop();
1475         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(MY_TOPIC, MY_EVENT));
1476
1477         // issues with topic
1478         setUp();
1479         mgr.configure(properties);
1480         mgr.start();
1481
1482         // null sinks
1483         when(endpoint.getTopicSinks(MY_TOPIC)).thenReturn(null);
1484         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(MY_TOPIC, MY_EVENT));
1485
1486         // empty sinks
1487         when(endpoint.getTopicSinks(MY_TOPIC)).thenReturn(Collections.emptyList());
1488         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(MY_TOPIC, MY_EVENT));
1489
1490         // too many sinks
1491         when(endpoint.getTopicSinks(MY_TOPIC)).thenReturn(sinks);
1492         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(MY_TOPIC, MY_EVENT));
1493     }
1494
1495     @Test
1496     void testDeliverStringStringObject() {
1497         mgr.configure(properties);
1498         mgr.start();
1499
1500         assertTrue(mgr.deliver(NOOP_STR, MY_TOPIC, MY_EVENT));
1501
1502         verify(sink1).send(MESSAGE);
1503
1504         // invalid parameters
1505         String nullStr = null;
1506         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(nullStr, MY_TOPIC, MY_EVENT));
1507         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver("", MY_TOPIC, MY_EVENT));
1508         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver("unknown-bus-type", MY_TOPIC, MY_EVENT));
1509
1510         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(NOOP_STR, nullStr, MY_EVENT));
1511         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(NOOP_STR, "", MY_EVENT));
1512
1513         Object nullObj = null;
1514         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(NOOP_STR, MY_TOPIC, nullObj));
1515
1516         // locked
1517         mgr.lock();
1518         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(NOOP_STR, MY_TOPIC, MY_EVENT));
1519         mgr.unlock();
1520
1521         // not running
1522         mgr.stop();
1523         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(NOOP_STR, MY_TOPIC, MY_EVENT));
1524     }
1525
1526     @Test
1527     void testDeliverCommInfrastructureStringObject() throws Exception {
1528         mgr.configure(properties);
1529         mgr.start();
1530
1531         assertTrue(mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT));
1532
1533         verify(controller, never()).deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT);
1534
1535         verify(coder).encode(MY_TOPIC, MY_EVENT);
1536         verify(sink1).send(MESSAGE);
1537
1538         // invalid parameters
1539         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, null, MY_EVENT));
1540         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, "", MY_EVENT));
1541
1542         Object nullObj = null;
1543         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, nullObj));
1544
1545         // locked
1546         mgr.lock();
1547         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT));
1548         mgr.unlock();
1549
1550         // not started
1551         mgr.stop();
1552         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT));
1553
1554         // send() throws an exception
1555         setUp();
1556         mgr.configure(properties);
1557         mgr.start();
1558         when(sink1.send(any())).thenThrow(new ArithmeticException(EXPECTED));
1559         assertThatThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT))
1560                         .isInstanceOf(ArithmeticException.class);
1561
1562         /*
1563          * For remaining tests, have the controller handle delivery.
1564          */
1565         setUp();
1566         mgr.configure(properties);
1567         mgr.start();
1568         DroolsController drools = mock(DroolsController.class);
1569         when(coder.getDroolsController(MY_TOPIC, MY_EVENT)).thenReturn(drools);
1570         when(controllerFactory.get(drools)).thenReturn(controller);
1571         when(controller.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT)).thenReturn(true);
1572
1573         assertTrue(mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT));
1574
1575         verify(controller).deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT);
1576
1577         verify(coder, never()).encode(MY_TOPIC, MY_EVENT);
1578         verify(sink1, never()).send(MESSAGE);
1579
1580         // controller throws exception, so should drop into regular handling
1581         when(controller.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT)).thenThrow(new RuntimeException(EXPECTED));
1582
1583         assertTrue(mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT));
1584
1585         // should have attempted this again
1586         verify(controller, times(2)).deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT);
1587
1588         // now these should have been called
1589         verify(coder).encode(MY_TOPIC, MY_EVENT);
1590         verify(sink1).send(MESSAGE);
1591     }
1592
1593     @Test
1594     void testDeliverCommInfrastructureStringString() {
1595         mgr.configure(properties);
1596
1597         // not started yet
1598         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MESSAGE));
1599
1600         // start it
1601         mgr.start();
1602
1603         assertTrue(mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MESSAGE));
1604         verify(sink1).send(MESSAGE);
1605         verify(sink2, never()).send(any());
1606
1607         // invalid parameters
1608         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, null, MESSAGE));
1609         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, "", MESSAGE));
1610
1611         String nullStr = null;
1612         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, nullStr));
1613         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, ""));
1614
1615         // unknown topic
1616         assertThatIllegalStateException()
1617                         .isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, "unknown-topic", MESSAGE));
1618
1619         // locked
1620         mgr.lock();
1621         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MESSAGE));
1622         mgr.unlock();
1623     }
1624
1625     @Test
1626     void testActivate() throws Throwable {
1627         // normal success case
1628         testActivate(() -> {
1629             // arrange for first provider and controller to throw exceptions
1630             when(prov1.beforeActivate(mgr)).thenThrow(new RuntimeException(EXPECTED));
1631             when(prov1.afterActivate(mgr)).thenThrow(new RuntimeException(EXPECTED));
1632             when(controller.start()).thenThrow(new RuntimeException(EXPECTED));
1633         });
1634
1635         // controller generates linkage error
1636         testActivate(() -> when(controller.start()).thenThrow(new LinkageError(EXPECTED)));
1637
1638         // other tests
1639         checkBeforeAfter(
1640             (prov, flag) -> when(prov.beforeActivate(mgr)).thenReturn(flag),
1641             (prov, flag) -> when(prov.afterActivate(mgr)).thenReturn(flag),
1642             () -> {
1643                 mgr.configure(properties);
1644                 mgr.lock();
1645                 mgr.activate();
1646             },
1647             prov -> verify(prov).beforeActivate(mgr),
1648             () -> assertFalse(mgr.isLocked()),
1649             prov -> verify(prov).afterActivate(mgr));
1650     }
1651
1652     /**
1653      * Tests the activate() method, after setting some option.
1654      *
1655      * @param setOption function that sets an option
1656      * @throws Throwable if an error occurs during setup
1657      */
1658     private void testActivate(RunnableWithEx setOption) throws Throwable {
1659         setUp();
1660         setOption.run();
1661
1662         mgr.configure(properties);
1663         mgr.lock();
1664         mgr.activate();
1665
1666         verify(prov1).beforeActivate(mgr);
1667         verify(prov2).beforeActivate(mgr);
1668
1669         // unlocked by activate() AND by unlock() (which is invoked by activate())
1670         verify(controller, times(2)).unlock();
1671         verify(controller2, times(2)).unlock();
1672
1673         verify(controller).start();
1674         verify(controller2).start();
1675
1676         assertFalse(mgr.isLocked());
1677
1678         verify(prov1).afterActivate(mgr);
1679         verify(prov2).afterActivate(mgr);
1680     }
1681
1682     @Test
1683     void testDeactivate() throws Throwable {
1684         // normal success case
1685         testDeactivate(() -> {
1686             // arrange for first provider and controller to throw exceptions
1687             when(prov1.beforeDeactivate(mgr)).thenThrow(new RuntimeException(EXPECTED));
1688             when(prov1.afterDeactivate(mgr)).thenThrow(new RuntimeException(EXPECTED));
1689             when(controller.stop()).thenThrow(new RuntimeException(EXPECTED));
1690         });
1691
1692         // controller generates linkage error
1693         testDeactivate(() -> when(controller.stop()).thenThrow(new LinkageError(EXPECTED)));
1694
1695         // other tests
1696         checkBeforeAfter(
1697             (prov, flag) -> when(prov.beforeDeactivate(mgr)).thenReturn(flag),
1698             (prov, flag) -> when(prov.afterDeactivate(mgr)).thenReturn(flag),
1699             () -> {
1700                 mgr.configure(properties);
1701                 mgr.deactivate();
1702             },
1703             prov -> verify(prov).beforeDeactivate(mgr),
1704             () -> assertTrue(mgr.isLocked()),
1705             prov -> verify(prov).afterDeactivate(mgr));
1706     }
1707
1708     /**
1709      * Tests the deactivate() method, after setting some option.
1710      *
1711      * @param setOption function that sets an option
1712      * @throws Throwable if an error occurs during setup
1713      */
1714     private void testDeactivate(RunnableWithEx setOption) throws Throwable {
1715         setUp();
1716         setOption.run();
1717
1718         mgr.configure(properties);
1719         mgr.deactivate();
1720
1721         verify(prov1).beforeDeactivate(mgr);
1722         verify(prov2).beforeDeactivate(mgr);
1723
1724         verify(controller).lock();
1725         verify(controller2).lock();
1726
1727         verify(controller).stop();
1728         verify(controller2).stop();
1729
1730         assertTrue(mgr.isLocked());
1731
1732         verify(prov1).afterDeactivate(mgr);
1733         verify(prov2).afterDeactivate(mgr);
1734     }
1735
1736     @Test
1737     void testCreateLock() {
1738         Lock lock = mock(Lock.class);
1739         LockCallback callback = mock(LockCallback.class);
1740         when(lockmgr.createLock(MY_RESOURCE, MY_OWNER, 10, callback, false)).thenReturn(lock);
1741
1742         // not configured yet, thus no lock manager
1743         assertThatIllegalStateException()
1744                         .isThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, 10, callback, false));
1745
1746         // now configure it and try again
1747         mgr.configure(properties);
1748         assertSame(lock, mgr.createLock(MY_RESOURCE, MY_OWNER, 10, callback, false));
1749
1750         // test illegal args
1751         assertThatThrownBy(() -> mgr.createLock(null, MY_OWNER, 10, callback, false))
1752                         .hasMessageContaining("resourceId");
1753         assertThatThrownBy(() -> mgr.createLock(MY_RESOURCE, null, 10, callback, false))
1754                         .hasMessageContaining("ownerKey");
1755         assertThatIllegalArgumentException()
1756                         .isThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, -1, callback, false))
1757                         .withMessageContaining("holdSec");
1758         assertThatThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, 10, null, false))
1759                         .hasMessageContaining("callback");
1760     }
1761
1762     @Test
1763     void testOpen() throws Throwable {
1764         when(prov1.beforeOpen(mgr)).thenThrow(new RuntimeException(EXPECTED));
1765         when(prov1.afterOpen(mgr)).thenThrow(new RuntimeException(EXPECTED));
1766
1767         assertTrue(mgr.lock());
1768         assertThatIllegalStateException().isThrownBy(() -> mgr.open());
1769         unsuccessfulOpen();
1770
1771         assertTrue(mgr.unlock());
1772         unsuccessfulOpen();
1773
1774         setUp();
1775         mgr.configure(properties);
1776         assertTrue(mgr.start());
1777
1778         verify(source1, never()).start();
1779         verify(source2, never()).start();
1780
1781         assertTrue(mgr.open());
1782
1783         verify(prov1).beforeOpen(mgr);
1784         verify(prov2).beforeOpen(mgr);
1785
1786         verify(source1).start();
1787         verify(source2).start();
1788
1789         verify(prov1).afterOpen(mgr);
1790         verify(prov2).afterOpen(mgr);
1791
1792         when(source1.start()).thenReturn(false);
1793         assertFalse(mgr.open());
1794         when(source1.start()).thenReturn(true);
1795
1796         when(sink1.start()).thenReturn(false);
1797         assertFalse(mgr.open());
1798         when(sink1.start()).thenReturn(true);
1799
1800         assertTrue(mgr.open());
1801     }
1802
1803     private void unsuccessfulOpen() {
1804         verify(prov1).beforeOpen(mgr);
1805         verify(prov2).beforeOpen(mgr);
1806
1807         verify(prov1, never()).afterOpen(mgr);
1808         verify(prov2, never()).afterOpen(mgr);
1809
1810         verify(source1, never()).start();
1811         verify(source2, never()).start();
1812
1813         verify(sink1, never()).start();
1814         verify(sink2, never()).start();
1815     }
1816
1817     @Test
1818     void testControllerConfig() throws Exception {
1819         mgr.configure(properties);
1820         assertTrue(mgr.configure(pdpConfig));
1821
1822         verify(controllerFactory).patch(controller3, drools3);
1823         verify(controllerFactory).patch(controller4, drools4);
1824
1825         // empty controllers
1826         pdpConfig.getControllers().clear();
1827         assertFalse(mgr.configure(pdpConfig));
1828
1829         // null controllers
1830         pdpConfig.setControllers(null);
1831         assertFalse(mgr.configure(pdpConfig));
1832
1833         // arrange for controller3 to fail
1834         setUp();
1835         config3.setOperation("fail-3");
1836         assertFalse(mgr.configure(pdpConfig));
1837
1838         verify(controllerFactory, never()).patch(controller3, drools3);
1839         verify(controllerFactory).patch(controller4, drools4);
1840
1841         // arrange for both controllers to fail
1842         setUp();
1843         config3.setOperation("fail-3");
1844         config4.setOperation("fail-4");
1845         assertFalse(mgr.configure(pdpConfig));
1846     }
1847
1848     @Test
1849     void testToString() {
1850         assertTrue(mgr.toString().startsWith("PolicyEngineManager("));
1851     }
1852
1853     /**
1854      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries
1855      * combinations where beforeXxx and afterXxx return {@code true} and {@code false}.
1856      *
1857      * @param setBefore function to set the return value of a provider's beforeXxx method
1858      * @param setAfter function to set the return value of a provider's afterXxx method
1859      * @param action invokes the operation
1860      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
1861      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
1862      *        and the afterXxx loop was invoked
1863      * @param verifyAfter verifies that a provider's afterXxx method was invoked
1864      * @throws Exception if an error occurs while calling {@link #setUp()}
1865      */
1866     private void checkBeforeAfter(BiConsumer<PolicyEngineFeatureApi, Boolean> setBefore,
1867                     BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action,
1868                     Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle,
1869                     Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception {
1870
1871         checkBeforeAfter_FalseFalse(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
1872         checkBeforeAfter_FalseTrue(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
1873         checkBeforeAfter_TrueFalse(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
1874
1875         // don't need to test true-true, as it's behavior is a subset of true-false
1876     }
1877
1878     /**
1879      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
1880      * case where both the beforeXxx and afterXxx methods return {@code false}.
1881      *
1882      * @param setBefore function to set the return value of a provider's beforeXxx method
1883      * @param setAfter function to set the return value of a provider's afterXxx method
1884      * @param action invokes the operation
1885      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
1886      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
1887      *        and the afterXxx loop was invoked
1888      * @param verifyAfter verifies that a provider's afterXxx method was invoked
1889      * @throws Exception if an error occurs while calling {@link #setUp()}
1890      */
1891     private void checkBeforeAfter_FalseFalse(BiConsumer<PolicyEngineFeatureApi, Boolean> setBefore,
1892                     BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action,
1893                     Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle,
1894                     Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception {
1895
1896         setUp();
1897
1898         // configure for the test
1899         setBefore.accept(prov1, false);
1900         setBefore.accept(prov2, false);
1901
1902         setAfter.accept(prov1, false);
1903         setAfter.accept(prov2, false);
1904
1905         // run the action
1906         action.run();
1907
1908         // verify that various methods were invoked
1909         verifyBefore.accept(prov1);
1910         verifyBefore.accept(prov2);
1911
1912         verifyMiddle.run();
1913
1914         verifyAfter.accept(prov1);
1915         verifyAfter.accept(prov2);
1916     }
1917
1918     /**
1919      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
1920      * case where the first provider's afterXxx returns {@code true}, while the others
1921      * return {@code false}.
1922      *
1923      * @param setBefore function to set the return value of a provider's beforeXxx method
1924      * @param setAfter function to set the return value of a provider's afterXxx method
1925      * @param action invokes the operation
1926      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
1927      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
1928      *        and the afterXxx loop was invoked
1929      * @param verifyAfter verifies that a provider's afterXxx method was invoked
1930      * @throws Exception if an error occurs while calling {@link #setUp()}
1931      */
1932     private void checkBeforeAfter_FalseTrue(BiConsumer<PolicyEngineFeatureApi, Boolean> setBefore,
1933                     BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action,
1934                     Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle,
1935                     Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception {
1936
1937         setUp();
1938
1939         // configure for the test
1940         setBefore.accept(prov1, false);
1941         setBefore.accept(prov2, false);
1942
1943         setAfter.accept(prov1, true);
1944         setAfter.accept(prov2, false);
1945
1946         // run the action
1947         action.run();
1948
1949         // verify that various methods were invoked
1950         verifyBefore.accept(prov1);
1951         verifyBefore.accept(prov2);
1952
1953         verifyMiddle.run();
1954
1955         verifyAfter.accept(prov1);
1956         assertThatThrownBy(() -> verifyAfter.accept(prov2)).isInstanceOf(AssertionError.class);
1957     }
1958
1959     /**
1960      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
1961      * case where the first provider's beforeXxx returns {@code true}, while the others
1962      * return {@code false}.
1963      *
1964      * @param setBefore function to set the return value of a provider's beforeXxx method
1965      * @param setAfter function to set the return value of a provider's afterXxx method
1966      * @param action invokes the operation
1967      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
1968      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
1969      *        and the afterXxx loop was invoked
1970      * @param verifyAfter verifies that a provider's afterXxx method was invoked
1971      * @throws Exception if an error occurs while calling {@link #setUp()}
1972      */
1973     private void checkBeforeAfter_TrueFalse(BiConsumer<PolicyEngineFeatureApi, Boolean> setBefore,
1974                     BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action,
1975                     Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle,
1976                     Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception {
1977
1978         setUp();
1979
1980         // configure for the test
1981         setBefore.accept(prov1, true);
1982         setBefore.accept(prov2, false);
1983
1984         setAfter.accept(prov1, false);
1985         setAfter.accept(prov2, false);
1986
1987         // run the action
1988         action.run();
1989
1990         // verify that various methods were invoked
1991         verifyBefore.accept(prov1);
1992
1993         // remaining methods should not have been invoked
1994         assertThatThrownBy(() -> verifyBefore.accept(prov2)).isInstanceOf(AssertionError.class);
1995
1996         assertThatThrownBy(verifyMiddle::run).isInstanceOf(AssertionError.class);
1997
1998         assertThatThrownBy(() -> verifyAfter.accept(prov1)).isInstanceOf(AssertionError.class);
1999         assertThatThrownBy(() -> verifyAfter.accept(prov2)).isInstanceOf(AssertionError.class);
2000     }
2001
2002     /**
2003      * Manager with overrides.
2004      */
2005     private class PolicyEngineManagerImpl extends PolicyEngineManager {
2006
2007         @Override
2008         protected List<PolicyEngineFeatureApi> getEngineProviders() {
2009             return providers;
2010         }
2011
2012         @Override
2013         protected List<PolicyControllerFeatureApi> getControllerProviders() {
2014             return contProviders;
2015         }
2016
2017         @Override
2018         protected void globalInitContainer(String[] cliArgs) {
2019             globalInitArgs = cliArgs;
2020         }
2021
2022         @Override
2023         protected TopicEndpoint getTopicEndpointManager() {
2024             return endpoint;
2025         }
2026
2027         @Override
2028         protected HttpServletServerFactory getServletFactory() {
2029             return serverFactory;
2030         }
2031
2032         @Override
2033         protected HttpClientFactory getHttpClientFactory() {
2034             return clientFactory;
2035         }
2036
2037         @Override
2038         protected PolicyControllerFactory getControllerFactory() {
2039             return controllerFactory;
2040         }
2041
2042         @Override
2043         protected void startPdpJmxListener() {
2044             jmxStarted = true;
2045         }
2046
2047         @Override
2048         protected void stopPdpJmxListener() {
2049             jmxStopped = true;
2050         }
2051
2052         @Override
2053         protected Thread makeShutdownThread() {
2054             shutdownThread = new MyShutdown();
2055             return shutdownThread;
2056         }
2057
2058         @Override
2059         protected EventProtocolCoder getProtocolCoder() {
2060             return coder;
2061         }
2062
2063         @Override
2064         protected SystemPersistence getPersistenceManager() {
2065             return persist;
2066         }
2067
2068         @Override
2069         protected PolicyEngine getPolicyEngine() {
2070             return engine;
2071         }
2072
2073         @Override
2074         protected ScheduledExecutorService makeScheduledExecutor(int nthreads) {
2075             return exsvc;
2076         }
2077
2078         @Override
2079         public PolicyStatsManager getStats() {
2080             return statsManager;
2081         }
2082
2083         /**
2084          * Shutdown thread with overrides.
2085          */
2086         private class MyShutdown extends ShutdownThread {
2087
2088             @Override
2089             protected void doSleep(long sleepMs) throws InterruptedException {
2090                 threadSleepMs = sleepMs;
2091
2092                 if (shouldInterrupt) {
2093                     throw new InterruptedException(EXPECTED);
2094                 }
2095             }
2096
2097             @Override
2098             protected void doExit(int code) {
2099                 threadExitCode = code;
2100             }
2101
2102             @Override
2103             public synchronized void start() {
2104                 threadStarted = true;
2105             }
2106
2107             @Override
2108             public void interrupt() {
2109                 threadInterrupted = true;
2110             }
2111         }
2112     }
2113
2114     @FunctionalInterface
2115     private interface RunnableWithEx {
2116         void run() throws Exception;
2117     }
2118 }