diff --git a/test/pom.xml b/test/pom.xml index a5014fac9c5033fee83c812c45c3a1eab809d934..6091a9222e47b0d13e9c8d9944e7454d3264a8e4 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -64,6 +64,16 @@ THE SOFTWARE. ${project.groupId} maven-plugin ${maven-plugin.version} + + + org.apache.httpcomponents + httpclient + + + org.apache.httpcomponents + httpcore + + org.jenkins-ci.plugins @@ -127,16 +137,9 @@ THE SOFTWARE. 1.3 - org.jenkins-ci + net.sourceforge.htmlunit htmlunit - 2.6-jenkins-6 - - - - xml-apis - xml-apis - - + 2.18 xalan diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/README.md b/test/src/main/java/com/gargoylesoftware/htmlunit/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5aadb8e2936ffe191c82c4ce9513577e17b92fa4 --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/README.md @@ -0,0 +1,39 @@ +# Overview +Jenkins used to maintain a forked version of HtmlUnit and use it via `JenkinsRule` (and `HudsonTestCase`). Moving +away from the forked version has allowed Jenkins GUI to start using more modern JavaScript libraries than were +possible through the forked version. + +Moving away from the forked version also means that some tests in plugins may no longer compile due to the +fact that they were using some methods that were added to the fork, but not available in the mainstream HtmlUnit. +To help with that, the test harness now provides static utilities for all of this functionality. + +# WebClientUtil +The `WebClientUtil` class provides static utilities for interacting asynchronously with HtmlUnit's `WebClient`, +supporting `waitForJSExec` calls to allow your test code wait for background (asynchronous) JavaScript code to complete +before the test continues. Calling these methods are not required in many cases as they are called for you from +other static utilities (e.g. `HtmlFormUtil.submit`), but sometimes it is required to call them directly. + +Because HtmlUnit executes JavaScript asynchronously, it's usually not possible to block and catch exceptions. For +that reason, `WebClientUtil` provides the `addExceptionListener` utility as a way of registering an exception listener. +This typically needs to be used in conjunction with the `waitForJSExec` method e.g. + +```java +WebClient webClient = jenkinsRule.createWebClient(); +WebClientUtil.ExceptionListener exceptionListener = WebClientUtil.addExceptionListener(webClient); + +// Interact with Jenkins UI as normal in a test... + +// Make sure all background JavaScript has completed so as expected exceptions have been thrown. +WebClientUtil.waitForJSExec(webClient); + +// Now we can check for exceptions etc... +exceptionListener.assertHasException(); +ScriptException e = exceptionListener.getScriptException(); +Assert.assertTrue(e.getMessage().contains("simulated error")); +``` + +# HtmlElementUtil, HtmlFormUtil and DomNodeUtil +These classes provide static utility methods to replace functionality that was added to the forked HtmlUnit e.g. +for triggering `
` submit, triggering a click event on an element etc. + +Use your IDE to access these utility classes and the static methods available. \ No newline at end of file diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..d330c77a4a3c38d62fa03a2358c217c316c12f54 --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java @@ -0,0 +1,139 @@ +/* + * The MIT License + * + * Copyright (c) 2015, CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.gargoylesoftware.htmlunit; + +import com.gargoylesoftware.htmlunit.javascript.JavaScriptErrorListener; +import org.junit.Assert; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * {@link WebClient} helper methods. + * @author tom.fennelly@gmail.com + */ +public class WebClientUtil { + + /** + * Wait for all async JavaScript tasks associated with the supplied {@link WebClient} instance + * to complete. + *

+ * Waits for 10 seconds before timing out. + * @param webClient The {@link WebClient} instance. + */ + public static void waitForJSExec(WebClient webClient) { + waitForJSExec(webClient, 10000); + } + + /** + * Wait for all async JavaScript tasks associated with the supplied {@link WebClient} instance + * to complete. + * @param webClient The {@link WebClient} instance. + * @param timeout The timeout in milliseconds. + */ + public static void waitForJSExec(WebClient webClient, long timeout) { + webClient.getJavaScriptEngine().processPostponedActions(); + webClient.waitForBackgroundJavaScript(timeout); + } + + /** + * Create and add an {@link ExceptionListener} to the {@link WebClient} instance. + * @param webClient The {@link WebClient} instance. + * @return The {@link ExceptionListener}. + */ + public static ExceptionListener addExceptionListener(WebClient webClient) { + ExceptionListener exceptionListener = new ExceptionListener(webClient); + webClient.setJavaScriptErrorListener(exceptionListener); + return exceptionListener; + } + + /** + * JavaScript Exception listener. + * @see #addExceptionListener(WebClient) + */ + public static class ExceptionListener implements JavaScriptErrorListener { + + private final WebClient webClient; + private ScriptException scriptException; + + private ExceptionListener(WebClient webClient) { + this.webClient = webClient; + } + + /** + * Get the last {@link ScriptException}. + * @return The last {@link ScriptException}, or {@code null} if none happened. + */ + public ScriptException getScriptException() { + return scriptException; + } + + /** + * Get the last {@link ScriptException}. + *

+ * Performs a call to {@link #assertHasException()}. + * @return The last {@link ScriptException}. + */ + public ScriptException getExpectedScriptException() { + assertHasException(); + return scriptException; + } + + /** + * {@inheritDoc} + */ + @Override + public void scriptException(InteractivePage htmlPage, ScriptException scriptException) { + this.scriptException = scriptException; + } + + /** + * Assert that a {@link ScriptException} occurred within the JavaScript executing + * on the associated {@link WebClient}. + */ + public void assertHasException() { + WebClientUtil.waitForJSExec(webClient); + Assert.assertNotNull("A JavaScript Exception was expected.", scriptException); + } + + /** + * {@inheritDoc} + */ + @Override + public void timeoutError(InteractivePage htmlPage, long allowedTime, long executionTime) { + } + /** + * {@inheritDoc} + */ + @Override + public void malformedScriptURL(InteractivePage htmlPage, String url, MalformedURLException malformedURLException) { + } + /** + * {@inheritDoc} + */ + @Override + public void loadScriptError(InteractivePage htmlPage, URL scriptUrl, Exception exception) { + } + } +} diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/WebResponseListener.java b/test/src/main/java/com/gargoylesoftware/htmlunit/WebResponseListener.java new file mode 100644 index 0000000000000000000000000000000000000000..75cd37e2fa9d82519d7a83e25ce418420c07453d --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/WebResponseListener.java @@ -0,0 +1,40 @@ +package com.gargoylesoftware.htmlunit; + +import org.junit.Assert; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * @author tom.fennelly@gmail.com + */ +public interface WebResponseListener { + + void onLoadWebResponse(WebRequest webRequest, WebResponse webResponse) throws IOException; + + public final class StatusListener implements WebResponseListener { + + private final int statusCode; + private final List responses = new CopyOnWriteArrayList<>(); + + public StatusListener(final int statusCode) { + this.statusCode = statusCode; + } + + @Override + public void onLoadWebResponse(WebRequest webRequest, WebResponse webResponse) throws IOException { + if (webResponse.getStatusCode() == statusCode) { + responses.add(webResponse); + } + } + + public void assertHasResponses() { + Assert.assertTrue(!responses.isEmpty()); + } + + public List getResponses() { + return responses; + } + } +} diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..a70716b85282c5041897ae5d4347ba6999730e22 --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java @@ -0,0 +1,68 @@ +/* + * The MIT License + * + * Copyright (c) 2015, CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.gargoylesoftware.htmlunit.html; + +import com.gargoylesoftware.htmlunit.WebClientUtil; +import com.gargoylesoftware.htmlunit.html.xpath.XPathUtils; + +import java.util.List; + +/** + * {@link DomNode} helper methods. + * + * @author tom.fennelly@gmail.com + */ +public class DomNodeUtil { + + /** + * Evaluates an XPath expression from the specified node, returning the resultant nodes. + *

+ * Calls {@link WebClientUtil#waitForJSExec(com.gargoylesoftware.htmlunit.WebClient)} before + * executing the query. + * + * @param domNode the node to start searching from + * @param xpathExpr the XPath expression + * @return the list of objects found. + */ + public static List selectNodes(final DomNode domNode, final String xpathExpr) { + WebClientUtil.waitForJSExec(domNode.getPage().getWebClient()); + return (List) XPathUtils.getByXPath(domNode, xpathExpr, null); + } + + /** + * Evaluates the specified XPath expression from this node, returning the first matching element, + * or null if no node matches the specified XPath expression. + *

+ * Calls {@link WebClientUtil#waitForJSExec(com.gargoylesoftware.htmlunit.WebClient)} before + * executing the query. + * + * @param domNode the node to start searching from + * @param xpathExpr the XPath expression + * @return the first element matching the specified XPath expression + */ + public static X selectSingleNode(final DomNode domNode, final String xpathExpr) { + WebClientUtil.waitForJSExec(domNode.getPage().getWebClient()); + return domNode.getFirstByXPath(xpathExpr); + } +} diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..c8d599b11f7e72673e0aa24185589fd68f0b2227 --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java @@ -0,0 +1,61 @@ +/* + * The MIT License + * + * Copyright (c) 2015, CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.gargoylesoftware.htmlunit.html; + +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.WebClientUtil; + +import java.io.IOException; + +/** + * {@link HtmlElement} helper methods. + * @author tom.fennelly@gmail.com + */ +public class HtmlElementUtil { + + /** + * Click on the supplied element. + *

+ * Waits for all executing JavaScript tasks to complete before returning. + * + * @param element The element to click. + * @return The page resulting from the click + * @throws IOException if an IO error occurs + */ + public static Page click(HtmlElement element) throws IOException { + if (element == null) { + return null; + } + + try { + return element.click(); + } finally { + // The JS script execution tasks are added to a queue and executed + // async. Wait for all to finish executing. + WebClient webClient = element.getPage().getWebClient(); + WebClientUtil.waitForJSExec(webClient); + } + } +} diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..af95c37cdf18c34eb5620d3574da18c925aaf77f --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java @@ -0,0 +1,142 @@ +/* + * The MIT License + * + * Copyright (c) 2015, CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.gargoylesoftware.htmlunit.html; + +import com.gargoylesoftware.htmlunit.ElementNotFoundException; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.WebClientUtil; + +import java.io.IOException; +import java.util.List; + +/** + * {@link HtmlForm} helper functions. + *

+ * In many cases, the methods defined here replace methods of the same name that were + * added to the {@link HtmlForm} class on the old forked version of HtmlUnit. + * + * @author tom.fennelly@gmail.com + */ +public class HtmlFormUtil { + + /** + * Submit the supplied {@link HtmlForm}. + *

+ * Locates the submit element/button on the form. + * @param htmlForm The {@link HtmlForm}. + * @return The submit result page. + * @throws IOException Error performing submit. + */ + public static Page submit(final HtmlForm htmlForm) throws IOException { + HtmlElement submitElement = getSubmitButton(htmlForm); + return submit(htmlForm, submitElement); + } + + /** + * Submit the supplied {@link HtmlForm} via the supplied submit element. + * @param htmlForm The {@link HtmlForm}. + * @param submitElement The element through which the submit should be performed. + * @return The submit result page. + * @throws IOException Error performing submit. + */ + public static Page submit(HtmlForm htmlForm, HtmlElement submitElement) throws IOException { + final HtmlPage htmlPage = (HtmlPage) htmlForm.getPage(); + final WebClient webClient = htmlPage.getWebClient(); + + try { + if (submitElement != null && !(submitElement instanceof SubmittableElement)) { + // Just click and return + return submitElement.click(); + } + + try { + htmlForm.submit((SubmittableElement) submitElement); + } finally { + // The HtmlForm submit doesn't really do anything. It just adds a "LoadJob" + // to an internal queue. What we are doing here is manually forcing the load of + // the response for that submit LoadJob and then getting the enclosing page + // from the current window on the WebClient, allowing us to return the correct + // HtmlPage object to the test. + webClient.loadDownloadedResponses(); + Page resultPage = webClient.getCurrentWindow().getEnclosedPage(); + + if (resultPage == htmlPage) { + return HtmlElementUtil.click(submitElement); + } else { + return resultPage; + } + } + } finally { + // Make sure all background JS has executed. + WebClientUtil.waitForJSExec(webClient); + } + } + + /** + * Returns all the <input type="submit"> elements in this form. + */ + public static List getSubmitButtons(final HtmlForm htmlForm) throws ElementNotFoundException { + final List list = htmlForm.getElementsByAttribute("input", "type", "submit"); + + // collect inputs from lost children + for (final HtmlElement elt : htmlForm.getLostChildren()) { + list.add(elt); + } + + return list; + } + + /** + * Gets the first <input type="submit"> element in this form. + */ + public static HtmlElement getSubmitButton(final HtmlForm htmlForm) throws ElementNotFoundException { + List submitButtons = getSubmitButtons(htmlForm); + if (!submitButtons.isEmpty()) { + return submitButtons.get(0); + } + for (HtmlElement element : htmlForm.getHtmlElementsByTagName("button")) { + if(element instanceof HtmlButton) { + return element; + } + } + return null; + } + + /** + * Get the form button having the specified text/caption. + * @param htmlForm The form containing the button. + * @param caption The button text/caption being searched for. + * @return The button if found. + * @throws ElementNotFoundException Failed to find the button on the form. + */ + public static HtmlButton getButtonByCaption(final HtmlForm htmlForm, final String caption) throws ElementNotFoundException { + for (HtmlElement b : htmlForm.getHtmlElementsByTagName("button")) { + if(b instanceof HtmlButton && b.getTextContent().trim().equals(caption)) { + return (HtmlButton) b; + } + } + throw new ElementNotFoundException("button", "caption", caption); + } +} diff --git a/test/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java b/test/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java index 07f2fafe5ca7bb8b31191f0e2e716ebc737b21dd..f50c04f3515bdb7ba28a5cf4a29229e3b70fd38b 100644 --- a/test/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java +++ b/test/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java @@ -28,8 +28,10 @@ import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebResponse; import com.gargoylesoftware.htmlunit.WebWindow; import com.gargoylesoftware.htmlunit.PageCreator; +import org.apache.commons.lang3.StringUtils; import java.io.IOException; +import java.io.InputStream; import java.util.Locale; /** @@ -46,5 +48,16 @@ public class HudsonPageCreator extends DefaultPageCreator { return super.createPage(webResponse, webWindow); } + @Override + protected String determineContentType(String contentType, InputStream contentAsStream) throws IOException { + // Need to sidestep HtmlUnit default behaviour here. It defaults the response type to + // being text/plain (and so creates a TextPage) if the content type in the response is + // blank + is an empty response. + if (StringUtils.isEmpty(contentType)) { + return "text/html"; + } + return super.determineContentType(contentType, contentAsStream); + } + public static final HudsonPageCreator INSTANCE = new HudsonPageCreator(); } diff --git a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java index 066ce52cea488a2dbc58ee8ed70bf54183759ffc..e17372122ce5f463f32d5eeab044425141589a24 100644 --- a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java +++ b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java @@ -25,6 +25,10 @@ package org.jvnet.hudson.test; import com.gargoylesoftware.htmlunit.AlertHandler; +import com.gargoylesoftware.htmlunit.WebClientUtil; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlImage; import com.google.inject.Injector; @@ -120,6 +124,7 @@ import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; +import javax.annotation.Nonnull; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; @@ -175,7 +180,6 @@ import com.gargoylesoftware.htmlunit.BrowserVersion; import com.gargoylesoftware.htmlunit.DefaultCssErrorHandler; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; import com.gargoylesoftware.htmlunit.html.DomNode; import com.gargoylesoftware.htmlunit.html.HtmlButton; import com.gargoylesoftware.htmlunit.html.HtmlElement; @@ -1042,7 +1046,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { */ public void assertXPath(HtmlPage page, String xpath) { assertNotNull("There should be an object that matches XPath:" + xpath, - page.getDocumentElement().selectSingleNode(xpath)); + DomNodeUtil.selectSingleNode(page.getDocumentElement(), xpath)); } /** Asserts that the XPath matches the contents of a DomNode page. This @@ -1098,7 +1102,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { * (By default, HtmlUnit doesn't load images.) */ public void assertAllImageLoadSuccessfully(HtmlPage p) { - for (HtmlImage img : p.selectNodes("//IMG")) { + for (HtmlImage img : DomNodeUtil.selectNodes(p, "//IMG")) { try { img.getHeight(); } catch (IOException e) { @@ -1160,7 +1164,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { * Plain {@link HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson. */ public HtmlPage submit(HtmlForm form) throws Exception { - return (HtmlPage)form.submit((HtmlButton)last(form.getHtmlElementsByTagName("button"))); + return (HtmlPage) HtmlFormUtil.submit(form, last(form.getHtmlElementsByTagName("button"))); } /** @@ -1172,24 +1176,15 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { public HtmlPage submit(HtmlForm form, String name) throws Exception { for( HtmlElement e : form.getHtmlElementsByTagName("button")) { HtmlElement p = (HtmlElement)e.getParentNode().getParentNode(); - if(p.getAttribute("name").equals(name)) { - // To make YUI event handling work, this combo seems to be necessary - // the click will trigger _onClick in buton-*.js, but it doesn't submit the form - // (a comment alluding to this behavior can be seen in submitForm method) - // so to complete it, submit the form later. - // - // Just doing form.submit() doesn't work either, because it doesn't do - // the preparation work needed to pass along the name of the button that - // triggered a submission (more concretely, m_oSubmitTrigger is not set.) - ((HtmlButton)e).click(); - return (HtmlPage)form.submit((HtmlButton)e); + if (e instanceof HtmlButton && p.getAttribute("name").equals(name)) { + return (HtmlPage)HtmlFormUtil.submit(form, (HtmlButton) e); } } throw new AssertionError("No such submit button with the name "+name); } protected HtmlInput findPreviousInputElement(HtmlElement current, String name) { - return (HtmlInput)current.selectSingleNode("(preceding::input[@name='_."+name+"'])[last()]"); + return DomNodeUtil.selectSingleNode(current, "(preceding::input[@name='_."+name+"'])[last()]"); } protected HtmlButton getButtonByCaption(HtmlForm f, String s) { @@ -1629,19 +1624,19 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { * for accessing Hudson. */ public class WebClient extends com.gargoylesoftware.htmlunit.WebClient { - private static final long serialVersionUID = 5808915989048338267L; + private static final long serialVersionUID = 8720028298174337333L; public WebClient() { // default is IE6, but this causes 'n.doScroll('left')' to fail in event-debug.js:1907 as HtmlUnit doesn't implement such a method, // so trying something else, until we discover another problem. - super(BrowserVersion.FIREFOX_2); + super(BrowserVersion.FIREFOX_38); setPageCreator(HudsonPageCreator.INSTANCE); clients.add(this); // make ajax calls run as post-action for predictable behaviors that simplify debugging setAjaxController(new AjaxController() { - private static final long serialVersionUID = -5844060943564822678L; - public boolean processSynchron(HtmlPage page, WebRequestSettings settings, boolean async) { + private static final long serialVersionUID = 6730107519583349963L; + public boolean processSynchron(HtmlPage page, WebRequest settings, boolean async) { return false; } }); @@ -1689,7 +1684,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { // avoid a hang by setting a time out. It should be long enough to prevent // false-positive timeout on slow systems - setTimeout(60*1000); + //setTimeout(60*1000); } /** @@ -1701,7 +1696,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { HtmlForm form = page.getFormByName("login"); form.getInputByName("j_username").setValueAttribute(username); form.getInputByName("j_password").setValueAttribute(password); - form.submit(null); + HtmlFormUtil.submit(form, null); return this; } @@ -1767,7 +1762,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { HtmlPage top = goTo(""); HtmlForm search = top.getFormByName("search"); search.getInputByName("q").setValueAttribute(q); - return (HtmlPage)search.submit(null); + return (HtmlPage)HtmlFormUtil.submit(search, null); } /** @@ -1821,7 +1816,11 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { @SuppressWarnings("unchecked") @Override public Page getPage(String url) throws IOException, FailingHttpStatusCodeException { - return super.getPage(url); + try { + return super.getPage(url); + } finally { + WebClientUtil.waitForJSExec(this); + } } /** @@ -1845,6 +1844,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { Page p; try { p = super.getPage(getContextPath() + relative); + WebClientUtil.waitForJSExec(this); } catch (IOException x) { if (x.getCause() != null) { x.getCause().printStackTrace(); @@ -1895,12 +1895,10 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { /** * Adds a security crumb to the quest */ - public WebRequestSettings addCrumb(WebRequestSettings req) { - NameValuePair crumb[] = { new NameValuePair() }; - - crumb[0].setName(jenkins.getCrumbIssuer().getDescriptor().getCrumbRequestField()); - crumb[0].setValue(jenkins.getCrumbIssuer().getCrumb( null )); - + public WebRequest addCrumb(WebRequest req) { + com.gargoylesoftware.htmlunit.util.NameValuePair crumb = new com.gargoylesoftware.htmlunit.util.NameValuePair( + jenkins.getCrumbIssuer().getDescriptor().getCrumbRequestField(), + jenkins.getCrumbIssuer().getCrumb( null )); req.setRequestParameters(Arrays.asList( crumb )); return req; } diff --git a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index f63842f3985d4fd66e03966cd4cdd080f67ca493..20bb06a0333db6bb31662b381bc41cc8e05e9a39 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -30,8 +30,10 @@ import com.gargoylesoftware.htmlunit.DefaultCssErrorHandler; import com.gargoylesoftware.htmlunit.ElementNotFoundException; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebClientUtil; +import com.gargoylesoftware.htmlunit.WebRequest; import com.gargoylesoftware.htmlunit.WebResponse; +import com.gargoylesoftware.htmlunit.WebResponseListener; import com.gargoylesoftware.htmlunit.html.DomNode; import com.gargoylesoftware.htmlunit.html.HtmlButton; import com.gargoylesoftware.htmlunit.html.HtmlElement; @@ -41,6 +43,7 @@ import com.gargoylesoftware.htmlunit.html.HtmlInput; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.javascript.HtmlUnitContextFactory; import com.gargoylesoftware.htmlunit.javascript.host.xml.XMLHttpRequest; +import com.gargoylesoftware.htmlunit.util.NameValuePair; import com.gargoylesoftware.htmlunit.xml.XmlPage; import hudson.ClassicPluginStrategy; import hudson.CloseProofOutputStream; @@ -99,6 +102,7 @@ import hudson.slaves.CommandLauncher; import hudson.slaves.ComputerConnector; import hudson.slaves.ComputerListener; import hudson.slaves.DumbSlave; +import hudson.slaves.OfflineCause; import hudson.slaves.RetentionStrategy; import hudson.tasks.Ant; import hudson.tasks.BuildWrapper; @@ -173,7 +177,6 @@ import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.userdetails.UserDetails; import org.acegisecurity.userdetails.UsernameNotFoundException; import org.apache.commons.beanutils.PropertyUtils; -import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.io.FileUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException; @@ -190,6 +193,8 @@ import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import org.jvnet.hudson.test.recipes.Recipe; import org.jvnet.hudson.test.rhino.JavaScriptDebugger; import org.kohsuke.stapler.ClassDescriptor; @@ -792,6 +797,31 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { return env.temporaryDirectoryAllocator.allocate(); } + public DumbSlave createSlave(boolean waitForChannelConnect) throws Exception { + DumbSlave slave = createSlave(); + if (waitForChannelConnect) { + long start = System.currentTimeMillis(); + while (slave.getChannel() == null) { + if (System.currentTimeMillis() > (start + 10000)) { + throw new IllegalStateException("Timed out waiting on DumbSlave channel to connect."); + } + Thread.sleep(200); + } + } + return slave; + } + + public void disconnectSlave(DumbSlave slave) throws Exception { + slave.getComputer().disconnect(new OfflineCause.ChannelTermination(new Exception("terminate"))); + long start = System.currentTimeMillis(); + while (slave.getChannel() != null) { + if (System.currentTimeMillis() > (start + 10000)) { + throw new IllegalStateException("Timed out waiting on DumbSlave channel to disconnect."); + } + Thread.sleep(200); + } + } + public DumbSlave createSlave() throws Exception { return createSlave("",null); } @@ -1179,8 +1209,9 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * Asserts that the XPath matches. */ public void assertXPath(HtmlPage page, String xpath) { + HtmlElement documentElement = page.getDocumentElement(); assertNotNull("There should be an object that matches XPath:" + xpath, - page.getDocumentElement().selectSingleNode(xpath)); + DomNodeUtil.selectSingleNode(documentElement, xpath)); } /** Asserts that the XPath matches the contents of a DomNode page. This @@ -1236,7 +1267,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * (By default, HtmlUnit doesn't load images.) */ public void assertAllImageLoadSuccessfully(HtmlPage p) { - for (HtmlImage img : p.selectNodes("//IMG")) { + for (HtmlImage img : DomNodeUtil.selectNodes(p, "//IMG")) { try { img.getHeight(); } catch (IOException e) { @@ -1299,7 +1330,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * Plain {@link com.gargoylesoftware.htmlunit.html.HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson. */ public HtmlPage submit(HtmlForm form) throws Exception { - return (HtmlPage) form.submit((HtmlButton) last(form.getHtmlElementsByTagName("button"))); + return (HtmlPage) HtmlFormUtil.submit(form); } /** @@ -1311,24 +1342,15 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { public HtmlPage submit(HtmlForm form, String name) throws Exception { for( HtmlElement e : form.getHtmlElementsByTagName("button")) { HtmlElement p = (HtmlElement)e.getParentNode().getParentNode(); - if(p.getAttribute("name").equals(name)) { - // To make YUI event handling work, this combo seems to be necessary - // the click will trigger _onClick in buton-*.js, but it doesn't submit the form - // (a comment alluding to this behavior can be seen in submitForm method) - // so to complete it, submit the form later. - // - // Just doing form.submit() doesn't work either, because it doesn't do - // the preparation work needed to pass along the name of the button that - // triggered a submission (more concretely, m_oSubmitTrigger is not set.) - ((HtmlButton)e).click(); - return (HtmlPage)form.submit((HtmlButton)e); + if(e instanceof HtmlButton && p.getAttribute("name").equals(name)) { + return (HtmlPage)HtmlFormUtil.submit(form, (HtmlButton) e); } } throw new AssertionError("No such submit button with the name "+name); } public HtmlInput findPreviousInputElement(HtmlElement current, String name) { - return (HtmlInput)current.selectSingleNode("(preceding::input[@name='_."+name+"'])[last()]"); + return DomNodeUtil.selectSingleNode(current, "(preceding::input[@name='_."+name+"'])[last()]"); } public HtmlButton getButtonByCaption(HtmlForm f, String s) { @@ -1834,20 +1856,22 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * for accessing Hudson. */ public class WebClient extends com.gargoylesoftware.htmlunit.WebClient { - private static final long serialVersionUID = 5808915989048338267L; + private static final long serialVersionUID = -7944895389154288881L; + + private List webResponseListeners = new ArrayList<>(); public WebClient() { // default is IE6, but this causes 'n.doScroll('left')' to fail in event-debug.js:1907 as HtmlUnit doesn't implement such a method, // so trying something else, until we discover another problem. - super(BrowserVersion.FIREFOX_2); + super(BrowserVersion.FIREFOX_38); // setJavaScriptEnabled(false); setPageCreator(HudsonPageCreator.INSTANCE); clients.add(this); // make ajax calls run as post-action for predictable behaviors that simplify debugging setAjaxController(new AjaxController() { - private static final long serialVersionUID = -5844060943564822678L; - public boolean processSynchron(HtmlPage page, WebRequestSettings settings, boolean async) { + private static final long serialVersionUID = -76034615893907856L; + public boolean processSynchron(HtmlPage page, WebRequest settings, boolean async) { return false; } }); @@ -1892,7 +1916,23 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { // avoid a hang by setting a time out. It should be long enough to prevent // false-positive timeout on slow systems - setTimeout(60*1000); + //setTimeout(60*1000); + } + + + public void addWebResponseListener(WebResponseListener listener) { + webResponseListeners.add(listener); + } + + @Override + public WebResponse loadWebResponse(final WebRequest webRequest) throws IOException { + WebResponse webResponse = super.loadWebResponse(webRequest); + if (!webResponseListeners.isEmpty()) { + for (WebResponseListener listener : webResponseListeners) { + listener.onLoadWebResponse(webRequest, webResponse); + } + } + return webResponse; } /** @@ -1902,6 +1942,14 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { return login(username,password,false); } + public boolean isJavaScriptEnabled() { + return getOptions().isJavaScriptEnabled(); + } + + public void setJavaScriptEnabled(boolean enabled) { + getOptions().setJavaScriptEnabled(enabled); + } + /** * Logs in to Jenkins. */ @@ -1918,7 +1966,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { // remember me not available is OK so long as the caller didn't ask for it assert !rememberMe; } - form.submit(null); + HtmlFormUtil.submit(form, null); return this; } @@ -1930,7 +1978,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * and passwords. All the test accounts have the same user name and password. */ public WebClient login(String username) throws Exception { - login(username,username); + login(username, username); return this; } @@ -1984,7 +2032,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { HtmlPage top = goTo(""); HtmlForm search = top.getFormByName("search"); search.getInputByName("q").setValueAttribute(q); - return (HtmlPage)search.submit(null); + return (HtmlPage)HtmlFormUtil.submit(search, null); } /** @@ -2013,7 +2061,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { } public HtmlPage getPage(Node item) throws IOException, SAXException { - return getPage(item,""); + return getPage(item, ""); } public HtmlPage getPage(Node item, String relative) throws IOException, SAXException { @@ -2038,7 +2086,11 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { @SuppressWarnings("unchecked") @Override public Page getPage(String url) throws IOException, FailingHttpStatusCodeException { - return super.getPage(url); + try { + return super.getPage(url); + } finally { + WebClientUtil.waitForJSExec(this); + } } /** @@ -2070,6 +2122,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { Page p; try { p = super.getPage(getContextPath() + relative); + WebClientUtil.waitForJSExec(this); } catch (IOException x) { Throwable cause = x.getCause(); if (cause instanceof SocketTimeoutException) { @@ -2126,15 +2179,13 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { /** * Adds a security crumb to the request. - * Use {@link #createCrumbedUrl} instead if you intend to call {@link WebRequestSettings#setRequestBody}, typical of a POST request. + * Use {@link #createCrumbedUrl} instead if you intend to call {@link WebRequest#setRequestBody}, typical of a POST request. */ - public WebRequestSettings addCrumb(WebRequestSettings req) { - NameValuePair crumb[] = { new NameValuePair() }; - - crumb[0].setName(jenkins.getCrumbIssuer().getDescriptor().getCrumbRequestField()); - crumb[0].setValue(jenkins.getCrumbIssuer().getCrumb( null )); - - req.setRequestParameters(Arrays.asList( crumb )); + public WebRequest addCrumb(WebRequest req) { + NameValuePair crumb = new NameValuePair( + jenkins.getCrumbIssuer().getDescriptor().getCrumbRequestField(), + jenkins.getCrumbIssuer().getCrumb( null )); + req.setRequestParameters(Arrays.asList(crumb)); return req; } diff --git a/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java b/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java index 364364ef8da606999f250326dfd0ccdea50dcd07..670a9d4e1e1ca91987f5c29d6cd7498780fc0c6e 100644 --- a/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java +++ b/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java @@ -51,4 +51,4 @@ public class FailedTest extends TestCase { if (problem!=null) throw problem; } -} +} \ No newline at end of file diff --git a/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy b/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy index f40a32ed3aaf43ebe1229a61b6d2b32a71caf45a..fe6c39351bbe1ffdb4271685e64ed70a471ccc15 100644 --- a/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy +++ b/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy @@ -25,18 +25,13 @@ package hudson.model; import com.gargoylesoftware.htmlunit.ElementNotFoundException import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.HttpMethod; -import com.gargoylesoftware.htmlunit.WebRequestSettings -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import hudson.security.* +import com.gargoylesoftware.htmlunit.HttpMethod +import com.gargoylesoftware.htmlunit.WebRequest; import hudson.tasks.BuildStepMonitor; -import hudson.tasks.BuildTrigger -import hudson.tasks.Publisher import hudson.tasks.Recorder; import com.gargoylesoftware.htmlunit.html.HtmlPage import hudson.maven.MavenModuleSet; import hudson.security.*; -import hudson.tasks.BuildTrigger; import hudson.tasks.Shell; import hudson.scm.NullSCM; import hudson.scm.SCM @@ -53,17 +48,12 @@ import hudson.triggers.TriggerDescriptor; import hudson.util.StreamTaskListener; import hudson.util.OneShotEvent import jenkins.model.Jenkins; -import org.acegisecurity.context.SecurityContext; -import org.acegisecurity.context.SecurityContextHolder import org.jvnet.hudson.test.HudsonTestCase import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.MemoryAssert -import org.jvnet.hudson.test.SequenceLock; import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.recipes.PresetData; import org.jvnet.hudson.test.recipes.PresetData.DataSet import org.apache.commons.io.FileUtils; -import java.lang.ref.WeakReference import org.jvnet.hudson.test.MockFolder @@ -127,10 +117,10 @@ public class AbstractProjectTest extends HudsonTestCase { def webClient = createWebClient(); HtmlPage page = webClient.getPage(jenkins.getItem("test0")); - page = (HtmlPage)page.getFirstAnchorByText("Workspace").click(); + page = (HtmlPage)page.getAnchorByText("Workspace").click(); try { String wipeOutLabel = ResourceBundle.getBundle("hudson/model/AbstractProject/sidepanel").getString("Wipe Out Workspace"); - page.getFirstAnchorByText(wipeOutLabel); + page.getAnchorByText(wipeOutLabel); fail("shouldn't find a link"); } catch (ElementNotFoundException e) { // OK @@ -393,7 +383,7 @@ public class AbstractProjectTest extends HudsonTestCase { private String deleteRedirectTarget(String job) { def wc = createWebClient(); String base = wc.getContextPath(); - String loc = wc.getPage(wc.addCrumb(new WebRequestSettings(new URL(base + job + "/doDelete"), HttpMethod.POST))).getWebResponse().getUrl().toString(); + String loc = wc.getPage(wc.addCrumb(new WebRequest(new URL(base + job + "/doDelete"), HttpMethod.POST))).getUrl().toString(); assert loc.startsWith(base): loc; return loc.substring(base.length()); } diff --git a/test/src/test/groovy/hudson/security/TokenBasedRememberMeServices2Test.groovy b/test/src/test/groovy/hudson/security/TokenBasedRememberMeServices2Test.groovy index 92d202a8627e65e50cd8697faafc9a5dfabcf89f..435eb4fbb7f8ab4b3f6c2eaaae948404e38f2586 100644 --- a/test/src/test/groovy/hudson/security/TokenBasedRememberMeServices2Test.groovy +++ b/test/src/test/groovy/hudson/security/TokenBasedRememberMeServices2Test.groovy @@ -9,7 +9,7 @@ import org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices import org.acegisecurity.userdetails.User import org.acegisecurity.userdetails.UserDetails import org.acegisecurity.userdetails.UsernameNotFoundException -import org.apache.commons.httpclient.Cookie +import com.gargoylesoftware.htmlunit.util.Cookie import org.junit.After import org.junit.Before import org.junit.Rule diff --git a/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy b/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy index 5e7d248be953ff0475ac2f02c23607b36a1b9ba0..b4c5c5fc9c6ccf35df0dba384a68fbb1c352691e 100644 --- a/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy +++ b/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy @@ -1,5 +1,6 @@ package jenkins.bugs +import com.gargoylesoftware.htmlunit.WebClientUtil import hudson.Launcher import hudson.model.AbstractBuild import hudson.model.AbstractProject @@ -40,10 +41,12 @@ class Jenkins19124Test { def wc = j.createWebClient(); def c = wc.getPage(p, "configure"); c.getElementByName("_.alpha").valueAttribute = "hello"; + WebClientUtil.waitForJSExec(wc); assert d.alpha=="hello"; assert d.bravo=="2"; c.getElementByName("_.bravo").setSelectedAttribute("1",true); + WebClientUtil.waitForJSExec(wc); assert d.alpha=="hello"; assert d.bravo=="1"; } diff --git a/test/src/test/java/hudson/ExceptionTest.java b/test/src/test/java/hudson/ExceptionTest.java index 907a2e30e792f72de8bdad2fbef6008ee8c00d40..1e68673c8293d0a274655f97a57ed20a104638b3 100644 --- a/test/src/test/java/hudson/ExceptionTest.java +++ b/test/src/test/java/hudson/ExceptionTest.java @@ -1,6 +1,8 @@ package hudson; import com.gargoylesoftware.htmlunit.ScriptException; +import com.gargoylesoftware.htmlunit.WebClientUtil; +import org.junit.Assert; import org.jvnet.hudson.test.HudsonTestCase; /** @@ -11,14 +13,12 @@ public class ExceptionTest extends HudsonTestCase { * Makes sure that an AJAX handler error results in a fatal problem in the unit test. */ public void testAjaxError() throws Exception { - try { - createWebClient().goTo("/self/ajaxError"); - fail("should have resulted in a ScriptException"); - } catch (ScriptException e) { - if (e.getMessage().contains("simulated error")) - return; // as expected - throw e; + WebClient webClient = createWebClient(); + WebClientUtil.ExceptionListener exceptionListener = WebClientUtil.addExceptionListener(webClient); + webClient.goTo("/self/ajaxError"); - } + // Check for the error. + ScriptException e = exceptionListener.getExpectedScriptException(); + Assert.assertTrue(e.getMessage().contains("simulated error")); } } diff --git a/test/src/test/java/hudson/bugs/JnlpAccessWithSecuredHudsonTest.java b/test/src/test/java/hudson/bugs/JnlpAccessWithSecuredHudsonTest.java index 52dc53e89b1d2adb87db123681c3282955c5e58b..778294e03477e2cfe302b6c7541b14944f0477a7 100644 --- a/test/src/test/java/hudson/bugs/JnlpAccessWithSecuredHudsonTest.java +++ b/test/src/test/java/hudson/bugs/JnlpAccessWithSecuredHudsonTest.java @@ -74,7 +74,7 @@ public class JnlpAccessWithSecuredHudsonTest extends HudsonTestCase { // parse the JNLP page into DOM to list up the jars. XmlPage jnlp = (XmlPage) wc.goTo("computer/test/slave-agent.jnlp","application/x-java-jnlp-file"); - URL baseUrl = jnlp.getWebResponse().getUrl(); + URL baseUrl = jnlp.getUrl(); Document dom = new DOMReader().read(jnlp.getXmlDocument()); for( Element jar : (List)dom.selectNodes("//jar") ) { URL url = new URL(baseUrl,jar.attributeValue("href")); diff --git a/test/src/test/java/hudson/bugs/LoginRedirectTest.java b/test/src/test/java/hudson/bugs/LoginRedirectTest.java index d26ab3c11a7311c6d8d2847668cc6eba616fb289..af63ad9380c3c1887b663b6665a451b3deab96e4 100644 --- a/test/src/test/java/hudson/bugs/LoginRedirectTest.java +++ b/test/src/test/java/hudson/bugs/LoginRedirectTest.java @@ -24,6 +24,7 @@ package hudson.bugs; import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import java.net.HttpURLConnection; import org.jvnet.hudson.test.Issue; @@ -47,15 +48,14 @@ public class LoginRedirectTest extends HudsonTestCase { public void testRedirect() throws Exception { WebClient wc = new WebClient(); // Hudson first causes 403 FORBIDDEN error, then redirect the browser to the page - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage p = wc.goTo("/"); - System.out.println(p.getDocumentURI()); assertEquals(200, p.getWebResponse().getStatusCode()); HtmlForm form = p.getFormByName("login"); form.getInputByName("j_username").setValueAttribute("alice"); form.getInputByName("j_password").setValueAttribute("alice"); - p = (HtmlPage) form.submit(null); + p = (HtmlPage) HtmlFormUtil.submit(form, null); System.out.println(p); } diff --git a/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java b/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java index 7ab76e9170c7883977cbcc959e6eab01ada183ee..83827f48607a04d991697dc70b8d09249ee7880e 100644 --- a/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java +++ b/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java @@ -2,7 +2,8 @@ package hudson.console; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.TextPage; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.FilePath; import hudson.Launcher; @@ -62,7 +63,7 @@ public class ConsoleAnnotatorTest { // make sure we see the annotation HtmlPage rsp = r.createWebClient().getPage(b, "console"); - assertEquals(1,rsp.selectNodes("//B[@class='demo']").size()); + assertEquals(1, DomNodeUtil.selectNodes(rsp, "//B[@class='demo']").size()); // make sure raw console output doesn't include the garbage TextPage raw = (TextPage)r.createWebClient().goTo(b.getUrl()+"consoleText","text/plain"); @@ -112,7 +113,7 @@ public class ConsoleAnnotatorTest { // make sure we see the annotation HtmlPage rsp = r.createWebClient().getPage(b, "console"); - assertEquals(1,rsp.selectNodes("//A[@href='http://infradna.com/']").size()); + assertEquals(1, DomNodeUtil.selectNodes(rsp, "//A[@href='http://infradna.com/']").size()); // make sure raw console output doesn't include the garbage TextPage raw = (TextPage)r.createWebClient().goTo(b.getUrl()+"consoleText","text/plain"); @@ -138,7 +139,8 @@ public class ConsoleAnnotatorTest { } String next() throws IOException { - WebRequestSettings req = new WebRequestSettings(new URL(r.getURL() + run.getUrl() + "/logText/progressiveHtml"+(start!=null?"?start="+start:""))); + WebRequest req = new WebRequest(new URL(r.getURL() + run.getUrl() + "/logText/progressiveHtml"+(start!=null?"?start="+start:""))); + req.setEncodingType(null); Map headers = new HashMap(); if (consoleAnnotator!=null) headers.put("X-ConsoleAnnotator",consoleAnnotator); diff --git a/test/src/test/java/hudson/diagnosis/ReverseProxySetupMonitorTest.java b/test/src/test/java/hudson/diagnosis/ReverseProxySetupMonitorTest.java index 2e2d8dd6f14522a06b0cc16e0de861d893ecc252..d44b77734b1f97830404573b90b52c675a828908 100644 --- a/test/src/test/java/hudson/diagnosis/ReverseProxySetupMonitorTest.java +++ b/test/src/test/java/hudson/diagnosis/ReverseProxySetupMonitorTest.java @@ -24,7 +24,7 @@ package hudson.diagnosis; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; import java.net.URL; import org.junit.Test; import org.junit.Rule; @@ -35,7 +35,8 @@ public class ReverseProxySetupMonitorTest { @Rule public JenkinsRule r = new JenkinsRule(); @Test public void normal() throws Exception { - WebRequestSettings wrs = new WebRequestSettings(new URL(r.getURL(), r.jenkins.getAdministrativeMonitor(ReverseProxySetupMonitor.class.getName()).getUrl() + "/test")); + WebRequest wrs = new WebRequest(new URL(r.getURL(), r.jenkins.getAdministrativeMonitor(ReverseProxySetupMonitor.class.getName()).getUrl() + "/test")); + wrs.setEncodingType(null); wrs.setAdditionalHeader("Referer", r.getURL() + "manage"); r.createWebClient().getPage(wrs); } diff --git a/test/src/test/java/hudson/diagnosis/TooManyJobsButNoViewTest.java b/test/src/test/java/hudson/diagnosis/TooManyJobsButNoViewTest.java index d8b15832718287a384add4f586d900fbd6c04cf8..2f6dab50726b9e67daed700343b3165c36f52b7b 100644 --- a/test/src/test/java/hudson/diagnosis/TooManyJobsButNoViewTest.java +++ b/test/src/test/java/hudson/diagnosis/TooManyJobsButNoViewTest.java @@ -55,7 +55,7 @@ public class TooManyJobsButNoViewTest { assertNotNull(f); // this should take us to the new view page - URL url = r.submit(f,"yes").getWebResponse().getUrl(); + URL url = r.submit(f,"yes").getUrl(); assertTrue(url.toExternalForm(),url.toExternalForm().endsWith("/newView")); // since we didn't create a view, if we go back, we should see the warning again diff --git a/test/src/test/java/hudson/model/AsynchPeopleTest.java b/test/src/test/java/hudson/model/AsynchPeopleTest.java index 00fae6b364bc34d9f5348905070a06cd4ba7f7ea..c13017848e1ccb26f2b1203ea4723a0e416908b8 100644 --- a/test/src/test/java/hudson/model/AsynchPeopleTest.java +++ b/test/src/test/java/hudson/model/AsynchPeopleTest.java @@ -25,7 +25,7 @@ package hudson.model; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; import static org.junit.Assert.*; import org.junit.Rule; @@ -53,7 +53,7 @@ public class AsynchPeopleTest { } assertEquals(0, wc.waitForBackgroundJavaScript(120000)); boolean found = false; - for (HtmlElement table : page.getElementsByTagName("table")) { + for (DomElement table : page.getElementsByTagName("table")) { if (table.getAttribute("class").contains("progress-bar")) { found = true; assertEquals("display: none;", table.getAttribute("style")); diff --git a/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java b/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java index f6f62d935f7c8d49e7302dcaf0052ea314d407ba..459862efa623c3c824252764c68ed989b3aee9ae 100644 --- a/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java +++ b/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java @@ -30,6 +30,7 @@ import java.net.URL; import javax.annotation.Nonnull; +import com.gargoylesoftware.htmlunit.WebRequest; import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; @@ -39,7 +40,6 @@ import org.jvnet.hudson.test.MockFolder; import com.gargoylesoftware.htmlunit.HttpMethod; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; import com.gargoylesoftware.htmlunit.WebResponse; public class DirectlyModifiableViewTest { @@ -186,8 +186,8 @@ public class DirectlyModifiableViewTest { private Page doPost(View view, String path) throws Exception { WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); - WebRequestSettings req = new WebRequestSettings( + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); + WebRequest req = new WebRequest( new URL(j.jenkins.getRootUrl() + view.getUrl() + path), HttpMethod.POST ); diff --git a/test/src/test/java/hudson/model/HelpLinkTest.java b/test/src/test/java/hudson/model/HelpLinkTest.java index 907f127cc9853b9fe8db9b684e85fd53c2702e4d..92bbaacc14291e9a613f640b8881e0b3f705c370 100644 --- a/test/src/test/java/hudson/model/HelpLinkTest.java +++ b/test/src/test/java/hudson/model/HelpLinkTest.java @@ -1,9 +1,12 @@ package hudson.model; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import com.gargoylesoftware.htmlunit.WebResponseListener; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; +import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; import hudson.tasks.BuildStepMonitor; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import com.gargoylesoftware.htmlunit.html.HtmlPage; @@ -48,16 +51,22 @@ public class HelpLinkTest { private void clickAllHelpLinks(AbstractProject p) throws Exception { // TODO: how do we add all the builders and publishers so that we can test this meaningfully? - clickAllHelpLinks(j.createWebClient().getPage(p, "configure")); + clickAllHelpLinks(j.createWebClient(), p); + } + + private void clickAllHelpLinks(JenkinsRule.WebClient webClient, AbstractProject p) throws Exception { + // TODO: how do we add all the builders and publishers so that we can test this meaningfully? + clickAllHelpLinks(webClient.getPage(p, "configure")); } private void clickAllHelpLinks(HtmlPage p) throws Exception { - List helpLinks = p.selectNodes("//a[@class='help-button']"); + List helpLinks = DomNodeUtil.selectNodes(p, "//a[@class='help-button']"); assertTrue(helpLinks.size()>0); System.out.println("Clicking "+helpLinks.size()+" help links"); - for (HtmlAnchor helpLink : (List)helpLinks) - helpLink.click(); + for (HtmlAnchor helpLink : (List)helpLinks) { + HtmlElementUtil.click(helpLink); + } } public static class HelpNotFoundBuilder extends Publisher { @@ -92,13 +101,15 @@ public class HelpLinkTest { try { FreeStyleProject p = j.createFreeStyleProject(); p.getPublishersList().add(new HelpNotFoundBuilder()); - clickAllHelpLinks(p); - fail("should detect a failure"); - } catch(AssertionError e) { - if(e.getMessage().contains(d.getHelpFile())) - ; // expected - else - throw e; + JenkinsRule.WebClient webclient = j.createWebClient(); + WebResponseListener.StatusListener statusListener = new WebResponseListener.StatusListener(404); + webclient.addWebResponseListener(statusListener); + + clickAllHelpLinks(webclient, p); + + statusListener.assertHasResponses(); + String contentAsString = statusListener.getResponses().get(0).getContentAsString(); + Assert.assertTrue(contentAsString.contains(d.getHelpFile())); } finally { Publisher.all().remove(d); } diff --git a/test/src/test/java/hudson/model/HudsonTest.java b/test/src/test/java/hudson/model/HudsonTest.java index 4a296f895fe9adaa944a28dd572de55a2ce321f2..5f5c006b59918d3cf034beb24498e57ccf374568 100644 --- a/test/src/test/java/hudson/model/HudsonTest.java +++ b/test/src/test/java/hudson/model/HudsonTest.java @@ -28,9 +28,10 @@ import static org.junit.Assert.*; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.HttpMethod; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.html.DomElement; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; -import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.model.Node.Mode; @@ -128,7 +129,7 @@ public class HudsonTest { FreeStyleProject p = j.createFreeStyleProject(); Page jobPage = j.search(p.getName()); - URL url = jobPage.getWebResponse().getUrl(); + URL url = jobPage.getUrl(); System.out.println(url); assertTrue(url.getPath().endsWith("/job/"+p.getName()+"/")); } @@ -139,8 +140,8 @@ public class HudsonTest { @Test public void breadcrumb() throws Exception { HtmlPage root = j.createWebClient().goTo(""); - HtmlElement navbar = root.getElementById("breadcrumbs"); - assertEquals(1,navbar.selectNodes("LI/A").size()); + DomElement navbar = root.getElementById("breadcrumbs"); + assertEquals(1, DomNodeUtil.selectNodes(navbar, "LI/A").size()); } /** @@ -165,7 +166,7 @@ public class HudsonTest { assertFalse(a.getHrefAttribute(),a.getHrefAttribute().endsWith("delete")); // try to delete it by hitting the final URL directly - WebRequestSettings req = new WebRequestSettings(new URL(wc.getContextPath()+"computer/(master)/doDelete"), HttpMethod.POST); + WebRequest req = new WebRequest(new URL(wc.getContextPath()+"computer/(master)/doDelete"), HttpMethod.POST); try { wc.getPage(wc.addCrumb(req)); fail("Error code expected"); diff --git a/test/src/test/java/hudson/model/JobTest.java b/test/src/test/java/hudson/model/JobTest.java index b8176491f44adb9ebf2ee7f8c5c7d520af41b5b4..b49b13e45d4450c9992c165e8015db276f4c02bf 100644 --- a/test/src/test/java/hudson/model/JobTest.java +++ b/test/src/test/java/hudson/model/JobTest.java @@ -25,6 +25,7 @@ package hudson.model; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.WebAssert; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.TextPage; @@ -211,7 +212,7 @@ public class JobTest { // But it posts invalid data so we expect 500 if we have permission, 403 if not HtmlPage page = wc.goTo("userContent/post.html"); try { - page.getForms().get(0).submit(); + HtmlFormUtil.submit(page.getForms().get(0)); fail("Expected exception: " + msg); } catch (FailingHttpStatusCodeException expected) { assertEquals(msg, status, expected.getStatusCode()); diff --git a/test/src/test/java/hudson/model/ManagementLinkTest.java b/test/src/test/java/hudson/model/ManagementLinkTest.java index 52622e28ef650d3d0f664ab1b243bda014e9e0ec..4b19f2c8bbc3009d044ab9c3c1d2534b52fb140e 100644 --- a/test/src/test/java/hudson/model/ManagementLinkTest.java +++ b/test/src/test/java/hudson/model/ManagementLinkTest.java @@ -25,6 +25,7 @@ package hudson.model; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.junit.Rule; @@ -47,7 +48,7 @@ public class ManagementLinkTest { @Test public void links() throws Exception { HtmlPage page = j.createWebClient().goTo("manage"); - List anchors = page.selectNodes("id('management-links')//*[@class='link']/a[not(@onclick)]"); + List anchors = DomNodeUtil.selectNodes(page, "id('management-links')//*[@class='link']/a[not(@onclick)]"); assertTrue(anchors.size()>=8); for(HtmlAnchor e : (List) anchors) { e.click(); diff --git a/test/src/test/java/hudson/model/ParametersTest.java b/test/src/test/java/hudson/model/ParametersTest.java index 2d87d5ef9e1f998c1e1c06f209561a08a5b957cd..9f525a420c48f383bfbc1b9e790ba5b3b05535c4 100644 --- a/test/src/test/java/hudson/model/ParametersTest.java +++ b/test/src/test/java/hudson/model/ParametersTest.java @@ -2,6 +2,8 @@ package hudson.model; import static org.junit.Assert.*; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import org.junit.Rule; import org.junit.Test; @@ -42,38 +44,38 @@ public class ParametersTest { project.getBuildersList().add(builder); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.goTo("job/" + project.getName() + "/build?delay=0sec"); HtmlForm form = page.getFormByName("parameters"); - HtmlElement element = (HtmlElement) form.selectSingleNode("//tr[td/div/input/@value='string']"); + HtmlElement element = (HtmlElement) DomNodeUtil.selectSingleNode(form, "//tr[td/div/input/@value='string']"); assertNotNull(element); - assertEquals("string description", ((HtmlElement) element.getNextSibling().getNextSibling().selectSingleNode("td[@class='setting-description']")).getTextContent()); + assertEquals("string description", ((HtmlElement) DomNodeUtil.selectSingleNode(element.getNextSibling().getNextSibling(), "td[@class='setting-description']")).getTextContent()); - HtmlTextInput stringParameterInput = (HtmlTextInput) element.selectSingleNode(".//input[@name='value']"); + HtmlTextInput stringParameterInput = (HtmlTextInput) DomNodeUtil.selectSingleNode(element, ".//input[@name='value']"); assertEquals("defaultValue", stringParameterInput.getAttribute("value")); - assertEquals("string", ((HtmlElement) element.selectSingleNode("td[@class='setting-name']")).getTextContent()); + assertEquals("string", ((HtmlElement) DomNodeUtil.selectSingleNode(element, "td[@class='setting-name']")).getTextContent()); stringParameterInput.setAttribute("value", "newValue"); - element = (HtmlElement) form.selectSingleNode("//tr[td/div/input/@value='boolean']"); + element = (HtmlElement) DomNodeUtil.selectSingleNode(form, "//tr[td/div/input/@value='boolean']"); assertNotNull(element); - assertEquals("boolean description", ((HtmlElement) element.getNextSibling().getNextSibling().selectSingleNode("td[@class='setting-description']")).getTextContent()); - Object o = element.selectSingleNode(".//input[@name='value']"); + assertEquals("boolean description", ((HtmlElement) DomNodeUtil.selectSingleNode(element.getNextSibling().getNextSibling(), "td[@class='setting-description']")).getTextContent()); + Object o = DomNodeUtil.selectSingleNode(element, ".//input[@name='value']"); System.out.println(o); HtmlCheckBoxInput booleanParameterInput = (HtmlCheckBoxInput) o; assertEquals(true, booleanParameterInput.isChecked()); - assertEquals("boolean", ((HtmlElement) element.selectSingleNode("td[@class='setting-name']")).getTextContent()); + assertEquals("boolean", ((HtmlElement) DomNodeUtil.selectSingleNode(element, "td[@class='setting-name']")).getTextContent()); - element = (HtmlElement) form.selectSingleNode(".//tr[td/div/input/@value='choice']"); + element = (HtmlElement) DomNodeUtil.selectSingleNode(form, ".//tr[td/div/input/@value='choice']"); assertNotNull(element); - assertEquals("choice description", ((HtmlElement) element.getNextSibling().getNextSibling().selectSingleNode("td[@class='setting-description']")).getTextContent()); - assertEquals("choice", ((HtmlElement) element.selectSingleNode("td[@class='setting-name']")).getTextContent()); + assertEquals("choice description", ((HtmlElement) DomNodeUtil.selectSingleNode(element.getNextSibling().getNextSibling(), "td[@class='setting-description']")).getTextContent()); + assertEquals("choice", ((HtmlElement) DomNodeUtil.selectSingleNode(element, "td[@class='setting-name']")).getTextContent()); - element = (HtmlElement) form.selectSingleNode(".//tr[td/div/input/@value='run']"); + element = (HtmlElement) DomNodeUtil.selectSingleNode(form, ".//tr[td/div/input/@value='run']"); assertNotNull(element); - assertEquals("run description", ((HtmlElement) element.getNextSibling().getNextSibling().selectSingleNode("td[@class='setting-description']")).getTextContent()); - assertEquals("run", ((HtmlElement) element.selectSingleNode("td[@class='setting-name']")).getTextContent()); + assertEquals("run description", ((HtmlElement) DomNodeUtil.selectSingleNode(element.getNextSibling().getNextSibling(), "td[@class='setting-description']")).getTextContent()); + assertEquals("run", ((HtmlElement) DomNodeUtil.selectSingleNode(element, "td[@class='setting-name']")).getTextContent()); j.submit(form); Queue.Item q = j.jenkins.getQueue().getItem(project); @@ -96,15 +98,15 @@ public class ParametersTest { project.getBuildersList().add(builder); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.goTo("job/" + project.getName() + "/build?delay=0sec"); HtmlForm form = page.getFormByName("parameters"); - HtmlElement element = (HtmlElement) form.selectSingleNode(".//tr[td/div/input/@value='choice']"); + HtmlElement element = (HtmlElement) DomNodeUtil.selectSingleNode(form, ".//tr[td/div/input/@value='choice']"); assertNotNull(element); - assertEquals("choice description", ((HtmlElement) element.getNextSibling().getNextSibling().selectSingleNode("td[@class='setting-description']")).getTextContent()); - assertEquals("choice", ((HtmlElement) element.selectSingleNode("td[@class='setting-name']")).getTextContent()); - HtmlOption opt = (HtmlOption)element.selectSingleNode("td/div/select/option[@value='Choice <2>']"); + assertEquals("choice description", ((HtmlElement) DomNodeUtil.selectSingleNode(element.getNextSibling().getNextSibling(), "td[@class='setting-description']")).getTextContent()); + assertEquals("choice", ((HtmlElement) DomNodeUtil.selectSingleNode(element, "td[@class='setting-name']")).getTextContent()); + HtmlOption opt = (HtmlOption)DomNodeUtil.selectSingleNode(element, "td/div/select/option[@value='Choice <2>']"); assertNotNull(opt); assertEquals("Choice <2>", opt.asText()); opt.setSelected(true); @@ -183,7 +185,7 @@ public class ParametersTest { project.addProperty(pdp); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.goTo("job/" + project.getName() + "/build?delay=0sec"); HtmlForm form = page.getFormByName("parameters"); @@ -206,12 +208,12 @@ public class ParametersTest { p.addProperty(pdb); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); // Ignore 405 + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); // Ignore 405 HtmlPage page = wc.getPage(p, "build"); // java.lang.IllegalArgumentException: No such parameter definition: . - wc.setThrowExceptionOnFailingStatusCode(true); + wc.getOptions().setThrowExceptionOnFailingStatusCode(true); final HtmlForm form = page.getFormByName("parameters"); - form.submit(form.getButtonByCaption("Build")); + HtmlFormUtil.submit(form, HtmlFormUtil.getButtonByCaption(form, "Build")); } } diff --git a/test/src/test/java/hudson/model/QueueTest.java b/test/src/test/java/hudson/model/QueueTest.java index 283b771a2cb23f3febcc49e01e1875562ee46d3c..6e566f71298854b189a44084fb0d59d699236a95 100644 --- a/test/src/test/java/hudson/model/QueueTest.java +++ b/test/src/test/java/hudson/model/QueueTest.java @@ -25,6 +25,7 @@ package hudson.model; import com.gargoylesoftware.htmlunit.html.HtmlFileInput; import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.xml.XmlPage; import hudson.Launcher; @@ -284,7 +285,7 @@ public class QueueTest { HtmlForm f = p.getFormByName("main"); HtmlFileInput input = (HtmlFileInput) f.getInputByName("test"); input.setData(testData); - f.submit(); + HtmlFormUtil.submit(f); } finally { server.stop(); } diff --git a/test/src/test/java/hudson/model/UserTest.java b/test/src/test/java/hudson/model/UserTest.java index c6a41de76dcb7922cd0f793f168455bef26ff07b..afc67d01315699dc001b3b799985e9176e0ceb4c 100644 --- a/test/src/test/java/hudson/model/UserTest.java +++ b/test/src/test/java/hudson/model/UserTest.java @@ -25,6 +25,7 @@ package hudson.model; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; +import com.gargoylesoftware.htmlunit.ScriptException; import com.gargoylesoftware.htmlunit.WebAssert; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; @@ -51,11 +52,12 @@ import org.acegisecurity.context.SecurityContextHolder; import static org.junit.Assert.*; import static org.junit.Assume.*; + +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.FakeChangeLogSCM; -import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.recipes.LocalData; @@ -452,6 +454,7 @@ public class UserTest { } catch(FailingHttpStatusCodeException e){ //ok exception should be thrown + Assert.assertEquals(400, e.getStatusCode()); } assertTrue("User should not delete himself from memory.", User.getAll().contains(user)); assertTrue("User should not delete his persistent data.", user.getConfigFile().exists()); diff --git a/test/src/test/java/hudson/model/ViewPropertyTest.java b/test/src/test/java/hudson/model/ViewPropertyTest.java index 5aa6ca9919f7b838a6362990d0abc056a8d7c46b..75248659845e05aa9ce3135ce0bde72e403e938d 100644 --- a/test/src/test/java/hudson/model/ViewPropertyTest.java +++ b/test/src/test/java/hudson/model/ViewPropertyTest.java @@ -23,6 +23,7 @@ */ package hudson.model; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlLabel; import hudson.model.Descriptor.FormException; @@ -42,7 +43,7 @@ public class ViewPropertyTest extends HudsonTestCase { // make sure it renders as optionalBlock HtmlForm f = createWebClient().getPage(foo, "configure").getFormByName("viewConfig"); - ((HtmlLabel)f.selectSingleNode(".//LABEL[text()='Debug Property']")).click(); + ((HtmlLabel) DomNodeUtil.selectSingleNode(f, ".//LABEL[text()='Debug Property']")).click(); submit(f); ViewPropertyImpl vp = foo.getProperties().get(ViewPropertyImpl.class); assertEquals("Duke",vp.name); diff --git a/test/src/test/java/hudson/model/ViewTest.java b/test/src/test/java/hudson/model/ViewTest.java index 68c370c2959e64f989e5483a6c9bc169457f211e..eb3d5e0da01a206a6232e7147906c8ff29a15667 100644 --- a/test/src/test/java/hudson/model/ViewTest.java +++ b/test/src/test/java/hudson/model/ViewTest.java @@ -23,11 +23,12 @@ */ package hudson.model; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import jenkins.model.Jenkins; import org.jvnet.hudson.test.Issue; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.HttpMethod; -import com.gargoylesoftware.htmlunit.WebRequestSettings; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlLabel; @@ -48,9 +49,7 @@ import hudson.slaves.DumbSlave; import hudson.util.HudsonIsLoading; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import static org.junit.Assert.*; import org.junit.Ignore; import org.junit.Rule; @@ -100,7 +99,7 @@ public class ViewTest { WebClient wc = j.createWebClient(); HtmlPage userPage = wc.goTo("user/me"); - HtmlAnchor privateViewsLink = userPage.getFirstAnchorByText("My Views"); + HtmlAnchor privateViewsLink = userPage.getAnchorByText("My Views"); assertNotNull("My Views link not available", privateViewsLink); HtmlPage privateViewsPage = (HtmlPage) privateViewsLink.click(); @@ -157,7 +156,7 @@ public class ViewTest { @Test public void allImagesCanBeLoaded() throws Exception { User.get("user", true); WebClient webClient = j.createWebClient(); - webClient.setJavaScriptEnabled(false); + webClient.getOptions().setJavaScriptEnabled(false); j.assertAllImageLoadSuccessfully(webClient.goTo("asynchPeople")); } @@ -196,8 +195,9 @@ public class ViewTest { String xml = wc.goToXml("view/v/config.xml").getContent(); assertTrue(xml, xml.contains("one")); xml = xml.replace("one", "two"); - WebRequestSettings req = new WebRequestSettings(wc.createCrumbedUrl("view/v/config.xml"), HttpMethod.POST); + WebRequest req = new WebRequest(wc.createCrumbedUrl("view/v/config.xml"), HttpMethod.POST); req.setRequestBody(xml); + req.setEncodingType(null); wc.getPage(req); assertEquals("two", view.getDescription()); xml = new XmlFile(Jenkins.XSTREAM, new File(j.jenkins.getRootDir(), "config.xml")).asString(); @@ -401,7 +401,7 @@ public class ViewTest { View view = listView("foo"); Thread.sleep(100000); HtmlForm f = j.createWebClient().getPage(view, "configure").getFormByName("viewConfig"); - ((HtmlLabel)f.selectSingleNode(".//LABEL[text()='Test property']")).click(); + ((HtmlLabel) DomNodeUtil.selectSingleNode(f, ".//LABEL[text()='Test property']")).click(); j.submit(f); assertNotNull("View should contains ViewPropertyImpl property.", view.getProperties().get(PropertyImpl.class)); } diff --git a/test/src/test/java/hudson/search/SearchTest.java b/test/src/test/java/hudson/search/SearchTest.java index 090fab430b2d4012b3b6b2831667e6d0038eaf5a..c8949a63171b8c0c67add052094f0d5e438e230e 100644 --- a/test/src/test/java/hudson/search/SearchTest.java +++ b/test/src/test/java/hudson/search/SearchTest.java @@ -118,7 +118,7 @@ public class SearchTest { assertNotNull(result); j.assertGoodStatus(result); - URL resultUrl = result.getWebResponse().getUrl(); + URL resultUrl = result.getUrl(); assertTrue(resultUrl.toString().equals(j.getInstance().getRootUrl() + myFreeStyleProject.getUrl())); } @@ -134,7 +134,7 @@ public class SearchTest { assertNotNull(result); j.assertGoodStatus(result); - URL resultUrl = result.getWebResponse().getUrl(); + URL resultUrl = result.getUrl(); assertTrue(resultUrl.toString().equals(j.getInstance().getRootUrl() + myFreeStyleProject.getUrl())); } diff --git a/test/src/test/java/hudson/security/LoginTest.java b/test/src/test/java/hudson/security/LoginTest.java index 37551a39a3b640dc770d2ec7cb00050f6db3e99c..86c1a0662ce9251321dc16267064f85c04169d34 100644 --- a/test/src/test/java/hudson/security/LoginTest.java +++ b/test/src/test/java/hudson/security/LoginTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput; @@ -40,7 +41,7 @@ public class LoginTest { private void verifyNotError(WebClient wc) throws IOException, SAXException { HtmlPage p = wc.goTo("loginError"); - URL url = p.getWebResponse().getUrl(); + URL url = p.getUrl(); System.out.println(url); assertFalse(url.toExternalForm().contains("login")); } @@ -84,7 +85,7 @@ public class LoginTest { public void loginRememberMe() throws Exception { WebClient wc = j.createWebClient(); - prepareLoginFormWithRememberMeChecked(wc).submit(null); + HtmlFormUtil.submit(prepareLoginFormWithRememberMeChecked(wc), null); assertNotNull(getRememberMeCookie(wc)); } @@ -100,7 +101,7 @@ public class LoginTest { HtmlForm form = prepareLoginFormWithRememberMeChecked(wc); j.jenkins.setDisableRememberMe(true); - form.submit(null); + HtmlFormUtil.submit(form, null); assertNull(getRememberMeCookie(wc)); } diff --git a/test/src/test/java/hudson/security/pages/SignupPage.java b/test/src/test/java/hudson/security/pages/SignupPage.java index 5007bce1b5cf062dc24877b036cf09861f3c427a..2b05f95a16616d4709f55b25de954487fb4223fb 100644 --- a/test/src/test/java/hudson/security/pages/SignupPage.java +++ b/test/src/test/java/hudson/security/pages/SignupPage.java @@ -60,6 +60,6 @@ public class SignupPage { } public void assertErrorContains(String msg) { - assertThat(signupForm.getElementById("main-panel").getTextContent(),containsString(msg)); + assertThat(signupForm.getPage().getElementById("main-panel").getTextContent(),containsString(msg)); } } diff --git a/test/src/test/java/hudson/slaves/JNLPLauncherTest.java b/test/src/test/java/hudson/slaves/JNLPLauncherTest.java index 26e7c1a1a2ae8c2336b4fec3f229ff7cb4764e5b..7184b1e147d5bfa39c50d39b97220c680e265e0e 100644 --- a/test/src/test/java/hudson/slaves/JNLPLauncherTest.java +++ b/test/src/test/java/hudson/slaves/JNLPLauncherTest.java @@ -137,7 +137,7 @@ public class JNLPLauncherTest extends HudsonTestCase { private String getJnlpLink(Computer c) throws Exception { HtmlPage p = new WebClient().goTo("computer/"+c.getName()+"/"); String href = ((HtmlAnchor) p.getElementById("jnlp-link")).getHrefAttribute(); - href = new URL(new URL(p.getDocumentURI()),href).toExternalForm(); + href = new URL(new URL(p.getUrl().toExternalForm()),href).toExternalForm(); return href; } diff --git a/test/src/test/java/hudson/slaves/NodePropertyTest.java b/test/src/test/java/hudson/slaves/NodePropertyTest.java index 6bcdb8070e0c1f57b4381dd77db4254d9a1988cf..27e88fc58af86bbddcafd3e7da605aedd4b395bd 100644 --- a/test/src/test/java/hudson/slaves/NodePropertyTest.java +++ b/test/src/test/java/hudson/slaves/NodePropertyTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlLabel; import hudson.model.Descriptor.FormException; @@ -63,7 +64,7 @@ public class NodePropertyTest { public void basicConfigRoundtrip() throws Exception { DumbSlave s = j.createSlave(); HtmlForm f = j.createWebClient().goTo("computer/" + s.getNodeName() + "/configure").getFormByName("config"); - ((HtmlLabel)f.selectSingleNode(".//LABEL[text()='Some Property']")).click(); + ((HtmlLabel)DomNodeUtil.selectSingleNode(f, ".//LABEL[text()='Some Property']")).click(); j.submit(f); PropertyImpl p = j.jenkins.getNode(s.getNodeName()).getNodeProperties().get(PropertyImpl.class); assertEquals("Duke",p.name); diff --git a/test/src/test/java/hudson/tools/JDKInstallerTest.java b/test/src/test/java/hudson/tools/JDKInstallerTest.java index f4b79f6ca57514269d693aaa4d2bc51e2c647229..8f7bf1cf651f753284b874b251ace86cd7b6a624 100644 --- a/test/src/test/java/hudson/tools/JDKInstallerTest.java +++ b/test/src/test/java/hudson/tools/JDKInstallerTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.tools.JDKInstaller.DescriptorImpl; import org.junit.Before; @@ -74,7 +75,7 @@ public class JDKInstallerTest { HtmlForm form = p.getFormByName("postCredential"); form.getInputByName("username").setValueAttribute("foo"); form.getInputByName("password").setValueAttribute("bar"); - form.submit(null); + HtmlFormUtil.submit(form, null); DescriptorImpl d = j.jenkins.getDescriptorByType(DescriptorImpl.class); assertEquals("foo",d.getUsername()); diff --git a/test/src/test/java/hudson/util/FormFieldValidatorTest.java b/test/src/test/java/hudson/util/FormFieldValidatorTest.java index bcdd0ecde02423beac3f04346bf6b917204dd562..521ee8c70e55ceabc019ea89485509ae7346cb09 100644 --- a/test/src/test/java/hudson/util/FormFieldValidatorTest.java +++ b/test/src/test/java/hudson/util/FormFieldValidatorTest.java @@ -25,11 +25,13 @@ package hudson.util; import static org.junit.Assert.fail; +import com.gargoylesoftware.htmlunit.WebResponseListener; import hudson.model.FreeStyleProject; import hudson.tasks.BuildStepMonitor; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.Publisher; import hudson.util.FormFieldValidatorTest.BrokenFormValidatorBuilder.DescriptorImpl; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; @@ -83,13 +85,16 @@ public class FormFieldValidatorTest { try { FreeStyleProject p = j.createFreeStyleProject(); p.getPublishersList().add(new BrokenFormValidatorBuilder()); - j.createWebClient().getPage(p, "configure"); - fail("should have failed"); - } catch(AssertionError e) { - if(e.getMessage().contains("doCheckXyz is broken")) - ; // expected - else - throw e; + + JenkinsRule.WebClient webclient = j.createWebClient(); + WebResponseListener.StatusListener statusListener = new WebResponseListener.StatusListener(500); + webclient.addWebResponseListener(statusListener); + + webclient.getPage(p, "configure"); + + statusListener.assertHasResponses(); + String contentAsString = statusListener.getResponses().get(0).getContentAsString(); + Assert.assertTrue(contentAsString.contains("doCheckXyz is broken")); } finally { Publisher.all().remove(d); } diff --git a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java index fa3d3ad1cf61b2fdac63056a96b403ccda723445..f929d6b2bc51784e0f524cae1cf61396abacda99 100644 --- a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java +++ b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java @@ -58,7 +58,7 @@ import org.kohsuke.stapler.StaplerRequest; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.HttpMethod; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; public class RobustReflectionConverterTest { @@ -201,10 +201,11 @@ public class RobustReflectionConverterTest { r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); WebClient wc = r.createWebClient(); wc.login("test", "test"); - WebRequestSettings req = new WebRequestSettings( + WebRequest req = new WebRequest( wc.createCrumbedUrl(String.format("%s/config.xml", p.getUrl())), HttpMethod.POST ); + req.setEncodingType(null); req.setRequestBody(String.format(CONFIGURATION_TEMPLATE, "badvalue", AcceptOnlySpecificKeyword.ACCEPT_KEYWORD)); wc.getPage(req); @@ -233,10 +234,11 @@ public class RobustReflectionConverterTest { r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); WebClient wc = r.createWebClient(); wc.login("test", "test"); - WebRequestSettings req = new WebRequestSettings( + WebRequest req = new WebRequest( wc.createCrumbedUrl(String.format("%s/config.xml", p.getUrl())), HttpMethod.POST ); + req.setEncodingType(null); req.setRequestBody(String.format(CONFIGURATION_TEMPLATE, AcceptOnlySpecificKeyword.ACCEPT_KEYWORD, "badvalue")); try { diff --git a/test/src/test/java/jenkins/model/JenkinsTest.java b/test/src/test/java/jenkins/model/JenkinsTest.java index 4b4bc7422d655efe635e155b95659dc0fe39361c..6664193d57d7d0db0f47a8ed1a783b658e63a548 100644 --- a/test/src/test/java/jenkins/model/JenkinsTest.java +++ b/test/src/test/java/jenkins/model/JenkinsTest.java @@ -35,7 +35,7 @@ import static org.junit.Assert.fail; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.HttpMethod; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; import com.gargoylesoftware.htmlunit.WebResponse; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; @@ -287,11 +287,11 @@ public class JenkinsTest { wc.goTo("script"); wc.assertFails("script?script=System.setProperty('hack','me')", HttpURLConnection.HTTP_BAD_METHOD); assertNull(System.getProperty("hack")); - WebRequestSettings req = new WebRequestSettings(new URL(wc.getContextPath() + "script?script=System.setProperty('hack','me')"), HttpMethod.POST); + WebRequest req = new WebRequest(new URL(wc.getContextPath() + "script?script=System.setProperty('hack','me')"), HttpMethod.POST); wc.getPage(wc.addCrumb(req)); assertEquals("me", System.getProperty("hack")); wc.assertFails("scriptText?script=System.setProperty('hack','me')", HttpURLConnection.HTTP_BAD_METHOD); - req = new WebRequestSettings(new URL(wc.getContextPath() + "scriptText?script=System.setProperty('huck','you')"), HttpMethod.POST); + req = new WebRequest(new URL(wc.getContextPath() + "scriptText?script=System.setProperty('huck','you')"), HttpMethod.POST); wc.getPage(wc.addCrumb(req)); assertEquals("you", System.getProperty("huck")); wc.login("bob"); @@ -333,7 +333,8 @@ public class JenkinsTest { } } private String eval(WebClient wc) throws Exception { - WebRequestSettings req = new WebRequestSettings(wc.createCrumbedUrl("eval"), HttpMethod.POST); + WebRequest req = new WebRequest(wc.createCrumbedUrl("eval"), HttpMethod.POST); + req.setEncodingType(null); req.setRequestBody("${1+2}"); return wc.getPage(req).getWebResponse().getContentAsString(); } @@ -393,7 +394,7 @@ public class JenkinsTest { assertTrue(!Jenkins.getInstance().getACL().hasPermission(Jenkins.ANONYMOUS,Jenkins.READ)); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage p = wc.goTo("error/reportError"); assertEquals(p.asText(), 400, p.getWebResponse().getStatusCode()); // not 403 forbidden @@ -436,13 +437,15 @@ public class JenkinsTest { @Test public void runScriptOnOfflineComputer() throws Exception { - DumbSlave slave = j.createSlave(); + DumbSlave slave = j.createSlave(true); + j.disconnectSlave(slave); + URL url = new URL(j.getURL(), "computer/" + slave.getNodeName() + "/scriptText?script=println(42)"); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); - WebRequestSettings req = new WebRequestSettings(url, HttpMethod.POST); + WebRequest req = new WebRequest(url, HttpMethod.POST); Page page = wc.getPage(wc.addCrumb(req)); WebResponse rsp = page.getWebResponse(); diff --git a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java index a28c0582a0412d1dfd67d2260c6369fb682b6a4d..906431328cd84a69752d6b08a1511da61701d683 100644 --- a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java +++ b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java @@ -5,24 +5,45 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.DownloadedContent; import com.gargoylesoftware.htmlunit.HttpWebConnection; +import com.gargoylesoftware.htmlunit.WebConnection; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.WebResponse; +import com.gargoylesoftware.htmlunit.WebResponseData; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.util.NameValuePair; +import com.gargoylesoftware.htmlunit.util.UrlUtils; import hudson.Util; import hudson.model.User; import jenkins.model.Jenkins; -import org.apache.commons.httpclient.Credentials; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.auth.AuthScheme; -import org.apache.commons.httpclient.auth.AuthScope; -import org.apache.commons.httpclient.auth.CredentialsNotAvailableException; -import org.apache.commons.httpclient.auth.CredentialsProvider; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScheme; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.AuthCache; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule.WebClient; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Callable; /** @@ -53,23 +74,10 @@ public class ApiTokenPropertyTest { assertSame(t, u.getProperty(ApiTokenProperty.class)); WebClient wc = j.createWebClient(); - wc.setCredentialsProvider(new CredentialsProvider() { - public Credentials getCredentials(AuthScheme scheme, String host, int port, boolean proxy) throws CredentialsNotAvailableException { - return new UsernamePasswordCredentials("foo", token); - } - }); - wc.setWebConnection(new HttpWebConnection(wc) { - @Override - protected HttpClient getHttpClient() { - HttpClient c = super.getHttpClient(); - c.getParams().setAuthenticationPreemptive(true); - c.getState().setCredentials(new AuthScope("localhost", AuthScope.ANY_PORT, AuthScope.ANY_REALM), new UsernamePasswordCredentials("foo", token)); - return c; - } - }); + configureWebConnection(wc, token); // test the authentication - assertEquals(u,wc.executeOnServer(new Callable() { + assertEquals(u, wc.executeOnServer(new Callable() { public User call() throws Exception { return User.current(); } @@ -98,4 +106,71 @@ public class ApiTokenPropertyTest { u.addProperty(t); assertTrue(t.getApiToken().equals(Util.getDigestOf(historicalInitialValue+"somethingElse"))); } + + private void configureWebConnection(final WebClient wc, final String token) throws IOException { + // See https://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html + final UsernamePasswordCredentials fooCreds = new UsernamePasswordCredentials("foo", token); + + URL hostUrl = j.getURL(); + final HttpHost targetHost = new HttpHost(hostUrl.getHost(), hostUrl.getPort(), hostUrl.getProtocol()); + CredentialsProvider credsProvider = new BasicCredentialsProvider() { + @Override + public Credentials getCredentials(AuthScope authscope) { + return fooCreds; + } + }; + credsProvider.setCredentials( + new AuthScope("localhost", AuthScope.ANY_PORT, AuthScope.ANY_REALM), + fooCreds); + + // Create AuthCache instance + AuthCache authCache = new BasicAuthCache(); + // Generate BASIC scheme object and add it to the local auth cache + AuthScheme authScheme = new BasicScheme(); + authCache.put(targetHost, authScheme); + + // Add AuthCache to the execution context + final HttpClientContext context = HttpClientContext.create(); + context.setCredentialsProvider(credsProvider); + context.setAuthCache(authCache); + + wc.setCredentialsProvider(credsProvider); + + // Need to create our own WebConnection that gives us control of HttpClient execution, + // allowing us to pass our own HttpClientContext etc. HttpWebConnection has its own + // private HttpClientContext instance, which means we can't authenticate properly. + wc.setWebConnection(new WebConnection() { + @Override + public WebResponse getResponse(WebRequest request) throws IOException { + try { + long startTime = System.currentTimeMillis(); + + HttpClientBuilder builder = HttpClientBuilder.create(); + CloseableHttpClient httpClient = builder.build(); + URL url = UrlUtils.encodeUrl(request.getUrl(), false, request.getCharset()); + HttpGet method = new HttpGet(url.toURI()); + + CloseableHttpResponse response = httpClient.execute(targetHost, method, context); + + HttpEntity httpEntity = response.getEntity(); + DownloadedContent responseBody = HttpWebConnection.downloadContent(httpEntity.getContent(), wc.getOptions().getMaxInMemory()); + + String statusMessage = response.getStatusLine().getReasonPhrase(); + if (statusMessage == null) { + statusMessage = "Unknown status message"; + } + int statusCode = response.getStatusLine().getStatusCode(); + List headers = new ArrayList<>(); + for (final Header header : response.getAllHeaders()) { + headers.add(new NameValuePair(header.getName(), header.getValue())); + } + + WebResponseData responseData = new WebResponseData(responseBody, statusCode, statusMessage, headers); + return new WebResponse(responseData, request, (System.currentTimeMillis() - startTime)); + } catch (Exception e) { + throw new AssertionError("Failed to execute WebRequest.", e); + } + } + }); + } } diff --git a/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java b/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java index b83327a11857a5419e464e9a3ca34f3756fa7337..9b334db55ea29efcf80e37ba0a89d78e86077ec8 100644 --- a/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java +++ b/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java @@ -5,7 +5,7 @@ import static org.junit.Assert.fail; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; import hudson.model.UnprotectedRootAction; import hudson.model.User; import hudson.util.HttpResponses; @@ -81,7 +81,8 @@ public class BasicHeaderProcessorTest { } private void makeRequestWithAuthAndVerify(String userAndPass, String username) throws IOException, SAXException { - WebRequestSettings req = new WebRequestSettings(new URL(j.getURL(),"test")); + WebRequest req = new WebRequest(new URL(j.getURL(),"test")); + req.setEncodingType(null); if (userAndPass!=null) req.setAdditionalHeader("Authorization","Basic "+Scrambler.scramble(userAndPass)); Page p = wc.getPage(req); diff --git a/test/src/test/java/jenkins/security/FrameOptionsPageDecoratorTest.java b/test/src/test/java/jenkins/security/FrameOptionsPageDecoratorTest.java index f4507f81c8236ce1b6e8d55499e6382241ccde17..0cb73f1d5a4a0ad41a52ffe82e51c82756a45b8b 100644 --- a/test/src/test/java/jenkins/security/FrameOptionsPageDecoratorTest.java +++ b/test/src/test/java/jenkins/security/FrameOptionsPageDecoratorTest.java @@ -5,7 +5,7 @@ import static org.junit.Assert.assertNull; import com.gargoylesoftware.htmlunit.WebResponse; import com.gargoylesoftware.htmlunit.html.HtmlPage; -import org.apache.commons.httpclient.NameValuePair; +import com.gargoylesoftware.htmlunit.util.NameValuePair; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; diff --git a/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java b/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java index 0797dc396fb4cbe82d2ce988ed730413ce3a9eff..ea7a08ba458726718dcf9efcea3125d0f08ee4ea 100644 --- a/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java +++ b/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java @@ -1,6 +1,7 @@ package jenkins.security; import com.gargoylesoftware.htmlunit.ElementNotFoundException; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlButton; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; @@ -100,8 +101,8 @@ public class RekeySecretAdminMonitorTest extends HudsonTestCase { // should be no warning/error now HtmlPage manage = wc.goTo("manage"); - assertEquals(0,manage.selectNodes("//*[class='error']").size()); - assertEquals(0,manage.selectNodes("//*[class='warning']").size()); + assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='error']").size()); + assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='warning']").size()); // and the data should be rewritten verifyRewrite(jenkins.getRootDir()); @@ -140,8 +141,8 @@ public class RekeySecretAdminMonitorTest extends HudsonTestCase { // should be no warning/error now HtmlPage manage = wc.goTo("/manage"); - assertEquals(0,manage.selectNodes("//*[class='error']").size()); - assertEquals(0,manage.selectNodes("//*[class='warning']").size()); + assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='error']").size()); + assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='warning']").size()); } private String encryptOld(String str) throws Exception { diff --git a/test/src/test/java/jenkins/security/Security177Test.java b/test/src/test/java/jenkins/security/Security177Test.java index c212cba2d23e3551647c20aa884f7210b646dd89..d52b30882290d315747206e224650be90cf96fa8 100644 --- a/test/src/test/java/jenkins/security/Security177Test.java +++ b/test/src/test/java/jenkins/security/Security177Test.java @@ -20,7 +20,7 @@ public class Security177Test { @Test public void nosniff() throws Exception { WebClient wc = jenkins.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); URL u = jenkins.getURL(); verifyNoSniff(wc.getPage(new URL(u, "adjuncts/507db12b/nosuch/adjunct.js"))); diff --git a/test/src/test/java/jenkins/widgets/BuildListTableTest.java b/test/src/test/java/jenkins/widgets/BuildListTableTest.java index bfdbaf60d166130d50d58e5b33d7835a8808909b..cc8992d04202ab9abccbce369187464d419bba0a 100644 --- a/test/src/test/java/jenkins/widgets/BuildListTableTest.java +++ b/test/src/test/java/jenkins/widgets/BuildListTableTest.java @@ -59,14 +59,14 @@ public class BuildListTableTest { assertEquals(0, wc.waitForBackgroundJavaScript(120000)); HtmlAnchor anchor = page.getAnchorByText("d » d2 » p"); String href = anchor.getHrefAttribute(); - URL target = URI.create(page.getDocumentURI()).resolve(href).toURL(); + URL target = URI.create(page.getUrl().toExternalForm()).resolve(href).toURL(); wc.getPage(target); assertEquals(href, r.getURL() + "view/v1/job/d/view/v2/job/d2/job/p/", target.toString()); page = wc.goTo("job/d/view/All/builds?suppressTimelineControl=true"); assertEquals(0, wc.waitForBackgroundJavaScript(120000)); anchor = page.getAnchorByText("d » d2 » p"); href = anchor.getHrefAttribute(); - target = URI.create(page.getDocumentURI()).resolve(href).toURL(); + target = URI.create(page.getUrl().toExternalForm()).resolve(href).toURL(); wc.getPage(target); assertEquals(href, r.getURL() + "job/d/job/d2/job/p/", target.toString()); } diff --git a/test/src/test/java/lib/form/AdvancedButtonTest.java b/test/src/test/java/lib/form/AdvancedButtonTest.java index afba6e2cb6630f4442215d885ebf1e084693608e..e96c2c61b6c035c1c0638ea2e0dc58a4a524297e 100644 --- a/test/src/test/java/lib/form/AdvancedButtonTest.java +++ b/test/src/test/java/lib/form/AdvancedButtonTest.java @@ -1,6 +1,7 @@ package lib.form; import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.util.FormValidation; import net.sf.json.JSONObject; @@ -17,7 +18,7 @@ public class AdvancedButtonTest extends HudsonTestCase { public void testNestedOptionalBlock() throws Exception { HtmlPage p = createWebClient().goTo("self/testNestedOptionalBlock"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Advanced...").click(); + HtmlFormUtil.getButtonByCaption(f, "Advanced...").click(); f.getInputByName("c").click(); submit(f); } diff --git a/test/src/test/java/lib/form/ExpandableTextboxTest.java b/test/src/test/java/lib/form/ExpandableTextboxTest.java index b930652d15a8338fc94009262cfcc3c7af649c68..75f24b917703a3caf27595acf3d23864ad05f65d 100644 --- a/test/src/test/java/lib/form/ExpandableTextboxTest.java +++ b/test/src/test/java/lib/form/ExpandableTextboxTest.java @@ -25,7 +25,7 @@ package lib.form; import static com.gargoylesoftware.htmlunit.HttpMethod.POST; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.HudsonTestCase; @@ -53,7 +53,8 @@ public class ExpandableTextboxTest extends HudsonTestCase { protected HtmlPage evaluateAsHtml(String jellyScript) throws Exception { HudsonTestCase.WebClient wc = new WebClient(); - WebRequestSettings req = new WebRequestSettings(wc.createCrumbedUrl("eval"), POST); + WebRequest req = new WebRequest(wc.createCrumbedUrl("eval"), POST); + req.setEncodingType(null); req.setRequestBody(""+jellyScript+""); Page page = wc.getPage(req); return (HtmlPage) page; diff --git a/test/src/test/java/lib/form/RepeatableTest.java b/test/src/test/java/lib/form/RepeatableTest.java index 9807f14f5a088baa902555d193719ce2fcb1067e..395e4b886f4b41c50a1c76ae6d7174cfe6c2741f 100644 --- a/test/src/test/java/lib/form/RepeatableTest.java +++ b/test/src/test/java/lib/form/RepeatableTest.java @@ -24,6 +24,7 @@ package lib.form; import com.gargoylesoftware.htmlunit.ElementNotFoundException; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlSelect; @@ -33,7 +34,6 @@ import java.util.ArrayList; import java.util.List; import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptJob; -import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptJobManagerImpl; import hudson.DescriptorExtensionList; import hudson.Extension; import hudson.ExtensionPoint; @@ -68,11 +68,11 @@ public class RepeatableTest extends HudsonTestCase { private void doTestSimple() throws Exception { HtmlPage p = createWebClient().goTo("self/testSimple"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("value one"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("value two"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("value three"); f.getInputsByName("bool").get(2).click(); submit(f); @@ -201,10 +201,10 @@ public class RepeatableTest extends HudsonTestCase { public void testRadio() throws Exception { HtmlPage p = createWebClient().goTo("self/testRadio"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("txt one"); f.getElementsByAttribute("INPUT", "type", "radio").get(1).click(); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("txt two"); f.getElementsByAttribute("INPUT", "type", "radio").get(3).click(); submit(f); @@ -224,7 +224,7 @@ public class RepeatableTest extends HudsonTestCase { list.add(new FooRadio("three", "one")); HtmlPage p = createWebClient().goTo("self/testRadio"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("txt 4"); f.getElementsByAttribute("INPUT", "type", "radio").get(7).click(); submit(f); @@ -238,12 +238,12 @@ public class RepeatableTest extends HudsonTestCase { public void testRadioBlock() throws Exception { HtmlPage p = createWebClient().goTo("self/testRadioBlock"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("txt one"); f.getInputByValue("").setValueAttribute("avalue do not send"); f.getElementsByAttribute("INPUT", "type", "radio").get(1).click(); f.getInputByValue("").setValueAttribute("bvalue"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("txt two"); f.getElementsByAttribute("INPUT", "type", "radio").get(2).click(); f.getInputByValue("").setValueAttribute("avalue two"); @@ -303,11 +303,11 @@ public class RepeatableTest extends HudsonTestCase { public void testDropdownList() throws Exception { HtmlPage p = createWebClient().goTo("self/testDropdownList"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); waitForJavaScript(p); f.getInputByValue("").setValueAttribute("17"); // seeds f.getInputByValue("").setValueAttribute("pie"); // word - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); waitForJavaScript(p); // select banana in 2nd select element: ((HtmlSelect)f.getElementsByTagName("select").get(1)).getOption(1).click(); @@ -367,7 +367,7 @@ public class RepeatableTest extends HudsonTestCase { } private void clickButton(HtmlPage p, HtmlForm f, String caption) throws IOException { - f.getButtonByCaption(caption).click(); + HtmlFormUtil.getButtonByCaption(f, caption).click(); waitForJavaScript(p); } @@ -377,10 +377,10 @@ public class RepeatableTest extends HudsonTestCase { try { clickButton(p, f, "Add"); f.getElementsByAttribute("input", "type", "radio").get(1).click(); // outer=two - f.getButtonByCaption("Add Moo").click(); + HtmlFormUtil.getButtonByCaption(f, "Add Moo").click(); waitForJavaScript(p); f.getElementsByAttribute("input", "type", "radio").get(2).click(); // inner=inone - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); waitForJavaScript(p); f.getElementsByAttribute("input", "type", "radio").get(4).click(); // outer=one Thread.sleep(500); diff --git a/test/src/test/java/lib/form/RowVisibilityGroupTest.java b/test/src/test/java/lib/form/RowVisibilityGroupTest.java index 2163ac0a6906c5fdc43f3bf6ca18af1fbc00bae9..1c00a255db466525f9400a57385da6883b415a9b 100644 --- a/test/src/test/java/lib/form/RowVisibilityGroupTest.java +++ b/test/src/test/java/lib/form/RowVisibilityGroupTest.java @@ -1,5 +1,6 @@ package lib.form; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlInput; import com.gargoylesoftware.htmlunit.html.HtmlOption; @@ -42,9 +43,9 @@ public class RowVisibilityGroupTest extends HudsonTestCase implements Describabl public void test1() throws Exception { HtmlPage p = createWebClient().goTo("self/test1"); - HtmlElement outer = (HtmlElement)p.selectSingleNode("//INPUT[@name='outer']"); - HtmlElement inner = (HtmlElement)p.selectSingleNode("//INPUT[@name='inner']"); - HtmlInput field = (HtmlInput)p.selectSingleNode("//INPUT[@type='text'][@name='_.field']"); + HtmlElement outer = (HtmlElement)DomNodeUtil.selectSingleNode(p, "//INPUT[@name='outer']"); + HtmlElement inner = (HtmlElement)DomNodeUtil.selectSingleNode(p, "//INPUT[@name='inner']"); + HtmlInput field = (HtmlInput)DomNodeUtil.selectSingleNode(p, "//INPUT[@type='text'][@name='_.field']"); // outer gets unfolded, but inner should be still folded outer.click(); @@ -67,7 +68,7 @@ public class RowVisibilityGroupTest extends HudsonTestCase implements Describabl public void test2() throws Exception { HtmlPage p = createWebClient().goTo("self/test2"); - HtmlSelect s = (HtmlSelect)p.selectSingleNode("//SELECT"); + HtmlSelect s = (HtmlSelect)DomNodeUtil.selectSingleNode(p, "//SELECT"); List opts = s.getOptions(); // those first selections will load additional HTMLs @@ -78,13 +79,13 @@ public class RowVisibilityGroupTest extends HudsonTestCase implements Describabl s.setSelectedAttribute(opts.get(0),true); // make sure that the inner control is still hidden - List textboxes = p.selectNodes("//INPUT[@name='_.textbox2']"); + List textboxes = DomNodeUtil.selectNodes(p, "//INPUT[@name='_.textbox2']"); assertEquals(2,textboxes.size()); for (HtmlInput e : textboxes) assertTrue(!e.isDisplayed()); // reveal the text box - List checkboxes = p.selectNodes("//INPUT[@name='inner']"); + List checkboxes = DomNodeUtil.selectNodes(p, "//INPUT[@name='inner']"); assertEquals(2,checkboxes.size()); checkboxes.get(0).click(); assertTrue(textboxes.get(0).isDisplayed()); diff --git a/test/src/test/java/lib/form/ValidateButtonTest.java b/test/src/test/java/lib/form/ValidateButtonTest.java index 6cd1e5fc923775cf8bef90aad1621fb200975a01..fe786090ed21f81bc0b6866a68542af736593c1d 100644 --- a/test/src/test/java/lib/form/ValidateButtonTest.java +++ b/test/src/test/java/lib/form/ValidateButtonTest.java @@ -23,6 +23,9 @@ */ package lib.form; +import com.gargoylesoftware.htmlunit.html.HtmlButton; +import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import org.jvnet.hudson.test.HudsonTestCase; import org.kohsuke.stapler.QueryParameter; import hudson.model.Describable; @@ -41,7 +44,8 @@ public class ValidateButtonTest extends HudsonTestCase implements Describable selects = page.selectNodes("//select"); + List selects = DomNodeUtil.selectNodes(page, "//select"); assertTrue(selects.size()>0); for (HtmlSelect select : selects) { Set title = new HashSet(); diff --git a/test/src/test/java/lib/layout/IconTest.java b/test/src/test/java/lib/layout/IconTest.java index dbcfc7e19b660e74e056ddd3bc8a0e1d818cb1f3..1e9814c8dfffcb7124150b646559660108744b2c 100644 --- a/test/src/test/java/lib/layout/IconTest.java +++ b/test/src/test/java/lib/layout/IconTest.java @@ -23,9 +23,7 @@ */ package lib.layout; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - +import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.google.common.collect.Lists; @@ -53,8 +51,8 @@ public class IconTest extends HudsonTestCase { public void testIcons() throws Exception { HtmlPage p = createWebClient().goTo("self/01_testIcons"); - HtmlElement iconsBlock = p.getElementById("iconsBlock"); - List icons = Lists.newArrayList(iconsBlock.getChildElements()); + DomElement iconsBlock = p.getElementById("iconsBlock"); + List icons = Lists.newArrayList(iconsBlock.getChildElements()); assertIconToImageOkay(icons.get(0), "/images/16x16/aborted.png", "icon-aborted icon-sm"); assertIconToImageOkay(icons.get(1), "/images/24x24/aborted.png", "icon-aborted icon-md"); @@ -72,12 +70,12 @@ public class IconTest extends HudsonTestCase { public void testBallColorTd() throws Exception { HtmlPage p = createWebClient().goTo("self/02_testBallColorTd"); - HtmlElement ballColorAborted = p.getElementById("ballColorAborted"); - List ballIcons = Lists.newArrayList(ballColorAborted.getChildElements()); + DomElement ballColorAborted = p.getElementById("ballColorAborted"); + List ballIcons = Lists.newArrayList(ballColorAborted.getChildElements()); assertIconToImageOkay(ballIcons.get(0), "/images/32x32/aborted.png", "icon-aborted icon-lg"); - HtmlElement statusIcons = p.getElementById("statusIcons"); - List statusIconsList = Lists.newArrayList(statusIcons.getChildElements()); + DomElement statusIcons = p.getElementById("statusIcons"); + List statusIconsList = Lists.newArrayList(statusIcons.getChildElements()); assertIconToImageOkay(statusIconsList.get(0), "/images/32x32/folder.png", "icon-folder icon-lg"); assertIconToImageOkay(statusIconsList.get(1), "/plugin/12345/icons/s2.png"); @@ -86,8 +84,8 @@ public class IconTest extends HudsonTestCase { public void testTasks() throws Exception { HtmlPage p = createWebClient().goTo("self/03_testTask"); - HtmlElement tasksDiv = p.getElementById("tasks"); - List taskDivs = Lists.newArrayList(tasksDiv.getChildElements()); + DomElement tasksDiv = p.getElementById("tasks"); + List taskDivs = Lists.newArrayList(tasksDiv.getChildElements()); assertIconToImageOkay(taskDivs.get(0).getElementsByTagName("img").get(0), "/images/24x24/up.png", "icon-up icon-md"); assertIconToImageOkay(taskDivs.get(1).getElementsByTagName("img").get(0), "/images/24x24/folder.png", "icon-folder icon-md"); @@ -120,11 +118,11 @@ public class IconTest extends HudsonTestCase { }; } - private void assertIconToImageOkay(HtmlElement icon, String imgPath) { + private void assertIconToImageOkay(DomElement icon, String imgPath) { assertIconToImageOkay(icon, imgPath, null); } - private void assertIconToImageOkay(HtmlElement icon, String imgPath, String classSpec) { + private void assertIconToImageOkay(DomElement icon, String imgPath, String classSpec) { assertEquals("img", icon.getTagName()); assertTrue(icon.getAttribute("src").endsWith(imgPath)); if (classSpec != null) { diff --git a/test/src/test/java/lib/layout/LayoutTest.java b/test/src/test/java/lib/layout/LayoutTest.java index 8590ff4aed53fa543e9b8da8ab8549befb528981..1889d71d51d677c70a7cfc1bf4e07c54cb20fd00 100644 --- a/test/src/test/java/lib/layout/LayoutTest.java +++ b/test/src/test/java/lib/layout/LayoutTest.java @@ -24,7 +24,7 @@ package lib.layout; -import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlLink; import org.junit.Rule; import org.junit.Test; @@ -41,7 +41,7 @@ public class LayoutTest { @Test public void rejectedLinks() throws Exception { JenkinsRule.WebClient wc = r.createWebClient(); String prefix = r.contextPath + '/'; - for (HtmlElement e : wc.goTo("login").getElementsByTagName("link")) { + for (DomElement e : wc.goTo("login").getElementsByTagName("link")) { String href = ((HtmlLink) e).getHrefAttribute(); if (!href.startsWith(prefix)) { System.err.println("ignoring " + href); diff --git a/test/src/test/java/lib/layout/RenderOnDemandTest.java b/test/src/test/java/lib/layout/RenderOnDemandTest.java index 7e450063e4a5257dfa2923d87dcf4f77e5dae43c..8f4a41e33a3cf91845f1aa235423726c6241841c 100644 --- a/test/src/test/java/lib/layout/RenderOnDemandTest.java +++ b/test/src/test/java/lib/layout/RenderOnDemandTest.java @@ -24,6 +24,8 @@ package lib.layout; import com.gargoylesoftware.htmlunit.ScriptResult; +import com.gargoylesoftware.htmlunit.WebClientUtil; +import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.jvnet.hudson.test.HudsonTestCase; @@ -41,9 +43,11 @@ public class RenderOnDemandTest extends HudsonTestCase { HtmlPage p = createWebClient().goTo("self/testBehaviour"); p.executeJavaScript("renderOnDemand(document.getElementsBySelector('.lazy')[0])"); + WebClientUtil.waitForJSExec(p.getWebClient()); // all AJAX calls complete before the above method returns ScriptResult r = p.executeJavaScript("var r=document.getElementsBySelector('DIV.a'); r[0].innerHTML+r[1].innerHTML+r[2].innerHTML"); + WebClientUtil.waitForJSExec(p.getWebClient()); assertEquals("AlphaBravoCharlie",r.getJavaScriptResult().toString()); } @@ -75,14 +79,17 @@ public class RenderOnDemandTest extends HudsonTestCase { HtmlPage p = createWebClient().goTo("self/testScript"); assertNull(p.getElementById("loaded")); - p.getElementById("button").click(); + ((HtmlElement)p.getElementById("button")).click(); + WebClientUtil.waitForJSExec(p.getWebClient()); // all AJAX calls complete before the above method returns - assertNotNull(p.getElementById("loaded")); ScriptResult r = p.executeJavaScript("x"); + WebClientUtil.waitForJSExec(p.getWebClient()); + assertEquals("xxx",r.getJavaScriptResult().toString()); r = p.executeJavaScript("y"); + WebClientUtil.waitForJSExec(p.getWebClient()); assertEquals("yyy",r.getJavaScriptResult().toString()); // if you want to test this in the browser diff --git a/test/src/test/java/lib/layout/TaskTest.java b/test/src/test/java/lib/layout/TaskTest.java index f56b61c4d8f897bb8f5d085fab966f56cafc54e2..916b36c4c8cc99a4897f1edbae7104f28455ea94 100644 --- a/test/src/test/java/lib/layout/TaskTest.java +++ b/test/src/test/java/lib/layout/TaskTest.java @@ -29,6 +29,7 @@ import java.io.IOException; import javax.servlet.ServletException; +import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; import hudson.model.UnprotectedRootAction; import org.junit.Rule; @@ -49,7 +50,7 @@ public class TaskTest { @Test public void postLink() throws Exception { WebClient wc = j.createWebClient(); HtmlPage page = wc.goTo(postLink.getUrlName()); - page.getAnchorByText("POST").click(); + HtmlElementUtil.click(page.getAnchorByText("POST")); assertTrue("Action method should be invoked", postLink.called); } diff --git a/test/src/test/java/org/jvnet/hudson/main/UseRecipesWithJenkinsRuleTest.java b/test/src/test/java/org/jvnet/hudson/main/UseRecipesWithJenkinsRuleTest.java index 18f1672c24ec38c80a74b19340fc00aa9ce5f9c5..c4ded0e43ee03f2b8460e0987d6196af1e495b6c 100644 --- a/test/src/test/java/org/jvnet/hudson/main/UseRecipesWithJenkinsRuleTest.java +++ b/test/src/test/java/org/jvnet/hudson/main/UseRecipesWithJenkinsRuleTest.java @@ -62,7 +62,7 @@ public class UseRecipesWithJenkinsRuleTest { private void verifyNotError(WebClient wc) throws IOException, SAXException { HtmlPage p = wc.goTo("loginError"); - URL url = p.getWebResponse().getUrl(); + URL url = p.getUrl(); System.out.println(url); assertFalse(url.toExternalForm().contains("login")); } diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js index eeeb1172e1889b3c887cec156bf2b1cf3f587ec7..434c64be773d308c3030bf6cc2196a42fcace8c4 100644 --- a/war/src/main/webapp/scripts/hudson-behavior.js +++ b/war/src/main/webapp/scripts/hudson-behavior.js @@ -29,6 +29,11 @@ // for memory leak patterns and how to prevent them. // +if (window.isRunAsTest) { + // Disable postMessage when running in test mode (HtmlUnit). + window.postMessage = false; +} + // create a new object whose prototype is the given object function object(o) { function F() {} diff --git a/war/src/main/webapp/scripts/prototype.js b/war/src/main/webapp/scripts/prototype.js index 79e009d86f67c078863f727a6d85379e088d8f39..63644c0a5c9270323bf7c8156f2301f5b265d88b 100644 --- a/war/src/main/webapp/scripts/prototype.js +++ b/war/src/main/webapp/scripts/prototype.js @@ -1923,13 +1923,7 @@ if (!Node.ELEMENT_NODE) { } var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){ - try { - var el = document.createElement(''); - return el.tagName.toLowerCase() === 'input' && el.name === 'x'; - } - catch(err) { - return false; - } + return false; })(); var element = global.Element;