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
 
  11  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  21 package org.onap.policy.drools.testtransaction;
 
  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;
 
  36 import java.util.Arrays;
 
  37 import java.util.Collections;
 
  38 import java.util.EventObject;
 
  39 import java.util.List;
 
  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;
 
  49 public class TestTransactionTest2 {
 
  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);
 
  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;
 
  77      * Initialize objects for each test.
 
  81         theThread = mock(Thread.class);
 
  82         controller = mock(PolicyController.class);
 
  83         controller2 = mock(PolicyController.class);
 
  84         controller3 = mock(PolicyController.class);
 
  88         drools = mock(DroolsController.class);
 
  89         container = mock(PolicyContainer.class);
 
  90         task2 = mock(TTControllerTask.class);
 
  91         task3 = mock(TTControllerTask.class);
 
  92         name2task = new TreeMap<>();
 
  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);
 
  99         when(controller.getName()).thenReturn(CONTROLLER1);
 
 100         when(controller.getDrools()).thenReturn(drools);
 
 101         when(controller.isAlive()).thenReturn(true);
 
 103         when(controller2.getName()).thenReturn(CONTROLLER2);
 
 104         when(controller2.getDrools()).thenReturn(drools);
 
 105         when(controller2.isAlive()).thenReturn(true);
 
 107         when(controller3.getName()).thenReturn(CONTROLLER3);
 
 108         when(controller3.getDrools()).thenReturn(drools);
 
 109         when(controller3.isAlive()).thenReturn(true);
 
 111         task = new TestTransControllerTaskTester(controller);
 
 113         name2task.put(CONTROLLER1, task);
 
 114         name2task.put(CONTROLLER2, task2);
 
 115         name2task.put(CONTROLLER3, task3);
 
 117         impl = new TestTransTImplTester();
 
 121     public void testTestTransactionImpl() {
 
 122         assertNotNull(TTImpl.manager);
 
 126     public void testTestTransactionImplRegister_testTestTransactionImplUnregister() {
 
 127         task = mock(TTControllerTask.class);
 
 128         when(task.isAlive()).thenReturn(true);
 
 129         name2task.put(CONTROLLER1, task);
 
 131         impl.register(controller);
 
 132         impl.register(controller2);
 
 135         impl.register(controller);
 
 137         // re-register when task is not running
 
 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);
 
 145         impl.unregister(controller);
 
 146         verify(task, never()).stop();
 
 147         verify(task2, never()).stop();
 
 148         verify(task3).stop();
 
 150         impl.unregister(controller2);
 
 151         verify(task2).stop();
 
 153         // unregister again - stop() should not be called again
 
 154         impl.unregister(controller3);
 
 155         verify(task3).stop();
 
 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();
 
 165     public void testTestTransactionControllerTaskFactory() throws Exception {
 
 166         task = new TTControllerTask(controller) {
 
 168             protected Thread makeThread(Runnable action) {
 
 173             protected void joinThread(long waitTimeMs) throws InterruptedException {
 
 179         assertEquals(Thread.currentThread(), task.getCurrentThread());
 
 183     public void testTestTransactionControllerTask() {
 
 184         assertEquals(task, theAction);
 
 185         assertTrue(task.isAlive());
 
 186         assertEquals(controller, task.getController());
 
 187         assertEquals(theThread, task.getThread());
 
 189         verify(theThread).start();
 
 193     public void testTestTransactionControllerTaskGetController() {
 
 194         assertEquals(controller, task.getController());
 
 198     public void testTestTransactionControllerTaskGetThread() {
 
 199         assertEquals(theThread, task.getThread());
 
 203     public void testTestTransactionControllerTaskStop() throws Exception {
 
 205         assertFalse(task.isAlive());
 
 206         verify(theThread).interrupt();
 
 207         assertTrue(waitJoinMs > 0);
 
 209         // throw interrupt during join()
 
 211         task = new TestTransControllerTaskTester(controller) {
 
 213             protected void joinThread(long waitTimeMs) throws InterruptedException {
 
 214                 waitJoinMs = waitTimeMs;
 
 215                 throw new InterruptedException(EXPECTED);
 
 219         assertFalse(task.isAlive());
 
 220         verify(theThread, times(2)).interrupt();
 
 221         assertTrue(waitJoinMs > 0);
 
 225     public void testTestTransactionControllerTaskRun() {
 
 227         assertFalse(task.isAlive());
 
 228         verify(theThread, never()).interrupt();
 
 229         verify(controller, times(MAX_SLEEP_COUNT + 1)).isAlive();
 
 230         assertTrue(doSleepMs > 0);
 
 234         when(drools.isBrained()).thenReturn(false);
 
 236         assertFalse(task.isAlive());
 
 237         verify(controller, never()).isAlive();
 
 238         assertEquals(-1, doSleepMs);
 
 240         // controller not running
 
 242         when(controller.isAlive()).thenReturn(false);
 
 244         assertFalse(task.isAlive());
 
 245         assertEquals(-1, doSleepMs);
 
 247         // controller is locked
 
 249         when(controller.isLocked()).thenReturn(true);
 
 251         assertFalse(task.isAlive());
 
 252         assertEquals(-1, doSleepMs);
 
 254         // un-brain during sleep
 
 256         task = new TestTransControllerTaskTester(controller) {
 
 258             protected void doSleep(long sleepMs) throws InterruptedException {
 
 259                 when(drools.isBrained()).thenReturn(false);
 
 260                 super.doSleep(sleepMs);
 
 264         assertFalse(task.isAlive());
 
 265         // only hit top of the loop twice
 
 266         verify(controller, times(2)).isAlive();
 
 267         assertTrue(doSleepMs > 0);
 
 271         task = new TestTransControllerTaskTester(controller) {
 
 273             protected void doSleep(long sleepMs) throws InterruptedException {
 
 275                 super.doSleep(sleepMs);
 
 279         assertFalse(task.isAlive());
 
 280         // only hit top of the loop twice
 
 281         verify(controller, times(2)).isAlive();
 
 282         assertTrue(doSleepMs > 0);
 
 284         // isInterrupted() returns true the first time, interrupt next time
 
 286         AtomicInteger count = new AtomicInteger(1);
 
 287         when(theThread.isInterrupted()).thenAnswer(args -> {
 
 288             if (count.decrementAndGet() >= 0) {
 
 291                 throw new InterruptedException(EXPECTED);
 
 295         assertFalse(task.isAlive());
 
 296         verify(controller, times(2)).isAlive();
 
 297         // doSleep() should not be called
 
 298         assertEquals(-1, doSleepMs);
 
 300         // interrupt during sleep
 
 302         task = new TestTransControllerTaskTester(controller) {
 
 304             protected void doSleep(long sleepMs) throws InterruptedException {
 
 305                 super.doSleep(sleepMs);
 
 306                 throw new InterruptedException(EXPECTED);
 
 310         assertFalse(task.isAlive());
 
 311         verify(theThread).interrupt();
 
 312         // only hit top of the loop once
 
 313         verify(controller).isAlive();
 
 314         assertTrue(doSleepMs > 0);
 
 316         // stop() during factQuery()
 
 318         when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenAnswer(args -> {
 
 323         assertFalse(task.isAlive());
 
 324         // only hit top of the loop once
 
 325         verify(controller).isAlive();
 
 327         // exception during isBrained() check
 
 329         when(drools.isBrained()).thenThrow(new IllegalArgumentException(EXPECTED));
 
 331         assertFalse(task.isAlive());
 
 333         // other exception during isBrained() check
 
 335         when(drools.isBrained()).thenThrow(new RuntimeException(EXPECTED));
 
 337         assertFalse(task.isAlive());
 
 341     public void testTestTransactionControllerTaskInjectTxIntoSessions() {
 
 343         verify(container, times(MAX_SLEEP_COUNT * sessions.size())).insert(anyString(), any(EventObject.class));
 
 347         when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(null);
 
 349         verify(container, never()).insert(anyString(), any());
 
 353         when(drools.factQuery(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(Collections.emptyList());
 
 355         verify(container, never()).insert(anyString(), any());
 
 359     public void testTestTransactionControllerTaskToString() {
 
 360         assertTrue(task.toString().startsWith("TTControllerTask ["));
 
 364      * TestTransaction with overridden methods.
 
 366     private class TestTransTImplTester extends TTImpl {
 
 369         protected TTControllerTask makeControllerTask(PolicyController controller) {
 
 370             return name2task.get(controller.getName());
 
 375      * Controller task with overridden methods.
 
 377     private class TestTransControllerTaskTester extends TTControllerTask {
 
 378         private int sleepCount = MAX_SLEEP_COUNT;
 
 380         public TestTransControllerTaskTester(PolicyController controller) {
 
 385         protected Thread makeThread(Runnable action) {
 
 391         protected void joinThread(long waitTimeMs) throws InterruptedException {
 
 392             waitJoinMs = waitTimeMs;
 
 396         protected void doSleep(long sleepMs) throws InterruptedException {
 
 399             if (--sleepCount <= 0) {
 
 400                 when(controller.isAlive()).thenReturn(false);
 
 405         protected Thread getCurrentThread() {