1 /*******************************************************************************
2  * Copyright (c) 2016 Google, Inc and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *   Stefan Xenos (Google) - Initial implementation
13  *******************************************************************************/
14 package org.eclipse.ui.editors.tests;
15 
16 import java.util.concurrent.TimeUnit;
17 
18 import org.junit.Assert;
19 
20 import org.eclipse.swt.widgets.Display;
21 
22 import org.eclipse.core.runtime.jobs.Job;
23 
24 public class TestUtil {
25 	/**
26 	 * Call this in the tearDown method of every test to clean up state that can
27 	 * otherwise leak through SWT between tests.
28 	 */
cleanUp()29 	public static void cleanUp() {
30 		// Ensure that the Thread.interrupted() flag didn't leak.
31 		Assert.assertFalse("The main thread should not be interrupted at the end of a test", Thread.interrupted());
32 		// Wait for any outstanding jobs to finish. Protect against deadlock by
33 		// terminating the wait after a timeout.
34 		boolean timedOut = waitForJobs(0, TimeUnit.MINUTES.toMillis(3));
35 		Assert.assertFalse("Some Job did not terminate at the end of the test", timedOut);
36 		// Wait for any pending *syncExec calls to finish
37 		runEventLoop();
38 		// Ensure that the Thread.interrupted() flag didn't leak.
39 		Assert.assertFalse("The main thread should not be interrupted at the end of a test", Thread.interrupted());
40 	}
41 
42 	/**
43 	 * Process all queued UI events. If called from background thread, does
44 	 * nothing.
45 	 */
runEventLoop()46 	public static void runEventLoop() {
47 		Display display = Display.getCurrent();
48 		if (display != null && !display.isDisposed()) {
49 			while (display.readAndDispatch()) {
50 				// Keep pumping events until the queue is empty
51 			}
52 		}
53 	}
54 
55 	/**
56 	 * Utility for waiting until the execution of jobs of any family has
57 	 * finished or timeout is reached. If no jobs are running, the method waits
58 	 * given minimum wait time. While this method is waiting for jobs, UI events
59 	 * are processed.
60 	 *
61 	 * @param minTimeMs
62 	 *            minimum wait time in milliseconds
63 	 * @param maxTimeMs
64 	 *            maximum wait time in milliseconds
65 	 * @return true if the method timed out, false if all the jobs terminated
66 	 *         before the timeout
67 	 */
waitForJobs(long minTimeMs, long maxTimeMs)68 	public static boolean waitForJobs(long minTimeMs, long maxTimeMs) {
69 		if (maxTimeMs < minTimeMs) {
70 			throw new IllegalArgumentException("Max time is smaller as min time!");
71 		}
72 		final long start = System.currentTimeMillis();
73 		while (System.currentTimeMillis() - start < minTimeMs) {
74 			runEventLoop();
75 			try {
76 				Thread.sleep(100);
77 			} catch (InterruptedException e) {
78 				// Uninterruptable
79 			}
80 		}
81 		while (!Job.getJobManager().isIdle()) {
82 			if (System.currentTimeMillis() - start >= maxTimeMs) {
83 				return true;
84 			}
85 			runEventLoop();
86 			try {
87 				Thread.sleep(100);
88 			} catch (InterruptedException e) {
89 				// Uninterruptable
90 			}
91 		}
92 		return false;
93 	}
94 }
95