/******************************************************************************* * Copyright (c) 2007, 2009 Ericsson 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: * Ericsson - Initial Implementation *******************************************************************************/ package org.eclipse.cdt.tests.dsf.gdb.framework; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.swt.widgets.Display; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.InitializationError; /** * This runner starts an eclipse job ro run the tests, so as * to release the UI thread. */ public class BackgroundRunner extends BlockJUnit4ClassRunner { public BackgroundRunner(Class<?> klass) throws InitializationError { super(klass); } final static QualifiedName BACKGROUND_TEST_EXECUTION_FINISHED = new QualifiedName(GdbPlugin.getDefault().getBundle().getSymbolicName(), "background_test_execution_finished"); //$NON-NLS-1$ void invokeSuperRunImpl(RunNotifier notifier) { super.run(notifier); } /* * This method overrides the one from TestClassRunner. * What we do here is start a background job which will call * TestClassRunner.run; this enables us to release * the main UI thread. * * This has been adapted from the JUnits tests of TargetManagement * (RSECoreTestCase and RSEWaitAndDispatchUtil) */ @Override public void run(final RunNotifier notifier) { // Start the test in a background thread Job job = new Job("GDB/MI JUnit Test Case Execution Job") { @Override protected IStatus run(IProgressMonitor monitor) { invokeSuperRunImpl(notifier); monitor.done(); setProperty(BACKGROUND_TEST_EXECUTION_FINISHED, Boolean.TRUE); // The job never fails. The test result is the real result. return Status.OK_STATUS; } }; // The job is not complete yet job.setProperty(BACKGROUND_TEST_EXECUTION_FINISHED, Boolean.FALSE); // schedule the job to run immediatelly job.schedule(); // wait till the job finishes executing waitAndDispatch(0, new BackgroundTestExecutionJobWaiter(job)); } public interface IInterruptCondition { public boolean isTrue(); public void dispose(); } private final static class BackgroundTestExecutionJobWaiter implements IInterruptCondition { private final Job job; public BackgroundTestExecutionJobWaiter(Job job) { assert job != null; this.job = job; } public boolean isTrue() { // Interrupt the wait method if the job signaled that it has finished. return ((Boolean)job.getProperty(BACKGROUND_TEST_EXECUTION_FINISHED)).booleanValue(); } public void dispose() { // nothing to do } } public static boolean waitAndDispatch(long timeout, IInterruptCondition condition) { assert timeout >= 0 && condition != null; boolean isTimedOut= false; if (timeout >= 0 && condition != null) { long start = System.currentTimeMillis(); Display display = Display.findDisplay(Thread.currentThread()); if (display != null) { // ok, we are running within a display thread --> keep the // display event dispatching running. long current = System.currentTimeMillis(); while (timeout == 0 || (current - start) < timeout) { if (condition.isTrue()) break; if (!display.readAndDispatch()) display.sleep(); current = System.currentTimeMillis(); } isTimedOut = (current - start) >= timeout && timeout > 0; } else { // ok, we are not running within a display thread --> we can // just block the thread here long current = System.currentTimeMillis(); while (timeout == 0 || (current - start) < timeout) { if (condition.isTrue()) break; try { Thread.sleep(50); } catch (InterruptedException e) { /* ignored on purpose */ } current = System.currentTimeMillis(); } isTimedOut = (current - start) >= timeout && timeout > 0; } } // Signal the interrupt condition that we are done here // and it can cleanup whatever necessary. if (condition != null) condition.dispose(); return isTimedOut; } }