Fixed a bug in GWTTestCase where it would access JUnitShell from the wrong thread, creating a SWT error when later tests run.
Patch by: jlabanca
Review by: jat
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6265 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/junit/BatchingStrategy.java b/user/src/com/google/gwt/junit/BatchingStrategy.java
index 1932854..14a5a11 100644
--- a/user/src/com/google/gwt/junit/BatchingStrategy.java
+++ b/user/src/com/google/gwt/junit/BatchingStrategy.java
@@ -19,6 +19,7 @@
import com.google.gwt.junit.client.impl.JUnitHost.TestInfo;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -37,6 +38,24 @@
* @return an ordered list of test blocks to run
*/
public abstract List<TestInfo[]> getTestBlocks(String syntheticModuleName);
+
+ /**
+ * Get the set of tests for this module, minus tests that should not be
+ * executed.
+ *
+ * @return the set of tests to execute
+ */
+ protected final Set<TestInfo> getTestsForModule(String syntheticModuleName) {
+ Set<TestInfo> toExecute = GWTTestCase.getTestsForModule(syntheticModuleName).getTests();
+ Set<TestInfo> toRemove = new HashSet<TestInfo>();
+ for (TestInfo info : toExecute) {
+ if (JUnitShell.mustNotExecuteTest(info)) {
+ toRemove.add(info);
+ }
+ }
+ toExecute.removeAll(toRemove);
+ return toExecute;
+ }
}
/**
@@ -46,8 +65,7 @@
class NoBatchingStrategy extends BatchingStrategy {
@Override
public List<TestInfo[]> getTestBlocks(String syntheticModuleName) {
- Set<TestInfo> allTestsInModule = GWTTestCase.getTestsForModule(
- syntheticModuleName).getTests();
+ Set<TestInfo> allTestsInModule = getTestsForModule(syntheticModuleName);
List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>();
for (TestInfo testInfo : allTestsInModule) {
testBlocks.add(new TestInfo[] {testInfo});
@@ -62,8 +80,7 @@
class ClassBatchingStrategy extends BatchingStrategy {
@Override
public List<TestInfo[]> getTestBlocks(String syntheticModuleName) {
- Set<TestInfo> allTestsInModule = GWTTestCase.getTestsForModule(
- syntheticModuleName).getTests();
+ Set<TestInfo> allTestsInModule = getTestsForModule(syntheticModuleName);
List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>();
String lastTestClass = null;
List<TestInfo> lastTestBlock = null;
@@ -96,11 +113,12 @@
class ModuleBatchingStrategy extends BatchingStrategy {
@Override
public List<TestInfo[]> getTestBlocks(String syntheticModuleName) {
- Set<TestInfo> allTestsInModule = GWTTestCase.getTestsForModule(
- syntheticModuleName).getTests();
- TestInfo[] testBlock = allTestsInModule.toArray(new TestInfo[allTestsInModule.size()]);
+ Set<TestInfo> allTestsInModule = getTestsForModule(syntheticModuleName);
List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>();
- testBlocks.add(testBlock);
+ if (allTestsInModule.size() > 0) {
+ TestInfo[] testBlock = allTestsInModule.toArray(new TestInfo[allTestsInModule.size()]);
+ testBlocks.add(testBlock);
+ }
return testBlocks;
}
}
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index 7dbf9de..e98603d 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -491,19 +491,34 @@
* @return the list of remote user agents
*/
public static String[] getRemoteUserAgents() {
- return getUnitTestShell().remoteUserAgents;
+ if (unitTestShell == null) {
+ return null;
+ }
+ return unitTestShell.remoteUserAgents;
}
/**
* Checks if a testCase should not be executed. Currently, a test is either
* executed on all clients (mentioned in this test) or on no clients.
*
- * @param testCase current testCase.
+ * @param testInfo the test info to check
* @return true iff the test should not be executed on any of the specified
* clients.
*/
- public static boolean mustNotExecuteTest(TestCase testCase) {
- return getUnitTestShell().mustNotExecuteTest(getBannedPlatforms(testCase));
+ public static boolean mustNotExecuteTest(TestInfo testInfo) {
+ if (unitTestShell == null) {
+ throw new IllegalStateException(
+ "mustNotExecuteTest cannot be called before runTest()");
+ }
+ try {
+ Class<?> testClass = TestCase.class.getClassLoader().loadClass(
+ testInfo.getTestClass());
+ return unitTestShell.mustNotExecuteTest(getBannedPlatforms(testClass,
+ testInfo.getTestMethod()));
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Could not load test class: "
+ + testInfo.getTestClass());
+ }
}
/**
@@ -583,16 +598,19 @@
}
/**
- * returns the set of banned {@code Platform} for a test method.
+ * Returns the set of banned {@code Platform} for a test method.
+ *
+ * @param testClass the testClass
+ * @param methodName the name of the test method
*/
- private static Set<Platform> getBannedPlatforms(TestCase testCase) {
- Class<?> testClass = testCase.getClass();
+ private static Set<Platform> getBannedPlatforms(Class<?> testClass,
+ String methodName) {
Set<Platform> bannedSet = EnumSet.noneOf(Platform.class);
if (testClass.isAnnotationPresent(DoNotRunWith.class)) {
bannedSet.addAll(Arrays.asList(testClass.getAnnotation(DoNotRunWith.class).value()));
}
try {
- Method testMethod = testClass.getMethod(testCase.getName());
+ Method testMethod = testClass.getMethod(methodName);
if (testMethod.isAnnotationPresent(DoNotRunWith.class)) {
bannedSet.addAll(Arrays.asList(testMethod.getAnnotation(
DoNotRunWith.class).value()));
@@ -630,6 +648,10 @@
// TODO: install a shutdown hook? Not necessary with GWTShell.
unitTestShell.lastLaunchFailed = false;
}
+ if (unitTestShell.thread != Thread.currentThread()) {
+ throw new IllegalThreadStateException(
+ "JUnitShell can only be accessed from the thread that created it.");
+ }
return unitTestShell;
}
@@ -727,10 +749,16 @@
private long testMethodTimeout;
/**
+ * The thread that created the JUnitShell.
+ */
+ private Thread thread;
+
+ /**
* Enforce the singleton pattern. The call to {@link GWTShell}'s ctor forces
* server mode and disables processing extra arguments as URLs to be shown.
*/
private JUnitShell() {
+ thread = Thread.currentThread();
setRunTomcat(true);
setHeadless(true);
@@ -937,7 +965,8 @@
private void runTestImpl(GWTTestCase testCase, TestResult testResult)
throws UnableToCompleteException {
- if (mustNotExecuteTest(testCase)) {
+ if (mustNotExecuteTest(getBannedPlatforms(testCase.getClass(),
+ testCase.getName()))) {
return;
}
diff --git a/user/src/com/google/gwt/junit/RunStyle.java b/user/src/com/google/gwt/junit/RunStyle.java
index c09200d..9757ad4 100644
--- a/user/src/com/google/gwt/junit/RunStyle.java
+++ b/user/src/com/google/gwt/junit/RunStyle.java
@@ -36,15 +36,6 @@
}
/**
- * Initialize the RunStyle after the shell has finished loading.
- *
- * @throws UnableToCompleteException
- */
- public void init() throws UnableToCompleteException {
- // nothing to do
- }
-
- /**
* Returns whether or not the local UI event loop needs to be pumped.
*/
public abstract boolean isLocal();
diff --git a/user/src/com/google/gwt/junit/RunStyleLocalHosted.java b/user/src/com/google/gwt/junit/RunStyleLocalHosted.java
index 94ebe3f..5861c45 100644
--- a/user/src/com/google/gwt/junit/RunStyleLocalHosted.java
+++ b/user/src/com/google/gwt/junit/RunStyleLocalHosted.java
@@ -32,15 +32,6 @@
super(shell);
}
- /**
- * We need to open the browser window in the same thread as {@link JUnitShell}
- * or SWT will throw an error.
- */
- @Override
- public void init() throws UnableToCompleteException {
- browserWindow = shell.openNewBrowserWindow();
- }
-
@Override
public boolean isLocal() {
return true;
diff --git a/user/src/com/google/gwt/junit/client/GWTTestCase.java b/user/src/com/google/gwt/junit/client/GWTTestCase.java
index 4ad6866..176c8a0 100644
--- a/user/src/com/google/gwt/junit/client/GWTTestCase.java
+++ b/user/src/com/google/gwt/junit/client/GWTTestCase.java
@@ -273,11 +273,6 @@
public void setName(String name) {
super.setName(name);
- // If we can't run this test, don't add it to the map of all tests to batch.
- if (JUnitShell.mustNotExecuteTest(this)) {
- return;
- }
-
synchronized (ALL_GWT_TESTS_LOCK) {
// Once the name is set, we can add ourselves to the global set.
String syntheticModuleName = getSyntheticModuleName();
diff --git a/user/test/com/google/gwt/junit/BatchingStrategyTest.java b/user/test/com/google/gwt/junit/BatchingStrategyTest.java
index bd86c18..8a44b09 100644
--- a/user/test/com/google/gwt/junit/BatchingStrategyTest.java
+++ b/user/test/com/google/gwt/junit/BatchingStrategyTest.java
@@ -26,10 +26,35 @@
import java.util.Set;
/**
- * Tests of {@link BatchingStrategy}.
+ * Tests of {@link BatchingStrategy}. This test must run after a
+ * {@link GWTTestCase} to ensure that JUnitShell is already initialized.
*/
public class BatchingStrategyTest extends TestCase {
+ private static class TestClass0 {
+ public void testMethod0() {
+ }
+
+ public void testMethod1() {
+ }
+ }
+
+ private static class TestClass1 {
+ public void testMethod2() {
+ }
+
+ public void testMethod3() {
+ }
+
+ public void testMethod4() {
+ }
+ }
+
+ private static class TestClass2 {
+ public void testMethod5() {
+ }
+ }
+
/**
* The synthetic name of the module used for this test.
*/
@@ -41,17 +66,17 @@
private static TestModuleInfo fakeModuleInfo;
private static final TestInfo TEST_INFO_0_0 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass0", "testMethod0");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass0.class.getName(), "testMethod0");
private static final TestInfo TEST_INFO_0_1 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass0", "testMethod1");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass0.class.getName(), "testMethod1");
private static final TestInfo TEST_INFO_1_2 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass1", "testMethod2");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass1.class.getName(), "testMethod2");
private static final TestInfo TEST_INFO_1_3 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass1", "testMethod3");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass1.class.getName(), "testMethod3");
private static final TestInfo TEST_INFO_1_4 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass1", "testMethod4");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass1.class.getName(), "testMethod4");
private static final TestInfo TEST_INFO_2_5 = new TestInfo(
- FAKE_MODULE_SYNTHETIC_NAME, "testClass2", "testMethod5");
+ FAKE_MODULE_SYNTHETIC_NAME, TestClass2.class.getName(), "testMethod5");
public void testClassBatchingStrategy() {
List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>();
diff --git a/user/test/com/google/gwt/junit/JUnitSuite.java b/user/test/com/google/gwt/junit/JUnitSuite.java
index ec1c25b..40f468e 100644
--- a/user/test/com/google/gwt/junit/JUnitSuite.java
+++ b/user/test/com/google/gwt/junit/JUnitSuite.java
@@ -27,17 +27,19 @@
public static Test suite() {
GWTTestSuite suite = new GWTTestSuite("Test for suite for com.google.gwt.junit");
- suite.addTestSuite(FakeMessagesMakerTest.class);
- suite.addTestSuite(BatchingStrategyTest.class);
- suite.addTestSuite(JUnitMessageQueueTest.class);
- suite.addTestSuite(GWTTestCaseNoClientTest.class);
- suite.addTestSuite(BenchmarkNoClientTest.class);
-
// client
// Suppressed due to flakiness on Linux
// suite.addTestSuite(BenchmarkTest.class);
suite.addTestSuite(GWTTestCaseTest.class);
+ // Must run after a GWTTestCase so JUnitShell is initialized.
+ suite.addTestSuite(BatchingStrategyTest.class);
+
+ suite.addTestSuite(FakeMessagesMakerTest.class);
+ suite.addTestSuite(JUnitMessageQueueTest.class);
+ suite.addTestSuite(GWTTestCaseNoClientTest.class);
+ suite.addTestSuite(BenchmarkNoClientTest.class);
+
// These two are intended only to be run manually. See class comments
// suite.addTestSuite(ParallelRemoteTest.class);
// suite.addTestSuite(TestManualAsync.class);