7c31ba9872dad84701e20bb4e097e28b6824e17f
[policy/drools-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * feature-test-transaction
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.drools.testtransaction;
22
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.mockito.Matchers.any;
28 import static org.mockito.Matchers.anyBoolean;
29 import static org.mockito.Matchers.anyString;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.times;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
35
36 import java.util.Arrays;
37 import java.util.Collections;
38 import java.util.EventObject;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.TreeMap;
42 import java.util.concurrent.atomic.AtomicInteger;
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.onap.policy.drools.controller.DroolsController;
46 import org.onap.policy.drools.core.PolicyContainer;
47 import org.onap.policy.drools.system.PolicyController;
48
49 public class TestTransactionTest2 {
50
51     private static final int MAX_SLEEP_COUNT = 3;
52     private static final String EXPECTED = "expected exception";
53     private static final String CONTROLLER1 = "controller-a";
54     private static final String CONTROLLER2 = "controller-b";
55     private static final String CONTROLLER3 = "controller-c";
56     private static final String SESSION1 = "session-a";
57     private static final String SESSION2 = "session-b";
58     private static final List<String> sessions = Arrays.asList(SESSION1, SESSION2);
59     private static final List<Object> facts = Arrays.asList(0L);
60
61     private Thread theThread;
62     private PolicyController controller;
63     private PolicyController controller2;
64     private PolicyController controller3;
65     private Runnable theAction;
66     private long waitJoinMs;
67     private long doSleepMs;
68     private DroolsController drools;
69     private PolicyContainer container;
70     private Map<String, TTControllerTask> name2task;
71     private TTControllerTask task;
72     private TTControllerTask task2;
73     private TTControllerTask task3;
74     private TestTransTImplTester impl;
75
76     /**
77      * Initialize objects for each test.
78      */
79     @Before
80     public void setUp() {
81         theThread = mock(Thread.class);
82         controller = mock(PolicyController.class);
83         controller2 = mock(PolicyController.class);
84         controller3 = mock(PolicyController.class);
85         theAction = null;
86         waitJoinMs = -1;
87         doSleepMs = -1;
88         drools = mock(DroolsController.class);
89         container = mock(PolicyContainer.class);
90         task2 = mock(TTControllerTask.class);
91         task3 = mock(TTControllerTask.class);
92         name2task = new TreeMap<>();
93
94         when(drools.getSessionNames()).thenReturn(sessions);
95         when(drools.isBrained()).thenReturn(true);
96         when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(facts);
97         when(drools.getContainer()).thenReturn(container);
98
99         when(controller.getName()).thenReturn(CONTROLLER1);
100         when(controller.getDrools()).thenReturn(drools);
101         when(controller.isAlive()).thenReturn(true);
102
103         when(controller2.getName()).thenReturn(CONTROLLER2);
104         when(controller2.getDrools()).thenReturn(drools);
105         when(controller2.isAlive()).thenReturn(true);
106
107         when(controller3.getName()).thenReturn(CONTROLLER3);
108         when(controller3.getDrools()).thenReturn(drools);
109         when(controller3.isAlive()).thenReturn(true);
110
111         task = new TestTransControllerTaskTester(controller);
112
113         name2task.put(CONTROLLER1, task);
114         name2task.put(CONTROLLER2, task2);
115         name2task.put(CONTROLLER3, task3);
116
117         impl = new TestTransTImplTester();
118     }
119
120     @Test
121     public void testTestTransactionImpl() {
122         assertNotNull(TTImpl.manager);
123     }
124
125     @Test
126     public void testTestTransactionImplRegister_testTestTransactionImplUnregister() {
127         task = mock(TTControllerTask.class);
128         when(task.isAlive()).thenReturn(true);
129         name2task.put(CONTROLLER1, task);
130
131         impl.register(controller);
132         impl.register(controller2);
133
134         // re-register
135         impl.register(controller);
136
137         // re-register when task is not running
138
139         // give controller3 same name as controller1 -> task3 replaces task
140         when(controller3.getName()).thenReturn(CONTROLLER1);
141         name2task.put(CONTROLLER1, task3);
142         when(task.isAlive()).thenReturn(false);
143         impl.register(controller3);
144
145         impl.unregister(controller);
146         verify(task, never()).stop();
147         verify(task2, never()).stop();
148         verify(task3).stop();
149
150         impl.unregister(controller2);
151         verify(task2).stop();
152
153         // unregister again - stop() should not be called again
154         impl.unregister(controller3);
155         verify(task3).stop();
156         
157         // unregister original controller - no stop() should be called again
158         impl.unregister(controller);
159         verify(task, never()).stop();
160         verify(task2).stop();
161         verify(task3).stop();
162     }
163
164     @Test
165     public void testTestTransactionControllerTaskFactory() throws Exception {
166         task = new TTControllerTask(controller) {
167             @Override
168             protected Thread makeThread(Runnable action) {
169                 return theThread;
170             }
171
172             @Override
173             protected void joinThread(long waitTimeMs) throws InterruptedException {
174                 // do nothing
175             }
176         };
177
178         task.doSleep(1);
179         assertEquals(Thread.currentThread(), task.getCurrentThread());
180     }
181
182     @Test
183     public void testTestTransactionControllerTask() {
184         assertEquals(task, theAction);
185         assertTrue(task.isAlive());
186         assertEquals(controller, task.getController());
187         assertEquals(theThread, task.getThread());
188
189         verify(theThread).start();
190     }
191
192     @Test
193     public void testTestTransactionControllerTaskGetController() {
194         assertEquals(controller, task.getController());
195     }
196
197     @Test
198     public void testTestTransactionControllerTaskGetThread() {
199         assertEquals(theThread, task.getThread());
200     }
201
202     @Test
203     public void testTestTransactionControllerTaskStop() throws Exception {
204         task.stop();
205         assertFalse(task.isAlive());
206         verify(theThread).interrupt();
207         assertTrue(waitJoinMs > 0);
208
209         // throw interrupt during join()
210         setUp();
211         task = new TestTransControllerTaskTester(controller) {
212             @Override
213             protected void joinThread(long waitTimeMs) throws InterruptedException {
214                 waitJoinMs = waitTimeMs;
215                 throw new InterruptedException(EXPECTED);
216             }
217         };
218         task.stop();
219         assertFalse(task.isAlive());
220         verify(theThread, times(2)).interrupt();
221         assertTrue(waitJoinMs > 0);
222     }
223
224     @Test
225     public void testTestTransactionControllerTaskRun() {
226         task.run();
227         assertFalse(task.isAlive());
228         verify(theThread, never()).interrupt();
229         verify(controller, times(MAX_SLEEP_COUNT + 1)).isAlive();
230         assertTrue(doSleepMs > 0);
231
232         // not brained
233         setUp();
234         when(drools.isBrained()).thenReturn(false);
235         task.run();
236         assertFalse(task.isAlive());
237         verify(controller, never()).isAlive();
238         assertEquals(-1, doSleepMs);
239
240         // controller not running
241         setUp();
242         when(controller.isAlive()).thenReturn(false);
243         task.run();
244         assertFalse(task.isAlive());
245         assertEquals(-1, doSleepMs);
246
247         // controller is locked
248         setUp();
249         when(controller.isLocked()).thenReturn(true);
250         task.run();
251         assertFalse(task.isAlive());
252         assertEquals(-1, doSleepMs);
253
254         // un-brain during sleep
255         setUp();
256         task = new TestTransControllerTaskTester(controller) {
257             @Override
258             protected void doSleep(long sleepMs) throws InterruptedException {
259                 when(drools.isBrained()).thenReturn(false);
260                 super.doSleep(sleepMs);
261             }
262         };
263         task.run();
264         assertFalse(task.isAlive());
265         // only hit top of the loop twice
266         verify(controller, times(2)).isAlive();
267         assertTrue(doSleepMs > 0);
268
269         // stop during sleep
270         setUp();
271         task = new TestTransControllerTaskTester(controller) {
272             @Override
273             protected void doSleep(long sleepMs) throws InterruptedException {
274                 task.stop();
275                 super.doSleep(sleepMs);
276             }
277         };
278         task.run();
279         assertFalse(task.isAlive());
280         // only hit top of the loop twice
281         verify(controller, times(2)).isAlive();
282         assertTrue(doSleepMs > 0);
283
284         // isInterrupted() returns true the first time, interrupt next time
285         setUp();
286         AtomicInteger count = new AtomicInteger(1);
287         when(theThread.isInterrupted()).thenAnswer(args -> {
288             if (count.decrementAndGet() >= 0) {
289                 return true;
290             } else {
291                 throw new InterruptedException(EXPECTED);
292             }
293         });
294         task.run();
295         assertFalse(task.isAlive());
296         verify(controller, times(2)).isAlive();
297         // doSleep() should not be called
298         assertEquals(-1, doSleepMs);
299
300         // interrupt during sleep
301         setUp();
302         task = new TestTransControllerTaskTester(controller) {
303             @Override
304             protected void doSleep(long sleepMs) throws InterruptedException {
305                 super.doSleep(sleepMs);
306                 throw new InterruptedException(EXPECTED);
307             }
308         };
309         task.run();
310         assertFalse(task.isAlive());
311         verify(theThread).interrupt();
312         // only hit top of the loop once
313         verify(controller).isAlive();
314         assertTrue(doSleepMs > 0);
315
316         // stop() during factQuery()
317         setUp();
318         when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenAnswer(args -> {
319             task.stop();
320             return facts;
321         });
322         task.run();
323         assertFalse(task.isAlive());
324         // only hit top of the loop once
325         verify(controller).isAlive();
326
327         // exception during isBrained() check
328         setUp();
329         when(drools.isBrained()).thenThrow(new IllegalArgumentException(EXPECTED));
330         task.run();
331         assertFalse(task.isAlive());
332
333         // other exception during isBrained() check
334         setUp();
335         when(drools.isBrained()).thenThrow(new RuntimeException(EXPECTED));
336         task.run();
337         assertFalse(task.isAlive());
338     }
339
340     @Test
341     public void testTestTransactionControllerTaskInjectTxIntoSessions() {
342         task.run();
343         verify(container, times(MAX_SLEEP_COUNT * sessions.size())).insert(anyString(), any(EventObject.class));
344
345         // null facts
346         setUp();
347         when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(null);
348         task.run();
349         verify(container, never()).insert(anyString(), any());
350
351         // empty fact list
352         setUp();
353         when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(Collections.emptyList());
354         task.run();
355         verify(container, never()).insert(anyString(), any());
356     }
357
358     @Test
359     public void testTestTransactionControllerTaskToString() {
360         assertTrue(task.toString().startsWith("TTControllerTask ["));
361     }
362
363     /**
364      * TestTransaction with overridden methods.
365      */
366     private class TestTransTImplTester extends TTImpl {
367
368         @Override
369         protected TTControllerTask makeControllerTask(PolicyController controller) {
370             return name2task.get(controller.getName());
371         }
372     }
373
374     /**
375      * Controller task with overridden methods.
376      */
377     private class TestTransControllerTaskTester extends TTControllerTask {
378         private int sleepCount = MAX_SLEEP_COUNT;
379
380         public TestTransControllerTaskTester(PolicyController controller) {
381             super(controller);
382         }
383
384         @Override
385         protected Thread makeThread(Runnable action) {
386             theAction = action;
387             return theThread;
388         }
389
390         @Override
391         protected void joinThread(long waitTimeMs) throws InterruptedException {
392             waitJoinMs = waitTimeMs;
393         }
394
395         @Override
396         protected void doSleep(long sleepMs) throws InterruptedException {
397             doSleepMs = sleepMs;
398
399             if (--sleepCount <= 0) {
400                 when(controller.isAlive()).thenReturn(false);
401             }
402         }
403
404         @Override
405         protected Thread getCurrentThread() {
406             return thread;
407         }
408     }
409 }