Revision: 6280 Author: [email protected] Date: Thu Oct 1 10:42:54 2009 Log: Merging tr...@6278:6279 trunk. - NoBatchingStrategy now runs tests as they are executed by JUnit.
svn merge -r6278:6279 --ignore-ancestry https://google-web-toolkit.googlecode.com/svn/trunk/ . http://code.google.com/p/google-web-toolkit/source/detail?r=6280 Added: /branches/snapshot-2009.09.23-r6200/user/test/com/google/gwt/junit/CompileStrategyTest.java Modified: /branches/snapshot-2009.09.23-r6200/branch-info.txt /branches/snapshot-2009.09.23-r6200/user/src/com/google/gwt/junit/BatchingStrategy.java /branches/snapshot-2009.09.23-r6200/user/src/com/google/gwt/junit/CompileStrategy.java /branches/snapshot-2009.09.23-r6200/user/src/com/google/gwt/junit/JUnitShell.java /branches/snapshot-2009.09.23-r6200/user/test/com/google/gwt/junit/BatchingStrategyTest.java /branches/snapshot-2009.09.23-r6200/user/test/com/google/gwt/junit/JUnitSuite.java ======================================= --- /dev/null +++ /branches/snapshot-2009.09.23-r6200/user/test/com/google/gwt/junit/CompileStrategyTest.java Thu Oct 1 10:42:54 2009 @@ -0,0 +1,274 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.junit; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.dev.cfg.ModuleDef; +import com.google.gwt.junit.JUnitShell.Strategy; +import com.google.gwt.junit.client.GWTTestCase; +import com.google.gwt.junit.client.impl.JUnitHost.TestInfo; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tests of {...@link BatchingStrategy}. This test must run after a + * {...@link GWTTestCase} to ensure that JUnitShell is already initialized. + */ +public class CompileStrategyTest extends TestCase { + + /** + * A mock {...@link RunStyle} used for testing. + */ + private static class MockRunStyle extends RunStyle { + + public MockRunStyle() { + super(null); + } + + @Override + public boolean isLocal() { + return true; + } + + @Override + public void launchModule(String moduleName) { + } + + @Override + public void maybeCompileModule(String moduleName) { + } + } + + /** + * A mock {...@link JUnitMessageQueue} used for testing. + */ + private static class MockJUnitMessageQueue extends JUnitMessageQueue { + + /** + * The test blocks added to the queue. + */ + private List<TestInfo[]> testBlocks; + + /** + * Indicates that this is the last test block. + */ + private boolean isLastBlock; + + public MockJUnitMessageQueue() { + super(1); + } + + @Override + void addTestBlocks(List<TestInfo[]> newTestBlocks, boolean isLastBlock) { + assertNull(testBlocks); + this.testBlocks = newTestBlocks; + this.isLastBlock = isLastBlock; + } + + void assertIsLastBlock(boolean expected) { + assertEquals(expected, isLastBlock); + } + + void assertTestBlocks(List<TestInfo[]> expected) { + if (expected == null || testBlocks == null) { + assertEquals(expected, testBlocks); + return; + } + + assertEquals(expected.size(), testBlocks.size()); + for (int i = 0; i < testBlocks.size(); i++) { + TestInfo[] actualBlock = testBlocks.get(i); + TestInfo[] expectedBlock = expected.get(i); + assertEquals(expectedBlock.length, actualBlock.length); + for (int j = 0; j < expectedBlock.length; j++) { + assertEquals(expectedBlock[j], actualBlock[j]); + } + } + } + } + + /** + * A mock {...@link CompileStrategy} used for testing. + */ + private static class MockCompileStrategy extends CompileStrategy { + + /** + * The number of modules to mock. + */ + private int mockModuleCount; + + private MockJUnitMessageQueue messageQueue = new MockJUnitMessageQueue(); + + /** + * Construct a new {...@link MockCompileStrategy}. + * + * @param mockModuleCount the number of modules + */ + public MockCompileStrategy(int mockModuleCount) { + this.mockModuleCount = mockModuleCount; + } + + @Override + public ModuleDef maybeCompileModule(String moduleName, + String syntheticModuleName, Strategy strategy, RunStyle runStyle, + BatchingStrategy batchingStrategy, TreeLogger treeLogger) { + fail("This method should not be called."); + return null; + } + + @Override + MockJUnitMessageQueue getMessageQueue() { + return messageQueue; + } + + @Override + int getModuleCount() { + return mockModuleCount; + } + + @Override + ModuleDef maybeCompileModuleImpl2(String moduleName, + String syntheticModuleName, Strategy strategy, RunStyle runStyle, + TreeLogger treeLogger) { + return null; + } + } + + /** + * A mock test case used for testing. + */ + private static class MockGWTTestCase extends GWTTestCase { + @Override + public String getModuleName() { + return "com.google.gwt.junit.JUnit"; + } + + @Override + public String getName() { + return "testMethod1"; + } + + public void testMethod0() { + } + + public void testMethod1() { + } + + public void testMethod2() { + } + } + + public void testMaybeAddTestBlockForCurrentTestWithoutBatching() { + BatchingStrategy batchingStrategy = new NoBatchingStrategy(); + assertTrue(batchingStrategy.isSingleTestOnly()); + + // Maybe add the current test. + GWTTestCase testCase = new MockGWTTestCase(); + MockCompileStrategy strategy = new MockCompileStrategy(-1); + strategy.maybeAddTestBlockForCurrentTest(testCase, batchingStrategy); + + // Generate the expected blocks. + TestInfo testInfo = new TestInfo(testCase.getSyntheticModuleName(), + testCase.getClass().getName(), testCase.getName()); + List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>(); + testBlocks.add(new TestInfo[] {testInfo}); + + // Verify the test is added to the queue. + strategy.getMessageQueue().assertIsLastBlock(false); + strategy.getMessageQueue().assertTestBlocks(testBlocks); + } + + public void testMaybeAddTestBlockForCurrentTestWithBatching() { + BatchingStrategy batchingStrategy = new ModuleBatchingStrategy(); + assertFalse(batchingStrategy.isSingleTestOnly()); + + // Maybe add the current test. + GWTTestCase testCase = new MockGWTTestCase(); + MockCompileStrategy strategy = new MockCompileStrategy(-1); + strategy.maybeAddTestBlockForCurrentTest(testCase, batchingStrategy); + + // Verify the test is not added to the queue. + strategy.getMessageQueue().assertTestBlocks(null); + } + + public void testMaybeCompileModuleImplWithoutBatching() { + BatchingStrategy batchingStrategy = new NoBatchingStrategy(); + assertTrue(batchingStrategy.isSingleTestOnly()); + + // Maybe add the current test. + RunStyle runStyle = new MockRunStyle(); + GWTTestCase testCase = new MockGWTTestCase(); + MockCompileStrategy strategy = new MockCompileStrategy(-1); + try { + strategy.maybeCompileModuleImpl(testCase.getModuleName(), + testCase.getSyntheticModuleName(), testCase.getStrategy(), runStyle, + batchingStrategy, TreeLogger.NULL); + } catch (UnableToCompleteException e) { + fail("Unexpected UnableToCompleteException: " + e.getMessage()); + } + + // Verify the test block is not added to the queue. + strategy.getMessageQueue().assertTestBlocks(null); + } + + public void testMaybeCompileModuleImplWithBatchingLastModule() { + BatchingStrategy batchingStrategy = new ModuleBatchingStrategy(); + assertFalse(batchingStrategy.isSingleTestOnly()); + + // Maybe add the current test. + RunStyle runStyle = new MockRunStyle(); + GWTTestCase testCase = new MockGWTTestCase(); + MockCompileStrategy strategy = new MockCompileStrategy(-1); + try { + strategy.maybeCompileModuleImpl(testCase.getModuleName(), + testCase.getSyntheticModuleName(), testCase.getStrategy(), runStyle, + batchingStrategy, TreeLogger.NULL); + } catch (UnableToCompleteException e) { + fail("Unexpected UnableToCompleteException: " + e.getMessage()); + } + + // Verify the test block is added to the queue. + strategy.getMessageQueue().assertIsLastBlock(true); + strategy.getMessageQueue().assertTestBlocks( + batchingStrategy.getTestBlocks(testCase.getSyntheticModuleName())); + } + + public void testMaybeCompileModuleImplWithBatchingNotLastModule() { + BatchingStrategy batchingStrategy = new ClassBatchingStrategy(); + assertFalse(batchingStrategy.isSingleTestOnly()); + + // Maybe add the current test. + RunStyle runStyle = new MockRunStyle(); + GWTTestCase testCase = new MockGWTTestCase(); + MockCompileStrategy strategy = new MockCompileStrategy(1000); + try { + strategy.maybeCompileModuleImpl(testCase.getModuleName(), + testCase.getSyntheticModuleName(), testCase.getStrategy(), runStyle, + batchingStrategy, TreeLogger.NULL); + } catch (UnableToCompleteException e) { + fail("Unexpected UnableToCompleteException: " + e.getMessage()); + } + + // Verify the test block is added to the queue. + strategy.getMessageQueue().assertIsLastBlock(false); + strategy.getMessageQueue().assertTestBlocks( + batchingStrategy.getTestBlocks(testCase.getSyntheticModuleName())); + } +} ======================================= --- /branches/snapshot-2009.09.23-r6200/branch-info.txt Wed Sep 30 12:56:26 2009 +++ /branches/snapshot-2009.09.23-r6200/branch-info.txt Thu Oct 1 10:42:54 2009 @@ -7,4 +7,5 @@ Merges: /trunk/@6234:6235 was merged (r6236) into this branch -/trunk/@6264:6265 was merged (r????) into this branch +/trunk/@6264:6265 was merged (r6266) into this branch +/trunk/@6278:6279 was merged (r????) into this branch ======================================= --- /branches/snapshot-2009.09.23-r6200/user/src/com/google/gwt/junit/BatchingStrategy.java Wed Sep 30 12:56:26 2009 +++ /branches/snapshot-2009.09.23-r6200/user/src/com/google/gwt/junit/BatchingStrategy.java Thu Oct 1 10:42:54 2009 @@ -39,6 +39,21 @@ */ public abstract List<TestInfo[]> getTestBlocks(String syntheticModuleName); + /** + * Check if this batching strategy only supports execution of a single test at + * a time. + * + * If this method returns true, test methods will be executed on the client as + * they are run by JUnit. If it returns false, test methods will be batched + * and sent to the clients in groups. If you are using a test runner that + * shards test methods across multiple clients, you should use a strategy that + * returns false (such as {...@link NoBatchingStrategy}) or all tests will be + * executed on all clients. + * + * @return true if batches never contain more than one test + */ + public abstract boolean isSingleTestOnly(); + /** * Get the set of tests for this module, minus tests that should not be * executed. @@ -72,6 +87,11 @@ } return testBlocks; } + + @Override + public boolean isSingleTestOnly() { + return true; + } } /** @@ -105,6 +125,11 @@ } return testBlocks; } + + @Override + public boolean isSingleTestOnly() { + return false; + } } /** @@ -121,4 +146,9 @@ } return testBlocks; } -} + + @Override + public boolean isSingleTestOnly() { + return false; + } +} ======================================= --- /branches/snapshot-2009.09.23-r6200/user/src/com/google/gwt/junit/CompileStrategy.java Thu Sep 17 13:59:15 2009 +++ /branches/snapshot-2009.09.23-r6200/user/src/com/google/gwt/junit/CompileStrategy.java Thu Oct 1 10:42:54 2009 @@ -43,6 +43,23 @@ * adding test batches that have already been added. */ private Set<String> compiledModuleNames = new HashSet<String>(); + + /** + * Maybe add a test block for the currently executed test case. + * + * @param testCase the test case being run + * @param batchingStrategy the batching strategy + */ + public void maybeAddTestBlockForCurrentTest(GWTTestCase testCase, + BatchingStrategy batchingStrategy) { + if (batchingStrategy.isSingleTestOnly()) { + TestInfo testInfo = new TestInfo(testCase.getSyntheticModuleName(), + testCase.getClass().getName(), testCase.getName()); + List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>(1); + testBlocks.add(new TestInfo[] {testInfo}); + getMessageQueue().addTestBlocks(testBlocks, false); + } + } /** * Let the compile strategy compile another module. This is called while @@ -85,6 +102,57 @@ BatchingStrategy batchingStrategy, TreeLogger treeLogger) throws UnableToCompleteException { + // Let the runstyle compile the module. + ModuleDef moduleDef = maybeCompileModuleImpl2(moduleName, + syntheticModuleName, strategy, runStyle, treeLogger); + + // Add all test blocks for the module if we haven't seen this module before. + if (!compiledModuleNames.contains(syntheticModuleName)) { + compiledModuleNames.add(syntheticModuleName); + if (!batchingStrategy.isSingleTestOnly()) { + // Use >= so we can mock getModuleCount and force isFinalModule to true + boolean isFinalModule = compiledModuleNames.size() >= getModuleCount(); + List<TestInfo[]> testBlocks = batchingStrategy.getTestBlocks(syntheticModuleName); + getMessageQueue().addTestBlocks(testBlocks, isFinalModule); + } + } + + return moduleDef; + } + + /** + * Visible for testing and mocking. + * + * @return the {...@link JUnitMessageQueue} + */ + JUnitMessageQueue getMessageQueue() { + return JUnitShell.getMessageQueue(); + } + + /** + * Visible for testing and mocking. + * + * @return the number of modules to test + */ + int getModuleCount() { + return GWTTestCase.getModuleCount(); + } + + /** + * Let the {...@link RunStyle} compile the module if needed + * + * Visible for testing and mocking. + * + * @param moduleName the module name + * @param syntheticModuleName the synthetic module name + * @param strategy the strategy + * @param runStyle the run style + * @param treeLogger the logger + * @return the {...@link ModuleDef} describing the synthetic module + */ + ModuleDef maybeCompileModuleImpl2(String moduleName, + String syntheticModuleName, Strategy strategy, RunStyle runStyle, + TreeLogger treeLogger) throws UnableToCompleteException { /* * Synthesize a synthetic module that derives from the user-specified module * but also includes JUnit support. @@ -103,14 +171,6 @@ moduleNameProp.setValue(syntheticModuleName); runStyle.maybeCompileModule(syntheticModuleName); - - // Add all test blocks for the module if we haven't seen this module before. - if (!compiledModuleNames.contains(syntheticModuleName)) { - compiledModuleNames.add(syntheticModuleName); - boolean isFinalModule = compiledModuleNames.size() == GWTTestCase.getModuleCount(); - List<TestInfo[]> testBlocks = batchingStrategy.getTestBlocks(syntheticModuleName); - JUnitShell.getMessageQueue().addTestBlocks(testBlocks, isFinalModule); - } return moduleDef; } ======================================= --- /branches/snapshot-2009.09.23-r6200/user/src/com/google/gwt/junit/JUnitShell.java Wed Sep 30 12:56:26 2009 +++ /branches/snapshot-2009.09.23-r6200/user/src/com/google/gwt/junit/JUnitShell.java Thu Oct 1 10:42:54 2009 @@ -1005,6 +1005,7 @@ processTestResult(testCase, testResult, strategy); return; } + compileStrategy.maybeAddTestBlockForCurrentTest(testCase, batchingStrategy); try { if (firstLaunch) { ======================================= --- /branches/snapshot-2009.09.23-r6200/user/test/com/google/gwt/junit/BatchingStrategyTest.java Wed Sep 30 12:56:26 2009 +++ /branches/snapshot-2009.09.23-r6200/user/test/com/google/gwt/junit/BatchingStrategyTest.java Thu Oct 1 10:42:54 2009 @@ -79,22 +79,28 @@ FAKE_MODULE_SYNTHETIC_NAME, TestClass2.class.getName(), "testMethod5"); public void testClassBatchingStrategy() { + BatchingStrategy strategy = new ClassBatchingStrategy(); + assertFalse(strategy.isSingleTestOnly()); List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>(); testBlocks.add(new TestInfo[] {TEST_INFO_0_0, TEST_INFO_0_1}); testBlocks.add(new TestInfo[] {TEST_INFO_1_2, TEST_INFO_1_3, TEST_INFO_1_4}); testBlocks.add(new TestInfo[] {TEST_INFO_2_5}); - testBatchingStrategy(new ClassBatchingStrategy(), testBlocks); + testBatchingStrategy(strategy, testBlocks); } public void testModuleBatchingStrategy() { + BatchingStrategy strategy = new ModuleBatchingStrategy(); + assertFalse(strategy.isSingleTestOnly()); List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>(); testBlocks.add(new TestInfo[] { TEST_INFO_0_0, TEST_INFO_0_1, TEST_INFO_1_2, TEST_INFO_1_3, TEST_INFO_1_4, TEST_INFO_2_5}); - testBatchingStrategy(new ModuleBatchingStrategy(), testBlocks); + testBatchingStrategy(strategy, testBlocks); } public void testNoBatchingStrategy() { + BatchingStrategy strategy = new NoBatchingStrategy(); + assertTrue(strategy.isSingleTestOnly()); List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>(); testBlocks.add(new TestInfo[] {TEST_INFO_0_0}); testBlocks.add(new TestInfo[] {TEST_INFO_0_1}); @@ -102,7 +108,7 @@ testBlocks.add(new TestInfo[] {TEST_INFO_1_3}); testBlocks.add(new TestInfo[] {TEST_INFO_1_4}); testBlocks.add(new TestInfo[] {TEST_INFO_2_5}); - testBatchingStrategy(new NoBatchingStrategy(), testBlocks); + testBatchingStrategy(strategy, testBlocks); } /** ======================================= --- /branches/snapshot-2009.09.23-r6200/user/test/com/google/gwt/junit/JUnitSuite.java Wed Sep 30 12:56:26 2009 +++ /branches/snapshot-2009.09.23-r6200/user/test/com/google/gwt/junit/JUnitSuite.java Thu Oct 1 10:42:54 2009 @@ -25,7 +25,8 @@ */ public class JUnitSuite { public static Test suite() { - GWTTestSuite suite = new GWTTestSuite("Test for suite for com.google.gwt.junit"); + GWTTestSuite suite = new GWTTestSuite( + "Test for suite for com.google.gwt.junit"); // client // Suppressed due to flakiness on Linux @@ -34,6 +35,7 @@ // Must run after a GWTTestCase so JUnitShell is initialized. suite.addTestSuite(BatchingStrategyTest.class); + suite.addTestSuite(CompileStrategyTest.class); suite.addTestSuite(FakeMessagesMakerTest.class); suite.addTestSuite(JUnitMessageQueueTest.class); --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---
