• 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 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      */
runAfter(final int delayMillis, final Runnable runnable)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      */
cleanUp()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