2 * ============LICENSE_START=======================================================
3 * feature-test-transaction
4 * ================================================================================
5 * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 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.testtransaction;
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.assertNotNull;
27 import static org.junit.jupiter.api.Assertions.assertTrue;
28 import static org.mockito.ArgumentMatchers.any;
29 import static org.mockito.ArgumentMatchers.anyBoolean;
30 import static org.mockito.ArgumentMatchers.anyString;
31 import static org.mockito.Mockito.mock;
32 import static org.mockito.Mockito.never;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.verify;
35 import static org.mockito.Mockito.when;
37 import java.util.Arrays;
38 import java.util.Collections;
39 import java.util.EventObject;
40 import java.util.List;
42 import java.util.TreeMap;
43 import java.util.concurrent.atomic.AtomicInteger;
44 import org.junit.jupiter.api.BeforeEach;
45 import org.junit.jupiter.api.Test;
46 import org.onap.policy.drools.controller.DroolsController;
47 import org.onap.policy.drools.core.PolicyContainer;
48 import org.onap.policy.drools.system.PolicyController;
50 class TestTransactionAdditionalTest {
52 private static final int MAX_SLEEP_COUNT = 3;
53 private static final String EXPECTED = "expected exception";
54 private static final String CONTROLLER1 = "controller-a";
55 private static final String CONTROLLER2 = "controller-b";
56 private static final String CONTROLLER3 = "controller-c";
57 private static final String SESSION1 = "session-a";
58 private static final String SESSION2 = "session-b";
59 private static final List<String> sessions = Arrays.asList(SESSION1, SESSION2);
60 private static final List<Object> facts = List.of(0L);
62 private Thread theThread;
63 private PolicyController controller;
64 private PolicyController controller2;
65 private PolicyController controller3;
66 private Runnable theAction;
67 private long waitJoinMs;
68 private long doSleepMs;
69 private DroolsController drools;
70 private PolicyContainer container;
71 private Map<String, TtControllerTask> name2task;
72 private TtControllerTask task;
73 private TtControllerTask task2;
74 private TtControllerTask task3;
75 private TestTransTImplTester impl;
78 * Initialize objects for each test.
82 theThread = mock(Thread.class);
83 controller = mock(PolicyController.class);
84 controller2 = mock(PolicyController.class);
85 controller3 = mock(PolicyController.class);
89 drools = mock(DroolsController.class);
90 container = mock(PolicyContainer.class);
91 task2 = mock(TtControllerTask.class);
92 task3 = mock(TtControllerTask.class);
93 name2task = new TreeMap<>();
95 when(drools.getSessionNames()).thenReturn(sessions);
96 when(drools.isBrained()).thenReturn(true);
97 when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(facts);
98 when(drools.getContainer()).thenReturn(container);
100 when(controller.getName()).thenReturn(CONTROLLER1);
101 when(controller.getDrools()).thenReturn(drools);
102 when(controller.isAlive()).thenReturn(true);
104 when(controller2.getName()).thenReturn(CONTROLLER2);
105 when(controller2.getDrools()).thenReturn(drools);
106 when(controller2.isAlive()).thenReturn(true);
108 when(controller3.getName()).thenReturn(CONTROLLER3);
109 when(controller3.getDrools()).thenReturn(drools);
110 when(controller3.isAlive()).thenReturn(true);
112 task = new TestTransControllerTaskTester(controller);
114 name2task.put(CONTROLLER1, task);
115 name2task.put(CONTROLLER2, task2);
116 name2task.put(CONTROLLER3, task3);
118 impl = new TestTransTImplTester();
122 void testTestTransactionImpl() {
123 assertNotNull(TestTransactionConstants.getManager());
127 void testTestTransactionImplRegister_testTestTransactionImplUnregister() {
128 task = mock(TtControllerTask.class);
129 when(task.isAlive()).thenReturn(true);
130 name2task.put(CONTROLLER1, task);
132 impl.register(controller);
133 impl.register(controller2);
136 impl.register(controller);
138 // re-register when task is not running
140 // give controller3 same name as controller1 -> task3 replaces task
141 when(controller3.getName()).thenReturn(CONTROLLER1);
142 name2task.put(CONTROLLER1, task3);
143 when(task.isAlive()).thenReturn(false);
144 impl.register(controller3);
146 impl.unregister(controller);
147 verify(task, never()).stop();
148 verify(task2, never()).stop();
149 verify(task3).stop();
151 impl.unregister(controller2);
152 verify(task2).stop();
154 // unregister again - stop() should not be called again
155 impl.unregister(controller3);
156 verify(task3).stop();
158 // unregister original controller - no stop() should be called again
159 impl.unregister(controller);
160 verify(task, never()).stop();
161 verify(task2).stop();
162 verify(task3).stop();
166 void testTestTransactionControllerTaskFactory() throws Exception {
167 task = new TtControllerTask(controller) {
169 protected Thread makeThread(Runnable action) {
174 protected void joinThread(long waitTimeMs) {
180 assertEquals(Thread.currentThread(), task.getCurrentThread());
184 void testTestTransactionControllerTask() {
185 assertEquals(task, theAction);
186 assertTrue(task.isAlive());
187 assertEquals(controller, task.getController());
188 assertEquals(theThread, task.getThread());
190 verify(theThread).start();
194 void testTestTransactionControllerTaskGetController() {
195 assertEquals(controller, task.getController());
199 void testTestTransactionControllerTaskGetThread() {
200 assertEquals(theThread, task.getThread());
204 void testTestTransactionControllerTaskStop() {
206 assertFalse(task.isAlive());
207 verify(theThread).interrupt();
208 assertTrue(waitJoinMs > 0);
210 // throw interrupt during join()
212 task = new TestTransControllerTaskTester(controller) {
214 protected void joinThread(long waitTimeMs) throws InterruptedException {
215 waitJoinMs = waitTimeMs;
216 throw new InterruptedException(EXPECTED);
220 assertFalse(task.isAlive());
221 verify(theThread, times(2)).interrupt();
222 assertTrue(waitJoinMs > 0);
226 void testTestTransactionControllerTaskRun() {
228 assertFalse(task.isAlive());
229 verify(theThread, never()).interrupt();
230 verify(controller, times(MAX_SLEEP_COUNT + 1)).isAlive();
231 assertTrue(doSleepMs > 0);
235 when(drools.isBrained()).thenReturn(false);
237 assertFalse(task.isAlive());
238 verify(controller, never()).isAlive();
239 assertEquals(-1, doSleepMs);
241 // controller not running
243 when(controller.isAlive()).thenReturn(false);
245 assertFalse(task.isAlive());
246 assertEquals(-1, doSleepMs);
248 // controller is locked
250 when(controller.isLocked()).thenReturn(true);
252 assertFalse(task.isAlive());
253 assertEquals(-1, doSleepMs);
255 // un-brain during sleep
257 task = new TestTransControllerTaskTester(controller) {
259 protected void doSleep(long sleepMs) throws InterruptedException {
260 when(drools.isBrained()).thenReturn(false);
261 super.doSleep(sleepMs);
265 assertFalse(task.isAlive());
266 // only hit top of the loop twice
267 verify(controller, times(2)).isAlive();
268 assertTrue(doSleepMs > 0);
272 task = new TestTransControllerTaskTester(controller) {
274 protected void doSleep(long sleepMs) throws InterruptedException {
276 super.doSleep(sleepMs);
280 assertFalse(task.isAlive());
281 // only hit top of the loop twice
282 verify(controller, times(2)).isAlive();
283 assertTrue(doSleepMs > 0);
285 // isInterrupted() returns true the first time, interrupt next time
287 AtomicInteger count = new AtomicInteger(1);
288 when(theThread.isInterrupted()).thenAnswer(args -> {
289 if (count.decrementAndGet() >= 0) {
292 throw new InterruptedException(EXPECTED);
296 assertFalse(task.isAlive());
297 verify(controller, times(2)).isAlive();
298 // doSleep() should not be called
299 assertEquals(-1, doSleepMs);
301 // interrupt during sleep
303 task = new TestTransControllerTaskTester(controller) {
305 protected void doSleep(long sleepMs) throws InterruptedException {
306 super.doSleep(sleepMs);
307 throw new InterruptedException(EXPECTED);
311 assertFalse(task.isAlive());
312 verify(theThread).interrupt();
313 // only hit top of the loop once
314 verify(controller).isAlive();
315 assertTrue(doSleepMs > 0);
317 // stop() during factQuery()
319 when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenAnswer(args -> {
324 assertFalse(task.isAlive());
325 // only hit top of the loop once
326 verify(controller).isAlive();
328 // exception during isBrained() check
330 when(drools.isBrained()).thenThrow(new IllegalArgumentException(EXPECTED));
332 assertFalse(task.isAlive());
334 // other exception during isBrained() check
336 when(drools.isBrained()).thenThrow(new RuntimeException(EXPECTED));
338 assertFalse(task.isAlive());
342 void testTestTransactionControllerTaskInjectTxIntoSessions() {
344 verify(container, times(MAX_SLEEP_COUNT * sessions.size())).insert(anyString(), any(EventObject.class));
348 when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(null);
350 verify(container, never()).insert(anyString(), any());
354 when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(Collections.emptyList());
356 verify(container, never()).insert(anyString(), any());
360 void testTestTransactionControllerTaskToString() {
361 assertTrue(task.toString().startsWith("TTControllerTask ["));
365 * TestTransaction with overridden methods.
367 private class TestTransTImplTester extends TtImpl {
370 protected TtControllerTask makeControllerTask(PolicyController controller) {
371 return name2task.get(controller.getName());
376 * Controller task with overridden methods.
378 private class TestTransControllerTaskTester extends TtControllerTask {
379 private int sleepCount = MAX_SLEEP_COUNT;
381 public TestTransControllerTaskTester(PolicyController controller) {
386 protected Thread makeThread(Runnable action) {
392 protected void joinThread(long waitTimeMs) throws InterruptedException {
393 waitJoinMs = waitTimeMs;
397 protected void doSleep(long sleepMs) throws InterruptedException {
400 if (--sleepCount <= 0) {
401 when(controller.isAlive()).thenReturn(false);
406 protected Thread getCurrentThread() {