Bug 506401 - testTranslateContainers diagnostics

Added TestUtil and some extra wait cycles to see if there are any jobs
preventing us from proper project import or doing something in parallel.

Change-Id: I69182557767612bcf7246218614348e03cc37ee6
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
index ddc35ae..c8335ed 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
@@ -26,6 +26,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
@@ -582,7 +583,7 @@
 	 * @throws Exception
 	 * @since 3.8
 	 */
-	void assertWelcomeScreenClosed() throws Exception {
+	protected final void assertWelcomeScreenClosed() throws Exception {
 		if(!welcomeClosed && PlatformUI.isWorkbenchRunning()) {
 			final IWorkbench wb = PlatformUI.getWorkbench();
 			if(wb != null) {
@@ -845,13 +846,24 @@
 		IProject pro = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
         if (pro.exists() && delete) {
 			pro.delete(true, true, null);
+			TestUtil.waitForJobs(300, TimeUnit.MINUTES.toMillis(3));
+			TestUtil.runEventLoop();
         }
         // create project and import source
         IJavaProject jp = JavaProjectHelper.createJavaProject(name, JavaProjectHelper.BIN_DIR);
+		TestUtil.waitForJobs(100, TimeUnit.MINUTES.toMillis(3));
+		TestUtil.runEventLoop();
+
         JavaProjectHelper.addSourceContainer(jp, JavaProjectHelper.SRC_DIR);
+		TestUtil.waitForJobs(100, TimeUnit.MINUTES.toMillis(3));
+		TestUtil.runEventLoop();
+
         File root = JavaTestPlugin.getDefault().getFileInPlugin(new Path(contentpath));
         JavaProjectHelper.importFilesFromDirectory(root, jp.getPath(), null);
 
+		TestUtil.waitForJobs(100, TimeUnit.MINUTES.toMillis(3));
+		TestUtil.runEventLoop();
+
         // add the EE library
         IVMInstall vm = JavaRuntime.getDefaultVMInstall();
         assertNotNull("No default JRE", vm);
@@ -866,6 +878,8 @@
         if (!folder.exists()) {
         	folder.create(true, true, null);
         }
+		TestUtil.waitForJobs(300, TimeUnit.MINUTES.toMillis(3));
+		TestUtil.runEventLoop();
         return jp;
 	}
 	
@@ -883,11 +897,18 @@
 		IProject pro = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
         if (pro.exists() && delete) {
 			pro.delete(true, true, null);
+			TestUtil.waitForJobs(100, TimeUnit.MINUTES.toMillis(3));
+			TestUtil.runEventLoop();
         }
         // create project and import source
         IProject pj = JavaProjectHelper.createProject(name);
+		TestUtil.waitForJobs(100, TimeUnit.MINUTES.toMillis(3));
+		TestUtil.runEventLoop();
+
         File root = JavaTestPlugin.getDefault().getFileInPlugin(new Path(contentpath));
         JavaProjectHelper.importFilesFromDirectory(root, pj.getFullPath(), null);
+		TestUtil.waitForJobs(100, TimeUnit.MINUTES.toMillis(3));
+		TestUtil.runEventLoop();
         return pj;
 	}
 	
@@ -2465,6 +2486,7 @@
 				tryAgain = false;
 			} catch (TestAgainException e) {
 				Status status = new Status(IStatus.ERROR, "org.eclipse.jdt.debug.tests", "Test failed attempt " + attempts + ". Re-testing: " + this.getName(), e); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				TestUtil.cleanUp();
 				DebugPlugin.log(status);
 				if (attempts > 5) {
 					tryAgain = false;
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java
new file mode 100644
index 0000000..7b3b088
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Google, Inc and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests;
+
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.swt.widgets.Display;
+import org.junit.Assert;
+
+public class TestUtil {
+	/**
+	 * Call this in the tearDown method of every test to clean up state that can
+	 * otherwise leak through SWT between tests.
+	 */
+	public static void cleanUp() {
+		// Ensure that the Thread.interrupted() flag didn't leak.
+		Assert.assertFalse("The main thread should not be interrupted at the end of a test", Thread.interrupted());
+		// Wait for any outstanding jobs to finish. Protect against deadlock by
+		// terminating the wait after a timeout.
+		boolean timedOut = waitForJobs(0, TimeUnit.MINUTES.toMillis(3));
+		Assert.assertFalse("Some Job did not terminate at the end of the test", timedOut);
+		// Wait for any pending *syncExec calls to finish
+		runEventLoop();
+		// Ensure that the Thread.interrupted() flag didn't leak.
+		Assert.assertFalse("The main thread should not be interrupted at the end of a test", Thread.interrupted());
+	}
+
+	/**
+	 * Process all queued UI events. If called from background thread, does
+	 * nothing.
+	 */
+	public static void runEventLoop() {
+		Display display = Display.getCurrent();
+		if (display != null && !display.isDisposed()) {
+			while (display.readAndDispatch()) {
+				// Keep pumping events until the queue is empty
+			}
+		}
+	}
+
+	/**
+	 * Utility for waiting until the execution of jobs of any family has
+	 * finished or timeout is reached. If no jobs are running, the method waits
+	 * given minimum wait time. While this method is waiting for jobs, UI events
+	 * are processed.
+	 *
+	 * @param minTimeMs
+	 *            minimum wait time in milliseconds
+	 * @param maxTimeMs
+	 *            maximum wait time in milliseconds
+	 * @return true if the method timed out, false if all the jobs terminated
+	 *         before the timeout
+	 */
+	public static boolean waitForJobs(long minTimeMs, long maxTimeMs) {
+		if (maxTimeMs < minTimeMs) {
+			throw new IllegalArgumentException("Max time is smaller as min time!");
+		}
+		final long start = System.currentTimeMillis();
+		while (System.currentTimeMillis() - start < minTimeMs) {
+			runEventLoop();
+			try {
+				Thread.sleep(100);
+			} catch (InterruptedException e) {
+				// Uninterruptable
+			}
+		}
+		while (!Job.getJobManager().isIdle()) {
+			if (System.currentTimeMillis() - start >= maxTimeMs) {
+				return true;
+			}
+			runEventLoop();
+			try {
+				Thread.sleep(100);
+			} catch (InterruptedException e) {
+				// Uninterruptable
+			}
+		}
+		return false;
+	}
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/JarSourceLookupTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/JarSourceLookupTests.java
index e91060d..0aa7d56 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/JarSourceLookupTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/JarSourceLookupTests.java
@@ -29,6 +29,7 @@
 import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.testplugin.JavaProjectHelper;
 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.debug.tests.TestUtil;
 import org.eclipse.jdt.internal.core.ClassFile;
 import org.eclipse.jdt.internal.launching.JavaSourceLookupUtil;
 import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
@@ -67,25 +68,24 @@
 		}
 	}
 	
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.debug.tests.AbstractDebugTest#getProjectContext()
-	 */
 	@Override
 	protected IJavaProject getProjectContext() {
 		return fgJarProject;
 	}
 	
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.debug.tests.AbstractDebugTest#setUp()
-	 */
 	@Override
 	protected void setUp() throws Exception {
+		assertWelcomeScreenClosed();
+		TestUtil.runEventLoop();
+		TestUtil.cleanUp();
 		IPath testrpath = new Path("testresources");
 		IProject jarProject = createProjectClone(fJarProject, testrpath.append(fJarProject).toString(), true);
+
 		IFile jar = jarProject.getFile("lib/sample.jar");
 		assertTrue("lib/sample.jar is missing in project: " + jarProject.getName(), jar.exists());
 
 		fgJarProject = createJavaProjectClone(RefPjName, testrpath.append(RefPjName).toString(), JavaProjectHelper.J2SE_1_4_EE_NAME, true);
+
 		IProject jarRefProject = fgJarProject.getProject();
 		IFile cp = jarRefProject.getFile(".classpath");
 		assertTrue(".classpath is missing in project: " + jarRefProject.getName(), cp.exists());
@@ -102,14 +102,16 @@
 			fail("The .classpath from project " + jarRefProject + " is unexpected and does not have an entry for " + SAMPLE_JAR_PATH + ": "
 					+ new String(Files.readAllBytes(path)));
 		}
+		waitForBuild();
 	}
 	
-	/* (non-Javadoc)
-	 * @see junit.framework.TestCase#tearDown()
-	 */
 	@Override
 	protected void tearDown() throws Exception {
 		removeAllBreakpoints();
+		if (fgJarProject.exists()) {
+			fgJarProject.getProject().delete(true, null);
+		}
+		TestUtil.cleanUp();
 		super.tearDown();
 	}