JUnitShell now subclasses DevMode instead of GWTShell. GWTShell has been deprecated for a long time. We'd like to remove it. But first, we to reimplement JUnitShell to use DevMode instead of GWTShell. http://gwt-code-reviews.appspot.com/361801/show Review by: jlabanca,jat,spoon,fabbott,amitmanjhi git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7955 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/Compiler.java b/dev/core/src/com/google/gwt/dev/Compiler.java index 7024343..31d8286 100644 --- a/dev/core/src/com/google/gwt/dev/Compiler.java +++ b/dev/core/src/com/google/gwt/dev/Compiler.java
@@ -165,6 +165,16 @@ } public boolean run(TreeLogger logger) throws UnableToCompleteException { + ModuleDef[] modules = new ModuleDef[options.getModuleNames().size()]; + int i = 0; + for (String moduleName : options.getModuleNames()) { + modules[i++] = ModuleDefLoader.loadFromClassPath(logger, moduleName, true); + } + return run(logger, modules); + } + + public boolean run(TreeLogger logger, ModuleDef... modules) + throws UnableToCompleteException { PerfLogger.start("compile"); boolean tempWorkDir = false; try { @@ -176,10 +186,8 @@ options.setExtraDir(new File("extras")); } - for (String moduleName : options.getModuleNames()) { - ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, - moduleName, true); - + for (ModuleDef module : modules) { + String moduleName = module.getCanonicalName(); if (options.isValidateOnly()) { if (!Precompile.validate(logger, options, module, options.getGenDir(), options.getDumpSignatureFile())) {
diff --git a/dev/core/src/com/google/gwt/dev/DevMode.java b/dev/core/src/com/google/gwt/dev/DevMode.java index 4b1f0b0..5dda46e 100644 --- a/dev/core/src/com/google/gwt/dev/DevMode.java +++ b/dev/core/src/com/google/gwt/dev/DevMode.java
@@ -155,7 +155,10 @@ } } - static class ArgProcessor extends DevModeBase.ArgProcessor { + /** + * The argument processor. + */ + protected static class ArgProcessor extends DevModeBase.ArgProcessor { public ArgProcessor(HostedModeOptions options) { super(options, false); registerHandler(new ArgHandlerServer(options)); @@ -177,7 +180,11 @@ } } - interface HostedModeOptions extends HostedModeBaseOptions, CompilerOptions { + /** + * Options controlling dev mode. + */ + protected interface HostedModeOptions extends HostedModeBaseOptions, + CompilerOptions { ServletContainerLauncher getServletContainerLauncher(); String getServletContainerLauncherArgs(); @@ -190,11 +197,10 @@ /** * Concrete class to implement all hosted mode options. */ - static class HostedModeOptionsImpl extends HostedModeBaseOptionsImpl - implements HostedModeOptions { + protected static class HostedModeOptionsImpl extends + HostedModeBaseOptionsImpl implements HostedModeOptions { private File extraDir; private int localWorkers; - private File outDir; private ServletContainerLauncher scl; private String sclArgs; private File warDir; @@ -209,7 +215,7 @@ @Deprecated public File getOutDir() { - return outDir; + return warDir; } public ServletContainerLauncher getServletContainerLauncher() { @@ -234,7 +240,7 @@ @Deprecated public void setOutDir(File outDir) { - this.outDir = outDir; + this.warDir = outDir; } public void setServletContainerLauncher(ServletContainerLauncher scl) { @@ -300,7 +306,7 @@ /** * Default constructor for testing; no public API yet. */ - DevMode() { + protected DevMode() { } /**
diff --git a/dev/core/src/com/google/gwt/dev/DevModeBase.java b/dev/core/src/com/google/gwt/dev/DevModeBase.java index b7a9eb7..2d1f2a7 100644 --- a/dev/core/src/com/google/gwt/dev/DevModeBase.java +++ b/dev/core/src/com/google/gwt/dev/DevModeBase.java
@@ -62,7 +62,7 @@ * The main executable class for the hosted mode shell. This class must not have * any GUI dependencies. */ -abstract class DevModeBase implements DoneCallback { +public abstract class DevModeBase implements DoneCallback { /** * Implementation of BrowserWidgetHost that supports the abstract UI @@ -165,6 +165,9 @@ * Handles the -blacklist command line argument. */ protected static class ArgHandlerBlacklist extends ArgHandlerString { + public ArgHandlerBlacklist() { + } + @Override public String getPurpose() { return "Prevents the user browsing URLs that match the specified regexes (comma or space separated)"; @@ -343,6 +346,9 @@ } } + /** + * Handles the -remoteUI command line flag. + */ protected static class ArgHandlerRemoteUI extends ArgHandlerString { private final HostedModeBaseOptions options; @@ -407,6 +413,9 @@ * Handles the -whitelist command line flag. */ protected static class ArgHandlerWhitelist extends ArgHandlerString { + public ArgHandlerWhitelist() { + } + @Override public String getPurpose() { return "Allows the user to browse URLs that match the specified regexes (comma or space separated)"; @@ -428,6 +437,9 @@ } } + /** + * Base options for dev mode. + */ protected interface HostedModeBaseOptions extends JJSOptions, OptionLogDir, OptionLogLevel, OptionGenDir, OptionNoServer, OptionPort, OptionCodeServerPort, OptionStartupURLs, OptionRemoteUI, @@ -548,6 +560,9 @@ } } + /** + * Controls what local address to bind to. + */ protected interface OptionBindAddress { String getBindAddress(); @@ -558,6 +573,9 @@ void setConnectAddress(String connectAddress); } + /** + * Controls what port the code server listens on. + */ protected interface OptionCodeServerPort { int getCodeServerPort(); @@ -626,7 +644,10 @@ List<String> getStartupURLs(); } - abstract static class ArgProcessor extends ArgProcessorBase { + /** + * The base dev mode argument processor. + */ + protected abstract static class ArgProcessor extends ArgProcessorBase { public ArgProcessor(HostedModeBaseOptions options, boolean forceServer) { if (!forceServer) { registerHandler(new ArgHandlerNoServerFlag(options));
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java index 4663d23..3dedb92 100644 --- a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java +++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
@@ -533,8 +533,7 @@ server.addConnector(connector); // Create a new web app in the war directory. - WebAppContext wac = new WebAppContextWithReload(logger, - appRootDir.getAbsolutePath(), "/"); + WebAppContext wac = createWebAppContext(logger, appRootDir); RequestLogHandler logHandler = new RequestLogHandler(); logHandler.setRequestLog(new JettyRequestLogger(logger, getBaseLogLevel())); @@ -546,8 +545,18 @@ // Now that we're started, log to the top level logger. Log.setLog(new JettyTreeLogger(logger)); - return new JettyServletContainer(logger, server, wac, - connector.getLocalPort(), appRootDir); + return createServletContainer(logger, appRootDir, server, wac, + connector.getLocalPort()); + } + + protected JettyServletContainer createServletContainer(TreeLogger logger, + File appRootDir, Server server, WebAppContext wac, int localPort) { + return new JettyServletContainer(logger, server, wac, localPort, appRootDir); + } + + protected WebAppContext createWebAppContext(TreeLogger logger, File appRootDir) { + return new WebAppContextWithReload(logger, appRootDir.getAbsolutePath(), + "/"); } protected AbstractConnector getConnector() {
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWarDir.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWarDir.java index 5077850..1f14f90 100644 --- a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWarDir.java +++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWarDir.java
@@ -22,7 +22,7 @@ /** * Argument handler for processing the output directory flag. */ -public final class ArgHandlerWarDir extends ArgHandlerDir { +public class ArgHandlerWarDir extends ArgHandlerDir { private final OptionWarDir option;
diff --git a/eclipse/user/.classpath b/eclipse/user/.classpath index 9f5fd37..0765257 100644 --- a/eclipse/user/.classpath +++ b/eclipse/user/.classpath
@@ -31,5 +31,6 @@ <classpathentry combineaccessrules="false" kind="src" path="/gwt-dev"/> <classpathentry kind="var" path="GWT_TOOLS/lib/htmlunit/htmlunit-r5607/htmlunit-r5607.jar" sourcepath="/GWT_TOOLS/lib/htmlunit/htmlunit-r5607/htmlunit-r5607-sources.jar"/> <classpathentry kind="var" path="GWT_TOOLS/lib/htmlunit/htmlunit-r5607/htmlunit-core-js-r5607.jar" sourcepath="/GWT_TOOLS/lib/htmlunit/htmlunit-r5607/htmlunit-core-js-r5607-sources.jar"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/jetty/jetty-6.1.11.jar" sourcepath="/GWT_TOOLS/lib/jetty/jetty-6.1.11-src.zip"/> <classpathentry kind="output" path="bin"/> </classpath>
diff --git a/user/build.xml b/user/build.xml index 8af9a42..cac355b 100755 --- a/user/build.xml +++ b/user/build.xml
@@ -36,13 +36,6 @@ <property name="test.args.web.selenium" value="${test.args}" /> <!-- - Only IFrameLinker actually supports -noserver mode; run the other linker - tests if and when they are supported - --> - <property name="gwt.junit.testcase.noserver.includes" value="**/IFrameLinkerTest.class" /> - <property name="gwt.junit.testcase.noserver.excludes" value="" /> - - <!-- Whether I18NSuite should test e.g. Foo$InnerMsgs_fr.properties (if the value is "dollar") or Foo_Inner_fr.properties (for "bar") --> @@ -394,22 +387,6 @@ <echo message="DEPRECATED: test.hosted has been renamed test.dev"/> </target> - <target name="test.noserver" - depends="compile, compile.tests" - description="Run noserver tests for this project." - unless="test.noserver.disable"> - <fileset id="test.noserver.tests" dir="${javac.junit.out}" - includes="${gwt.junit.testcase.noserver.includes}" - excludes="${gwt.junit.testcase.noserver.excludes}" /> - <gwt.junit test.name="test.noserver" - test.args="${test.args} -prod -standardsMode -noserver" - test.out="${junit.out}/noserver" test.cases="test.noserver.tests"> - <extraclasspaths> - <path refid="test.extraclasspath" /> - </extraclasspaths> - </gwt.junit> - </target> - <target name="test.web.htmlunit" depends="compile, compile.tests" description="Run web-mode tests with HtmlUnit." @@ -489,7 +466,6 @@ <antcall target="test.web.selenium"/> <antcall target="test.draft.selenium"/> <antcall target="test.nometa.selenium"/> - <antcall target="test.noserver"/> <antcall target="test.dev.htmlunit"/> <antcall target="test.emma.htmlunit"/> <antcall target="test.web.htmlunit"/> @@ -516,7 +492,6 @@ <antcall target="test.web.htmlunit"/> <antcall target="test.draft.htmlunit"/> <antcall target="test.nometa.htmlunit"/> - <antcall target="test.noserver"/> </parallel> </limit> </target>
diff --git a/user/src/com/google/gwt/junit/CompileStrategy.java b/user/src/com/google/gwt/junit/CompileStrategy.java index b6917b7..cc62ecd 100644 --- a/user/src/com/google/gwt/junit/CompileStrategy.java +++ b/user/src/com/google/gwt/junit/CompileStrategy.java
@@ -181,7 +181,7 @@ strategy.processModule(moduleDef); - junitShell.maybeCompileForWebMode(syntheticModuleName, + junitShell.maybeCompileForWebMode(moduleDef, JUnitShell.getRemoteUserAgents()); return moduleDef;
diff --git a/user/src/com/google/gwt/junit/JUnit.gwt.xml b/user/src/com/google/gwt/junit/JUnit.gwt.xml index 8963a34..c2ae43c 100644 --- a/user/src/com/google/gwt/junit/JUnit.gwt.xml +++ b/user/src/com/google/gwt/junit/JUnit.gwt.xml
@@ -38,7 +38,7 @@ <!-- Override the regular symbolMaps linker to put the data somewhere we can find it --> <define-linker name="symbolMaps" class="com.google.gwt.junit.linker.JUnitSymbolMapsLinker" /> - <servlet path='/junithost' class='com.google.gwt.junit.server.JUnitHostImpl'/> + <servlet path='/junithost/*' class='com.google.gwt.junit.server.JUnitHostImpl'/> <inherits name="com.google.gwt.benchmarks.Benchmarks"/>
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java index 4c0e927..3633eba 100644 --- a/user/src/com/google/gwt/junit/JUnitShell.java +++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -20,26 +20,31 @@ import com.google.gwt.core.ext.TreeLogger.Type; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.TypeOracle; -import com.google.gwt.dev.GWTCompiler; -import com.google.gwt.dev.GWTShell; -import com.google.gwt.dev.LegacyCompilerOptions; -import com.google.gwt.dev.GWTCompiler.GWTCompilerOptionsImpl; +import com.google.gwt.dev.ArgProcessorBase; +import com.google.gwt.dev.Compiler; +import com.google.gwt.dev.DevMode; import com.google.gwt.dev.cfg.BindingProperty; import com.google.gwt.dev.cfg.ModuleDef; -import com.google.gwt.dev.cfg.ModuleDefLoader; import com.google.gwt.dev.cfg.Properties; import com.google.gwt.dev.cfg.Property; import com.google.gwt.dev.javac.CompilationState; import com.google.gwt.dev.javac.CompilationUnit; import com.google.gwt.dev.shell.CheckForUpdates; +import com.google.gwt.dev.shell.jetty.JettyLauncher; import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization; import com.google.gwt.dev.util.arg.ArgHandlerDisableCastChecking; import com.google.gwt.dev.util.arg.ArgHandlerDisableClassMetadata; +import com.google.gwt.dev.util.arg.ArgHandlerDisableRunAsync; import com.google.gwt.dev.util.arg.ArgHandlerDraftCompile; import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions; +import com.google.gwt.dev.util.arg.ArgHandlerExtraDir; +import com.google.gwt.dev.util.arg.ArgHandlerGenDir; import com.google.gwt.dev.util.arg.ArgHandlerLocalWorkers; import com.google.gwt.dev.util.arg.ArgHandlerLogLevel; +import com.google.gwt.dev.util.arg.ArgHandlerMaxPermsPerPrecompile; import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle; +import com.google.gwt.dev.util.arg.ArgHandlerWarDir; +import com.google.gwt.dev.util.arg.ArgHandlerWorkDirOptional; import com.google.gwt.junit.JUnitMessageQueue.ClientStatus; import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.junit.client.TimeoutException; @@ -53,6 +58,10 @@ import junit.framework.TestCase; import junit.framework.TestResult; +import org.mortbay.jetty.Server; +import org.mortbay.jetty.webapp.WebAppContext; + +import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -61,6 +70,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; +import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.Map.Entry; @@ -96,8 +106,7 @@ * {@link JUnitMessageQueue}, thus closing the loop. * </p> */ -@SuppressWarnings("deprecation") -public class JUnitShell extends GWTShell { +public class JUnitShell extends DevMode { /** * A strategy for running the test. @@ -112,54 +121,73 @@ void processResult(TestCase testCase, JUnitResult result); } - class ArgProcessor extends GWTShell.ArgProcessor { + class ArgProcessor extends ArgProcessorBase { + @SuppressWarnings("deprecation") public ArgProcessor() { - super(options, true, true); + /* + * ----- Options from DevModeBase ------- + */ + // DISABLE: ArgHandlerNoServerFlag. + registerHandler(new ArgHandlerPort(options) { + @Override + public String[] getDefaultArgs() { + // Override port to auto by default. + return new String[]{"-port", "auto"}; + } + }); + registerHandler(new ArgHandlerWhitelist()); + registerHandler(new ArgHandlerBlacklist()); + registerHandler(new ArgHandlerLogDir(options)); + registerHandler(new ArgHandlerLogLevel(options)); + registerHandler(new ArgHandlerGenDir(options)); + // DISABLE: ArgHandlerBindAddress. + registerHandler(new ArgHandlerCodeServerPort(options) { + @Override + public String[] getDefaultArgs() { + // Override code server port to auto by default. + return new String[]{this.getTag(), "auto"}; + } + }); + // DISABLE: ArgHandlerRemoteUI. + + /* + * ----- Options from DevMode ------- + */ + // Hard code the server. + options.setServletContainerLauncher(new MyJettyLauncher()); + // DISABLE: ArgHandlerStartupURLs + registerHandler(new com.google.gwt.dev.ArgHandlerOutDirDeprecated(options)); + registerHandler(new ArgHandlerWarDir(options) { + @Override + public String[] getDefaultArgs() { + // If an outDir was already specified, don't clobber it. + if (options.getOutDir() != null) { + return null; + } + return super.getDefaultArgs(); + } + }); + registerHandler(new ArgHandlerExtraDir(options)); + registerHandler(new ArgHandlerWorkDirOptional(options)); + // DISABLE: ArgHandlerModuleName + + /* + * ----- Additional options from Compiler not already included ------- + */ registerHandler(new ArgHandlerScriptStyle(options)); registerHandler(new ArgHandlerEnableAssertions(options)); registerHandler(new ArgHandlerDisableAggressiveOptimization(options)); registerHandler(new ArgHandlerDisableClassMetadata(options)); registerHandler(new ArgHandlerDisableCastChecking(options)); + registerHandler(new ArgHandlerDisableRunAsync(options)); registerHandler(new ArgHandlerDraftCompile(options)); + registerHandler(new ArgHandlerMaxPermsPerPrecompile(options)); registerHandler(new ArgHandlerLocalWorkers(options)); - // Override port to set auto by default. - registerHandler(new ArgHandlerPort(options) { - @Override - public String[] getDefaultArgs() { - return new String[]{"-port", "auto"}; - } - }); - - // Override port to set auto by default. - registerHandler(new ArgHandlerCodeServerPort(options) { - @Override - public String[] getDefaultArgs() { - return new String[]{this.getTag(), "auto"}; - } - }); - - // Disable -bindAddress, fail if it is given - // TODO(jat): support -bindAddress in JUnitShell, which will probably - // require changes to the RunStyle API. - registerHandler(new ArgHandlerBindAddress(options) { - @Override - public String[] getDefaultArgs() { - return null; - } - - @Override - public boolean isUndocumented() { - return true; - } - - @Override - public boolean setString(String value) { - System.err.println("-bindAddress is not supported for JUnitShell"); - return false; - } - }); + /* + * ----- Options specific to JUnitShell ----- + */ // Override log level to set WARN by default.. registerHandler(new ArgHandlerLogLevel(options) { @@ -172,24 +200,6 @@ registerHandler(new ArgHandlerFlag() { @Override public String getPurpose() { - return "Causes your test to run in -noserver development mode (defaults to development mode)"; - } - - @Override - public String getTag() { - return "-noserver"; - } - - @Override - public boolean setFlag() { - shouldAutoGenerateResources = false; - return true; - } - }); - - registerHandler(new ArgHandlerFlag() { - @Override - public String getPurpose() { return "Synonym for -prod (deprecated)"; } @@ -374,7 +384,7 @@ @Override public boolean setFlag() { - setHeadlessAccessor(false); + JUnitShell.this.setHeadless(false); return true; } }); @@ -492,6 +502,49 @@ } }); } + + @Override + protected String getName() { + return JUnitShell.class.getName(); + } + } + + private final class MyJettyLauncher extends JettyLauncher { + + /** + * Adds in special JUnit stuff. + */ + @Override + protected JettyServletContainer createServletContainer(TreeLogger logger, + File appRootDir, Server server, WebAppContext wac, int localPort) { + // Don't bother shutting down cleanly. + server.setStopAtShutdown(false); + // Save off the Context so we can add our own servlets later. + JUnitShell.this.wac = wac; + return super.createServletContainer(logger, appRootDir, server, wac, + localPort); + } + + /** + * Ignore DevMode's normal WEB-INF classloader rules and just allow the + * system classloader to dominate. This makes JUnitHostImpl live in the + * right classloader (mine). + */ + @SuppressWarnings("unchecked") + @Override + protected WebAppContext createWebAppContext(TreeLogger logger, + File appRootDir) { + return new WebAppContext(appRootDir.getAbsolutePath(), "/") { + { + // Prevent file locking on Windows; pick up file changes. + getInitParams().put( + "org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false"); + + // Prefer the parent class loader so that JUnit works. + setParentLoaderPriority(true); + } + }; + } } /** @@ -597,6 +650,39 @@ } /** + * Retrieves the JUnitShell. This should only be invoked during TestRunner + * execution of JUnit tests. + */ + static JUnitShell getUnitTestShell() { + if (unitTestShell == null) { + unitTestShell = new JUnitShell(); + unitTestShell.lastLaunchFailed = true; + String[] args = unitTestShell.synthesizeArgs(); + ArgProcessor argProcessor = unitTestShell.new ArgProcessor(); + if (!argProcessor.processArgs(args)) { + throw new JUnitFatalLaunchException("Error processing shell arguments"); + } + // Always bind to the wildcard address and substitute the host address in + // URLs. Note that connectAddress isn't actually used here, as we + // override it from the runsStyle in getModuleUrl, but we set it to match + // what will actually be used anyway to avoid confusion. + unitTestShell.options.setBindAddress("0.0.0.0"); + try { + unitTestShell.options.setConnectAddress(InetAddress.getLocalHost().getHostAddress()); + } catch (UnknownHostException e) { + throw new JUnitFatalLaunchException("Unable to resolve my address"); + } + if (!unitTestShell.startUp()) { + throw new JUnitFatalLaunchException("Shell failed to start"); + } + // TODO: install a shutdown hook? Not necessary with GWTShell. + unitTestShell.lastLaunchFailed = false; + } + unitTestShell.checkArgs(); + return unitTestShell; + } + + /** * Sanity check; if the type we're trying to run did not actually wind up in * the type oracle, there's no way this test can possibly run. Bail early * instead of failing on the client. @@ -660,37 +746,9 @@ } /** - * Retrieves the JUnitShell. This should only be invoked during TestRunner - * execution of JUnit tests. + * Our server's web app context; used to dynamically add servlets. */ - private static JUnitShell getUnitTestShell() { - if (unitTestShell == null) { - unitTestShell = new JUnitShell(); - unitTestShell.lastLaunchFailed = true; - String[] args = unitTestShell.synthesizeArgs(); - ArgProcessor argProcessor = unitTestShell.new ArgProcessor(); - if (!argProcessor.processArgs(args)) { - throw new JUnitFatalLaunchException("Error processing shell arguments"); - } - // Always bind to the wildcard address and substitute the host address in - // URLs. Note that connectAddress isn't actually used here, as we - // override it from the runsStyle in getModuleUrl, but we set it to match - // what will actually be used anyway to avoid confusion. - unitTestShell.options.setBindAddress("0.0.0.0"); - try { - unitTestShell.options.setConnectAddress(InetAddress.getLocalHost().getHostAddress()); - } catch (UnknownHostException e) { - throw new JUnitFatalLaunchException("Unable to resolve my address"); - } - if (!unitTestShell.startUp()) { - throw new JUnitFatalLaunchException("Shell failed to start"); - } - // TODO: install a shutdown hook? Not necessary with GWTShell. - unitTestShell.lastLaunchFailed = false; - } - unitTestShell.checkArgs(); - return unitTestShell; - } + WebAppContext wac; /** * The amount of time to wait for all clients to have contacted the server and @@ -758,6 +816,11 @@ private ModuleDef lastModule; /** + * Records what servlets have been loaded at which paths. + */ + private final Map<String, String> loadedServletsByPath = new HashMap<String, String>(); + + /** * Portal to interact with the servlet. */ private JUnitMessageQueue messageQueue; @@ -785,8 +848,6 @@ */ private String runStyleName = "HtmlUnit"; - private boolean shouldAutoGenerateResources = true; - private boolean standardsMode = false; /** @@ -987,20 +1048,12 @@ } @Override - protected boolean shouldAutoGenerateResources() { - return shouldAutoGenerateResources; - } - - @Override protected void warnAboutNoStartupUrls() { // do nothing -- JUnitShell isn't expected to have startup URLs } - void compileForWebMode(String moduleName, String... userAgents) + void compileForWebMode(ModuleDef module, String... userAgents) throws UnableToCompleteException { - // Never fresh during JUnit. - ModuleDef module = ModuleDefLoader.loadFromClassPath(getTopLogger(), - moduleName, false); if (userAgents != null && userAgents.length > 0) { Properties props = module.getProperties(); Property userAgent = props.find("user.agent"); @@ -1010,28 +1063,36 @@ userAgents); } } - LegacyCompilerOptions newOptions = new GWTCompilerOptionsImpl(options); - if (!new GWTCompiler(newOptions).run(getTopLogger(), module)) { + if (!new Compiler(options).run(getTopLogger(), module)) { throw new UnableToCompleteException(); } // TODO(scottb): prepopulate currentCompilationState somehow? } - void maybeCompileForWebMode(String moduleName, String... userAgents) + void maybeCompileForWebMode(ModuleDef module, String... userAgents) throws UnableToCompleteException { - if (!developmentMode || !shouldAutoGenerateResources) { - compileForWebMode(moduleName, userAgents); + // Load any declared servlets. + for (String path : module.getServletPaths()) { + String servletClass = module.findServletForPath(path); + path = '/' + module.getName() + path; + if (!servletClass.equals(loadedServletsByPath.get(path))) { + try { + wac.addServlet(servletClass, path); + loadedServletsByPath.put(path, servletClass); + } catch (RuntimeException alreadyLoggedByJetty) { + } + } } - } - - /** - * Accessor method to DevModeBase.setHeadless -- without this, we get - * IllegalAccessError from the -notHeadless arg handler. Compiler bug? - * - * @param headlessMode - */ - void setHeadlessAccessor(boolean headlessMode) { - setHeadless(headlessMode); + if (developmentMode) { + // BACKWARDS COMPATIBILITY: most linkers currently fail in dev mode. + if (module.getLinker("std") != null) { + // TODO: unfortunately, this could be race condition between dev/prod + module.addLinker("std"); + } + super.link(getTopLogger(), module); + } else { + compileForWebMode(module, userAgents); + } } /**
diff --git a/user/src/com/google/gwt/junit/server/JUnitHostImpl.java b/user/src/com/google/gwt/junit/server/JUnitHostImpl.java index 958d05a..1915918 100644 --- a/user/src/com/google/gwt/junit/server/JUnitHostImpl.java +++ b/user/src/com/google/gwt/junit/server/JUnitHostImpl.java
@@ -111,10 +111,11 @@ public InitialResponse getTestBlock(int blockIndex, ClientInfo clientInfo) throws TimeoutException { ClientInfoExt clientInfoExt; + HttpServletRequest request = getThreadLocalRequest(); if (clientInfo.getSessionId() < 0) { - clientInfoExt = createNewClientInfo(clientInfo.getUserAgent()); + clientInfoExt = createNewClientInfo(clientInfo.getUserAgent(), request); } else { - clientInfoExt = createClientInfo(clientInfo); + clientInfoExt = createClientInfo(clientInfo, request); } TestBlock initialTestBlock = getHost().getTestBlock(clientInfoExt, blockIndex, TIME_TO_WAIT_FOR_TESTNAME); @@ -131,7 +132,8 @@ result.setException(deserialize(ew)); } JUnitMessageQueue host = getHost(); - ClientInfoExt clientInfoExt = createClientInfo(clientInfo); + ClientInfoExt clientInfoExt = createClientInfo(clientInfo, + getThreadLocalRequest()); host.reportResults(clientInfoExt, results); return host.getTestBlock(clientInfoExt, testBlock, TIME_TO_WAIT_FOR_TESTNAME); @@ -146,21 +148,23 @@ JUnitResult result = new JUnitResult(); initResult(request, result); result.setException(new JUnitFatalLaunchException(requestPayload)); - getHost().reportFatalLaunch(createNewClientInfo(null), result); + getHost().reportFatalLaunch(createNewClientInfo(null, request), result); } else { super.service(request, response); } } - private ClientInfoExt createClientInfo(ClientInfo clientInfo) { + private ClientInfoExt createClientInfo(ClientInfo clientInfo, + HttpServletRequest request) { assert (clientInfo.getSessionId() >= 0); return new ClientInfoExt(clientInfo.getSessionId(), - clientInfo.getUserAgent(), getClientDesc(getThreadLocalRequest())); + clientInfo.getUserAgent(), getClientDesc(request)); } - private ClientInfoExt createNewClientInfo(String userAgent) { + private ClientInfoExt createNewClientInfo(String userAgent, + HttpServletRequest request) { return new ClientInfoExt(createSessionId(), userAgent, - getClientDesc(getThreadLocalRequest())); + getClientDesc(request)); } private int createSessionId() { @@ -346,12 +350,12 @@ JsniRef ref = JsniRef.parse(parts[0].substring(0, parts[0].lastIndexOf(')') + 1)); - toReturn = new Object[] { + toReturn = new Object[]{ ref.className(), ref.memberName(), stw.fileName, stw.lineNumber}; } else { // Use the raw data from the client - toReturn = new Object[] { + toReturn = new Object[]{ stw.className, stw.methodName, stw.fileName, stw.lineNumber}; } return toReturn;
diff --git a/user/test-super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/DevModeOnCompiledScriptTest.java b/user/test-super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/DevModeOnCompiledScriptTest.java new file mode 100644 index 0000000..ffdda16 --- /dev/null +++ b/user/test-super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/DevModeOnCompiledScriptTest.java
@@ -0,0 +1,37 @@ +/* + * Copyright 2010 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.client; + +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.Platform; + +import junit.framework.TestCase; + +/** + * Translatable trivial implementation. + */ +@DoNotRunWith(Platform.Prod) +public class DevModeOnCompiledScriptTest extends GWTTestCase { + + @Override + public String getModuleName() { + return "com.google.gwt.junit.DevModeWithCompiledScriptTest"; + } + + public void testSomethingTrivial() { + assertTrue(true); + } +}
diff --git a/user/test/com/google/gwt/core/ext/test/XSLinkerTest.java b/user/test/com/google/gwt/core/ext/test/XSLinkerTest.java index 9b9d019..64da6cd 100644 --- a/user/test/com/google/gwt/core/ext/test/XSLinkerTest.java +++ b/user/test/com/google/gwt/core/ext/test/XSLinkerTest.java
@@ -15,9 +15,13 @@ */ package com.google.gwt.core.ext.test; +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.Platform; + /** * Tests the cross-site linker. */ +@DoNotRunWith(Platform.Devel) public class XSLinkerTest extends LinkerTest { @Override public String getModuleName() {
diff --git a/user/test/com/google/gwt/dev/jjs/RunAsyncFailure.gwt.xml b/user/test/com/google/gwt/dev/jjs/RunAsyncFailure.gwt.xml index 9e5ae07..0fa0e34 100644 --- a/user/test/com/google/gwt/dev/jjs/RunAsyncFailure.gwt.xml +++ b/user/test/com/google/gwt/dev/jjs/RunAsyncFailure.gwt.xml
@@ -15,7 +15,7 @@ <module> <inherits name="com.google.gwt.core.Core" /> <source path="test" /> - <servlet path="/runAsyncFailure" + <servlet path="/runAsyncFailure/*" class="com.google.gwt.user.server.runasync.RunAsyncFailureServlet" /> <set-configuration-property name="iframe.linker.deferredjs.subdir" value="runAsyncFailure/deferredjs" />
diff --git a/user/test/com/google/gwt/http/RequestBuilderTest.gwt.xml b/user/test/com/google/gwt/http/RequestBuilderTest.gwt.xml index 0a5e76f..9e01f79 100644 --- a/user/test/com/google/gwt/http/RequestBuilderTest.gwt.xml +++ b/user/test/com/google/gwt/http/RequestBuilderTest.gwt.xml
@@ -15,6 +15,6 @@ <module> <inherits name='com.google.gwt.user.User' /> - <servlet path='/testRequestBuilder' + <servlet path='/testRequestBuilder/*' class='com.google.gwt.http.server.RequestBuilderTestServlet' /> </module>
diff --git a/user/test/com/google/gwt/http/ResponseTest.gwt.xml b/user/test/com/google/gwt/http/ResponseTest.gwt.xml index e3c0479..55735ff 100644 --- a/user/test/com/google/gwt/http/ResponseTest.gwt.xml +++ b/user/test/com/google/gwt/http/ResponseTest.gwt.xml
@@ -15,6 +15,6 @@ <module> <inherits name='com.google.gwt.user.User' /> - <servlet path='/testResponse' + <servlet path='/testResponse/*' class='com.google.gwt.http.server.ResponseTestServlet' /> </module>
diff --git a/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java b/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java index e07692b..abfef22 100644 --- a/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java +++ b/user/test/com/google/gwt/http/server/RequestBuilderTestServlet.java
@@ -30,10 +30,6 @@ */ public class RequestBuilderTestServlet extends HttpServlet { - private static String getPathInfoBase() { - return "/com.google.gwt.http.RequestBuilderTest.JUnit/testRequestBuilder/"; - } - @Override protected void doDelete(HttpServletRequest request, HttpServletResponse response) { @@ -49,7 +45,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { String pathInfo = request.getPathInfo(); - if (pathInfo.equals(getPathInfoBase() + "setRequestHeader")) { + if (pathInfo.equals("/setRequestHeader")) { String value = request.getHeader("Foo"); if (value.equals("Bar1")) { response.setStatus(HttpServletResponse.SC_OK); @@ -57,13 +53,13 @@ } else { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); } - } else if (pathInfo.equals(getPathInfoBase() + "send_GET")) { + } else if (pathInfo.equals("/send_GET")) { response.setStatus(HttpServletResponse.SC_OK); response.getWriter().write(RequestBuilderTest.SERVLET_GET_RESPONSE); - } else if (pathInfo.equals(getPathInfoBase() + "sendRequest_GET")) { + } else if (pathInfo.equals("/sendRequest_GET")) { response.setStatus(HttpServletResponse.SC_OK); response.getWriter().write(RequestBuilderTest.SERVLET_GET_RESPONSE); - } else if (pathInfo.equals(getPathInfoBase() + "setTimeout/timeout")) { + } else if (pathInfo.equals("/setTimeout/timeout")) { // cause a timeout on the client try { Thread.sleep(5000); @@ -71,7 +67,7 @@ } response.setStatus(HttpServletResponse.SC_OK); response.getWriter().print(RequestBuilderTest.SERVLET_GET_RESPONSE); - } else if (pathInfo.equals(getPathInfoBase() + "setTimeout/noTimeout")) { + } else if (pathInfo.equals("/setTimeout/noTimeout")) { // wait but not long enough to timeout try { Thread.sleep(1000); @@ -79,7 +75,7 @@ } response.setStatus(HttpServletResponse.SC_OK); response.getWriter().print(RequestBuilderTest.SERVLET_GET_RESPONSE); - } else if (pathInfo.equals(getPathInfoBase() + "user/pass")) { + } else if (pathInfo.equals("/user/pass")) { String auth = request.getHeader("Authorization"); if (auth == null) { response.setHeader("WWW-Authenticate", "BASIC"); @@ -111,7 +107,7 @@ */ response.getWriter().print(RequestBuilderTest.SERVLET_POST_RESPONSE); response.setStatus(HttpServletResponse.SC_OK); - } else if (request.getPathInfo().equals(getPathInfoBase() + "simplePost")) { + } else if (request.getPathInfo().equals("/simplePost")) { response.getWriter().print(RequestBuilderTest.SERVLET_POST_RESPONSE); response.setStatus(HttpServletResponse.SC_OK); } else {
diff --git a/user/test/com/google/gwt/junit/DevModeOnCompiledScriptTest.gwt.xml b/user/test/com/google/gwt/junit/DevModeOnCompiledScriptTest.gwt.xml new file mode 100644 index 0000000..02929e7 --- /dev/null +++ b/user/test/com/google/gwt/junit/DevModeOnCompiledScriptTest.gwt.xml
@@ -0,0 +1,17 @@ +<!-- --> +<!-- Copyright 2008 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 --> +<!-- 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. License for the specific language governing permissions and --> +<!-- limitations under the License. --> + +<module> + <inherits name='com.google.gwt.junit.JUnitTest' /> +</module>
diff --git a/user/test/com/google/gwt/junit/JUnitBridge.java b/user/test/com/google/gwt/junit/JUnitBridge.java new file mode 100644 index 0000000..cb69546 --- /dev/null +++ b/user/test/com/google/gwt/junit/JUnitBridge.java
@@ -0,0 +1,31 @@ +/* + * Copyright 2010 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.UnableToCompleteException; +import com.google.gwt.dev.cfg.ModuleDef; + +/** + * Provides access to {@link JUnitShell}. + */ +public class JUnitBridge { + public static void compileForWebMode(ModuleDef module) + throws UnableToCompleteException { + JUnitShell.getUnitTestShell().compileForWebMode(module, + JUnitShell.getRemoteUserAgents()); + } + +}
diff --git a/user/test/com/google/gwt/junit/JUnitSuite.java b/user/test/com/google/gwt/junit/JUnitSuite.java index 79833e1..4a198cd 100644 --- a/user/test/com/google/gwt/junit/JUnitSuite.java +++ b/user/test/com/google/gwt/junit/JUnitSuite.java
@@ -15,6 +15,7 @@ */ package com.google.gwt.junit; +import com.google.gwt.junit.client.DevModeOnCompiledScriptTest; import com.google.gwt.junit.client.GWTTestCaseTest; import com.google.gwt.junit.client.PropertyDefiningGWTTest; import com.google.gwt.junit.tools.GWTTestSuite; @@ -33,6 +34,7 @@ // Suppressed due to flakiness on Linux // suite.addTestSuite(BenchmarkTest.class); suite.addTestSuite(GWTTestCaseTest.class); + suite.addTestSuite(DevModeOnCompiledScriptTest.class); // Must run after a GWTTestCase so JUnitShell is initialized. suite.addTestSuite(BatchingStrategyTest.class);
diff --git a/user/test/com/google/gwt/junit/client/DevModeOnCompiledScriptTest.java b/user/test/com/google/gwt/junit/client/DevModeOnCompiledScriptTest.java new file mode 100644 index 0000000..f9aefe8 --- /dev/null +++ b/user/test/com/google/gwt/junit/client/DevModeOnCompiledScriptTest.java
@@ -0,0 +1,75 @@ +/* + * Copyright 2010 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.client; + +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.dev.cfg.ModuleDef; +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.JUnitBridge; +import com.google.gwt.junit.Platform; +import com.google.gwt.junit.JUnitShell.Strategy; +import com.google.gwt.junit.client.impl.JUnitResult; + +import junit.framework.TestCase; + +/** + * Tests that we can run a test in dev mode even when the selection script is + * from a compile. Note that this is the VM-only version of the class; there is + * a translatable version for the client side. + */ +@DoNotRunWith(Platform.Prod) +public class DevModeOnCompiledScriptTest extends GWTTestCase { + + @Override + public String getModuleName() { + return "com.google.gwt.junit.DevModeOnCompiledScriptTest"; + } + + /** + * GWT-unfriendly, forcing us to use a translatable class. + */ + @Override + public Strategy getStrategy() { + final Strategy impl = super.getStrategy(); + return new Strategy() { + public String getModuleInherit() { + return impl.getModuleInherit(); + } + + public String getSyntheticModuleExtension() { + return impl.getSyntheticModuleExtension(); + } + + public void processModule(ModuleDef module) { + impl.processModule(module); + try { + JUnitBridge.compileForWebMode(module); + } catch (UnableToCompleteException e) { + throw new RuntimeException("Failed to manually compile test module", + e); + } + } + + public void processResult(TestCase testCase, JUnitResult result) { + impl.processResult(testCase, result); + } + }; + } + + public void testSomethingTrivial() { + assertTrue(true); + } +}