2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2020, 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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 package org.onap.policy.drools.pooling;
24 import static org.junit.jupiter.api.Assertions.assertEquals;
25 import static org.junit.jupiter.api.Assertions.assertFalse;
26 import static org.junit.jupiter.api.Assertions.assertNotEquals;
27 import static org.junit.jupiter.api.Assertions.assertNotNull;
28 import static org.junit.jupiter.api.Assertions.assertThrows;
29 import static org.junit.jupiter.api.Assertions.assertTrue;
30 import static org.mockito.ArgumentMatchers.any;
31 import static org.mockito.Mockito.doThrow;
32 import static org.mockito.Mockito.mock;
33 import static org.mockito.Mockito.never;
34 import static org.mockito.Mockito.times;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.when;
38 import java.util.Collections;
39 import java.util.LinkedList;
40 import java.util.List;
41 import java.util.Properties;
42 import java.util.concurrent.CountDownLatch;
43 import org.apache.commons.lang3.tuple.Pair;
44 import org.junit.jupiter.api.BeforeEach;
45 import org.junit.jupiter.api.Test;
46 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
47 import org.onap.policy.common.endpoints.event.comm.TopicSink;
48 import org.onap.policy.common.endpoints.event.comm.TopicSource;
49 import org.onap.policy.drools.controller.DroolsController;
50 import org.onap.policy.drools.system.PolicyController;
51 import org.onap.policy.drools.system.PolicyEngine;
53 class PoolingFeatureTest {
55 private static final String CONTROLLER1 = "controllerA";
56 private static final String CONTROLLER2 = "controllerB";
57 private static final String CONTROLLER_DISABLED = "controllerDisabled";
58 private static final String CONTROLLER_EX = "controllerException";
59 private static final String CONTROLLER_UNKNOWN = "controllerUnknown";
61 private static final String TOPIC1 = "topic.one";
62 private static final String TOPIC2 = "topic.two";
64 private static final String EVENT1 = "event.one";
65 private static final String EVENT2 = "event.two";
67 private static final Object OBJECT1 = new Object();
68 private static final Object OBJECT2 = new Object();
70 private Properties props;
71 private PolicyEngine engine;
72 private PolicyController controller1;
73 private PolicyController controller2;
74 private PolicyController controllerDisabled;
75 private PolicyController controllerException;
76 private PolicyController controllerUnknown;
77 private DroolsController drools1;
78 private DroolsController drools2;
79 private DroolsController droolsDisabled;
80 private List<Pair<PoolingManagerImpl, PoolingProperties>> managers;
81 private PoolingManagerImpl mgr1;
82 private PoolingManagerImpl mgr2;
84 private PoolingFeature pool;
89 * @throws Exception exception
92 public void setUp() throws Exception {
93 props = initProperties();
94 engine = mock(PolicyEngine.class);
95 controller1 = mock(PolicyController.class);
96 controller2 = mock(PolicyController.class);
97 controllerDisabled = mock(PolicyController.class);
98 controllerException = mock(PolicyController.class);
99 controllerUnknown = mock(PolicyController.class);
100 drools1 = mock(DroolsController.class);
101 drools2 = mock(DroolsController.class);
102 droolsDisabled = mock(DroolsController.class);
103 managers = new LinkedList<>();
105 when(controller1.getName()).thenReturn(CONTROLLER1);
106 when(controller2.getName()).thenReturn(CONTROLLER2);
107 when(controllerDisabled.getName()).thenReturn(CONTROLLER_DISABLED);
108 when(controllerException.getName()).thenReturn(CONTROLLER_EX);
109 when(controllerUnknown.getName()).thenReturn(CONTROLLER_UNKNOWN);
111 pool = new PoolingFeatureImpl();
113 pool.beforeStart(engine);
115 pool.afterCreate(controller1);
116 pool.afterCreate(controller2);
118 mgr1 = managers.get(0).getLeft();
119 mgr2 = managers.get(1).getLeft();
124 assertEquals(2, managers.size());
129 String host = pool.getHost();
132 // create another and ensure it generates another host name
133 pool = new PoolingFeatureImpl();
134 String host2 = pool.getHost();
135 assertNotNull(host2);
137 assertNotEquals(host, host2);
141 void testGetSequenceNumber() {
142 assertEquals(0, pool.getSequenceNumber());
146 void testBeforeStartEngine() {
147 pool = new PoolingFeatureImpl();
149 assertFalse(pool.beforeStart(engine));
153 void testAfterCreate() {
155 pool = new PoolingFeatureImpl();
156 pool.beforeStart(engine);
158 assertFalse(pool.afterCreate(controller1));
159 assertEquals(1, managers.size());
162 assertFalse(pool.afterCreate(controller1));
163 assertEquals(1, managers.size());
166 assertFalse(pool.afterCreate(controller2));
167 assertEquals(2, managers.size());
171 void testAfterCreate_NotEnabled() {
173 pool = new PoolingFeatureImpl();
174 pool.beforeStart(engine);
176 assertFalse(pool.afterCreate(controllerDisabled));
177 assertTrue(managers.isEmpty());
181 void testAfterCreate_PropertyEx() {
183 pool = new PoolingFeatureImpl();
184 pool.beforeStart(engine);
186 assertThrows(PoolingFeatureRtException.class, () -> pool.afterCreate(controllerException));
190 void testAfterCreate_NoProps() {
191 pool = new PoolingFeatureImpl();
193 // did not perform globalInit, which is an error
195 assertThrows(PoolingFeatureRtException.class, () -> pool.afterCreate(controller1));
199 void testAfterCreate_NoFeatProps() {
201 pool = new PoolingFeatureImpl();
202 pool.beforeStart(engine);
204 assertFalse(pool.afterCreate(controllerUnknown));
205 assertTrue(managers.isEmpty());
209 void testBeforeStart() throws Exception {
210 assertFalse(pool.beforeStart(controller1));
211 verify(mgr1).beforeStart();
213 // ensure it's still in the map by re-invoking
214 assertFalse(pool.beforeStart(controller1));
215 verify(mgr1, times(2)).beforeStart();
217 assertFalse(pool.beforeStart(controllerDisabled));
221 void testAfterStart() {
222 assertFalse(pool.afterStart(controller1));
223 verify(mgr1).afterStart();
225 // ensure it's still in the map by re-invoking
226 assertFalse(pool.afterStart(controller1));
227 verify(mgr1, times(2)).afterStart();
229 assertFalse(pool.afterStart(controllerDisabled));
233 void testBeforeStop() {
234 assertFalse(pool.beforeStop(controller1));
235 verify(mgr1).beforeStop();
237 // ensure it's still in the map by re-invoking
238 assertFalse(pool.beforeStop(controller1));
239 verify(mgr1, times(2)).beforeStop();
241 assertFalse(pool.beforeStop(controllerDisabled));
245 void testAfterStop() {
246 assertFalse(pool.afterStop(controller1));
247 verify(mgr1).afterStop();
249 assertFalse(pool.afterStop(controllerDisabled));
251 // count should be unchanged
252 verify(mgr1).afterStop();
256 void testAfterHalt() {
257 assertFalse(pool.afterHalt(controller1));
258 assertFalse(pool.afterHalt(controller1));
260 verify(mgr1, never()).afterStop();
262 assertFalse(pool.afterStop(controllerDisabled));
266 void testAfterShutdown() {
267 assertFalse(pool.afterShutdown(controller1));
268 assertFalse(pool.afterShutdown(controller1));
270 verify(mgr1, never()).afterStop();
272 assertFalse(pool.afterStop(controllerDisabled));
276 void testBeforeLock() {
277 assertFalse(pool.beforeLock(controller1));
278 verify(mgr1).beforeLock();
280 // ensure it's still in the map by re-invoking
281 assertFalse(pool.beforeLock(controller1));
282 verify(mgr1, times(2)).beforeLock();
284 assertFalse(pool.beforeLock(controllerDisabled));
288 void testAfterUnlock() {
289 assertFalse(pool.afterUnlock(controller1));
290 verify(mgr1).afterUnlock();
292 // ensure it's still in the map by re-invoking
293 assertFalse(pool.afterUnlock(controller1));
294 verify(mgr1, times(2)).afterUnlock();
296 assertFalse(pool.afterUnlock(controllerDisabled));
300 void testBeforeOffer() {
301 assertFalse(pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1));
302 verify(mgr1).beforeOffer(TOPIC1, EVENT1);
304 // ensure that the args were captured
305 pool.beforeInsert(drools1, OBJECT1);
306 verify(mgr1).beforeInsert(TOPIC1, OBJECT1);
309 // ensure it's still in the map by re-invoking
310 assertFalse(pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC2, EVENT2));
311 verify(mgr1).beforeOffer(TOPIC2, EVENT2);
313 // ensure that the new args were captured
314 pool.beforeInsert(drools1, OBJECT2);
315 verify(mgr1).beforeInsert(TOPIC2, OBJECT2);
318 assertFalse(pool.beforeOffer(controllerDisabled, CommInfrastructure.UEB, TOPIC1, EVENT1));
322 void testBeforeOffer_NotFound() {
323 assertFalse(pool.beforeOffer(controllerDisabled, CommInfrastructure.UEB, TOPIC1, EVENT1));
327 void testBeforeOffer_MgrTrue() {
329 // manager will return true
330 when(mgr1.beforeOffer(any(), any())).thenReturn(true);
332 assertTrue(pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1));
333 verify(mgr1).beforeOffer(TOPIC1, EVENT1);
335 // ensure it's still in the map by re-invoking
336 assertTrue(pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC2, EVENT2));
337 verify(mgr1).beforeOffer(TOPIC2, EVENT2);
339 assertFalse(pool.beforeOffer(controllerDisabled, CommInfrastructure.UEB, TOPIC1, EVENT1));
343 void testBeforeInsert() {
344 pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1);
345 assertFalse(pool.beforeInsert(drools1, OBJECT1));
346 verify(mgr1).beforeInsert(TOPIC1, OBJECT1);
348 // ensure it's still in the map by re-invoking
349 pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC2, EVENT2);
350 assertFalse(pool.beforeInsert(drools1, OBJECT2));
351 verify(mgr1).beforeInsert(TOPIC2, OBJECT2);
353 pool.beforeOffer(controllerDisabled, CommInfrastructure.UEB, TOPIC2, EVENT2);
354 assertFalse(pool.beforeInsert(droolsDisabled, OBJECT1));
358 void testBeforeInsert_NoArgs() {
360 // call beforeInsert without beforeOffer
361 assertFalse(pool.beforeInsert(drools1, OBJECT1));
362 verify(mgr1, never()).beforeInsert(any(), any());
364 assertFalse(pool.beforeInsert(droolsDisabled, OBJECT1));
365 verify(mgr1, never()).beforeInsert(any(), any());
369 void testBeforeInsert_ArgEx() {
370 // generate exception
371 pool = new PoolingFeatureImpl() {
373 protected PolicyController getController(DroolsController droolsController) {
374 throw new IllegalArgumentException();
378 pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1);
379 assertFalse(pool.beforeInsert(drools1, OBJECT1));
380 verify(mgr1, never()).beforeInsert(any(), any());
384 void testBeforeInsert_StateEx() {
385 // generate exception
386 pool = new PoolingFeatureImpl() {
388 protected PolicyController getController(DroolsController droolsController) {
389 throw new IllegalStateException();
393 pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1);
394 assertFalse(pool.beforeInsert(drools1, OBJECT1));
395 verify(mgr1, never()).beforeInsert(any(), any());
399 void testBeforeInsert_NullController() {
401 // return null controller
402 pool = new PoolingFeatureImpl() {
404 protected PolicyController getController(DroolsController droolsController) {
409 pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1);
410 assertFalse(pool.beforeInsert(drools1, OBJECT1));
411 verify(mgr1, never()).beforeInsert(any(), any());
415 void testBeforeInsert_NotFound() {
417 pool.beforeOffer(controllerDisabled, CommInfrastructure.UEB, TOPIC2, EVENT2);
418 assertFalse(pool.beforeInsert(droolsDisabled, OBJECT1));
422 void testAfterOffer() {
423 // this will create OfferArgs
424 pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1);
426 // this should clear them
427 assertFalse(pool.afterOffer(controller1, CommInfrastructure.UEB, TOPIC2, EVENT2, true));
429 assertFalse(pool.beforeInsert(drools1, OBJECT1));
430 verify(mgr1, never()).beforeInsert(any(), any());
433 assertFalse(pool.beforeInsert(droolsDisabled, OBJECT1));
437 void testDoManager() {
438 assertFalse(pool.beforeStart(controller1));
439 verify(mgr1).beforeStart();
441 // ensure it's still in the map by re-invoking
442 assertFalse(pool.beforeStart(controller1));
443 verify(mgr1, times(2)).beforeStart();
446 // different controller
447 assertFalse(pool.beforeStart(controller2));
448 verify(mgr2).beforeStart();
450 // ensure it's still in the map by re-invoking
451 assertFalse(pool.beforeStart(controller2));
452 verify(mgr2, times(2)).beforeStart();
455 assertFalse(pool.beforeStart(controllerDisabled));
459 void testDoManager_NotFound() {
460 assertFalse(pool.beforeStart(controllerDisabled));
464 void testDoManager_Ex() {
466 // generate exception
467 doThrow(new RuntimeException()).when(mgr1).beforeStart();
469 assertThrows(RuntimeException.class, () -> pool.beforeStart(controller1));
472 private Properties initProperties() {
473 Properties props = new Properties();
475 initProperties(props, "A", 0);
476 initProperties(props, "B", 1);
477 initProperties(props, "Exception", 2);
479 props.setProperty("pooling.controllerDisabled.enabled", "false");
481 props.setProperty("pooling.controllerException.offline.queue.limit", "INVALID NUMBER");
486 private void initProperties(Properties props, String suffix, int offset) {
487 props.setProperty("pooling.controller" + suffix + ".topic", "topic." + suffix);
488 props.setProperty("pooling.controller" + suffix + ".enabled", "true");
489 props.setProperty("pooling.controller" + suffix + ".offline.queue.limit", String.valueOf(5 + offset));
490 props.setProperty("pooling.controller" + suffix + ".offline.queue.age.milliseconds",
491 String.valueOf(100 + offset));
492 props.setProperty("pooling.controller" + suffix + ".start.heartbeat.milliseconds", String.valueOf(10 + offset));
493 props.setProperty("pooling.controller" + suffix + ".reactivate.milliseconds", String.valueOf(20 + offset));
494 props.setProperty("pooling.controller" + suffix + ".identification.milliseconds", String.valueOf(30 + offset));
495 props.setProperty("pooling.controller" + suffix + ".active.heartbeat.milliseconds",
496 String.valueOf(40 + offset));
497 props.setProperty("pooling.controller" + suffix + ".inter.heartbeat.milliseconds", String.valueOf(50 + offset));
501 * Feature with overrides.
503 private class PoolingFeatureImpl extends PoolingFeature {
506 protected Properties getProperties(String featName) {
507 if (PoolingProperties.FEATURE_NAME.equals(featName)) {
510 throw new IllegalArgumentException("unknown feature name");
515 protected PoolingManagerImpl makeManager(String host, PolicyController controller, PoolingProperties props,
516 CountDownLatch activeLatch) {
518 PoolingManagerImpl mgr = mock(PoolingManagerImpl.class);
520 managers.add(Pair.of(mgr, props));
526 protected PolicyController getController(DroolsController droolsController) {
527 if (droolsController == drools1) {
529 } else if (droolsController == drools2) {
531 } else if (droolsController == droolsDisabled) {
532 return controllerDisabled;
534 throw new IllegalArgumentException("unknown drools controller");
539 protected List<TopicSource> initTopicSources(Properties props) {
540 return Collections.emptyList();
544 protected List<TopicSink> initTopicSinks(Properties props) {
545 return Collections.emptyList();