Increase code coverage in policy-management
[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()).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()).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()).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()).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_Exceptions() 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     @Test
781     void testUpdatePolicyController() throws Exception {
782         /*
783          * For remaining tests, the factory will return the controller instead of creating
784          * one.
785          */
786         setUp();
787         when(controllerFactory.get(CONTROLLER3)).thenReturn(controller3);
788
789         assertEquals(controller3, mgr.updatePolicyController(config3));
790
791         // should NOT have created a new controller
792         verify(engine, never()).createPolicyController(any(), any());
793
794         int countPatch = 0;
795         int countLock = 0;
796         int countUnlock = 0;
797
798         // check different operations
799
800         // CREATE only invokes patch() (note: mgr.update() has already been called)
801         verify(controllerFactory, times(++countPatch)).patch(controller3, drools3);
802         verify(controller3, times(countLock)).lock();
803         verify(controller3, times(countUnlock)).unlock();
804
805         // UPDATE invokes unlock() and patch()
806         config3.setOperation(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UPDATE);
807         assertEquals(controller3, mgr.updatePolicyController(config3));
808         verify(controllerFactory, times(++countPatch)).patch(controller3, drools3);
809         verify(controller3, times(countLock)).lock();
810         verify(controller3, times(++countUnlock)).unlock();
811
812         // LOCK invokes lock()
813         config3.setOperation(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_LOCK);
814         assertEquals(controller3, mgr.updatePolicyController(config3));
815         verify(controllerFactory, times(countPatch)).patch(controller3, drools3);
816         verify(controller3, times(++countLock)).lock();
817         verify(controller3, times(countUnlock)).unlock();
818
819         // UNLOCK invokes unlock()
820         config3.setOperation(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UNLOCK);
821         assertEquals(controller3, mgr.updatePolicyController(config3));
822         verify(controllerFactory, times(countPatch)).patch(controller3, drools3);
823         verify(controller3, times(countLock)).lock();
824         verify(controller3, times(++countUnlock)).unlock();
825
826         // invalid operation
827         config3.setOperation("invalid-operation");
828         assertThatIllegalArgumentException().isThrownBy(() -> mgr.updatePolicyController(config3));
829     }
830
831     @Test
832     void testStart() throws Throwable {
833         // normal success case
834         testStart(true, () -> {
835             // arrange for first provider, server, source, and sink to throw exceptions
836             when(prov1.beforeStart(mgr)).thenThrow(new RuntimeException(EXPECTED));
837             when(prov1.afterStart(mgr)).thenThrow(new RuntimeException(EXPECTED));
838             when(server1.waitedStart(anyLong())).thenThrow(new RuntimeException(EXPECTED));
839             when(client1.start()).thenThrow(new RuntimeException(EXPECTED));
840             when(source1.start()).thenThrow(new RuntimeException(EXPECTED));
841             when(sink1.start()).thenThrow(new RuntimeException(EXPECTED));
842         });
843
844         // lock manager fails to start - still does everything
845         testStart(false, () -> when(lockmgr.start()).thenReturn(false));
846
847         //  lock manager throws an exception - still does everything
848         testStart(false, () -> when(lockmgr.start()).thenThrow(new RuntimeException(EXPECTED)));
849
850         // servlet wait fails - still does everything
851         testStart(false, () -> when(server1.waitedStart(anyLong())).thenReturn(false));
852
853         // client fails - still does everything
854         testStart(false, () -> when(client1.start()).thenReturn(false));
855
856         // topic source is not started with start
857         testStart(true, () -> when(source1.start()).thenReturn(false));
858
859         // topic sink is not started with start
860         testStart(true, () -> when(sink1.start()).thenReturn(false));
861
862         // controller fails to start - still does everything
863         testStart(false, () -> when(controller.start()).thenReturn(false));
864
865         // controller throws an exception - still does everything
866         testStart(false, () -> when(controller.start()).thenThrow(new RuntimeException(EXPECTED)));
867
868         // endpoint manager fails to start - still does everything
869         testStart(false, () -> when(endpoint.start()).thenReturn(false));
870
871         // endpoint manager throws an exception - still does everything AND succeeds
872         testStart(true, () -> when(endpoint.start()).thenThrow(new IllegalStateException(EXPECTED)));
873
874         // locked - nothing other than beforeXxx methods should be invoked
875         setUp();
876         mgr.configure(properties);
877         mgr.lock();
878         assertThatIllegalStateException().isThrownBy(() -> mgr.start());
879         verify(prov2).beforeStart(mgr);
880         verify(server2, never()).waitedStart(anyLong());
881         verify(source2, never()).start();
882         verify(sink1, never()).start();
883         verify(controller, never()).start();
884         verify(endpoint, never()).start();
885         assertFalse(jmxStarted);
886         verify(prov1, never()).afterStart(mgr);
887
888         // other tests
889         checkBeforeAfter(
890             (prov, flag) -> when(prov.beforeStart(mgr)).thenReturn(flag),
891             (prov, flag) -> when(prov.afterStart(mgr)).thenReturn(flag),
892             () -> {
893                 mgr.configure(properties);
894                 assertTrue(mgr.start());
895             },
896             prov -> verify(prov).beforeStart(mgr),
897             () -> assertTrue(jmxStarted),
898             prov -> verify(prov).afterStart(mgr));
899     }
900
901     /**
902      * Tests the start() method, after setting some option.
903      *
904      * @param expectedResult what start() is expected to return
905      * @param setOption function that sets an option
906      * @throws Throwable if an error occurs during setup
907      */
908     private void testStart(boolean expectedResult, RunnableWithEx setOption) throws Throwable {
909         setUp();
910         setOption.run();
911
912         mgr.configure(properties);
913         assertEquals(expectedResult, mgr.start());
914
915         verify(prov1).beforeStart(mgr);
916         verify(prov2).beforeStart(mgr);
917
918         verify(server1).waitedStart(anyLong());
919         verify(server2).waitedStart(anyLong());
920
921         verify(client1).start();
922         verify(client2).start();
923
924         verify(source1, never()).start();
925         verify(source2, never()).start();
926
927         verify(sink1, never()).start();
928         verify(sink2, never()).start();
929
930         verify(controller).start();
931         verify(controller2).start();
932
933         verify(endpoint).start();
934
935         assertTrue(jmxStarted);
936
937         verify(prov1).afterStart(mgr);
938         verify(prov2).afterStart(mgr);
939     }
940
941     @Test
942     void testStop() throws Throwable {
943         // normal success case
944         testStop(true, () -> {
945             // arrange for first provider, server, source, and sink to throw exceptions
946             when(prov1.beforeStop(mgr)).thenThrow(new RuntimeException(EXPECTED));
947             when(prov1.afterStop(mgr)).thenThrow(new RuntimeException(EXPECTED));
948             when(server1.stop()).thenThrow(new RuntimeException(EXPECTED));
949             when(client1.stop()).thenThrow(new RuntimeException(EXPECTED));
950             when(source1.stop()).thenThrow(new RuntimeException(EXPECTED));
951             when(sink1.stop()).thenThrow(new RuntimeException(EXPECTED));
952         });
953
954         // not alive - shouldn't run anything besides beforeStop()
955         setUp();
956         mgr.configure(properties);
957         assertTrue(mgr.stop());
958         verify(prov1).beforeStop(mgr);
959         verify(prov2).beforeStop(mgr);
960         verifyNeverCalled();
961
962         // controller fails to stop - still does everything
963         testStop(false, () -> when(controller.stop()).thenReturn(false));
964
965         // controller throws an exception - still does everything
966         testStop(false, () -> when(controller.stop()).thenThrow(new RuntimeException(EXPECTED)));
967
968         // topic source fails to stop - still does everything
969         testStop(false, () -> when(source1.stop()).thenReturn(false));
970
971         // topic sink fails to stop - still does everything
972         testStop(false, () -> when(sink1.stop()).thenReturn(false));
973
974         // endpoint manager fails to stop - still does everything
975         testStop(false, () -> when(endpoint.stop()).thenReturn(false));
976
977         // servlet fails to stop - still does everything
978         testStop(false, () -> when(server1.stop()).thenReturn(false));
979
980         // client fails to stop - still does everything
981         testStop(false, () -> when(client1.stop()).thenReturn(false));
982
983         // lock manager fails to stop - still does everything
984         testStop(false, () -> when(lockmgr.stop()).thenReturn(false));
985
986         // lock manager throws an exception - still does everything
987         testStop(false, () -> when(lockmgr.stop()).thenThrow(new RuntimeException(EXPECTED)));
988
989         // other tests
990         checkBeforeAfter(
991             (prov, flag) -> when(prov.beforeStop(mgr)).thenReturn(flag),
992             (prov, flag) -> when(prov.afterStop(mgr)).thenReturn(flag),
993             () -> {
994                 mgr.configure(properties);
995                 mgr.start();
996                 assertTrue(mgr.stop());
997             },
998             prov -> verify(prov).beforeStop(mgr),
999             () -> verify(endpoint).stop(),
1000             prov -> verify(prov).afterStop(mgr));
1001     }
1002
1003     /**
1004      * Tests the stop() method, after setting some option.
1005      *
1006      * @param expectedResult what stop() is expected to return
1007      * @param setOption function that sets an option
1008      * @throws Throwable if an error occurs during setup
1009      */
1010     private void testStop(boolean expectedResult, RunnableWithEx setOption) throws Throwable {
1011         setUp();
1012         setOption.run();
1013
1014         mgr.configure(properties);
1015         mgr.start();
1016         assertEquals(expectedResult, mgr.stop());
1017
1018         verify(prov1).beforeStop(mgr);
1019         verify(prov2).beforeStop(mgr);
1020
1021         verify(controller).stop();
1022         verify(controller2).stop();
1023
1024         verify(source1).stop();
1025         verify(source2).stop();
1026
1027         verify(sink1).stop();
1028         verify(sink2).stop();
1029
1030         verify(endpoint).stop();
1031
1032         verify(server1).stop();
1033         verify(server2).stop();
1034
1035         verify(client1).stop();
1036         verify(client2).stop();
1037
1038         verify(prov1).afterStop(mgr);
1039         verify(prov2).afterStop(mgr);
1040     }
1041
1042     @Test
1043     void testShutdown() throws Throwable {
1044         // normal success case
1045         testShutdown(() -> {
1046             // arrange for first provider, source, and sink to throw exceptions
1047             when(prov1.beforeShutdown(mgr)).thenThrow(new RuntimeException(EXPECTED));
1048             when(prov1.afterShutdown(mgr)).thenThrow(new RuntimeException(EXPECTED));
1049             doThrow(new RuntimeException(EXPECTED)).when(source1).shutdown();
1050             doThrow(new RuntimeException(EXPECTED)).when(sink1).shutdown();
1051         });
1052
1053         assertNotNull(shutdownThread);
1054         assertTrue(threadStarted);
1055         assertTrue(threadInterrupted);
1056
1057
1058         // lock manager throws an exception - still does everything
1059         testShutdown(() -> doThrow(new RuntimeException(EXPECTED)).when(lockmgr).shutdown());
1060
1061         // other tests
1062         checkBeforeAfter(
1063             (prov, flag) -> when(prov.beforeShutdown(mgr)).thenReturn(flag),
1064             (prov, flag) -> when(prov.afterShutdown(mgr)).thenReturn(flag),
1065             () -> {
1066                 mgr.configure(properties);
1067                 mgr.start();
1068                 mgr.shutdown();
1069             },
1070             prov -> verify(prov).beforeShutdown(mgr),
1071             () -> assertTrue(jmxStopped),
1072             prov -> verify(prov).afterShutdown(mgr));
1073     }
1074
1075     /**
1076      * Tests the shutdown() method, after setting some option.
1077      *
1078      * @param setOption function that sets an option
1079      * @throws Throwable if an error occurs during setup
1080      */
1081     private void testShutdown(RunnableWithEx setOption) throws Throwable {
1082         setUp();
1083         setOption.run();
1084
1085         mgr.configure(properties);
1086         mgr.start();
1087         mgr.shutdown();
1088
1089         verify(prov1).beforeShutdown(mgr);
1090         verify(prov2).beforeShutdown(mgr);
1091
1092         verify(source1).shutdown();
1093         verify(source2).shutdown();
1094
1095         verify(sink1).shutdown();
1096         verify(sink2).shutdown();
1097
1098         verify(controllerFactory).shutdown();
1099         verify(endpoint).shutdown();
1100         verify(serverFactory).destroy();
1101         verify(clientFactory).destroy();
1102
1103         assertTrue(jmxStopped);
1104
1105         verify(prov1).afterShutdown(mgr);
1106         verify(prov2).afterShutdown(mgr);
1107
1108         verify(exsvc).shutdownNow();
1109     }
1110
1111     @Test
1112     void testShutdownThreadRun() throws Throwable {
1113         // arrange for first server to throw exceptions
1114         testShutdownThreadRun(() -> doThrow(new RuntimeException(EXPECTED)).when(server1).shutdown());
1115
1116         // sleep throws an exception
1117         testShutdownThreadRun(() -> shouldInterrupt = true);
1118     }
1119
1120     /**
1121      * Tests the ShutdownThread.run() method, after setting some option.
1122      *
1123      * @param setOption function that sets an option
1124      * @throws Throwable if an error occurs during setup
1125      */
1126     private void testShutdownThreadRun(RunnableWithEx setOption) throws Throwable {
1127         setUp();
1128         setOption.run();
1129
1130         mgr.configure(properties);
1131         mgr.start();
1132         mgr.shutdown();
1133
1134         assertNotNull(shutdownThread);
1135
1136         shutdownThread.run();
1137
1138         assertTrue(threadSleepMs >= 0);
1139         assertEquals(0, threadExitCode);
1140
1141         verify(server1).shutdown();
1142         verify(server2).shutdown();
1143
1144         verify(clientFactory).destroy();
1145     }
1146
1147     @Test
1148     void testIsAlive() {
1149         mgr.configure(properties);
1150         assertFalse(mgr.isAlive());
1151
1152         mgr.start();
1153         assertTrue(mgr.isAlive());
1154
1155         mgr.stop();
1156         assertFalse(mgr.isAlive());
1157     }
1158
1159     @Test
1160     void testLock() throws Throwable {
1161         // normal success case
1162         testLock(true, () -> {
1163             // arrange for first provider to throw exceptions
1164             when(prov1.beforeLock(mgr)).thenThrow(new RuntimeException(EXPECTED));
1165             when(prov1.afterLock(mgr)).thenThrow(new RuntimeException(EXPECTED));
1166         });
1167
1168         // already locked - shouldn't run anything besides beforeLock()
1169         setUp();
1170         mgr.configure(properties);
1171         mgr.lock();
1172         assertTrue(mgr.lock());
1173         verify(prov1, times(2)).beforeLock(mgr);
1174         verify(prov2, times(2)).beforeLock(mgr);
1175         verify(controller).lock();
1176         verify(controller2).lock();
1177         verify(endpoint).lock();
1178         verify(prov1).afterLock(mgr);
1179         verify(prov2).afterLock(mgr);
1180
1181         // controller fails to lock - still does everything
1182         testLock(false, () -> when(controller.lock()).thenReturn(false));
1183
1184         // controller throws an exception - still does everything
1185         testLock(false, () -> when(controller.lock()).thenThrow(new RuntimeException(EXPECTED)));
1186
1187         // endpoint manager fails to lock - still does everything
1188         testLock(false, () -> when(endpoint.lock()).thenReturn(false));
1189
1190         // lock manager fails to lock - still does everything
1191         testLock(false, () -> when(lockmgr.lock()).thenReturn(false));
1192
1193         // lock manager throws an exception - still does everything
1194         testLock(false, () -> when(lockmgr.lock()).thenThrow(new RuntimeException(EXPECTED)));
1195
1196         // other tests
1197         checkBeforeAfter(
1198             (prov, flag) -> when(prov.beforeLock(mgr)).thenReturn(flag),
1199             (prov, flag) -> when(prov.afterLock(mgr)).thenReturn(flag),
1200             () -> {
1201                 mgr.configure(properties);
1202                 mgr.start();
1203                 assertTrue(mgr.lock());
1204             },
1205             prov -> verify(prov).beforeLock(mgr),
1206             () -> verify(endpoint).lock(),
1207             prov -> verify(prov).afterLock(mgr));
1208     }
1209
1210     /**
1211      * Tests the lock() method, after setting some option.
1212      *
1213      * @param expectedResult what lock() is expected to return
1214      * @param setOption function that sets an option
1215      * @throws Throwable if an error occurs during setup
1216      */
1217     private void testLock(boolean expectedResult, RunnableWithEx setOption) throws Throwable {
1218         setUp();
1219         setOption.run();
1220
1221         mgr.configure(properties);
1222         assertEquals(expectedResult, mgr.lock());
1223
1224         verify(prov1).beforeLock(mgr);
1225         verify(prov2).beforeLock(mgr);
1226
1227         verify(controller).lock();
1228         verify(controller2).lock();
1229
1230         verify(endpoint).lock();
1231
1232         verify(prov1).afterLock(mgr);
1233         verify(prov2).afterLock(mgr);
1234     }
1235
1236     @Test
1237     void testUnlock() throws Throwable {
1238         // normal success case
1239         testUnlock(true, () -> {
1240             // arrange for first provider to throw exceptions
1241             when(prov1.beforeUnlock(mgr)).thenThrow(new RuntimeException(EXPECTED));
1242             when(prov1.afterUnlock(mgr)).thenThrow(new RuntimeException(EXPECTED));
1243         });
1244
1245         // not locked - shouldn't run anything besides beforeUnlock()
1246         setUp();
1247         mgr.configure(properties);
1248         assertTrue(mgr.unlock());
1249         verify(prov1).beforeUnlock(mgr);
1250         verify(prov2).beforeUnlock(mgr);
1251         verify(controller, never()).unlock();
1252         verify(controller2, never()).unlock();
1253         verify(endpoint, never()).unlock();
1254         verify(prov1, never()).afterUnlock(mgr);
1255         verify(prov2, never()).afterUnlock(mgr);
1256
1257         // controller fails to unlock - still does everything
1258         testUnlock(false, () -> when(controller.unlock()).thenReturn(false));
1259
1260         // controller throws an exception - still does everything
1261         testUnlock(false, () -> when(controller.unlock()).thenThrow(new RuntimeException(EXPECTED)));
1262
1263         // endpoint manager fails to unlock - still does everything
1264         testUnlock(false, () -> when(endpoint.unlock()).thenReturn(false));
1265
1266         // lock manager fails to lock - still does everything
1267         testUnlock(false, () -> when(lockmgr.unlock()).thenReturn(false));
1268
1269         // lock manager throws an exception - still does everything
1270         testUnlock(false, () -> when(lockmgr.unlock()).thenThrow(new RuntimeException(EXPECTED)));
1271
1272         // other tests
1273         checkBeforeAfter(
1274             (prov, flag) -> when(prov.beforeUnlock(mgr)).thenReturn(flag),
1275             (prov, flag) -> when(prov.afterUnlock(mgr)).thenReturn(flag),
1276             () -> {
1277                 mgr.configure(properties);
1278                 mgr.lock();
1279                 assertTrue(mgr.unlock());
1280             },
1281             prov -> verify(prov).beforeUnlock(mgr),
1282             () -> verify(endpoint).unlock(),
1283             prov -> verify(prov).afterUnlock(mgr));
1284     }
1285
1286     /**
1287      * Tests the unlock() method, after setting some option.
1288      *
1289      * @param expectedResult what unlock() is expected to return
1290      * @param setOption function that sets an option
1291      * @throws Throwable if an error occurs during setup
1292      */
1293     private void testUnlock(boolean expectedResult, RunnableWithEx setOption) throws Throwable {
1294         setUp();
1295         setOption.run();
1296
1297         mgr.configure(properties);
1298         mgr.lock();
1299         assertEquals(expectedResult, mgr.unlock());
1300
1301         verify(prov1).beforeUnlock(mgr);
1302         verify(prov2).beforeUnlock(mgr);
1303
1304         verify(controller).unlock();
1305         verify(controller2).unlock();
1306
1307         verify(endpoint).unlock();
1308
1309         verify(prov1).afterUnlock(mgr);
1310         verify(prov2).afterUnlock(mgr);
1311     }
1312
1313     @Test
1314     void testIsLocked() {
1315         mgr.configure(properties);
1316         assertFalse(mgr.isLocked());
1317
1318         mgr.lock();
1319         assertTrue(mgr.isLocked());
1320
1321         mgr.unlock();
1322         assertFalse(mgr.isLocked());
1323     }
1324
1325     @Test
1326     void testRemovePolicyControllerString() {
1327         mgr.removePolicyController(MY_NAME);
1328
1329         verify(controllerFactory).destroy(MY_NAME);
1330     }
1331
1332     @Test
1333     void testRemovePolicyControllerPolicyController() {
1334         mgr.removePolicyController(controller);
1335
1336         verify(controllerFactory).destroy(controller);
1337     }
1338
1339     @Test
1340     void testGetPolicyControllers() {
1341         assertEquals(controllers, mgr.getPolicyControllers());
1342     }
1343
1344     @Test
1345     void testGetPolicyControllerIds() {
1346         assertEquals(Arrays.asList(CONTROLLER1, CONTROLLER2), mgr.getPolicyControllerIds());
1347     }
1348
1349     @Test
1350     void testGetProperties() {
1351         properties.setProperty("prop-x", "value-x");
1352         properties.setProperty("prop-y", "value-y");
1353
1354         mgr.configure(properties);
1355         assertEquals(properties, mgr.getProperties());
1356     }
1357
1358     @Test
1359     void testGetSources() {
1360         mgr.configure(properties);
1361         assertEquals(sources, mgr.getSources());
1362     }
1363
1364     @Test
1365     void testGetSinks() {
1366         mgr.configure(properties);
1367         assertEquals(sinks, mgr.getSinks());
1368     }
1369
1370     @Test
1371     void testGetHttpServers() {
1372         mgr.configure(properties);
1373         assertEquals(servers, mgr.getHttpServers());
1374     }
1375
1376     @Test
1377     void testGetFeatures() {
1378         assertEquals(Arrays.asList(FEATURE1, FEATURE2), mgr.getFeatures());
1379     }
1380
1381     @Test
1382     void testGetFeatureProviders() {
1383         assertEquals(providers, mgr.getFeatureProviders());
1384     }
1385
1386     @Test
1387     void testGetFeatureProvider() {
1388         assertEquals(prov1, mgr.getFeatureProvider(FEATURE1));
1389         assertEquals(prov2, mgr.getFeatureProvider(FEATURE2));
1390
1391         // null feature
1392         assertThatIllegalArgumentException().isThrownBy(() -> mgr.getFeatureProvider(null));
1393
1394         // empty feature
1395         assertThatIllegalArgumentException().isThrownBy(() -> mgr.getFeatureProvider(""));
1396
1397         // unknown feature
1398         assertThatIllegalArgumentException().isThrownBy(() -> mgr.getFeatureProvider("unknown-feature"));
1399     }
1400
1401     @Test
1402     void testTransaction() {
1403         mgr.metric(CONTROLLER1, POLICY, new Metric());
1404         assertEquals(0, mgr.getStats().getGroupStat().getPolicyExecutedCount());
1405         assertEquals(0, mgr.getStats().getSubgroupStats().size());
1406
1407         Metric metric = new Metric();
1408         mgr.transaction(CONTROLLER1, CONTROLLOOP, metric);
1409         assertEquals(1, mgr.getStats().getGroupStat().getPolicyExecutedCount());
1410         assertEquals(1, mgr.getStats().getSubgroupStats().size());
1411         assertEquals(1, mgr.getStats().getSubgroupStats().get(CONTROLLOOP).getPolicyExecutedFailCount());
1412
1413         Summary.Child.Value summary =
1414                 PolicyEngineManagerImpl.transLatencySecsSummary
1415                         .labels(CONTROLLER1, CONTROLLOOP, POLICY, PdpResponseStatus.FAIL.name()).get();
1416
1417         assertEquals(0, summary.count, 0.0);
1418         assertEquals(0, summary.sum, 0.0);
1419
1420         metric.setServiceInstanceId(POLICY);
1421         metric.setElapsedTime(5000L);
1422         metric.setSuccess(false);
1423         mgr.transaction(CONTROLLER1, CONTROLLOOP, metric);
1424
1425         summary =
1426                 PolicyEngineManagerImpl.transLatencySecsSummary
1427                         .labels(CONTROLLER1, CONTROLLOOP, POLICY, PdpResponseStatus.FAIL.name()).get();
1428
1429         assertEquals(1, summary.count, 0.0);
1430         assertEquals(5, summary.sum, 0.0);
1431     }
1432
1433     @Test
1434     void testOnTopicEvent() {
1435         mgr.onTopicEvent(CommInfrastructure.NOOP, MY_TOPIC, pdpConfigJson);
1436
1437         verify(controllerFactory).patch(controller3, drools3);
1438         verify(controllerFactory).patch(controller4, drools4);
1439
1440         // null json - no additional patches
1441         mgr.onTopicEvent(CommInfrastructure.NOOP, MY_TOPIC, null);
1442
1443         verify(controllerFactory).patch(controller3, drools3);
1444         verify(controllerFactory).patch(controller4, drools4);
1445     }
1446
1447     @Test
1448     void testDeliverStringObject() throws Exception {
1449         mgr.configure(properties);
1450         mgr.start();
1451
1452         assertTrue(mgr.deliver(MY_TOPIC, MY_EVENT));
1453
1454         verify(sink1).send(MESSAGE);
1455
1456         // invalid parameters
1457         String nullStr = null;
1458         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(nullStr, MY_EVENT));
1459         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver("", MY_EVENT));
1460
1461         Object nullObj = null;
1462         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(MY_TOPIC, nullObj));
1463
1464         // locked
1465         mgr.lock();
1466         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(MY_TOPIC, MY_EVENT));
1467         mgr.unlock();
1468
1469         // not running
1470         mgr.stop();
1471         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(MY_TOPIC, MY_EVENT));
1472
1473         // issues with topic
1474         setUp();
1475         mgr.configure(properties);
1476         mgr.start();
1477
1478         // null sinks
1479         when(endpoint.getTopicSinks(MY_TOPIC)).thenReturn(null);
1480         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(MY_TOPIC, MY_EVENT));
1481
1482         // empty sinks
1483         when(endpoint.getTopicSinks(MY_TOPIC)).thenReturn(Collections.emptyList());
1484         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(MY_TOPIC, MY_EVENT));
1485
1486         // too many sinks
1487         when(endpoint.getTopicSinks(MY_TOPIC)).thenReturn(sinks);
1488         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(MY_TOPIC, MY_EVENT));
1489     }
1490
1491     @Test
1492     void testDeliverStringStringObject() {
1493         mgr.configure(properties);
1494         mgr.start();
1495
1496         assertTrue(mgr.deliver(NOOP_STR, MY_TOPIC, MY_EVENT));
1497
1498         verify(sink1).send(MESSAGE);
1499
1500         // invalid parameters
1501         String nullStr = null;
1502         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(nullStr, MY_TOPIC, MY_EVENT));
1503         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver("", MY_TOPIC, MY_EVENT));
1504         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver("unknown-bus-type", MY_TOPIC, MY_EVENT));
1505
1506         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(NOOP_STR, nullStr, MY_EVENT));
1507         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(NOOP_STR, "", MY_EVENT));
1508
1509         Object nullObj = null;
1510         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(NOOP_STR, MY_TOPIC, nullObj));
1511
1512         // locked
1513         mgr.lock();
1514         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(NOOP_STR, MY_TOPIC, MY_EVENT));
1515         mgr.unlock();
1516
1517         // not running
1518         mgr.stop();
1519         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(NOOP_STR, MY_TOPIC, MY_EVENT));
1520     }
1521
1522     @Test
1523     void testDeliverCommInfrastructureStringObject() throws Exception {
1524         mgr.configure(properties);
1525         mgr.start();
1526
1527         assertTrue(mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT));
1528
1529         verify(controller, never()).deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT);
1530
1531         verify(coder).encode(MY_TOPIC, MY_EVENT);
1532         verify(sink1).send(MESSAGE);
1533
1534         // invalid parameters
1535         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, null, MY_EVENT));
1536         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, "", MY_EVENT));
1537
1538         Object nullObj = null;
1539         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, nullObj));
1540
1541         // locked
1542         mgr.lock();
1543         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT));
1544         mgr.unlock();
1545
1546         // not started
1547         mgr.stop();
1548         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT));
1549
1550         // send() throws an exception
1551         setUp();
1552         mgr.configure(properties);
1553         mgr.start();
1554         when(sink1.send(any())).thenThrow(new ArithmeticException(EXPECTED));
1555         assertThatThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT))
1556                         .isInstanceOf(ArithmeticException.class);
1557
1558         /*
1559          * For remaining tests, have the controller handle delivery.
1560          */
1561         setUp();
1562         mgr.configure(properties);
1563         mgr.start();
1564         DroolsController drools = mock(DroolsController.class);
1565         when(coder.getDroolsController(MY_TOPIC, MY_EVENT)).thenReturn(drools);
1566         when(controllerFactory.get(drools)).thenReturn(controller);
1567         when(controller.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT)).thenReturn(true);
1568
1569         assertTrue(mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT));
1570
1571         verify(controller).deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT);
1572
1573         verify(coder, never()).encode(MY_TOPIC, MY_EVENT);
1574         verify(sink1, never()).send(MESSAGE);
1575
1576         // controller throws exception, so should drop into regular handling
1577         when(controller.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT)).thenThrow(new RuntimeException(EXPECTED));
1578
1579         assertTrue(mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT));
1580
1581         // should have attempted this again
1582         verify(controller, times(2)).deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT);
1583
1584         // now these should have been called
1585         verify(coder).encode(MY_TOPIC, MY_EVENT);
1586         verify(sink1).send(MESSAGE);
1587     }
1588
1589     @Test
1590     void testDeliverCommInfrastructureStringString() {
1591         mgr.configure(properties);
1592
1593         // not started yet
1594         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MESSAGE));
1595
1596         // start it
1597         mgr.start();
1598
1599         assertTrue(mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MESSAGE));
1600         verify(sink1).send(MESSAGE);
1601         verify(sink2, never()).send(any());
1602
1603         // invalid parameters
1604         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, null, MESSAGE));
1605         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, "", MESSAGE));
1606
1607         String nullStr = null;
1608         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, nullStr));
1609         assertThatIllegalArgumentException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, ""));
1610
1611         // unknown topic
1612         assertThatIllegalStateException()
1613                         .isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, "unknown-topic", MESSAGE));
1614
1615         // locked
1616         mgr.lock();
1617         assertThatIllegalStateException().isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MESSAGE));
1618         mgr.unlock();
1619     }
1620
1621     @Test
1622     void testActivate() throws Throwable {
1623         // normal success case
1624         testActivate(() -> {
1625             // arrange for first provider and controller to throw exceptions
1626             when(prov1.beforeActivate(mgr)).thenThrow(new RuntimeException(EXPECTED));
1627             when(prov1.afterActivate(mgr)).thenThrow(new RuntimeException(EXPECTED));
1628             when(controller.start()).thenThrow(new RuntimeException(EXPECTED));
1629         });
1630
1631         // controller generates linkage error
1632         testActivate(() -> when(controller.start()).thenThrow(new LinkageError(EXPECTED)));
1633
1634         // other tests
1635         checkBeforeAfter(
1636             (prov, flag) -> when(prov.beforeActivate(mgr)).thenReturn(flag),
1637             (prov, flag) -> when(prov.afterActivate(mgr)).thenReturn(flag),
1638             () -> {
1639                 mgr.configure(properties);
1640                 mgr.lock();
1641                 mgr.activate();
1642             },
1643             prov -> verify(prov).beforeActivate(mgr),
1644             () -> assertFalse(mgr.isLocked()),
1645             prov -> verify(prov).afterActivate(mgr));
1646     }
1647
1648     /**
1649      * Tests the activate() method, after setting some option.
1650      *
1651      * @param setOption function that sets an option
1652      * @throws Throwable if an error occurs during setup
1653      */
1654     private void testActivate(RunnableWithEx setOption) throws Throwable {
1655         setUp();
1656         setOption.run();
1657
1658         mgr.configure(properties);
1659         mgr.lock();
1660         mgr.activate();
1661
1662         verify(prov1).beforeActivate(mgr);
1663         verify(prov2).beforeActivate(mgr);
1664
1665         // unlocked by activate() AND by unlock() (which is invoked by activate())
1666         verify(controller, times(2)).unlock();
1667         verify(controller2, times(2)).unlock();
1668
1669         verify(controller).start();
1670         verify(controller2).start();
1671
1672         assertFalse(mgr.isLocked());
1673
1674         verify(prov1).afterActivate(mgr);
1675         verify(prov2).afterActivate(mgr);
1676     }
1677
1678     @Test
1679     void testDeactivate() throws Throwable {
1680         // normal success case
1681         testDeactivate(() -> {
1682             // arrange for first provider and controller to throw exceptions
1683             when(prov1.beforeDeactivate(mgr)).thenThrow(new RuntimeException(EXPECTED));
1684             when(prov1.afterDeactivate(mgr)).thenThrow(new RuntimeException(EXPECTED));
1685             when(controller.stop()).thenThrow(new RuntimeException(EXPECTED));
1686         });
1687
1688         // controller generates linkage error
1689         testDeactivate(() -> when(controller.stop()).thenThrow(new LinkageError(EXPECTED)));
1690
1691         // other tests
1692         checkBeforeAfter(
1693             (prov, flag) -> when(prov.beforeDeactivate(mgr)).thenReturn(flag),
1694             (prov, flag) -> when(prov.afterDeactivate(mgr)).thenReturn(flag),
1695             () -> {
1696                 mgr.configure(properties);
1697                 mgr.deactivate();
1698             },
1699             prov -> verify(prov).beforeDeactivate(mgr),
1700             () -> assertTrue(mgr.isLocked()),
1701             prov -> verify(prov).afterDeactivate(mgr));
1702     }
1703
1704     /**
1705      * Tests the deactivate() method, after setting some option.
1706      *
1707      * @param setOption function that sets an option
1708      * @throws Throwable if an error occurs during setup
1709      */
1710     private void testDeactivate(RunnableWithEx setOption) throws Throwable {
1711         setUp();
1712         setOption.run();
1713
1714         mgr.configure(properties);
1715         mgr.deactivate();
1716
1717         verify(prov1).beforeDeactivate(mgr);
1718         verify(prov2).beforeDeactivate(mgr);
1719
1720         verify(controller).lock();
1721         verify(controller2).lock();
1722
1723         verify(controller).stop();
1724         verify(controller2).stop();
1725
1726         assertTrue(mgr.isLocked());
1727
1728         verify(prov1).afterDeactivate(mgr);
1729         verify(prov2).afterDeactivate(mgr);
1730     }
1731
1732     @Test
1733     void testCreateLock() {
1734         Lock lock = mock(Lock.class);
1735         LockCallback callback = mock(LockCallback.class);
1736         when(lockmgr.createLock(MY_RESOURCE, MY_OWNER, 10, callback, false)).thenReturn(lock);
1737
1738         // not configured yet, thus no lock manager
1739         assertThatIllegalStateException()
1740                         .isThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, 10, callback, false));
1741
1742         // now configure it and try again
1743         mgr.configure(properties);
1744         assertSame(lock, mgr.createLock(MY_RESOURCE, MY_OWNER, 10, callback, false));
1745
1746         // test illegal args
1747         assertThatThrownBy(() -> mgr.createLock(null, MY_OWNER, 10, callback, false))
1748                         .hasMessageContaining("resourceId");
1749         assertThatThrownBy(() -> mgr.createLock(MY_RESOURCE, null, 10, callback, false))
1750                         .hasMessageContaining("ownerKey");
1751         assertThatIllegalArgumentException()
1752                         .isThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, -1, callback, false))
1753                         .withMessageContaining("holdSec");
1754         assertThatThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, 10, null, false))
1755                         .hasMessageContaining("callback");
1756     }
1757
1758     @Test
1759     void testOpen() throws Throwable {
1760         when(prov1.beforeOpen(mgr)).thenThrow(new RuntimeException(EXPECTED));
1761         when(prov1.afterOpen(mgr)).thenThrow(new RuntimeException(EXPECTED));
1762
1763         assertTrue(mgr.lock());
1764         assertThatIllegalStateException().isThrownBy(() -> mgr.open());
1765         unsuccessfulOpen();
1766
1767         assertTrue(mgr.unlock());
1768         unsuccessfulOpen();
1769
1770         setUp();
1771         mgr.configure(properties);
1772         assertTrue(mgr.start());
1773
1774         verify(source1, never()).start();
1775         verify(source2, never()).start();
1776
1777         assertTrue(mgr.open());
1778
1779         verify(prov1).beforeOpen(mgr);
1780         verify(prov2).beforeOpen(mgr);
1781
1782         verify(source1).start();
1783         verify(source2).start();
1784
1785         verify(prov1).afterOpen(mgr);
1786         verify(prov2).afterOpen(mgr);
1787
1788         when(source1.start()).thenReturn(false);
1789         assertFalse(mgr.open());
1790         when(source1.start()).thenReturn(true);
1791
1792         when(sink1.start()).thenReturn(false);
1793         assertFalse(mgr.open());
1794         when(sink1.start()).thenReturn(true);
1795
1796         assertTrue(mgr.open());
1797     }
1798
1799     private void unsuccessfulOpen() {
1800         verify(prov1).beforeOpen(mgr);
1801         verify(prov2).beforeOpen(mgr);
1802
1803         verify(prov1, never()).afterOpen(mgr);
1804         verify(prov2, never()).afterOpen(mgr);
1805
1806         verify(source1, never()).start();
1807         verify(source2, never()).start();
1808
1809         verify(sink1, never()).start();
1810         verify(sink2, never()).start();
1811     }
1812
1813     @Test
1814     void testControllerConfig() throws Exception {
1815         mgr.configure(properties);
1816         assertTrue(mgr.configure(pdpConfig));
1817
1818         verify(controllerFactory).patch(controller3, drools3);
1819         verify(controllerFactory).patch(controller4, drools4);
1820
1821         // empty controllers
1822         pdpConfig.getControllers().clear();
1823         assertFalse(mgr.configure(pdpConfig));
1824
1825         // null controllers
1826         pdpConfig.setControllers(null);
1827         assertFalse(mgr.configure(pdpConfig));
1828
1829         // arrange for controller3 to fail
1830         setUp();
1831         config3.setOperation("fail-3");
1832         assertFalse(mgr.configure(pdpConfig));
1833
1834         verify(controllerFactory, never()).patch(controller3, drools3);
1835         verify(controllerFactory).patch(controller4, drools4);
1836
1837         // arrange for both controllers to fail
1838         setUp();
1839         config3.setOperation("fail-3");
1840         config4.setOperation("fail-4");
1841         assertFalse(mgr.configure(pdpConfig));
1842     }
1843
1844     @Test
1845     void testToString() {
1846         assertTrue(mgr.toString().startsWith("PolicyEngineManager("));
1847     }
1848
1849     /**
1850      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries
1851      * combinations where beforeXxx and afterXxx return {@code true} and {@code false}.
1852      *
1853      * @param setBefore function to set the return value of a provider's beforeXxx method
1854      * @param setAfter function to set the return value of a provider's afterXxx method
1855      * @param action invokes the operation
1856      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
1857      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
1858      *        and the afterXxx loop was invoked
1859      * @param verifyAfter verifies that a provider's afterXxx method was invoked
1860      * @throws Exception if an error occurs while calling {@link #setUp()}
1861      */
1862     private void checkBeforeAfter(BiConsumer<PolicyEngineFeatureApi, Boolean> setBefore,
1863                     BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action,
1864                     Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle,
1865                     Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception {
1866
1867         checkBeforeAfter_FalseFalse(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
1868         checkBeforeAfter_FalseTrue(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
1869         checkBeforeAfter_TrueFalse(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter);
1870
1871         // don't need to test true-true, as it's behavior is a subset of true-false
1872     }
1873
1874     /**
1875      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
1876      * case where both the beforeXxx and afterXxx methods return {@code false}.
1877      *
1878      * @param setBefore function to set the return value of a provider's beforeXxx method
1879      * @param setAfter function to set the return value of a provider's afterXxx method
1880      * @param action invokes the operation
1881      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
1882      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
1883      *        and the afterXxx loop was invoked
1884      * @param verifyAfter verifies that a provider's afterXxx method was invoked
1885      * @throws Exception if an error occurs while calling {@link #setUp()}
1886      */
1887     private void checkBeforeAfter_FalseFalse(BiConsumer<PolicyEngineFeatureApi, Boolean> setBefore,
1888                     BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action,
1889                     Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle,
1890                     Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception {
1891
1892         setUp();
1893
1894         // configure for the test
1895         setBefore.accept(prov1, false);
1896         setBefore.accept(prov2, false);
1897
1898         setAfter.accept(prov1, false);
1899         setAfter.accept(prov2, false);
1900
1901         // run the action
1902         action.run();
1903
1904         // verify that various methods were invoked
1905         verifyBefore.accept(prov1);
1906         verifyBefore.accept(prov2);
1907
1908         verifyMiddle.run();
1909
1910         verifyAfter.accept(prov1);
1911         verifyAfter.accept(prov2);
1912     }
1913
1914     /**
1915      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
1916      * case where the first provider's afterXxx returns {@code true}, while the others
1917      * return {@code false}.
1918      *
1919      * @param setBefore function to set the return value of a provider's beforeXxx method
1920      * @param setAfter function to set the return value of a provider's afterXxx method
1921      * @param action invokes the operation
1922      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
1923      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
1924      *        and the afterXxx loop was invoked
1925      * @param verifyAfter verifies that a provider's afterXxx method was invoked
1926      * @throws Exception if an error occurs while calling {@link #setUp()}
1927      */
1928     private void checkBeforeAfter_FalseTrue(BiConsumer<PolicyEngineFeatureApi, Boolean> setBefore,
1929                     BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action,
1930                     Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle,
1931                     Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception {
1932
1933         setUp();
1934
1935         // configure for the test
1936         setBefore.accept(prov1, false);
1937         setBefore.accept(prov2, false);
1938
1939         setAfter.accept(prov1, true);
1940         setAfter.accept(prov2, false);
1941
1942         // run the action
1943         action.run();
1944
1945         // verify that various methods were invoked
1946         verifyBefore.accept(prov1);
1947         verifyBefore.accept(prov2);
1948
1949         verifyMiddle.run();
1950
1951         verifyAfter.accept(prov1);
1952         assertThatThrownBy(() -> verifyAfter.accept(prov2)).isInstanceOf(AssertionError.class);
1953     }
1954
1955     /**
1956      * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the
1957      * case where the first provider's beforeXxx returns {@code true}, while the others
1958      * return {@code false}.
1959      *
1960      * @param setBefore function to set the return value of a provider's beforeXxx method
1961      * @param setAfter function to set the return value of a provider's afterXxx method
1962      * @param action invokes the operation
1963      * @param verifyBefore verifies that a provider's beforeXxx method was invoked
1964      * @param verifyMiddle verifies that the action occurring between the beforeXxx loop
1965      *        and the afterXxx loop was invoked
1966      * @param verifyAfter verifies that a provider's afterXxx method was invoked
1967      * @throws Exception if an error occurs while calling {@link #setUp()}
1968      */
1969     private void checkBeforeAfter_TrueFalse(BiConsumer<PolicyEngineFeatureApi, Boolean> setBefore,
1970                     BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action,
1971                     Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle,
1972                     Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception {
1973
1974         setUp();
1975
1976         // configure for the test
1977         setBefore.accept(prov1, true);
1978         setBefore.accept(prov2, false);
1979
1980         setAfter.accept(prov1, false);
1981         setAfter.accept(prov2, false);
1982
1983         // run the action
1984         action.run();
1985
1986         // verify that various methods were invoked
1987         verifyBefore.accept(prov1);
1988
1989         // remaining methods should not have been invoked
1990         assertThatThrownBy(() -> verifyBefore.accept(prov2)).isInstanceOf(AssertionError.class);
1991
1992         assertThatThrownBy(verifyMiddle::run).isInstanceOf(AssertionError.class);
1993
1994         assertThatThrownBy(() -> verifyAfter.accept(prov1)).isInstanceOf(AssertionError.class);
1995         assertThatThrownBy(() -> verifyAfter.accept(prov2)).isInstanceOf(AssertionError.class);
1996     }
1997
1998     private void verifyNeverCalled() {
1999         verify(controller, never()).stop();
2000         verify(source1, never()).stop();
2001         verify(sink1, never()).stop();
2002         verify(endpoint, never()).stop();
2003         verify(server1, never()).stop();
2004         verify(client1, never()).stop();
2005         verify(prov1, never()).afterStop(mgr);
2006         verify(prov2, never()).afterStop(mgr);
2007     }
2008
2009     /**
2010      * Manager with overrides.
2011      */
2012     private class PolicyEngineManagerImpl extends PolicyEngineManager {
2013
2014         @Override
2015         protected List<PolicyEngineFeatureApi> getEngineProviders() {
2016             return providers;
2017         }
2018
2019         @Override
2020         protected List<PolicyControllerFeatureApi> getControllerProviders() {
2021             return contProviders;
2022         }
2023
2024         @Override
2025         protected void globalInitContainer(String[] cliArgs) {
2026             globalInitArgs = cliArgs;
2027         }
2028
2029         @Override
2030         protected TopicEndpoint getTopicEndpointManager() {
2031             return endpoint;
2032         }
2033
2034         @Override
2035         protected HttpServletServerFactory getServletFactory() {
2036             return serverFactory;
2037         }
2038
2039         @Override
2040         protected HttpClientFactory getHttpClientFactory() {
2041             return clientFactory;
2042         }
2043
2044         @Override
2045         protected PolicyControllerFactory getControllerFactory() {
2046             return controllerFactory;
2047         }
2048
2049         @Override
2050         protected void startPdpJmxListener() {
2051             jmxStarted = true;
2052         }
2053
2054         @Override
2055         protected void stopPdpJmxListener() {
2056             jmxStopped = true;
2057         }
2058
2059         @Override
2060         protected Thread makeShutdownThread() {
2061             shutdownThread = new MyShutdown();
2062             return shutdownThread;
2063         }
2064
2065         @Override
2066         protected EventProtocolCoder getProtocolCoder() {
2067             return coder;
2068         }
2069
2070         @Override
2071         protected SystemPersistence getPersistenceManager() {
2072             return persist;
2073         }
2074
2075         @Override
2076         protected PolicyEngine getPolicyEngine() {
2077             return engine;
2078         }
2079
2080         @Override
2081         protected ScheduledExecutorService makeScheduledExecutor(int nthreads) {
2082             return exsvc;
2083         }
2084
2085         @Override
2086         public PolicyStatsManager getStats() {
2087             return statsManager;
2088         }
2089
2090         /**
2091          * Shutdown thread with overrides.
2092          */
2093         private class MyShutdown extends ShutdownThread {
2094
2095             @Override
2096             protected void doSleep() throws InterruptedException {
2097                 threadSleepMs = 300L;
2098
2099                 if (shouldInterrupt) {
2100                     throw new InterruptedException(EXPECTED);
2101                 }
2102             }
2103
2104             @Override
2105             protected void doExit() {
2106                 threadExitCode = 0;
2107             }
2108
2109             @Override
2110             public synchronized void start() {
2111                 threadStarted = true;
2112             }
2113
2114             @Override
2115             public void interrupt() {
2116                 threadInterrupted = true;
2117             }
2118         }
2119     }
2120
2121     @FunctionalInterface
2122     private interface RunnableWithEx {
2123         void run() throws Exception;
2124     }
2125 }