• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * //TODO convert to test rule
15  */
16 public class AsyncTesting {
17 
18     //Sanity limit of threas. Increase it if justified.
19     private final static int MAX_THREADS = 4;
20 
21     private final LinkedList<Exception> problems = new LinkedList<Exception>();
22     private final LinkedList<Thread> threads = new LinkedList<Thread>();
23     private boolean stopping;
24 
25     /**
26      * Schedules execution of runnable with some delay.
27      * Starts thread immediately and returns.
28      * The thread will execute the runnable after given delay in millis.
29      *
30      * @param delayMillis - the delay in millis
31      * @param runnable - to be executed in a thread after delay
32      */
runAfter(final int delayMillis, final Runnable runnable)33     public void runAfter(final int delayMillis, final Runnable runnable) {
34         if (threads.size() == MAX_THREADS) {
35             throw new RuntimeException("Please don't schedule any more threads. Figure out how to test the code with minimum amount of threads");
36         }
37         Thread t = new Thread() {
38             public void run() {
39                 try {
40                     Thread.sleep(delayMillis);
41                     runnable.run();
42                 } catch (Exception e) {
43                     boolean cleanStop = e instanceof InterruptedException && stopping;
44                     if (!cleanStop) {
45                         problems.add(e);
46                     }
47                 }
48             }
49         };
50         System.out.println("[AsyncTesting] Starting thread that will execute the runnable after " + delayMillis + " millis. Threads so far: " + threads.size());
51         threads.add(t);
52         t.start();
53     }
54 
55     /**
56      * Interrupts and waits for all threads to complete (using 'join()').
57      * Rethrows exceptions accumulated by the execution of threads.
58      */
cleanUp()59     public void cleanUp() {
60         stopping = true;
61         System.out.println("[AsyncTesting] Interrupting and waiting for " + threads.size() + " threads to complete...");
62         while(!threads.isEmpty()) {
63             Thread t = threads.removeFirst();
64             try {
65                 t.interrupt();
66                 t.join();
67             } catch (InterruptedException e) {
68                 throw new RuntimeException(e);
69             }
70         }
71         if (!problems.isEmpty()) {
72             throw new RuntimeException("Caught " + problems.size() + " exception(s). First one is included as cause", problems.getFirst());
73         }
74     }
75 }
76