Home | History | Annotate | Download | only in async
      1 /*
      2  * Copyright (c) 2018 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockitoutil.async;
      6 
      7 import java.util.LinkedList;
      8 
      9 /**
     10  * Streamlines testing async code for Mockito tests.
     11  *
     12  * Instances of this class are NOT thread safe (intentionally, they are not required to be thread safe)
     13  */
     14 public class AsyncTesting {
     15 
     16     //Sanity limit of threas. Increase it if justified.
     17     private final static int MAX_THREADS = 3;
     18 
     19     private final LinkedList<Exception> problems = new LinkedList<Exception>();
     20     private final LinkedList<Thread> threads = new LinkedList<Thread>();
     21     private boolean stopping;
     22 
     23     /**
     24      * Schedules execution of runnable with some delay.
     25      * Starts thread immediately and returns.
     26      * The thread will execute the runnable after given delay in millis.
     27      *
     28      * @param delayMillis - the delay in millis
     29      * @param runnable - to be executed in a thread after delay
     30      */
     31     public void runAfter(final int delayMillis, final Runnable runnable) {
     32         if (threads.size() == MAX_THREADS) {
     33             throw new RuntimeException("Please don't schedule any more threads. Figure out how to test the code with minimum amount of threads");
     34         }
     35         Thread t = new Thread() {
     36             public void run() {
     37                 try {
     38                     Thread.sleep(delayMillis);
     39                     runnable.run();
     40                 } catch (Exception e) {
     41                     boolean cleanStop = e instanceof InterruptedException && stopping;
     42                     if (!cleanStop) {
     43                         problems.add(e);
     44                     }
     45                 }
     46             }
     47         };
     48         System.out.println("[AsyncTesting] Starting thread that will execute the runnable after " + delayMillis + " millis. Threads so far: " + threads.size());
     49         threads.add(t);
     50         t.start();
     51     }
     52 
     53     /**
     54      * Interrupts and waits for all threads to complete (using 'join()').
     55      * Rethrows exceptions accumulated by the execution of threads.
     56      */
     57     public void cleanUp() {
     58         stopping = true;
     59         System.out.println("[AsyncTesting] Interrupting and waiting for " + threads.size() + " threads to complete...");
     60         while(!threads.isEmpty()) {
     61             Thread t = threads.removeFirst();
     62             try {
     63                 t.interrupt();
     64                 t.join();
     65             } catch (InterruptedException e) {
     66                 throw new RuntimeException(e);
     67             }
     68         }
     69         if (!problems.isEmpty()) {
     70             throw new RuntimeException("Caught " + problems.size() + " exception(s). First one is included as cause", problems.getFirst());
     71         }
     72     }
     73 }
     74