• 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 static final 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(
36                     "Please don't schedule any more threads. Figure out how to test the code with minimum amount of threads");
37         }
38         Thread t =
39                 new Thread() {
40                     public void run() {
41                         try {
42                             Thread.sleep(delayMillis);
43                             runnable.run();
44                         } catch (Exception e) {
45                             boolean cleanStop = e instanceof InterruptedException && stopping;
46                             if (!cleanStop) {
47                                 problems.add(e);
48                             }
49                         }
50                     }
51                 };
52         System.out.println(
53                 "[AsyncTesting] Starting thread that will execute the runnable after "
54                         + delayMillis
55                         + " millis. Threads so far: "
56                         + threads.size());
57         threads.add(t);
58         t.start();
59     }
60 
61     /**
62      * Interrupts and waits for all threads to complete (using 'join()').
63      * Rethrows exceptions accumulated by the execution of threads.
64      */
cleanUp()65     public void cleanUp() {
66         stopping = true;
67         System.out.println(
68                 "[AsyncTesting] Interrupting and waiting for "
69                         + threads.size()
70                         + " threads to complete...");
71         while (!threads.isEmpty()) {
72             Thread t = threads.removeFirst();
73             try {
74                 t.interrupt();
75                 t.join();
76             } catch (InterruptedException e) {
77                 throw new RuntimeException(e);
78             }
79         }
80         if (!problems.isEmpty()) {
81             throw new RuntimeException(
82                     "Caught " + problems.size() + " exception(s). First one is included as cause",
83                     problems.getFirst());
84         }
85     }
86 }
87