diff --git a/pom.xml b/pom.xml index 1c2f83a8708a531a980b934c2b5be9c4ba88b35a..be2b7039bdaf040eee41e72ac2e2e5fdce1d8928 100644 --- a/pom.xml +++ b/pom.xml @@ -50,8 +50,6 @@ THE SOFTWARE. core war - test-harness - test-harness-tools test cli plugins diff --git a/test-harness-tools/pom.xml b/test-harness-tools/pom.xml deleted file mode 100644 index 62206c9a5464defa9dbaff5c4e9f00e497e824b2..0000000000000000000000000000000000000000 --- a/test-harness-tools/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - 4.0.0 - - - org.jenkins-ci.main - pom - 1.645-SNAPSHOT - - - jenkins-test-harness-tools - - Test harness tools - Tool installations that may be used by functional tests. - - - - ${project.groupId} - jenkins-test-harness - ${project.version} - - - org.jenkins-ci.plugins - ant - 1.2 - - - - diff --git a/test-harness-tools/src/main/java/org/jvnet/hudson/test/ToolInstallations.java b/test-harness-tools/src/main/java/org/jvnet/hudson/test/ToolInstallations.java deleted file mode 100644 index ccfe529ce69773bf190d75fa8f891b11386f0a63..0000000000000000000000000000000000000000 --- a/test-harness-tools/src/main/java/org/jvnet/hudson/test/ToolInstallations.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * The MIT License - * - * Copyright 2016 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 org.jvnet.hudson.test; - -import hudson.FilePath; -import hudson.Functions; -import hudson.Launcher; -import hudson.tasks.Ant; -import hudson.tasks.Maven; -import hudson.util.StreamTaskListener; -import hudson.util.jna.GNUCLibrary; -import java.io.File; -import java.util.logging.Level; -import java.util.logging.Logger; -import jenkins.model.Jenkins; -import org.junit.rules.TemporaryFolder; - -/** - * Utility to install standard tools in the Jenkins under test. - */ -public class ToolInstallations { - - private static final Logger LOGGER = Logger.getLogger(ToolInstallations.class.getName()); - - /** - * Returns the older default Maven, while still allowing specification of - * other bundled Mavens. - */ - public static Maven.MavenInstallation configureDefaultMaven() throws Exception { - return configureDefaultMaven("apache-maven-2.2.1", Maven.MavenInstallation.MAVEN_20); - } - - public static Maven.MavenInstallation configureMaven3() throws Exception { - Maven.MavenInstallation mvn = configureDefaultMaven("apache-maven-3.0.1", Maven.MavenInstallation.MAVEN_30); - - Maven.MavenInstallation m3 = new Maven.MavenInstallation("apache-maven-3.0.1", mvn.getHome(), JenkinsRule.NO_PROPERTIES); - Jenkins.getInstance().getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(m3); - return m3; - } - - /** - * Locates Maven2 and configure that as the only Maven in the system. - */ - public static Maven.MavenInstallation configureDefaultMaven(String mavenVersion, int mavenReqVersion) throws Exception { - // first if we are running inside Maven, pick that Maven, if it meets the criteria we require.. - File buildDirectory = new File(System.getProperty("buildDirectory", "target")); // TODO relative path - File mvnHome = new File(buildDirectory, mavenVersion); - if (mvnHome.exists()) { - Maven.MavenInstallation mavenInstallation = new Maven.MavenInstallation("default", mvnHome.getAbsolutePath(), JenkinsRule.NO_PROPERTIES); - Jenkins.getInstance().getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(mavenInstallation); - return mavenInstallation; - } - - // Does maven.home point to a Maven installation which satisfies mavenReqVersion? - String home = System.getProperty("maven.home"); - if (home != null) { - Maven.MavenInstallation mavenInstallation = new Maven.MavenInstallation("default", home, JenkinsRule.NO_PROPERTIES); - if (mavenInstallation.meetsMavenReqVersion(new Launcher.LocalLauncher(StreamTaskListener.fromStdout()), mavenReqVersion)) { - Jenkins.getInstance().getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(mavenInstallation); - return mavenInstallation; - } - } - - // otherwise extract the copy we have. - // this happens when a test is invoked from an IDE, for example. - LOGGER.log(Level.WARNING,"Extracting a copy of Maven bundled in the test harness into {0}. " - + "To avoid a performance hit, set the system property ''maven.home'' to point to a Maven2 installation.", mvnHome); - FilePath mvn = Jenkins.getInstance().getRootPath().createTempFile("maven", "zip"); - mvn.copyFrom(JenkinsRule.class.getClassLoader().getResource(mavenVersion + "-bin.zip")); - mvn.unzip(new FilePath(buildDirectory)); - // TODO: switch to tar that preserves file permissions more easily - try { - GNUCLibrary.LIBC.chmod(new File(mvnHome, "bin/mvn").getPath(), 0755); - } catch (LinkageError x) { - // skip; TODO 1.630+ can use Functions.isGlibcSupported - } - - Maven.MavenInstallation mavenInstallation = new Maven.MavenInstallation("default", - mvnHome.getAbsolutePath(), JenkinsRule.NO_PROPERTIES); - Jenkins.getInstance().getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(mavenInstallation); - return mavenInstallation; - } - - /** - * Extracts Ant and configures it. - */ - public static Ant.AntInstallation configureDefaultAnt(TemporaryFolder tmp) throws Exception { - Ant.AntInstallation antInstallation; - if (System.getenv("ANT_HOME") != null) { - antInstallation = new Ant.AntInstallation("default", System.getenv("ANT_HOME"), JenkinsRule.NO_PROPERTIES); - } else { - LOGGER.warning("Extracting a copy of Ant bundled in the test harness. " - + "To avoid a performance hit, set the environment variable ANT_HOME to point to an Ant installation."); - FilePath ant = Jenkins.getInstance().getRootPath().createTempFile("ant", "zip"); - ant.copyFrom(JenkinsRule.class.getClassLoader().getResource("apache-ant-1.8.1-bin.zip")); - File antHome = tmp.newFolder("antHome"); - ant.unzip(new FilePath(antHome)); - // TODO: switch to tar that preserves file permissions more easily - try { - GNUCLibrary.LIBC.chmod(new File(antHome, "apache-ant-1.8.1/bin/ant").getPath(), 0755); - } catch (LinkageError x) { - // skip; TODO 1.630+ can use Functions.isGlibcSupported - } - - antInstallation = new Ant.AntInstallation("default", new File(antHome, "apache-ant-1.8.1").getAbsolutePath(), JenkinsRule.NO_PROPERTIES); - } - Jenkins.getInstance().getDescriptorByType(Ant.DescriptorImpl.class).setInstallations(antInstallation); - return antInstallation; - } - - private ToolInstallations() { - } - -} diff --git a/test-harness-tools/src/main/resources/apache-ant-1.8.1-bin.zip b/test-harness-tools/src/main/resources/apache-ant-1.8.1-bin.zip deleted file mode 100644 index 236c901f9482fbe7218f015a2dcc59acdf7ed829..0000000000000000000000000000000000000000 Binary files a/test-harness-tools/src/main/resources/apache-ant-1.8.1-bin.zip and /dev/null differ diff --git a/test-harness-tools/src/main/resources/apache-maven-2.2.1-bin.zip b/test-harness-tools/src/main/resources/apache-maven-2.2.1-bin.zip deleted file mode 100644 index 641b60a67952ce89628037b07aff2c2cbab86736..0000000000000000000000000000000000000000 Binary files a/test-harness-tools/src/main/resources/apache-maven-2.2.1-bin.zip and /dev/null differ diff --git a/test-harness-tools/src/main/resources/apache-maven-3.0.1-bin.zip b/test-harness-tools/src/main/resources/apache-maven-3.0.1-bin.zip deleted file mode 100644 index d4fdcfb2cd334a3c9fc361f8bdd311cdada9c8d0..0000000000000000000000000000000000000000 Binary files a/test-harness-tools/src/main/resources/apache-maven-3.0.1-bin.zip and /dev/null differ diff --git a/test-harness-tools/src/main/resources/apache-maven-3.1.0-bin.zip b/test-harness-tools/src/main/resources/apache-maven-3.1.0-bin.zip deleted file mode 100644 index 10d8f5c252e4bfaad4bfb56477f1e897fe8a5b00..0000000000000000000000000000000000000000 Binary files a/test-harness-tools/src/main/resources/apache-maven-3.1.0-bin.zip and /dev/null differ diff --git a/test-harness-tools/src/main/resources/maven-2.0.7-bin.zip b/test-harness-tools/src/main/resources/maven-2.0.7-bin.zip deleted file mode 100644 index 5ac0244e6afef7e53fb79d5a502d17b2a4f499a0..0000000000000000000000000000000000000000 Binary files a/test-harness-tools/src/main/resources/maven-2.0.7-bin.zip and /dev/null differ diff --git a/test-harness/pom.xml b/test-harness/pom.xml deleted file mode 100644 index aa6b210546d75a427759f0b3944684e8ba779476..0000000000000000000000000000000000000000 --- a/test-harness/pom.xml +++ /dev/null @@ -1,185 +0,0 @@ - - - - 4.0.0 - - - org.jenkins-ci.main - pom - 1.645-SNAPSHOT - - - jenkins-test-harness - - Test harness for Jenkins and plugins - Harness used to run functional tests of Jenkins core and plugins. - - - - - ${project.groupId} - jenkins-war - 1.580.1 - war-for-test - - - org.jenkins-ci.modules - sshd - - - - - org.mortbay.jetty - jetty - 6.1.26 - - - junit - junit - - - org.hamcrest - hamcrest-library - 1.3 - - - net.sourceforge.htmlunit - htmlunit - 2.18 - - - commons-codec - commons-codec - - - - - org.jvnet.hudson - embedded-rhino-debugger - 1.2 - - - org.jvnet.hudson - htmlunit-core-js - - - - - org.netbeans.modules - org-netbeans-insane - RELEASE72 - - - com.github.stephenc.findbugs - findbugs-annotations - 1.3.9-1 - - - org.jenkins-ci.lib - lib-jenkins-maven-embedder - 3.11 - - - org.sonatype.sisu - sisu-guice - - - - - org.jenkins-ci.plugins - matrix-auth - 1.0.2 - test - - - - - - - org.kohsuke.stapler - maven-stapler-plugin - - true - - - org.apache.maven.plugins - maven-surefire-plugin - - - -Dfile.encoding=UTF-8 -Xmx256m -XX:MaxPermSize=128m - - - true - ${mavenDebug} - ${project.build.directory} - ${ignore.random.failures} - - - - - org.codehaus.gmaven - gmaven-plugin - - - - preset-packager - process-resources - - execute - - - ${pom.basedir}/src/main/preset-data/package.groovy - - - - - - org.apache.ant - ant - 1.8.0 - - - - org.apache.ant - ant-launcher - 1.8.0 - - - org.codehaus.gmaven.runtime - gmaven-runtime-2.0 - 1.5-jenkins-1 - - - - 2.0 - - - - - - diff --git a/test-harness/src/main/java/com/gargoylesoftware/htmlunit/README.md b/test-harness/src/main/java/com/gargoylesoftware/htmlunit/README.md deleted file mode 100644 index 5aadb8e2936ffe191c82c4ce9513577e17b92fa4..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/com/gargoylesoftware/htmlunit/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# 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-harness/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java b/test-harness/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java deleted file mode 100644 index d330c77a4a3c38d62fa03a2358c217c316c12f54..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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-harness/src/main/java/com/gargoylesoftware/htmlunit/WebResponseListener.java b/test-harness/src/main/java/com/gargoylesoftware/htmlunit/WebResponseListener.java deleted file mode 100644 index 75cd37e2fa9d82519d7a83e25ce418420c07453d..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/com/gargoylesoftware/htmlunit/WebResponseListener.java +++ /dev/null @@ -1,40 +0,0 @@ -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-harness/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java b/test-harness/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java deleted file mode 100644 index a70716b85282c5041897ae5d4347ba6999730e22..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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-harness/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java b/test-harness/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java deleted file mode 100644 index 23372d6740385d1c529533cbc6f035b5636cff8a..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -/** - * {@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); - } - } - - /** - * Does the supplied element define the specified HTML "class" name. - * @param element The element to check. - * @param className The HTML "class" name to check for. - * @return {@code true} if the element defines the specified class, otherwise {@code false}. - */ - public static boolean hasClassName(HtmlElement element, String className) { - String classAttribute = element.getAttribute("class"); - Set classes = new HashSet<>(Arrays.asList(classAttribute.split(" "))); - return classes.contains(className); - } -} diff --git a/test-harness/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java b/test-harness/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java deleted file mode 100644 index af95c37cdf18c34eb5620d3574da18c925aaf77f..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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-harness/src/main/java/hudson/cli/CLICommandInvoker.java b/test-harness/src/main/java/hudson/cli/CLICommandInvoker.java deleted file mode 100644 index 00c603a970d8cec2a555d9c0ccfd17e56de8066f..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/hudson/cli/CLICommandInvoker.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * The MIT License - * - * Copyright 2013 Red Hat, 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 hudson.cli; - -import hudson.Extension; -import hudson.model.User; -import hudson.security.ACL; -import hudson.security.AuthorizationStrategy; -import hudson.security.Permission; -import hudson.security.SidACL; - -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.PrintStream; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Locale; - -import jenkins.model.Jenkins; -import org.acegisecurity.acls.sid.PrincipalSid; -import org.acegisecurity.acls.sid.Sid; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeMatcher; -import org.jvnet.hudson.test.JenkinsRule; - -/** - * Helper class to invoke {@link CLICommand} and check the response. - * - * @author ogondza - */ -public class CLICommandInvoker { - - private static final String username = "user"; - private final JenkinsRule rule; - private final CLICommand command; - - private InputStream stdin; - private List args = Collections.emptyList(); - private List permissions = Collections.emptyList(); - private Locale locale = Locale.ENGLISH; - - public CLICommandInvoker(final JenkinsRule rule, final CLICommand command) { - - if (command.getClass().getAnnotation(Extension.class) == null) { - - throw new AssertionError(String.format( - "Command %s is missing @Extension annotation.", - command.getClass() - )); - } - - this.rule = rule; - this.command = command; - } - - public CLICommandInvoker(final JenkinsRule rule, final String command) { - this.rule = rule; - this.command = CLICommand.clone(command); - - if (this.command == null) throw new AssertionError("No such command: " + command); - } - - public CLICommandInvoker authorizedTo(final Permission... permissions) { - - this.permissions = Arrays.asList(permissions); - return this; - } - - public CLICommandInvoker withStdin(final InputStream stdin) { - - if (stdin == null) throw new NullPointerException("No stdin provided"); - - this.stdin = stdin; - return this; - } - - public CLICommandInvoker withArgs(final String... args) { - - this.args = Arrays.asList(args); - return this; - } - - public Result invokeWithArgs(final String... args) { - - return withArgs(args).invoke(); - } - - public Result invoke() { - - setAuth(); - - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - final ByteArrayOutputStream err = new ByteArrayOutputStream(); - - final int returnCode = command.main( - args, locale, stdin, new PrintStream(out), new PrintStream(err) - ); - - return new Result(returnCode, out, err); - } - - private static class GrantPermissions extends AuthorizationStrategy { - final String username; - final List permissions; - GrantPermissions(String username, List permissions) { - this.username = username; - this.permissions = permissions; - for (Permission p : permissions) { - p.setEnabled(true); - } - } - @Override - public ACL getRootACL() { - return new SidACL() { - @Override - protected Boolean hasPermission(Sid u, Permission permission) { - if (u instanceof PrincipalSid && ((PrincipalSid) u).getPrincipal().equals(username)) { - for (Permission p = permission; p != null; p = p.impliedBy) { - if (permissions.contains(p)) { - return true; - } - } - } - return false; - } - }; - } - @Override - public Collection getGroups() { - return Collections.emptySet(); - } - } - private void setAuth() { - - if (permissions.isEmpty()) return; - - JenkinsRule.DummySecurityRealm realm = rule.createDummySecurityRealm(); - realm.addGroups(username, "group"); - rule.jenkins.setSecurityRealm(realm); - - rule.jenkins.setAuthorizationStrategy(new GrantPermissions(username, permissions)); - - command.setTransportAuth(user().impersonate()); - // Otherwise it is SYSTEM, which would be relevant for a command overriding main: - ACL.impersonate(Jenkins.ANONYMOUS); - } - - public User user() { - - return User.get(username); - } - - public static class Result { - - private final int result; - private final ByteArrayOutputStream out; - private final ByteArrayOutputStream err; - - private Result( - final int result, - final ByteArrayOutputStream out, - final ByteArrayOutputStream err - ) { - - this.result = result; - this.out = out; - this.err = err; - } - - public int returnCode() { - - return result; - } - - public String stdout() { - - return out.toString(); - } - - public String stderr() { - - return err.toString(); - } - - @Override - public String toString() { - - StringBuilder builder = new StringBuilder("CLI command exited with ").append(result); - String stdout = stdout(); - if (!"".equals(stdout)) { - builder.append("\nSTDOUT:\n").append(stdout); - } - String stderr = stderr(); - if (!"".equals(stderr)) { - builder.append("\nSTDERR:\n").append(stderr); - } - - return builder.toString(); - } - } - - public abstract static class Matcher extends TypeSafeMatcher { - - private final String description; - - private Matcher(String description) { - this.description = description; - } - - @Override - protected void describeMismatchSafely(Result result, Description description) { - description.appendText(result.toString()); - } - - public void describeTo(Description description) { - description.appendText(this.description); - } - - public static Matcher hasNoStandardOutput() { - return new Matcher("No standard output") { - @Override protected boolean matchesSafely(Result result) { - return "".equals(result.stdout()); - } - }; - } - - public static Matcher hasNoErrorOutput() { - return new Matcher("No error output") { - @Override protected boolean matchesSafely(Result result) { - return "".equals(result.stderr()); - } - }; - } - - public static Matcher succeeded() { - return new Matcher("Exited with 0 return code") { - @Override protected boolean matchesSafely(Result result) { - return result.result == 0; - } - }; - } - - public static Matcher succeededSilently() { - return new Matcher("Succeeded silently") { - @Override protected boolean matchesSafely(Result result) { - return result.result == 0 && "".equals(result.stderr()) && "".equals(result.stdout()); - } - }; - } - - public static Matcher failedWith(final long expectedCode) { - return new Matcher("Exited with " + expectedCode + " return code") { - @Override protected boolean matchesSafely(Result result) { - return result.result == expectedCode; - } - }; - } - } -} diff --git a/test-harness/src/main/java/hudson/util/SecretHelper.java b/test-harness/src/main/java/hudson/util/SecretHelper.java deleted file mode 100644 index b76b1f8be41cbbfe7ed76c91a86f950a2ddae0d3..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/hudson/util/SecretHelper.java +++ /dev/null @@ -1,10 +0,0 @@ -package hudson.util; - -/** - * @author Kohsuke Kawaguchi - */ -public class SecretHelper { - public static void set(String s) { - Secret.SECRET = s; - } -} diff --git a/test-harness/src/main/java/jenkins/model/JenkinsAdaptor.java b/test-harness/src/main/java/jenkins/model/JenkinsAdaptor.java deleted file mode 100644 index efe14b9cb10a19483ada62fc5dc5aefd855b9e1c..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/jenkins/model/JenkinsAdaptor.java +++ /dev/null @@ -1,11 +0,0 @@ -package jenkins.model; - -/** - * Access the package protected quiet period - */ -public class JenkinsAdaptor { - public static void setQuietPeriod(Jenkins jenkins, int quietPeriod) { - jenkins.quietPeriod = quietPeriod; - } - -} diff --git a/test-harness/src/main/java/jenkins/model/WorkspaceWriter.java b/test-harness/src/main/java/jenkins/model/WorkspaceWriter.java deleted file mode 100644 index 5738f9ed8e53d7a3374f084e4e08b616433d7757..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/jenkins/model/WorkspaceWriter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2015 Red Hat, 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 jenkins.model; - -import hudson.Launcher; -import hudson.model.BuildListener; -import hudson.model.AbstractBuild; - -import java.io.IOException; - -import org.jvnet.hudson.test.TestBuilder; - -/** - * Write text into file in workspace. - * - * @author ogondza - */ -public class WorkspaceWriter extends TestBuilder { - - private final String path; - private final String content; - - public WorkspaceWriter(String path, String content) { - this.path = path; - this.content = content; - } - - @Override - public boolean perform( - AbstractBuild build, Launcher launcher, BuildListener listener - ) throws InterruptedException, IOException { - build.getWorkspace().child(path).write(content, "UTF-8"); - return true; - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/BuildWatcher.java b/test-harness/src/main/java/org/jvnet/hudson/test/BuildWatcher.java deleted file mode 100644 index 053c3cf467d10d21e2b15b499fab28918b73a7eb..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/BuildWatcher.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * The MIT License - * - * Copyright 2015 Jesse Glick. - * - * 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 org.jvnet.hudson.test; - -import hudson.Extension; -import hudson.console.AnnotatedLargeText; -import hudson.console.LineTransformationOutputStream; -import hudson.model.Run; -import hudson.model.TaskListener; -import hudson.model.listeners.RunListener; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import org.junit.rules.ExternalResource; - -/** - * Echoes build output to standard error as it arrives. - * Usage:

{@code @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher();}
- * Should work in combination with {@link JenkinsRule} or {@link RestartableJenkinsRule}. - * @see JenkinsRule#waitForCompletion - * @see JenkinsRule#waitForMessage - * @since 1.607 - */ -public final class BuildWatcher extends ExternalResource { - - private static boolean active; - private static final Map builds = new ConcurrentHashMap(); - - private Thread thread; - - @Override protected void before() throws Throwable { - active = true; - thread = new Thread("watching builds") { - @Override public void run() { - try { - while (active) { - for (RunningBuild build : builds.values()) { - build.copy(); - } - Thread.sleep(50); - } - } catch (InterruptedException x) { - // stopped - } - // last chance - for (RunningBuild build : builds.values()) { - build.copy(); - } - } - }; - thread.setDaemon(true); - thread.start(); - } - - @Override protected void after() { - active = false; - thread.interrupt(); - } - - @Extension public static final class Listener extends RunListener> { - - @Override public void onStarted(Run r, TaskListener listener) { - if (!active) { - return; - } - RunningBuild build = new RunningBuild(r); - RunningBuild orig = builds.put(r.getLogFile(), build); - if (orig != null) { - System.err.println(r + " was started twice?!"); - } - } - - @Override public void onFinalized(Run r) { - if (!active) { - return; - } - RunningBuild build = builds.remove(r.getLogFile()); - if (build != null) { - build.copy(); - } else { - System.err.println(r + " was finalized but not started?!"); - } - } - - } - - private static final class RunningBuild { - - private final AnnotatedLargeText log; - private final OutputStream sink; - private long pos; - - RunningBuild(Run r) { - log = r.getLogText(); - sink = new LogLinePrefixOutputFilter(System.err, "[" + r + "] "); - } - - synchronized void copy() { - try { - pos = log.writeLogTo(pos, sink); - // Note that !log.isComplete() after the initial call to copy, even if the build is complete, because Run.getLogText never calls markComplete! - // That is why Run.writeWholeLogTo calls getLogText repeatedly. - // Even if it did call markComplete this might not work from RestartableJenkinsRule since you would have a different Run object after the restart. - // Anyway we can just rely on onFinalized to let us know when to stop. - } catch (FileNotFoundException x) { - // build deleted or not started - } catch (Exception x) { - x.printStackTrace(); - } - } - - } - - // Copied from WorkflowRun. - private static final class LogLinePrefixOutputFilter extends LineTransformationOutputStream { - - private final PrintStream logger; - private final String prefix; - - LogLinePrefixOutputFilter(PrintStream logger, String prefix) { - this.logger = logger; - this.prefix = prefix; - } - - @Override protected void eol(byte[] b, int len) throws IOException { - logger.append(prefix); - logger.write(b, 0, len); - } - - } - -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/CaptureEnvironmentBuilder.java b/test-harness/src/main/java/org/jvnet/hudson/test/CaptureEnvironmentBuilder.java deleted file mode 100644 index 775eb8d14648ed06ed9d9d0fd5101a8b470b333b..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/CaptureEnvironmentBuilder.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, 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 org.jvnet.hudson.test; - -import hudson.Launcher; -import hudson.Extension; -import hudson.EnvVars; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.model.Descriptor; -import hudson.tasks.Builder; -import net.sf.json.JSONObject; -import org.kohsuke.stapler.StaplerRequest; - -import java.io.IOException; - -/** - * {@link Builder} that captures the environment variables used during a build. - * - * @author Kohsuke Kawaguchi - */ -public class CaptureEnvironmentBuilder extends Builder { - - private EnvVars envVars; - - public EnvVars getEnvVars() { - return envVars; - } - - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - envVars = build.getEnvironment(listener); - return true; - } - - @Extension - public static final class DescriptorImpl extends Descriptor { - public Builder newInstance(StaplerRequest req, JSONObject data) { - throw new UnsupportedOperationException(); - } - - public String getDisplayName() { - return "Capture Environment Variables"; - } - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/ChannelShutdownListener.java b/test-harness/src/main/java/org/jvnet/hudson/test/ChannelShutdownListener.java deleted file mode 100644 index 935aeca28fdebc4f8823b03a0c1b00dd58310155..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/ChannelShutdownListener.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.jvnet.hudson.test; - -import hudson.Extension; -import hudson.model.Computer; -import hudson.model.TaskListener; -import hudson.remoting.Channel; -import hudson.remoting.VirtualChannel; -import hudson.slaves.ComputerListener; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * Runs at the end of the test to cleanup any live channels. - * -* @author Kohsuke Kawaguchi -*/ -@Extension -public class ChannelShutdownListener extends ComputerListener implements EndOfTestListener { - /** - * Remember channels that are created, to release them at the end. - */ - private List channels = new ArrayList(); - - @Override - public synchronized void onOnline(Computer c, TaskListener listener) throws IOException, InterruptedException { - VirtualChannel ch = c.getChannel(); - if (ch instanceof Channel) { - channels.add((Channel)ch); - } - } - - @Override - public synchronized void onTearDown() throws Exception { - for (Channel c : channels) - c.close(); - for (Channel c : channels) - c.join(); - channels.clear(); - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/ClosureExecuterAction.java b/test-harness/src/main/java/org/jvnet/hudson/test/ClosureExecuterAction.java deleted file mode 100644 index 9feb531faf3d15299b04e35da700d7604e92badd..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/ClosureExecuterAction.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, 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 org.jvnet.hudson.test; - -import hudson.Extension; -import hudson.model.RootAction; -import org.kohsuke.stapler.QueryParameter; -import org.kohsuke.stapler.StaplerResponse; - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * Server-side logic that implements {@link HudsonTestCase#executeOnServer(Callable)}. - * - * @author Kohsuke Kawaguchi - */ -@Extension -public final class ClosureExecuterAction implements RootAction { - private final Map runnables = Collections.synchronizedMap(new HashMap()); - - public void add(UUID uuid, Runnable r) { - runnables.put(uuid,r); - } - - public void doIndex(StaplerResponse rsp, @QueryParameter("uuid") String uuid) throws IOException { - Runnable r = runnables.remove(UUID.fromString(uuid)); - if (r!=null) { - r.run(); - } else { - rsp.sendError(404); - } - } - - public String getIconFileName() { - return null; - } - - public String getDisplayName() { - return null; - } - - public String getUrlName() { - return "closures"; - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/ComputerConnectorTester.java b/test-harness/src/main/java/org/jvnet/hudson/test/ComputerConnectorTester.java deleted file mode 100644 index c1b320c05ecf9e53735b744d7ee52ef4fca004a1..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/ComputerConnectorTester.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2010, InfraDNA, 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 org.jvnet.hudson.test; - -import hudson.Extension; -import hudson.model.AbstractDescribableImpl; -import hudson.model.Descriptor; -import hudson.slaves.ComputerConnector; -import hudson.slaves.ComputerConnectorDescriptor; -import org.kohsuke.stapler.StaplerRequest; - -import javax.servlet.ServletException; -import java.io.IOException; -import java.util.List; - -/** - * Test bed to verify the configuration roundtripness of the {@link ComputerConnector}. - * - * @author Kohsuke Kawaguchi - * @see HudsonTestCase#computerConnectorTester - */ -public class ComputerConnectorTester extends AbstractDescribableImpl { - public final HudsonTestCase testCase; - public ComputerConnector connector; - - public ComputerConnectorTester(HudsonTestCase testCase) { - this.testCase = testCase; - } - - public void doConfigSubmit(StaplerRequest req) throws IOException, ServletException { - connector = req.bindJSON(ComputerConnector.class, req.getSubmittedForm().getJSONObject("connector")); - } - - public List getConnectorDescriptors() { - return ComputerConnectorDescriptor.all(); - } - - @Extension - public static class DescriptorImpl extends Descriptor { - @Override // TODO 1.635+ delete - public String getDisplayName() { - return "ComputerConnectorTester"; - } - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/CreateFileBuilder.java b/test-harness/src/main/java/org/jvnet/hudson/test/CreateFileBuilder.java deleted file mode 100644 index ad82193e015dd9b2cd1f2ec23d39c95db4d775bf..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/CreateFileBuilder.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2015 Oleg Nenashev. - * - * 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 org.jvnet.hudson.test; - -import hudson.AbortException; -import hudson.Extension; -import hudson.FilePath; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.model.Descriptor; -import hudson.tasks.Builder; -import java.io.IOException; -import javax.annotation.Nonnull; -import net.sf.json.JSONObject; -import org.kohsuke.stapler.StaplerRequest; - -/** - * Creates a test builder, which creates a file in the workspace. - * @author Oleg Nenashev - * @since TODO - */ -public class CreateFileBuilder extends Builder { - - @Nonnull - private final String fileName; - - @Nonnull - private final String fileContent; - - public CreateFileBuilder(@Nonnull String fileName, @Nonnull String fileContent) { - this.fileName = fileName; - this.fileContent = fileContent; - } - - @Nonnull - public String getFileName() { - return fileName; - } - - @Nonnull - public String getFileContent() { - return fileContent; - } - - @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - listener.getLogger().println("Creating a file " + fileName); - - FilePath workspace = build.getWorkspace(); - if (workspace == null) { - throw new AbortException("Cannot get the workspace of the build"); - } - workspace.child(fileName).write(fileContent, "UTF-8"); - - return true; - } - - @Override - public Descriptor getDescriptor() { - return new DescriptorImpl(); - } - - @Extension - public static final class DescriptorImpl extends Descriptor { - - @Override - public Builder newInstance(StaplerRequest req, JSONObject data) { - throw new UnsupportedOperationException("This is a temporarytest class, " - + "which should not be configured from UI"); - } - - @Override - public String getDisplayName() { - return "Create a file"; - } - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/DefaultConstructorChecker.java b/test-harness/src/main/java/org/jvnet/hudson/test/DefaultConstructorChecker.java deleted file mode 100644 index 9c862edc4773d6a89af2497dcc74a39b9d124130..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/DefaultConstructorChecker.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.jvnet.hudson.test; - -import junit.framework.TestCase; - -/** - * Tests that the specified class has the default constructor. - * - * @author Kohsuke Kawaguchi - */ -public class DefaultConstructorChecker extends TestCase { - private final Class clazz; - - public DefaultConstructorChecker(Class clazz) { - this.clazz = clazz; - setName(clazz.getName()+".verifyDefaultConstructor"); - } - - @Override - protected void runTest() throws Throwable { - try { - clazz.getConstructor(); - } catch (NoSuchMethodException e) { - throw new Error(clazz+" must have the default constructor",e); - } catch (SecurityException e) { - throw new Error(clazz+" must have the default constructor",e); - } - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/EndOfTestListener.java b/test-harness/src/main/java/org/jvnet/hudson/test/EndOfTestListener.java deleted file mode 100644 index e6d9c143cfd99c3f15a0f99bf8bbe527e517d06f..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/EndOfTestListener.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.jvnet.hudson.test; - -import hudson.ExtensionPoint; - -/** - * Gets notified before the test completes to perform additional cleanup. - * - * @author Kohsuke Kawaguchi - * @since 1.520 - */ -public interface EndOfTestListener extends ExtensionPoint { - /** - * Called for clean up. - */ - void onTearDown() throws Exception; -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/ExtractChangeLogParser.java b/test-harness/src/main/java/org/jvnet/hudson/test/ExtractChangeLogParser.java deleted file mode 100644 index a2bd723e6b4c72f028d1e30feaeb43a1fab43357..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/ExtractChangeLogParser.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, 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 org.jvnet.hudson.test; - -import hudson.model.AbstractBuild; -import hudson.model.User; -import hudson.scm.ChangeLogParser; -import hudson.scm.ChangeLogSet; -import org.apache.commons.digester.Digester; -import org.kohsuke.stapler.export.Exported; -import org.kohsuke.stapler.export.ExportedBean; -import org.xml.sax.SAXException; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * @author Andrew Bayer - */ -public class ExtractChangeLogParser extends ChangeLogParser { - @SuppressWarnings("rawtypes") - @Override - public ExtractChangeLogSet parse(AbstractBuild build, File changeLogFile) throws IOException, SAXException { - if (changeLogFile.exists()) { - FileInputStream fis = new FileInputStream(changeLogFile); - ExtractChangeLogSet logSet = parse(build, fis); - fis.close(); - return logSet; - } else { - return new ExtractChangeLogSet(build, new ArrayList()); - } - } - - @SuppressWarnings("rawtypes") - public ExtractChangeLogSet parse(AbstractBuild build, InputStream changeLogStream) throws IOException, SAXException { - - ArrayList changeLog = new ArrayList(); - - Digester digester = new Digester(); - digester.setClassLoader(ExtractChangeLogSet.class.getClassLoader()); - digester.push(changeLog); - digester.addObjectCreate("*/extractChanges/entry", ExtractChangeLogEntry.class); - - digester.addBeanPropertySetter("*/extractChanges/entry/zipFile"); - - digester.addObjectCreate("*/extractChanges/entry/file", - FileInZip.class); - digester.addBeanPropertySetter("*/extractChanges/entry/file/fileName"); - digester.addSetNext("*/extractChanges/entry/file", "addFile"); - digester.addSetNext("*/extractChanges/entry", "add"); - - digester.parse(changeLogStream); - - return new ExtractChangeLogSet(build, changeLog); - } - - - @ExportedBean(defaultVisibility = 999) - public static class ExtractChangeLogEntry extends ChangeLogSet.Entry { - private List files = new ArrayList(); - private String zipFile; - - public ExtractChangeLogEntry() { - } - - public ExtractChangeLogEntry(String zipFile) { - this.zipFile = zipFile; - } - - public void setZipFile(String zipFile) { - this.zipFile = zipFile; - } - - @Exported - public String getZipFile() { - return zipFile; - } - - @Override - public void setParent(ChangeLogSet parent) { - super.setParent(parent); - } - - @Override - public Collection getAffectedPaths() { - Collection paths = new ArrayList(files.size()); - for (FileInZip file : files) { - paths.add(file.getFileName()); - } - return paths; - } - - @Override - @Exported - public User getAuthor() { - return User.get("testuser"); - } - - @Override - @Exported - public String getMsg() { - return "Extracted from " + zipFile; - } - - public void addFile(FileInZip fileName) { - files.add(fileName); - } - - public void addFiles(Collection fileNames) { - this.files.addAll(fileNames); - } - } - - @ExportedBean(defaultVisibility = 999) - public static class FileInZip { - private String fileName = ""; - - public FileInZip() { - } - - public FileInZip(String fileName) { - this.fileName = fileName; - } - - @Exported - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } - } - -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/ExtractChangeLogSet.java b/test-harness/src/main/java/org/jvnet/hudson/test/ExtractChangeLogSet.java deleted file mode 100644 index 5e36aaeb243eb866c002c0d62f1f72f8eb4c564f..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/ExtractChangeLogSet.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, 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 org.jvnet.hudson.test; - -import hudson.model.AbstractBuild; -import hudson.scm.ChangeLogSet; - -import java.util.List; -import java.util.Collections; -import java.util.Iterator; - - -/** - * @author Andrew Bayer - */ -public class ExtractChangeLogSet extends ChangeLogSet { - private List changeLogs = null; - - public ExtractChangeLogSet(AbstractBuild build, List changeLogs) { - super(build); - for (ExtractChangeLogParser.ExtractChangeLogEntry entry : changeLogs) { - entry.setParent(this); - } - this.changeLogs = Collections.unmodifiableList(changeLogs); - } - - @Override - public boolean isEmptySet() { - return changeLogs.isEmpty(); - } - - public Iterator iterator() { - return changeLogs.iterator(); - } - -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/ExtractResourceSCM.java b/test-harness/src/main/java/org/jvnet/hudson/test/ExtractResourceSCM.java deleted file mode 100644 index 495e88ee6177890d0e2df9370917aa53e5c09928..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/ExtractResourceSCM.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, 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 org.jvnet.hudson.test; - -import hudson.FilePath; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.scm.NullSCM; -import hudson.scm.SCM; -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.net.URL; - -/** - * {@link SCM} useful for testing that extracts the given resource as a zip file. - * - * @author Kohsuke Kawaguchi - */ -public class ExtractResourceSCM extends NullSCM { - private final URL zip; - - private String parentFolder; - - /** - * - * @param zip - */ - public ExtractResourceSCM(URL zip) { - if(zip==null) - throw new IllegalArgumentException(); - this.zip = zip; - } - - /** - * with this constructor your zip can contains a folder - * more useful to create a project test zip foo.zip foo - * @param zip - * @param parentFolder - */ - public ExtractResourceSCM(URL zip, String parentFolder) { - if(zip==null) - throw new IllegalArgumentException(); - this.zip = zip; - this.parentFolder = parentFolder; - } - - @Override - public boolean checkout(AbstractBuild build, Launcher launcher, FilePath workspace, BuildListener listener, File changeLogFile) throws IOException, InterruptedException { - if (workspace.exists()) { - listener.getLogger().println("Deleting existing workspace " + workspace.getRemote()); - workspace.deleteRecursive(); - } - listener.getLogger().println("Staging "+zip); - workspace.unzipFrom(zip.openStream()); - if (parentFolder != null) { - FileUtils.copyDirectory( new File(workspace.getRemote() + "/" + parentFolder), new File( workspace.getRemote())); - } - return true; - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/ExtractResourceWithChangesSCM.java b/test-harness/src/main/java/org/jvnet/hudson/test/ExtractResourceWithChangesSCM.java deleted file mode 100644 index cd6c0c714eb0537c3cfb7162887ac43902a7a7f1..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/ExtractResourceWithChangesSCM.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, 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 org.jvnet.hudson.test; - -import hudson.FilePath; -import hudson.Launcher; -import hudson.Util; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.scm.ChangeLogParser; -import hudson.scm.NullSCM; -import hudson.scm.SCM; -import hudson.scm.SCMDescriptor; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.net.URL; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -/** - * {@link SCM} useful for testing that extracts the given resource as a zip file. - * - * @author Kohsuke Kawaguchi - */ -public class ExtractResourceWithChangesSCM extends NullSCM { - private final URL firstZip; - private final URL secondZip; - private final String moduleRoot; - - public ExtractResourceWithChangesSCM(URL firstZip, URL secondZip) { - if ((firstZip == null) || (secondZip == null)) - throw new IllegalArgumentException(); - this.firstZip = firstZip; - this.secondZip = secondZip; - this.moduleRoot = null; - } - - public ExtractResourceWithChangesSCM(URL firstZip, URL secondZip, String moduleRoot) { - if ((firstZip == null) || (secondZip == null)) - throw new IllegalArgumentException(); - this.firstZip = firstZip; - this.secondZip = secondZip; - this.moduleRoot = moduleRoot; - } - - @Override - public FilePath getModuleRoot(FilePath workspace) { - if (moduleRoot!=null) { - return workspace.child(moduleRoot); - } - return workspace; - } - - @Override - public boolean checkout(AbstractBuild build, Launcher launcher, FilePath workspace, BuildListener listener, File changeLogFile) throws IOException, InterruptedException { - if (workspace.exists()) { - listener.getLogger().println("Deleting existing workspace " + workspace.getRemote()); - workspace.deleteRecursive(); - } - listener.getLogger().println("Staging first zip: " + firstZip); - workspace.unzipFrom(firstZip.openStream()); - listener.getLogger().println("Staging second zip: " + secondZip); - workspace.unzipFrom(secondZip.openStream()); - - // Get list of files changed in secondZip. - ZipInputStream zip = new ZipInputStream(secondZip.openStream()); - ZipEntry e; - ExtractChangeLogParser.ExtractChangeLogEntry changeLog = new ExtractChangeLogParser.ExtractChangeLogEntry(secondZip.toString()); - - try { - while ((e = zip.getNextEntry()) != null) { - if (!e.isDirectory()) - changeLog.addFile(new ExtractChangeLogParser.FileInZip(e.getName())); - } - } - finally { - zip.close(); - } - saveToChangeLog(changeLogFile, changeLog); - - return true; - } - - @Override - public ChangeLogParser createChangeLogParser() { - return new ExtractChangeLogParser(); - } - - private static String escapeForXml(String string) { - return Util.xmlEscape(Util.fixNull(string)); - } - - public void saveToChangeLog(File changeLogFile, ExtractChangeLogParser.ExtractChangeLogEntry changeLog) throws IOException { - FileOutputStream outputStream = new FileOutputStream(changeLogFile); - - PrintStream stream = new PrintStream(outputStream, false, "UTF-8"); - - stream.println(""); - stream.println(""); - stream.println(""); - stream.println("" + escapeForXml(changeLog.getZipFile()) + ""); - - for (String fileName : changeLog.getAffectedPaths()) { - stream.println(""); - stream.println("" + escapeForXml(fileName) + ""); - stream.println(""); - } - - stream.println(""); - stream.println(""); - - stream.close(); - } - - /** - * Don't write 'this', so that subtypes can be implemented as anonymous class. - */ - private Object writeReplace() { return new Object(); } - - @Override public SCMDescriptor getDescriptor() { - return new SCMDescriptor(ExtractResourceWithChangesSCM.class, null) { - @Override // TODO 1.635+ delete - public String getDisplayName() { - return "ExtractResourceWithChangesSCM"; - } -}; - } - -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/FailureBuilder.java b/test-harness/src/main/java/org/jvnet/hudson/test/FailureBuilder.java deleted file mode 100644 index 2c5e48642713795fa2fbe70bdf9e60d2633c9015..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/FailureBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * - * 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 org.jvnet.hudson.test; - -import hudson.Extension; -import hudson.model.Descriptor; -import hudson.model.Result; -import hudson.tasks.Builder; -import net.sf.json.JSONObject; -import org.kohsuke.stapler.StaplerRequest; - -/** - * Mock {@link Builder} that always cause a build to fail. - * - * @author Kohsuke Kawaguchi - */ -public class FailureBuilder extends MockBuilder { - public FailureBuilder() { - super(Result.FAILURE); - } - - @Extension - public static final class DescriptorImpl extends Descriptor { - public FailureBuilder newInstance(StaplerRequest req, JSONObject data) { - return new FailureBuilder(); - } - - @Override // TODO 1.635+ delete - public String getDisplayName() { - return "FailureBuilder"; - } - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/FakeChangeLogSCM.java b/test-harness/src/main/java/org/jvnet/hudson/test/FakeChangeLogSCM.java deleted file mode 100644 index 640302fdaa6d03e86f90b57e1baadfa82edb2d2d..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/FakeChangeLogSCM.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2011, 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 org.jvnet.hudson.test; - -import hudson.FilePath; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.model.InvisibleAction; -import hudson.model.User; -import hudson.scm.ChangeLogParser; -import hudson.scm.ChangeLogSet; -import hudson.scm.ChangeLogSet.Entry; -import hudson.scm.NullSCM; -import hudson.scm.SCM; -import hudson.scm.SCMDescriptor; -import org.xml.sax.SAXException; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -/** - * Fake SCM implementation that can report arbitrary commits from arbitrary users. - * - * @author Kohsuke Kawaguchi - */ -public class FakeChangeLogSCM extends NullSCM { - - /** - * Changes to be reported in the next build. - */ - private List entries = new ArrayList(); - - public EntryImpl addChange() { - EntryImpl e = new EntryImpl(); - entries.add(e); - return e; - } - - @Override - public boolean checkout(AbstractBuild build, Launcher launcher, FilePath remoteDir, BuildListener listener, File changeLogFile) throws IOException, InterruptedException { - new FilePath(changeLogFile).touch(0); - build.addAction(new ChangelogAction(entries)); - entries = new ArrayList(); - return true; - } - - @Override - public ChangeLogParser createChangeLogParser() { - return new FakeChangeLogParser(); - } - - @Override public SCMDescriptor getDescriptor() { - return new SCMDescriptor(null) { - @Override // TODO 1.635+ delete - public String getDisplayName() { - return "FakeChangeLogSCM"; - } -}; - } - - public static class ChangelogAction extends InvisibleAction { - private final List entries; - - public ChangelogAction(List entries) { - this.entries = entries; - } - } - - public static class FakeChangeLogParser extends ChangeLogParser { - @SuppressWarnings("rawtypes") - @Override - public FakeChangeLogSet parse(AbstractBuild build, File changelogFile) throws IOException, SAXException { - return new FakeChangeLogSet(build, build.getAction(ChangelogAction.class).entries); - } - } - - public static class FakeChangeLogSet extends ChangeLogSet { - private List entries; - - public FakeChangeLogSet(AbstractBuild build, List entries) { - super(build); - this.entries = entries; - } - - @Override - public boolean isEmptySet() { - return entries.isEmpty(); - } - - public Iterator iterator() { - return entries.iterator(); - } - } - - public static class EntryImpl extends Entry { - private String msg = "some commit message"; - private String author = "someone"; - - public EntryImpl withAuthor(String author) { - this.author = author; - return this; - } - - public EntryImpl withMsg(String msg) { - this.msg = msg; - return this; - } - - @Override - public String getMsg() { - return msg; - } - - @Override - public User getAuthor() { - return User.get(author); - } - - @Override - public Collection getAffectedPaths() { - return Collections.singleton("path"); - } - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/FakeLauncher.java b/test-harness/src/main/java/org/jvnet/hudson/test/FakeLauncher.java deleted file mode 100644 index 9ca68019d4991ee5172bcf51c57a951fb057e182..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/FakeLauncher.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.jvnet.hudson.test; - -import hudson.Launcher.ProcStarter; -import hudson.Proc; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Fake a process launch. - * - * @author Kohsuke Kawaguchi - * @see PretendSlave - */ -public interface FakeLauncher { - /** - * Called whenever a {@link PretendSlave} is asked to fork a new process. - * - *

- * The callee can inspect the {@link ProcStarter} object to determine what process is being launched, - * and if necessary, fake a process launch by either returning a valid {@link Proc} object, or let - * the normal process launch happen by returning null. - */ - Proc onLaunch(ProcStarter p) throws IOException; - - /** - * Fake {@link Proc} implementation that represents a completed process. - */ - class FinishedProc extends Proc { - public final int exitCode; - - public FinishedProc(int exitCode) { - this.exitCode = exitCode; - } - - @Override - public boolean isAlive() throws IOException, InterruptedException { - return false; - } - - @Override - public void kill() throws IOException, InterruptedException { - throw new UnsupportedOperationException(); - } - - @Override - public int join() throws IOException, InterruptedException { - return exitCode; - } - - @Override - public InputStream getStdout() { - // TODO - throw new UnsupportedOperationException(); - } - - @Override - public InputStream getStderr() { - // TODO - throw new UnsupportedOperationException(); - } - - @Override - public OutputStream getStdin() { - // TODO - throw new UnsupportedOperationException(); - } - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/GroovyHudsonTestCase.java b/test-harness/src/main/java/org/jvnet/hudson/test/GroovyHudsonTestCase.java deleted file mode 100644 index 9e7a90d431c04b764e4fe1d6c4b069a5b021c6bf..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/GroovyHudsonTestCase.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.jvnet.hudson.test; - -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import groovy.lang.Closure; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.tasks.Builder; -import hudson.Launcher; - -import java.util.concurrent.Callable; -import java.io.IOException; - -/** - * {@link HudsonTestCase} with more convenience methods for Groovy. - * - * @author Kohsuke Kawaguchi - * @deprecated Use {@link GroovyJenkinsRule} instead. - */ -@Deprecated -public abstract class GroovyHudsonTestCase extends HudsonTestCase { - /** - * Executes the given closure on the server, in the context of an HTTP request. - * This is useful for testing some methods that require {@link StaplerRequest} and {@link StaplerResponse}. - * - *

- * The closure will get the request and response as parameters. - */ - public Object executeOnServer(final Closure c) throws Exception { - return executeOnServer(new Callable() { - public Object call() throws Exception { - return c.call(); - } - }); - } - - /** - * Wraps a closure as a {@link Builder}. - */ - public Builder builder(final Closure c) { - return new TestBuilder() { - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - Object r = c.call(new Object[]{build,launcher,listener}); - if (r instanceof Boolean) return (Boolean)r; - return true; - } - }; - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/GroovyJenkinsRule.java b/test-harness/src/main/java/org/jvnet/hudson/test/GroovyJenkinsRule.java deleted file mode 100644 index 3c20aa713577a9fcaefadf4140e26ccedd1bcecf..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/GroovyJenkinsRule.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * The MIT License - * - * Copyright 2013 Jesse Glick. - * - * 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 org.jvnet.hudson.test; - -import groovy.lang.Closure; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.tasks.Builder; -import java.io.IOException; -import java.util.concurrent.Callable; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; - -/** - * {@link JenkinsRule} variant with special options for tests written in Groovy. - * @since 1.535 - */ -public class GroovyJenkinsRule extends JenkinsRule { - - /** - * Executes the given closure on the server, in the context of an HTTP request. - * This is useful for testing some methods that require {@link StaplerRequest} and {@link StaplerResponse}. - * - *

- * The closure will get the request and response as parameters. - */ - public Object executeOnServer(final Closure c) throws Exception { - return executeOnServer(new Callable() { - @Override public Object call() throws Exception { - return c.call(); - } - }); - } - - /** - * Wraps a closure as a {@link Builder}. - */ - public Builder builder(final Closure c) { - return new TestBuilder() { - @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - Object r = c.call(new Object[] {build, launcher, listener}); - if (r instanceof Boolean) { - return (Boolean) r; - } - return true; - } - }; - } - -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/HudsonHomeLoader.java b/test-harness/src/main/java/org/jvnet/hudson/test/HudsonHomeLoader.java deleted file mode 100644 index 303de9593ee947c6e02a5b71f55fc7bbeca4a978..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/HudsonHomeLoader.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * - * 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 org.jvnet.hudson.test; - -import hudson.FilePath; -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; - -/** - * Controls how a {@link HudsonTestCase} initializes JENKINS_HOME. - * - * @author Kohsuke Kawaguchi - */ -public interface HudsonHomeLoader { - /** - * Returns a directory to be used as JENKINS_HOME - * - * @throws Exception - * to cause a test to fail. - */ - File allocate() throws Exception; - - /** - * Allocates a new empty directory, meaning this will emulate the fresh Hudson installation. - */ - HudsonHomeLoader NEW = new HudsonHomeLoader() { - public File allocate() throws IOException { - return TestEnvironment.get().temporaryDirectoryAllocator.allocate(); - } - }; - - /** - * Allocates a new directory by copying from an existing directory, or unzipping from a zip file. - */ - final class CopyExisting implements HudsonHomeLoader { - private final URL source; - - /** - * Either a zip file or a directory that contains the home image. - */ - public CopyExisting(File source) throws MalformedURLException { - this(source.toURI().toURL()); - } - - /** - * Extracts from a zip file in the resource. - * - *

- * This is useful in case you want to have a test data in the resources. - * Only file URL is supported. - */ - public CopyExisting(URL source) { - this.source = source; - } - - public File allocate() throws Exception { - File target = NEW.allocate(); - if(source.getProtocol().equals("file")) { - File src = new File(source.toURI()); - if(src.isDirectory()) - new FilePath(src).copyRecursiveTo("**/*",new FilePath(target)); - else - if(src.getName().endsWith(".zip")) - new FilePath(src).unzip(new FilePath(target)); - } else { - File tmp = File.createTempFile("hudson","zip"); - try { - FileUtils.copyURLToFile(source,tmp); - new FilePath(tmp).unzip(new FilePath(target)); - } finally { - tmp.delete(); - } - } - return target; - } - } - - /** - * Allocates a new directory by copying from a test resource - */ - final class Local implements HudsonHomeLoader { - private final Method testMethod; - - public Local(Method testMethod) { - this.testMethod = testMethod; - } - - public File allocate() throws Exception { - URL res = findDataResource(); - if(!res.getProtocol().equals("file")) - throw new AssertionError("Test data is not available in the file system: "+res); - // if we picked up a directory, it's one level above config.xml - File home = new File(res.toURI()); - if(!home.getName().endsWith(".zip")) - home = home.getParentFile(); - - return new CopyExisting(home).allocate(); - } - - private URL findDataResource() { - // first, check method specific resource - Class clazz = testMethod.getDeclaringClass(); - - for( String middle : new String[]{ '/'+testMethod.getName(), "" }) { - for( String suffix : SUFFIXES ) { - URL res = clazz.getResource(clazz.getSimpleName() + middle+suffix); - if(res!=null) return res; - } - } - - throw new AssertionError("No test resource was found for "+testMethod); - } - - private static final String[] SUFFIXES = {"/config.xml",".zip"}; - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java b/test-harness/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java deleted file mode 100644 index f50c04f3515bdb7ba28a5cf4a29229e3b70fd38b..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * - * 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 org.jvnet.hudson.test; - -import com.gargoylesoftware.htmlunit.DefaultPageCreator; -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; - -/** - * {@link PageCreator} that understands JNLP file. - * - * @author Kohsuke Kawaguchi - */ -public class HudsonPageCreator extends DefaultPageCreator { - @Override - public Page createPage(WebResponse webResponse, WebWindow webWindow) throws IOException { - String contentType = webResponse.getContentType().toLowerCase(Locale.ENGLISH); - if(contentType.equals("application/x-java-jnlp-file")) - return createXmlPage(webResponse, webWindow); - 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-harness/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java b/test-harness/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java deleted file mode 100644 index f2ce2d2d8050fc96d9778afc2322c2f1e05113b1..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java +++ /dev/null @@ -1,1913 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, Erik Ramfelt, - * Yahoo! Inc., Tom Huybrechts, Olivier Lamy - * - * 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 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; - -import hudson.ClassicPluginStrategy; -import hudson.CloseProofOutputStream; -import hudson.DNSMultiCast; -import hudson.DescriptorExtensionList; -import hudson.EnvVars; -import hudson.Extension; -import hudson.ExtensionList; -import hudson.Functions; -import hudson.Functions.ThreadGroupMap; -import hudson.Launcher; -import hudson.Launcher.LocalLauncher; -import hudson.Main; -import hudson.PluginManager; -import hudson.Util; -import hudson.WebAppMain; -import hudson.model.*; -import hudson.model.Executor; -import hudson.model.Node.Mode; -import hudson.model.Queue.Executable; -import hudson.os.PosixAPI; -import hudson.remoting.Which; -import hudson.security.ACL; -import hudson.security.AbstractPasswordBasedSecurityRealm; -import hudson.security.GroupDetails; -import hudson.security.SecurityRealm; -import hudson.security.csrf.CrumbIssuer; -import hudson.slaves.CommandLauncher; -import hudson.slaves.ComputerConnector; -import hudson.slaves.ComputerListener; -import hudson.slaves.DumbSlave; -import hudson.slaves.NodeProperty; -import hudson.slaves.RetentionStrategy; -import hudson.tasks.BuildWrapper; -import hudson.tasks.BuildWrapperDescriptor; -import hudson.tasks.Builder; -import hudson.tasks.Publisher; -import hudson.tools.ToolProperty; -import hudson.util.PersistedList; -import hudson.util.ReflectionUtils; -import hudson.util.StreamTaskListener; - -import java.beans.PropertyDescriptor; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.annotation.Annotation; -import java.lang.management.ThreadInfo; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Timer; -import java.util.TimerTask; -import java.util.UUID; -import java.util.concurrent.*; -import java.util.jar.Manifest; -import java.util.logging.Filter; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; - -import jenkins.model.Jenkins; -import jenkins.model.JenkinsAdaptor; -import junit.framework.TestCase; -import net.sf.json.JSONObject; -import net.sourceforge.htmlunit.corejs.javascript.Context; -import net.sourceforge.htmlunit.corejs.javascript.ContextFactory.Listener; - -import org.acegisecurity.AuthenticationException; -import org.acegisecurity.BadCredentialsException; -import org.acegisecurity.GrantedAuthority; -import org.acegisecurity.userdetails.UserDetails; -import org.acegisecurity.userdetails.UsernameNotFoundException; -import org.apache.commons.beanutils.PropertyUtils; -import org.apache.commons.io.FileUtils; -import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException; -import org.codehaus.plexus.component.repository.exception.ComponentLookupException; -import org.jvnet.hudson.test.HudsonHomeLoader.CopyExisting; -import org.jvnet.hudson.test.recipes.Recipe; -import org.jvnet.hudson.test.recipes.Recipe.Runner; -import org.jvnet.hudson.test.recipes.WithPlugin; -import org.jvnet.hudson.test.rhino.JavaScriptDebugger; -import org.kohsuke.stapler.ClassDescriptor; -import org.kohsuke.stapler.DataBoundConstructor; -import org.kohsuke.stapler.Dispatcher; -import org.kohsuke.stapler.MetaClass; -import org.kohsuke.stapler.MetaClassLoader; -import org.kohsuke.stapler.Stapler; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.mortbay.jetty.MimeTypes; -import org.mortbay.jetty.Server; -import org.mortbay.jetty.bio.SocketConnector; -import org.mortbay.jetty.security.HashUserRealm; -import org.mortbay.jetty.security.UserRealm; -import org.mortbay.jetty.webapp.Configuration; -import org.mortbay.jetty.webapp.WebAppContext; -import org.mortbay.jetty.webapp.WebXmlConfiguration; -import org.mozilla.javascript.tools.debugger.Dim; -import org.mozilla.javascript.tools.shell.Global; -import org.springframework.dao.DataAccessException; -import org.w3c.css.sac.CSSException; -import org.w3c.css.sac.CSSParseException; -import org.w3c.css.sac.ErrorHandler; -import org.xml.sax.SAXException; - -import com.gargoylesoftware.htmlunit.AjaxController; -import com.gargoylesoftware.htmlunit.BrowserVersion; -import com.gargoylesoftware.htmlunit.DefaultCssErrorHandler; -import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.html.DomNode; -import com.gargoylesoftware.htmlunit.html.HtmlButton; -import com.gargoylesoftware.htmlunit.html.HtmlElement; -import com.gargoylesoftware.htmlunit.html.HtmlForm; -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.xml.XmlPage; -import hudson.maven.MavenEmbedder; -import hudson.maven.MavenEmbedderException; -import hudson.maven.MavenRequest; -import java.net.HttpURLConnection; - - -import jenkins.model.JenkinsLocationConfiguration; - -/** - * Base class for all Jenkins test cases. - * - * @see Wiki article about unit testing in Hudson - * @author Kohsuke Kawaguchi - * @deprecated New code should use {@link JenkinsRule}. - */ -@Deprecated -@SuppressWarnings("rawtypes") -public abstract class HudsonTestCase extends TestCase implements RootAction { - /** - * Points to the same object as {@link #jenkins} does. - */ - public Hudson hudson; - - public Jenkins jenkins; - - protected final TestEnvironment env = new TestEnvironment(this); - protected HudsonHomeLoader homeLoader = HudsonHomeLoader.NEW; - /** - * TCP/IP port that the server is listening on. - */ - protected int localPort; - protected Server server; - - /** - * Where in the {@link Server} is Hudson deployed? - *

- * Just like {@link ServletContext#getContextPath()}, starts with '/' but doesn't end with '/'. - */ - protected String contextPath = ""; - - /** - * {@link Runnable}s to be invoked at {@link #tearDown()}. - */ - protected List tearDowns = new ArrayList(); - - protected List recipes = new ArrayList(); - - /** - * Remember {@link WebClient}s that are created, to release them properly. - */ - private List clients = new ArrayList(); - - /** - * JavaScript "debugger" that provides you information about the JavaScript call stack - * and the current values of the local variables in those stack frame. - * - *

- * Unlike Java debugger, which you as a human interfaces directly and interactively, - * this JavaScript debugger is to be interfaced by your program (or through the - * expression evaluation capability of your Java debugger.) - */ - protected JavaScriptDebugger jsDebugger = new JavaScriptDebugger(); - - /** - * If this test case has additional {@link WithPlugin} annotations, set to true. - * This will cause a fresh {@link PluginManager} to be created for this test. - * Leaving this to false enables the test harness to use a pre-loaded plugin manager, - * which runs faster. - * - * @deprecated - * Use {@link #pluginManager} - */ - public boolean useLocalPluginManager; - - /** - * Number of seconds until the test times out. - */ - public int timeout = Integer.getInteger("jenkins.test.timeout", 180); - - private volatile Timer timeoutTimer; - - /** - * Set the plugin manager to be passed to {@link Jenkins} constructor. - * - * For historical reasons, {@link #useLocalPluginManager}==true will take the precedence. - */ - private PluginManager pluginManager = TestPluginManager.INSTANCE; - - public ComputerConnectorTester computerConnectorTester = new ComputerConnectorTester(this); - - /** - * The directory where a war file gets exploded. - */ - protected File explodedWarDir; - - private boolean origDefaultUseCache = true; - - protected HudsonTestCase(String name) { - super(name); - } - - protected HudsonTestCase() { - } - - @Override - public void runBare() throws Throwable { - // override the thread name to make the thread dump more useful. - Thread t = Thread.currentThread(); - String o = getClass().getName()+'.'+t.getName(); - t.setName("Executing "+getName()); - try { - super.runBare(); - } finally { - t.setName(o); - } - } - - @Override - protected void setUp() throws Exception { - if(Functions.isWindows()) { - // JENKINS-4409. - // URLConnection caches handles to jar files by default, - // and it prevents delete temporary directories on Windows. - // Disables caching here. - // Though defaultUseCache is a static field, - // its setter and getter are provided as instance methods. - URLConnection aConnection = new File(".").toURI().toURL().openConnection(); - origDefaultUseCache = aConnection.getDefaultUseCaches(); - aConnection.setDefaultUseCaches(false); - } - - env.pin(); - recipe(); - for (Runner r : recipes) { - if (r instanceof WithoutJenkins.RunnerImpl) - return; // no setup - } - AbstractProject.WORKSPACE.toString(); - User.clear(); - - // just in case tearDown failed in the middle, make sure to really clean them up so that there's no left-over from earlier tests - ExtensionList.clearLegacyInstances(); - DescriptorExtensionList.clearLegacyInstances(); - - try { - jenkins = hudson = newHudson(); - } catch (Exception e) { - // if Jenkins instance fails to initialize, it leaves the instance field non-empty and break all the rest of the tests, so clean that up. - Field f = Jenkins.class.getDeclaredField("theInstance"); - f.setAccessible(true); - f.set(null,null); - throw e; - } - jenkins.setNoUsageStatistics(true); // collecting usage stats from tests are pointless. - - jenkins.setCrumbIssuer(new TestCrumbIssuer()); - - jenkins.servletContext.setAttribute("app", jenkins); - jenkins.servletContext.setAttribute("version","?"); - WebAppMain.installExpressionFactory(new ServletContextEvent(jenkins.servletContext)); - JenkinsLocationConfiguration.get().setUrl(getURL().toString()); - - // set a default JDK to be the one that the harness is using. - jenkins.getJDKs().add(new JDK("default",System.getProperty("java.home"))); - - configureUpdateCenter(); - - // expose the test instance as a part of URL tree. - // this allows tests to use a part of the URL space for itself. - jenkins.getActions().add(this); - - // cause all the descriptors to reload. - // ideally we'd like to reset them to properly emulate the behavior, but that's not possible. - for( Descriptor d : jenkins.getExtensionList(Descriptor.class) ) - d.load(); - - // allow the test class to inject Jenkins components - jenkins.lookup(Injector.class).injectMembers(this); - - setUpTimeout(); - } - - protected void setUpTimeout() { - if (timeout<=0) return; // no timeout - - final Thread testThread = Thread.currentThread(); - timeoutTimer = new Timer(); - timeoutTimer.schedule(new TimerTask() { - @Override - public void run() { - if (timeoutTimer!=null) { - LOGGER.warning(String.format("Test timed out (after %d seconds).", timeout)); - testThread.interrupt(); - } - } - }, TimeUnit.SECONDS.toMillis(timeout)); - } - - - /** - * Configures the update center setting for the test. - * By default, we load updates from local proxy to avoid network traffic as much as possible. - */ - protected void configureUpdateCenter() throws Exception { - final String updateCenterUrl = "http://localhost:"+ JavaNetReverseProxy.getInstance().localPort+"/update-center.json"; - - // don't waste bandwidth talking to the update center - DownloadService.neverUpdate = true; - UpdateSite.neverUpdate = true; - - PersistedList sites = jenkins.getUpdateCenter().getSites(); - sites.clear(); - sites.add(new UpdateSite("default", updateCenterUrl)); - } - - @Override - protected void tearDown() throws Exception { - try { - if (jenkins!=null) { - for (EndOfTestListener tl : jenkins.getExtensionList(EndOfTestListener.class)) - tl.onTearDown(); - } - - if (timeoutTimer!=null) { - timeoutTimer.cancel(); - timeoutTimer = null; - } - - // cancel pending asynchronous operations, although this doesn't really seem to be working - for (WebClient client : clients) { - // unload the page to cancel asynchronous operations - client.getPage("about:blank"); - client.closeAllWindows(); - } - clients.clear(); - } finally { - if (server!=null) - server.stop(); - for (LenientRunnable r : tearDowns) - r.run(); - - if (jenkins!=null) - jenkins.cleanUp(); - ExtensionList.clearLegacyInstances(); - DescriptorExtensionList.clearLegacyInstances(); - - try { - env.dispose(); - } catch (Exception x) { - x.printStackTrace(); - } - - // Jenkins creates ClassLoaders for plugins that hold on to file descriptors of its jar files, - // but because there's no explicit dispose method on ClassLoader, they won't get GC-ed until - // at some later point, leading to possible file descriptor overflow. So encourage GC now. - // see http://bugs.sun.com/view_bug.do?bug_id=4950148 - System.gc(); - - // restore defaultUseCache - if(Functions.isWindows()) { - URLConnection aConnection = new File(".").toURI().toURL().openConnection(); - aConnection.setDefaultUseCaches(origDefaultUseCache); - } - } - } - - @Override - protected void runTest() throws Throwable { - System.out.println("=== Starting "+ getClass().getSimpleName() + "." + getName()); - // so that test code has all the access to the system - ACL.impersonate(ACL.SYSTEM); - - try { - super.runTest(); - } catch (Throwable t) { - // allow the late attachment of a debugger in case of a failure. Useful - // for diagnosing a rare failure - try { - throw new BreakException(); - } catch (BreakException e) {} - - // dump threads - ThreadInfo[] threadInfos = Functions.getThreadInfos(); - ThreadGroupMap m = Functions.sortThreadsAndGetGroupMap(threadInfos); - for (ThreadInfo ti : threadInfos) { - System.err.println(Functions.dumpThreadInfo(ti, m)); - } - throw t; - } - } - - @SuppressWarnings("serial") - public static class BreakException extends Exception {} - - public String getIconFileName() { - return null; - } - - public String getDisplayName() { - return null; - } - - public String getUrlName() { - return "self"; - } - - /** - * Creates a new instance of {@link jenkins.model.Jenkins}. If the derived class wants to create it in a different way, - * you can override it. - */ - protected Hudson newHudson() throws Exception { - File home = homeLoader.allocate(); - for (Runner r : recipes) - r.decorateHome(this,home); - return new Hudson(home, createWebServer(), useLocalPluginManager ? null : pluginManager); - } - - /** - * Sets the {@link PluginManager} to be used when creating a new {@link Jenkins} instance. - * - * @param pluginManager - * null to let Jenkins create a new instance of default plugin manager, like it normally does when running as a webapp outside the test. - */ - public void setPluginManager(PluginManager pluginManager) { - this.useLocalPluginManager = false; - this.pluginManager = pluginManager; - if (jenkins !=null) - throw new IllegalStateException("Too late to override the plugin manager"); - } - - /** - * Prepares a webapp hosting environment to get {@link ServletContext} implementation - * that we need for testing. - */ - protected ServletContext createWebServer() throws Exception { - server = new Server(); - - explodedWarDir = WarExploder.getExplodedDir(); - WebAppContext context = new WebAppContext(explodedWarDir.getPath(), contextPath); - context.setClassLoader(getClass().getClassLoader()); - context.setConfigurations(new Configuration[]{new WebXmlConfiguration(), new NoListenerConfiguration()}); - server.setHandler(context); - context.setMimeTypes(MIME_TYPES); - - SocketConnector connector = new SocketConnector(); - connector.setHeaderBufferSize(12*1024); // use a bigger buffer as Stapler traces can get pretty large on deeply nested URL - - server.setThreadPool(new ThreadPoolImpl(new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(),new ThreadFactory() { - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setName("Jetty Thread Pool"); - return t; - } - }))); - server.addConnector(connector); - server.addUserRealm(configureUserRealm()); - server.start(); - - localPort = connector.getLocalPort(); - - return context.getServletContext(); - } - - /** - * Configures a security realm for a test. - */ - protected UserRealm configureUserRealm() { - HashUserRealm realm = new HashUserRealm(); - realm.setName("default"); // this is the magic realm name to make it effective on everywhere - realm.put("alice","alice"); - realm.put("bob","bob"); - realm.put("charlie","charlie"); - - realm.addUserToRole("alice","female"); - realm.addUserToRole("bob","male"); - realm.addUserToRole("charlie","male"); - - return realm; - } - -// -// Convenience methods -// - - protected FreeStyleProject createFreeStyleProject() throws IOException { - return createFreeStyleProject(createUniqueProjectName()); - } - - protected FreeStyleProject createFreeStyleProject(String name) throws IOException { - return jenkins.createProject(FreeStyleProject.class, name); - } - - protected String createUniqueProjectName() { - return "test"+ jenkins.getItems().size(); - } - - /** - * Creates {@link LocalLauncher}. Useful for launching processes. - */ - protected LocalLauncher createLocalLauncher() { - return new LocalLauncher(StreamTaskListener.fromStdout()); - } - - /** - * Allocates a new temporary directory for the duration of this test. - */ - public File createTmpDir() throws IOException { - return env.temporaryDirectoryAllocator.allocate(); - } - - public DumbSlave createSlave() throws Exception { - return createSlave("",null); - } - - /** - * Creates and launches a new slave on the local host. - */ - public DumbSlave createSlave(Label l) throws Exception { - return createSlave(l, null); - } - - /** - * Creates a test {@link SecurityRealm} that recognizes username==password as valid. - */ - public SecurityRealm createDummySecurityRealm() { - return new AbstractPasswordBasedSecurityRealm() { - @Override - protected UserDetails authenticate(String username, String password) throws AuthenticationException { - if (username.equals(password)) - return loadUserByUsername(username); - throw new BadCredentialsException(username); - } - - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { - return new org.acegisecurity.userdetails.User(username,"",true,true,true,true,new GrantedAuthority[]{AUTHENTICATED_AUTHORITY}); - } - - @Override - public GroupDetails loadGroupByGroupname(String groupname) throws UsernameNotFoundException, DataAccessException { - throw new UsernameNotFoundException(groupname); - } - }; - } - - /** - * Returns the URL of the webapp top page. - * URL ends with '/'. - */ - public URL getURL() throws IOException { - return new URL("http://localhost:"+localPort+contextPath+"/"); - } - - public DumbSlave createSlave(EnvVars env) throws Exception { - return createSlave("",env); - } - - public DumbSlave createSlave(Label l, EnvVars env) throws Exception { - return createSlave(l==null ? null : l.getExpression(), env); - } - - /** - * Creates a slave with certain additional environment variables - */ - public DumbSlave createSlave(String labels, EnvVars env) throws Exception { - synchronized (jenkins) { - int sz = jenkins.getNodes().size(); - return createSlave("slave" + sz,labels,env); - } - } - - public DumbSlave createSlave(String nodeName, String labels, EnvVars env) throws Exception { - synchronized (jenkins) { - DumbSlave slave = new DumbSlave(nodeName, "dummy", - createTmpDir().getPath(), "1", Mode.NORMAL, labels==null?"":labels, createComputerLauncher(env), - RetentionStrategy.NOOP, Collections.>emptyList()); - jenkins.addNode(slave); - return slave; - } - } - - public PretendSlave createPretendSlave(FakeLauncher faker) throws Exception { - synchronized (jenkins) { - int sz = jenkins.getNodes().size(); - PretendSlave slave = new PretendSlave("slave" + sz, createTmpDir().getPath(), "", createComputerLauncher(null), faker); - jenkins.addNode(slave); - return slave; - } - } - - /** - * Creates a {@link CommandLauncher} for launching a slave locally. - * - * @param env - * Environment variables to add to the slave process. Can be null. - */ - public CommandLauncher createComputerLauncher(EnvVars env) throws URISyntaxException, MalformedURLException { - int sz = jenkins.getNodes().size(); - return new CommandLauncher( - String.format("\"%s/bin/java\" %s -jar \"%s\"", - System.getProperty("java.home"), - SLAVE_DEBUG_PORT>0 ? " -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address="+(SLAVE_DEBUG_PORT+sz): "", - new File(jenkins.getJnlpJars("slave.jar").getURL().toURI()).getAbsolutePath()), - env); - } - - /** - * Create a new slave on the local host and wait for it to come onilne - * before returning. - */ - public DumbSlave createOnlineSlave() throws Exception { - return createOnlineSlave(null); - } - - /** - * Create a new slave on the local host and wait for it to come onilne - * before returning. - */ - public DumbSlave createOnlineSlave(Label l) throws Exception { - return createOnlineSlave(l, null); - } - - /** - * Create a new slave on the local host and wait for it to come online - * before returning - */ - @SuppressWarnings("deprecation") - public DumbSlave createOnlineSlave(Label l, EnvVars env) throws Exception { - final CountDownLatch latch = new CountDownLatch(1); - ComputerListener waiter = new ComputerListener() { - @Override - public void onOnline(Computer C, TaskListener t) { - latch.countDown(); - unregister(); - } - }; - waiter.register(); - - DumbSlave s = createSlave(l, env); - latch.await(); - - return s; - } - - /** - * Blocks until the ENTER key is hit. - * This is useful during debugging a test so that one can inspect the state of Jenkins through the web browser. - */ - public void interactiveBreak() throws Exception { - System.out.println("Jenkins is running at http://localhost:"+localPort+"/"); - new BufferedReader(new InputStreamReader(System.in)).readLine(); - } - - /** - * Returns the last item in the list. - */ - protected T last(List items) { - return items.get(items.size()-1); - } - - /** - * Pauses the execution until ENTER is hit in the console. - *

- * This is often very useful so that you can interact with Hudson - * from an browser, while developing a test case. - */ - protected void pause() throws IOException { - new BufferedReader(new InputStreamReader(System.in)).readLine(); - } - - /** - * Performs a search from the search box. - */ - protected Page search(String q) throws Exception { - return new WebClient().search(q); - } - - /** - * Hits the Hudson system configuration and submits without any modification. - */ - protected void configRoundtrip() throws Exception { - submit(createWebClient().goTo("configure").getFormByName("config")); - } - - /** - * Loads a configuration page and submits it without any modifications, to - * perform a round-trip configuration test. - *

- * See http://wiki.jenkins-ci.org/display/JENKINS/Unit+Test#UnitTest-Configurationroundtriptesting - */ - protected

P configRoundtrip(P job) throws Exception { - submit(createWebClient().getPage(job,"configure").getFormByName("config")); - return job; - } - - protected

P configRoundtrip(P job) throws Exception { - submit(createWebClient().getPage(job, "configure").getFormByName("config")); - return job; - } - - /** - * Performs a configuration round-trip testing for a builder. - */ - @SuppressWarnings("unchecked") - protected B configRoundtrip(B before) throws Exception { - FreeStyleProject p = createFreeStyleProject(); - p.getBuildersList().add(before); - configRoundtrip((Item)p); - return (B)p.getBuildersList().get(before.getClass()); - } - - /** - * Performs a configuration round-trip testing for a publisher. - */ - @SuppressWarnings("unchecked") - protected

P configRoundtrip(P before) throws Exception { - FreeStyleProject p = createFreeStyleProject(); - p.getPublishersList().add(before); - configRoundtrip((Item) p); - return (P)p.getPublishersList().get(before.getClass()); - } - - @SuppressWarnings("unchecked") - protected C configRoundtrip(C before) throws Exception { - computerConnectorTester.connector = before; - submit(createWebClient().goTo("self/computerConnectorTester/configure").getFormByName("config")); - return (C)computerConnectorTester.connector; - } - - protected User configRoundtrip(User u) throws Exception { - submit(createWebClient().goTo(u.getUrl()+"/configure").getFormByName("config")); - return u; - } - - @SuppressWarnings("unchecked") - protected N configRoundtrip(N node) throws Exception { - submit(createWebClient().goTo("/computer/" + node.getNodeName() + "/configure").getFormByName("config")); - return (N) jenkins.getNode(node.getNodeName()); - } - - protected V configRoundtrip(V view) throws Exception { - submit(createWebClient().getPage(view, "configure").getFormByName("viewConfig")); - return view; - } - - - /** - * Asserts that the outcome of the build is a specific outcome. - */ - public R assertBuildStatus(Result status, R r) throws Exception { - if(status==r.getResult()) - return r; - - // dump the build output in failure message - String msg = "unexpected build status; build log was:\n------\n" + getLog(r) + "\n------\n"; - assertEquals(msg, status,r.getResult()); - return r; - } - - /** Determines whether the specified HTTP status code is generally "good" */ - public boolean isGoodHttpStatus(int status) { - if ((400 <= status) && (status <= 417)) { - return false; - } - if ((500 <= status) && (status <= 505)) { - return false; - } - return true; - } - - /** Assert that the specified page can be served with a "good" HTTP status, - * eg, the page is not missing and can be served without a server error - * @param page - */ - public void assertGoodStatus(Page page) { - assertTrue(isGoodHttpStatus(page.getWebResponse().getStatusCode())); - } - - - public R assertBuildStatusSuccess(R r) throws Exception { - assertBuildStatus(Result.SUCCESS, r); - return r; - } - - public R assertBuildStatusSuccess(Future r) throws Exception { - assertNotNull("build was actually scheduled", r); - return assertBuildStatusSuccess(r.get()); - } - - public ,R extends AbstractBuild> R buildAndAssertSuccess(J job) throws Exception { - return assertBuildStatusSuccess(job.scheduleBuild2(0)); - } - - /** - * Avoids need for cumbersome {@code this.buildAndAssertSuccess(...)} type hints under JDK 7 javac (and supposedly also IntelliJ). - */ - public FreeStyleBuild buildAndAssertSuccess(FreeStyleProject job) throws Exception { - return assertBuildStatusSuccess(job.scheduleBuild2(0)); - } - - /** - * Asserts that the console output of the build contains the given substring. - */ - public void assertLogContains(String substring, Run run) throws Exception { - String log = getLog(run); - assertTrue("Console output of "+run+" didn't contain "+substring+":\n"+log,log.contains(substring)); - } - - /** - * Asserts that the console output of the build does not contain the given substring. - */ - public void assertLogNotContains(String substring, Run run) throws Exception { - String log = getLog(run); - assertFalse("Console output of "+run+" contains "+substring+":\n"+log,log.contains(substring)); - } - - /** - * Get entire log file (this method is deprecated in hudson.model.Run, - * but in tests it is OK to load entire log). - */ - protected static String getLog(Run run) throws IOException { - return Util.loadFile(run.getLogFile(), run.getCharset()); - } - - /** - * Asserts that the XPath matches. - */ - public void assertXPath(HtmlPage page, String xpath) { - assertNotNull("There should be an object that matches XPath:" + xpath, - DomNodeUtil.selectSingleNode(page.getDocumentElement(), xpath)); - } - - /** Asserts that the XPath matches the contents of a DomNode page. This - * variant of assertXPath(HtmlPage page, String xpath) allows us to - * examine XmlPages. - * @param page - * @param xpath - */ - public void assertXPath(DomNode page, String xpath) { - List< ? extends Object> nodes = page.getByXPath(xpath); - assertFalse("There should be an object that matches XPath:" + xpath, nodes.isEmpty()); - } - - public void assertXPathValue(DomNode page, String xpath, String expectedValue) { - Object node = page.getFirstByXPath(xpath); - assertNotNull("no node found", node); - assertTrue("the found object was not a Node " + xpath, node instanceof org.w3c.dom.Node); - - org.w3c.dom.Node n = (org.w3c.dom.Node) node; - String textString = n.getTextContent(); - assertEquals("xpath value should match for " + xpath, expectedValue, textString); - } - - public void assertXPathValueContains(DomNode page, String xpath, String needle) { - Object node = page.getFirstByXPath(xpath); - assertNotNull("no node found", node); - assertTrue("the found object was not a Node " + xpath, node instanceof org.w3c.dom.Node); - - org.w3c.dom.Node n = (org.w3c.dom.Node) node; - String textString = n.getTextContent(); - assertTrue("needle found in haystack", textString.contains(needle)); - } - - public void assertXPathResultsContainText(DomNode page, String xpath, String needle) { - List nodes = page.getByXPath(xpath); - assertFalse("no nodes matching xpath found", nodes.isEmpty()); - boolean found = false; - for (Object o : nodes) { - if (o instanceof org.w3c.dom.Node) { - org.w3c.dom.Node n = (org.w3c.dom.Node) o; - String textString = n.getTextContent(); - if ((textString != null) && textString.contains(needle)) { - found = true; - break; - } - } - } - assertTrue("needle found in haystack", found); - } - - /** - * Makes sure that all the images in the page loads successfully. - * (By default, HtmlUnit doesn't load images.) - */ - public void assertAllImageLoadSuccessfully(HtmlPage p) { - for (HtmlImage img : DomNodeUtil.selectNodes(p, "//IMG")) { - try { - img.getHeight(); - } catch (IOException e) { - throw new Error("Failed to load "+img.getSrcAttribute(),e); - } - } - } - - - public void assertStringContains(String message, String haystack, String needle) { - assertTrue(message + " (seeking '" + needle + "')",haystack.contains(needle)); - } - - public void assertStringContains(String haystack, String needle) { - assertTrue("Could not find '" + needle + "'.",haystack.contains(needle)); - } - - /** - * Asserts that help files exist for the specified properties of the given instance. - * - * @param type - * The describable class type that should have the associated help files. - * @param properties - * ','-separated list of properties whose help files should exist. - */ - public void assertHelpExists(final Class type, final String properties) throws Exception { - executeOnServer(new Callable() { - public Object call() throws Exception { - Descriptor d = jenkins.getDescriptor(type); - WebClient wc = createWebClient(); - for (String property : listProperties(properties)) { - String url = d.getHelpFile(property); - assertNotNull("Help file for the property "+property+" is missing on "+type, url); - wc.goTo(url); // make sure it successfully loads - } - return null; - } - }); - } - - /** - * Tokenizes "foo,bar,zot,-bar" and returns "foo,zot" (the token that starts with '-' is handled as - * a cancellation. - */ - private List listProperties(String properties) { - List props = new ArrayList(Arrays.asList(properties.split(","))); - for (String p : props.toArray(new String[props.size()])) { - if (p.startsWith("-")) { - props.remove(p); - props.remove(p.substring(1)); - } - } - return props; - } - - /** - * Submits the form. - * - * 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) HtmlFormUtil.submit(form, last(form.getHtmlElementsByTagName("button"))); - } - - /** - * Submits the form by clikcing the submit button of the given name. - * - * @param name - * This corresponds to the @name of <f:submit /> - */ - public HtmlPage submit(HtmlForm form, String name) throws Exception { - for( HtmlElement e : form.getHtmlElementsByTagName("button")) { - HtmlElement p = (HtmlElement)e.getParentNode().getParentNode(); - 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 DomNodeUtil.selectSingleNode(current, "(preceding::input[@name='_."+name+"'])[last()]"); - } - - protected HtmlButton getButtonByCaption(HtmlForm f, String s) { - for (HtmlElement b : f.getHtmlElementsByTagName("button")) { - if(b.getTextContent().trim().equals(s)) - return (HtmlButton)b; - } - return null; - } - - /** - * Creates a {@link TaskListener} connected to stdout. - */ - public TaskListener createTaskListener() { - return new StreamTaskListener(new CloseProofOutputStream(System.out)); - } - - /** - * Asserts that two JavaBeans are equal as far as the given list of properties are concerned. - * - *

- * This method takes two objects that have properties (getXyz, isXyz, or just the public xyz field), - * and makes sure that the property values for each given property are equals (by using {@link #assertEquals(Object, Object)}) - * - *

- * Property values can be null on both objects, and that is OK, but passing in a property that doesn't - * exist will fail an assertion. - * - *

- * This method is very convenient for comparing a large number of properties on two objects, - * for example to verify that the configuration is identical after a config screen roundtrip. - * - * @param lhs - * One of the two objects to be compared. - * @param rhs - * The other object to be compared - * @param properties - * ','-separated list of property names that are compared. - * @since 1.297 - */ - public void assertEqualBeans(Object lhs, Object rhs, String properties) throws Exception { - assertNotNull("lhs is null",lhs); - assertNotNull("rhs is null",rhs); - for (String p : properties.split(",")) { - PropertyDescriptor pd = PropertyUtils.getPropertyDescriptor(lhs, p); - Object lp,rp; - if(pd==null) { - // field? - try { - Field f = lhs.getClass().getField(p); - lp = f.get(lhs); - rp = f.get(rhs); - } catch (NoSuchFieldException e) { - assertNotNull("No such property "+p+" on "+lhs.getClass(),pd); - return; - } - } else { - lp = PropertyUtils.getProperty(lhs, p); - rp = PropertyUtils.getProperty(rhs, p); - } - - if (lp!=null && rp!=null && lp.getClass().isArray() && rp.getClass().isArray()) { - // deep array equality comparison - int m = Array.getLength(lp); - int n = Array.getLength(rp); - assertEquals("Array length is different for property "+p, m,n); - for (int i=0; i primitiveProperties = new ArrayList(); - - String[] names = ClassDescriptor.loadParameterNames(lc); - Class[] types = lc.getParameterTypes(); - assertEquals(names.length,types.length); - for (int i=0; i lhs, List rhs) throws Exception { - assertEquals(lhs.size(), rhs.size()); - for (int i=0; i findDataBoundConstructor(Class c) { - for (Constructor m : c.getConstructors()) { - if (m.getAnnotation(DataBoundConstructor.class)!=null) - return m; - } - return null; - } - - /** - * Gets the descriptor instance of the current Hudson by its type. - */ - protected > T get(Class d) { - return jenkins.getDescriptorByType(d); - } - - - /** - * Returns true if Hudson is building something or going to build something. - */ - protected boolean isSomethingHappening() { - if (!jenkins.getQueue().isEmpty()) - return true; - for (Computer n : jenkins.getComputers()) - if (!n.isIdle()) - return true; - return false; - } - - /** - * Waits until Hudson finishes building everything, including those in the queue. - *

- * This method uses a default time out to prevent infinite hang in the automated test execution environment. - */ - protected void waitUntilNoActivity() throws Exception { - waitUntilNoActivityUpTo(60*1000); - } - - /** - * Waits until Jenkins finishes building everything, including those builds in the queue, or fail the test - * if the specified timeout milliseconds is exceeded. - */ - protected void waitUntilNoActivityUpTo(int timeout) throws Exception { - long startTime = System.currentTimeMillis(); - int streak = 0; - - while (true) { - Thread.sleep(100); - if (isSomethingHappening()) - streak=0; - else - streak++; - - if (streak>2) // the system is quiet for a while - return; - - if (System.currentTimeMillis()-startTime > timeout) { - List building = new ArrayList(); - for (Computer c : jenkins.getComputers()) { - for (Executor e : c.getExecutors()) { - if (e.isBusy()) - building.add(e.getCurrentExecutable()); - } - } - throw new AssertionError(String.format("Jenkins is still doing something after %dms: queue=%s building=%s", - timeout, Arrays.asList(jenkins.getQueue().getItems()), building)); - } - } - } - - - -// -// recipe methods. Control the test environments. -// - - /** - * Called during the {@link #setUp()} to give a test case an opportunity to - * control the test environment in which Hudson is run. - * - *

- * One could override this method and call a series of {@code withXXX} methods, - * or you can use the annotations with {@link Recipe} meta-annotation. - */ - protected void recipe() throws Exception { - recipeLoadCurrentPlugin(); - // look for recipe meta-annotation - try { - Method runMethod= getClass().getMethod(getName()); - for( final Annotation a : runMethod.getAnnotations() ) { - Recipe r = a.annotationType().getAnnotation(Recipe.class); - if(r==null) continue; - final Runner runner = r.value().newInstance(); - recipes.add(runner); - tearDowns.add(new LenientRunnable() { - public void run() throws Exception { - runner.tearDown(HudsonTestCase.this,a); - } - }); - runner.setup(this,a); - } - } catch (NoSuchMethodException e) { - // not a plain JUnit test. - } - } - - /** - * If this test harness is launched for a Jenkins plugin, locate the target/test-classes/the.jpl - * and add a recipe to install that to the new Jenkins. - * - *

- * This file is created by maven-hpi-plugin at the testCompile phase when the current - * packaging is hpi. - */ - protected void recipeLoadCurrentPlugin() throws Exception { - final Enumeration jpls = getClass().getClassLoader().getResources("the.jpl"); - final Enumeration hpls = getClass().getClassLoader().getResources("the.hpl"); - - final List all = Collections.list(jpls); - all.addAll(Collections.list(hpls)); - - if(all.isEmpty()) return; // nope - - recipes.add(new Runner() { - @Override - public void decorateHome(HudsonTestCase testCase, File home) throws Exception { - - for (URL hpl : all) { - - // make the plugin itself available - Manifest m = new Manifest(hpl.openStream()); - String shortName = m.getMainAttributes().getValue("Short-Name"); - if(shortName==null) - throw new Error(hpl+" doesn't have the Short-Name attribute"); - FileUtils.copyURLToFile(hpl,new File(home,"plugins/"+shortName+".jpl")); - - // make dependency plugins available - // TODO: probably better to read POM, but where to read from? - // TODO: this doesn't handle transitive dependencies - - // Tom: plugins are now searched on the classpath first. They should be available on - // the compile or test classpath. As a backup, we do a best-effort lookup in the Maven repository - // For transitive dependencies, we could evaluate Plugin-Dependencies transitively. - - String dependencies = m.getMainAttributes().getValue("Plugin-Dependencies"); - if(dependencies!=null) { - // TODO can we switch this to use Aether directly? - MavenEmbedder embedder = new MavenEmbedder(MavenEmbedder.class.getClassLoader(), new MavenRequest()); - for( String dep : dependencies.split(",")) { - String suffix = ";resolution:=optional"; - boolean optional = dep.endsWith(suffix); - if (optional) { - dep = dep.substring(0, dep.length() - suffix.length()); - } - String[] tokens = dep.split(":"); - String artifactId = tokens[0]; - String version = tokens[1]; - File dependencyJar=resolveDependencyJar(embedder,artifactId,version); - if (dependencyJar == null) { - if (optional) { - System.err.println("cannot resolve optional dependency " + dep + " of " + shortName + "; skipping"); - continue; - } - throw new IOException("Could not resolve " + dep); - } - - File dst = new File(home, "plugins/" + artifactId + ".jpi"); - if(!dst.exists() || dst.lastModified()!=dependencyJar.lastModified()) { - FileUtils.copyFile(dependencyJar, dst); - } - } - } - } - } - - private File resolveDependencyJar(MavenEmbedder embedder, String artifactId, String version) throws Exception { - // try to locate it from manifest - Enumeration manifests = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF"); - while (manifests.hasMoreElements()) { - URL manifest = manifests.nextElement(); - InputStream is = manifest.openStream(); - Manifest m = new Manifest(is); - is.close(); - - if (artifactId.equals(m.getMainAttributes().getValue("Short-Name"))) - return Which.jarFile(manifest); - } - - // need to search multiple group IDs - // TODO: extend manifest to include groupID:artifactID:version - Exception resolutionError=null; - for (String groupId : new String[]{"org.jvnet.hudson.plugins","org.jvnet.hudson.main"}) { - - // first try to find it on the classpath. - // this takes advantage of Maven POM located in POM - URL dependencyPomResource = getClass().getResource("/META-INF/maven/"+groupId+"/"+artifactId+"/pom.xml"); - if (dependencyPomResource != null) { - // found it - return Which.jarFile(dependencyPomResource); - } else { - - try { - // currently the most of the plugins are still hpi - return resolvePluginFile(embedder, artifactId, version, groupId, "hpi"); - } catch(AbstractArtifactResolutionException x){ - try { - // but also try with the new jpi - return resolvePluginFile(embedder, artifactId, version, groupId, "jpi"); - } catch(AbstractArtifactResolutionException x2){ - // could be a wrong groupId - resolutionError = x; - } - } - - } - } - - throw new Exception("Failed to resolve plugin (tryied with types: 'jpi' and 'hpi'): "+artifactId+" version "+version, resolutionError); - } - - private File resolvePluginFile(MavenEmbedder embedder, String artifactId, String version, String groupId, String type) - throws MavenEmbedderException, ComponentLookupException, AbstractArtifactResolutionException { - final Artifact jpi = embedder.createArtifact(groupId, artifactId, version, "compile"/*doesn't matter*/, type); - embedder.resolve(jpi, Arrays.asList(embedder.createRepository("http://repo.jenkins-ci.org/public/", "repo.jenkins-ci.org")),embedder.getLocalRepository()); - return jpi.getFile(); - - } - }); - } - - public HudsonTestCase withNewHome() { - return with(HudsonHomeLoader.NEW); - } - - public HudsonTestCase withExistingHome(File source) throws Exception { - return with(new CopyExisting(source)); - } - - /** - * Declares that this test case expects to start with one of the preset data sets. - * See {@code test/src/main/preset-data/} - * for available datasets and what they mean. - */ - public HudsonTestCase withPresetData(String name) { - name = "/" + name + ".zip"; - URL res = getClass().getResource(name); - if(res==null) throw new IllegalArgumentException("No such data set found: "+name); - - return with(new CopyExisting(res)); - } - - public HudsonTestCase with(HudsonHomeLoader homeLoader) { - this.homeLoader = homeLoader; - return this; - } - - - /** - * Executes the given closure on the server, by the servlet request handling thread, - * in the context of an HTTP request. - * - *

- * In {@link HudsonTestCase}, a thread that's executing the test code is different from the thread - * that carries out HTTP requests made through {@link WebClient}. But sometimes you want to - * make assertions and other calls with side-effect from within the request handling thread. - * - *

- * This method allows you to do just that. It is useful for testing some methods that - * require {@link StaplerRequest} and {@link StaplerResponse}, or getting the credential - * of the current user (via {@link jenkins.model.Jenkins#getAuthentication()}, and so on. - * - * @param c - * The closure to be executed on the server. - * @return - * The return value from the closure. - * @throws Exception - * If a closure throws any exception, that exception will be carried forward. - */ - public V executeOnServer(Callable c) throws Exception { - return createWebClient().executeOnServer(c); - } - - /** - * Sometimes a part of a test case may ends up creeping into the serialization tree of {@link Saveable#save()}, - * so detect that and flag that as an error. - */ - private Object writeReplace() { - throw new AssertionError("HudsonTestCase "+getName()+" is not supposed to be serialized"); - } - - /** - * This is to assist Groovy test clients who are incapable of instantiating the inner classes properly. - */ - public WebClient createWebClient() { - return new WebClient(); - } - - /** - * Extends {@link com.gargoylesoftware.htmlunit.WebClient} and provide convenience methods - * for accessing Hudson. - */ - public class WebClient extends com.gargoylesoftware.htmlunit.WebClient { - 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_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 = 6730107519583349963L; - public boolean processSynchron(HtmlPage page, WebRequest settings, boolean async) { - return false; - } - }); - - setCssErrorHandler(new ErrorHandler() { - final ErrorHandler defaultHandler = new DefaultCssErrorHandler(); - - public void warning(CSSParseException exception) throws CSSException { - if (!ignore(exception)) - defaultHandler.warning(exception); - } - - public void error(CSSParseException exception) throws CSSException { - if (!ignore(exception)) - defaultHandler.error(exception); - } - - public void fatalError(CSSParseException exception) throws CSSException { - if (!ignore(exception)) - defaultHandler.fatalError(exception); - } - - private boolean ignore(CSSParseException e) { - return e.getURI().contains("/yui/"); - } - }); - - // if no other debugger is installed, install jsDebugger, - // so as not to interfere with the 'Dim' class. - getJavaScriptEngine().getContextFactory().addListener(new Listener() { - public void contextCreated(Context cx) { - if (cx.getDebugger() == null) - cx.setDebugger(jsDebugger, null); - } - - public void contextReleased(Context cx) { - } - }); - - setAlertHandler(new AlertHandler() { - public void handleAlert(Page page, String message) { - throw new AssertionError("Alert dialog poped up: "+message); - } - }); - - // avoid a hang by setting a time out. It should be long enough to prevent - // false-positive timeout on slow systems - //setTimeout(60*1000); - } - - /** - * Logs in to Jenkins. - */ - public WebClient login(String username, String password) throws Exception { - HtmlPage page = goTo("/login"); - - HtmlForm form = page.getFormByName("login"); - form.getInputByName("j_username").setValueAttribute(username); - form.getInputByName("j_password").setValueAttribute(password); - HtmlFormUtil.submit(form, null); - return this; - } - - /** - * Logs in to Hudson, by using the user name as the password. - * - *

- * See {@link HudsonTestCase#configureUserRealm()} for how the container is set up with the user names - * and passwords. All the test accounts have the same user name and password. - */ - public WebClient login(String username) throws Exception { - login(username,username); - return this; - } - - /** - * Executes the given closure on the server, by the servlet request handling thread, - * in the context of an HTTP request. - * - *

- * In {@link HudsonTestCase}, a thread that's executing the test code is different from the thread - * that carries out HTTP requests made through {@link WebClient}. But sometimes you want to - * make assertions and other calls with side-effect from within the request handling thread. - * - *

- * This method allows you to do just that. It is useful for testing some methods that - * require {@link StaplerRequest} and {@link StaplerResponse}, or getting the credential - * of the current user (via {@link jenkins.model.Jenkins#getAuthentication()}, and so on. - * - * @param c - * The closure to be executed on the server. - * @return - * The return value from the closure. - * @throws Exception - * If a closure throws any exception, that exception will be carried forward. - */ - public V executeOnServer(final Callable c) throws Exception { - final Exception[] t = new Exception[1]; - final List r = new ArrayList(1); // size 1 list - - ClosureExecuterAction cea = jenkins.getExtensionList(RootAction.class).get(ClosureExecuterAction.class); - UUID id = UUID.randomUUID(); - cea.add(id,new Runnable() { - public void run() { - try { - StaplerResponse rsp = Stapler.getCurrentResponse(); - rsp.setStatus(200); - rsp.setContentType("text/html"); - r.add(c.call()); - } catch (Exception e) { - t[0] = e; - } - } - }); - goTo("closures/?uuid="+id); - - if (t[0]!=null) - throw t[0]; - return r.get(0); - } - - public HtmlPage search(String q) throws IOException, SAXException { - HtmlPage top = goTo(""); - HtmlForm search = top.getFormByName("search"); - search.getInputByName("q").setValueAttribute(q); - return (HtmlPage)HtmlFormUtil.submit(search, null); - } - - /** - * Short for {@code getPage(r,"")}, to access the top page of a build. - */ - public HtmlPage getPage(Run r) throws IOException, SAXException { - return getPage(r,""); - } - - /** - * Accesses a page inside {@link Run}. - * - * @param relative - * Relative URL within the build URL, like "changes". Doesn't start with '/'. Can be empty. - */ - public HtmlPage getPage(Run r, String relative) throws IOException, SAXException { - return goTo(r.getUrl()+relative); - } - - public HtmlPage getPage(Item item) throws IOException, SAXException { - return getPage(item,""); - } - - public HtmlPage getPage(Item item, String relative) throws IOException, SAXException { - return goTo(item.getUrl()+relative); - } - - public HtmlPage getPage(Node item) throws IOException, SAXException { - return getPage(item,""); - } - - public HtmlPage getPage(Node item, String relative) throws IOException, SAXException { - return goTo(item.toComputer().getUrl()+relative); - } - - public HtmlPage getPage(View view) throws IOException, SAXException { - return goTo(view.getUrl()); - } - - public HtmlPage getPage(View view, String relative) throws IOException, SAXException { - return goTo(view.getUrl()+relative); - } - - /** - * @deprecated - * This method expects a full URL. This method is marked as deprecated to warn you - * that you probably should be using {@link #goTo(String)} method, which accepts - * a relative path within the Hudson being tested. (IOW, if you really need to hit - * a website on the internet, there's nothing wrong with using this method.) - */ - @SuppressWarnings("unchecked") - @Override - public Page getPage(String url) throws IOException, FailingHttpStatusCodeException { - try { - return super.getPage(url); - } finally { - WebClientUtil.waitForJSExec(this); - } - } - - /** - * Requests a page within Hudson. - * - * @param relative - * Relative path within Hudson. Starts without '/'. - * For example, "job/test/" to go to a job top page. - */ - public HtmlPage goTo(String relative) throws IOException, SAXException { - Page p = goTo(relative, "text/html"); - if (p instanceof HtmlPage) { - return (HtmlPage) p; - } else { - throw new AssertionError("Expected text/html but instead the content type was "+p.getWebResponse().getContentType()); - } - } - - public Page goTo(String relative, String expectedContentType) throws IOException, SAXException { - while (relative.startsWith("/")) relative = relative.substring(1); - Page p; - try { - p = super.getPage(getContextPath() + relative); - WebClientUtil.waitForJSExec(this); - } catch (IOException x) { - if (x.getCause() != null) { - x.getCause().printStackTrace(); - } - throw x; - } - assertEquals(expectedContentType,p.getWebResponse().getContentType()); - return p; - } - - /** Loads a page as XML. Useful for testing Hudson's xml api, in concert with - * assertXPath(DomNode page, String xpath) - * @param path the path part of the url to visit - * @return the XmlPage found at that url - * @throws IOException - * @throws SAXException - */ - public XmlPage goToXml(String path) throws IOException, SAXException { - Page page = goTo(path, "application/xml"); - if (page instanceof XmlPage) - return (XmlPage) page; - else - return null; - } - - /** - * Verify that the server rejects an attempt to load the given page. - * @param url a URL path (relative to Jenkins root) - * @param statusCode the expected failure code (such as {@link HttpURLConnection#HTTP_FORBIDDEN}) - * @since 1.502 - */ - public void assertFails(String url, int statusCode) throws Exception { - try { - fail(url + " should have been rejected but produced: " + super.getPage(getContextPath() + url).getWebResponse().getContentAsString()); - } catch (FailingHttpStatusCodeException x) { - assertEquals(statusCode, x.getStatusCode()); - } - } - - /** - * Returns the URL of the webapp top page. - * URL ends with '/'. - */ - public String getContextPath() throws IOException { - return getURL().toExternalForm(); - } - - /** - * Adds a security crumb to the quest - */ - 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; - } - - /** - * Creates a URL with crumb parameters relative to {{@link #getContextPath()} - */ - public URL createCrumbedUrl(String relativePath) throws IOException { - CrumbIssuer issuer = jenkins.getCrumbIssuer(); - String crumbName = issuer.getDescriptor().getCrumbRequestField(); - String crumb = issuer.getCrumb(null); - - return new URL(getContextPath()+relativePath+"?"+crumbName+"="+crumb); - } - - /** - * Makes an HTTP request, process it with the given request handler, and returns the response. - */ - public HtmlPage eval(final Runnable requestHandler) throws IOException, SAXException { - ClosureExecuterAction cea = jenkins.getExtensionList(RootAction.class).get(ClosureExecuterAction.class); - UUID id = UUID.randomUUID(); - cea.add(id,requestHandler); - return goTo("closures/?uuid="+id); - } - - /** - * Starts an interactive JavaScript debugger, and break at the next JavaScript execution. - * - *

- * This is useful during debugging a test so that you can step execute and inspect state of JavaScript. - * This will launch a Swing GUI, and the method returns immediately. - * - *

- * Note that installing a debugger appears to make an execution of JavaScript substantially slower. - * - *

- * TODO: because each script block evaluation in HtmlUnit is done in a separate Rhino context, - * if you step over from one script block, the debugger fails to kick in on the beginning of the next script block. - * This makes it difficult to set a break point on arbitrary script block in the HTML page. We need to fix this - * by tweaking {@link Dim.StackFrame#onLineChange(Context, int)}. - */ - public Dim interactiveJavaScriptDebugger() { - Global global = new Global(); - HtmlUnitContextFactory cf = getJavaScriptEngine().getContextFactory(); - global.init(cf); - - Dim dim = org.mozilla.javascript.tools.debugger.Main.mainEmbedded(cf, global, "Rhino debugger: " + getName()); - - // break on exceptions. this catch most of the errors - dim.setBreakOnExceptions(true); - - return dim; - } - } - - // needs to keep reference, or it gets GC-ed. - private static final Logger XML_HTTP_REQUEST_LOGGER = Logger.getLogger(XMLHttpRequest.class.getName()); - - static { - // screen scraping relies on locale being fixed. - Locale.setDefault(Locale.ENGLISH); - - {// enable debug assistance, since tests are often run from IDE - Dispatcher.TRACE = true; - MetaClass.NO_CACHE=true; - // load resources from the source dir. - File dir = new File("src/main/resources"); - if(dir.exists() && MetaClassLoader.debugLoader==null) - try { - MetaClassLoader.debugLoader = new MetaClassLoader( - new URLClassLoader(new URL[]{dir.toURI().toURL()})); - } catch (MalformedURLException e) { - throw new AssertionError(e); - } - } - - // suppress INFO output from Spring, which is verbose - Logger.getLogger("org.springframework").setLevel(Level.WARNING); - - // hudson-behavior.js relies on this to decide whether it's running unit tests. - Main.isUnitTest = true; - - // prototype.js calls this method all the time, so ignore this warning. - XML_HTTP_REQUEST_LOGGER.setFilter(new Filter() { - public boolean isLoggable(LogRecord record) { - return !record.getMessage().contains("XMLHttpRequest.getResponseHeader() was called before the response was available."); - } - }); - - // remove the upper bound of the POST data size in Jetty. - System.setProperty("org.mortbay.jetty.Request.maxFormContentSize","-1"); - } - - private static final Logger LOGGER = Logger.getLogger(HudsonTestCase.class.getName()); - - protected static final List> NO_PROPERTIES = Collections.>emptyList(); - - /** - * Specify this to a TCP/IP port number to have slaves started with the debugger. - */ - public static int SLAVE_DEBUG_PORT = Integer.getInteger(HudsonTestCase.class.getName()+".slaveDebugPort",-1); - - public static final MimeTypes MIME_TYPES = new MimeTypes(); - static { - MIME_TYPES.addMimeMapping("js","application/javascript"); - Functions.DEBUG_YUI = true; - - // during the unit test, predictably releasing classloader is important to avoid - // file descriptor leak. - ClassicPluginStrategy.useAntClassLoader = true; - - // DNS multicast support takes up a lot of time during tests, so just disable it altogether - // this also prevents tests from falsely advertising Hudson - DNSMultiCast.disabled = true; - - if (!Functions.isWindows()) { - try { - PosixAPI.jnr().unsetenv("MAVEN_OPTS"); - PosixAPI.jnr().unsetenv("MAVEN_DEBUG_OPTS"); - } catch (Exception e) { - LOGGER.log(Level.WARNING,"Failed to cancel out MAVEN_OPTS",e); - } - } - } - - public static class TestBuildWrapper extends BuildWrapper { - public Result buildResultInTearDown; - - @Override - public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { - return new BuildWrapper.Environment() { - @Override - public boolean tearDown(AbstractBuild build, BuildListener listener) throws IOException, InterruptedException { - buildResultInTearDown = build.getResult(); - return true; - } - }; - } - - @Extension - public static class TestBuildWrapperDescriptor extends BuildWrapperDescriptor { - @Override - public boolean isApplicable(AbstractProject project) { - return true; - } - - @Override - public BuildWrapper newInstance(StaplerRequest req, JSONObject formData) { - throw new UnsupportedOperationException(); - } - - @Override // TODO 1.635+ delete - public String getDisplayName() { - return "TestBuildWrapper"; - } - } - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/JavaNetReverseProxy.java b/test-harness/src/main/java/org/jvnet/hudson/test/JavaNetReverseProxy.java deleted file mode 100644 index ccc3df518cdf17cff8d3b02fccdd669fef2850dc..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/JavaNetReverseProxy.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.jvnet.hudson.test; - -import hudson.Util; -import hudson.util.IOUtils; -import org.apache.commons.io.FileUtils; -import org.mortbay.jetty.Server; -import org.mortbay.jetty.bio.SocketConnector; -import org.mortbay.jetty.handler.ContextHandlerCollection; -import org.mortbay.jetty.servlet.Context; -import org.mortbay.jetty.servlet.ServletHolder; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.IOException; -import java.net.URL; - -/** - * Acts as a reverse proxy, so that during a test we can avoid hitting updates.jenkins-ci.org. - * - *

- * The contents are cached locally. - * - * @author Kohsuke Kawaguchi - */ -public class JavaNetReverseProxy extends HttpServlet { - private final Server server; - public final int localPort; - - private final File cacheFolder; - - public JavaNetReverseProxy(File cacheFolder) throws Exception { - this.cacheFolder = cacheFolder; - cacheFolder.mkdirs(); - - server = new Server(); - - ContextHandlerCollection contexts = new ContextHandlerCollection(); - server.setHandler(contexts); - - Context root = new Context(contexts, "/", Context.SESSIONS); - root.addServlet(new ServletHolder(this), "/"); - - SocketConnector connector = new SocketConnector(); - server.addConnector(connector); - server.start(); - - localPort = connector.getLocalPort(); - } - - public void stop() throws Exception { - server.stop(); - } - -// class Response { -// final URL url; -// final String contentType; -// final ByteArrayOutputStream data = new ByteArrayOutputStream(); -// -// Response(URL url) throws IOException { -// this.url = url; -// URLConnection con = url.openConnection(); -// contentType = con.getContentType(); -// IOUtils.copy(con.getInputStream(),data); -// } -// -// void reproduceTo(HttpServletResponse rsp) throws IOException { -// rsp.setContentType(contentType); -// data.writeTo(rsp.getOutputStream()); -// } -// } - - @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String path = req.getServletPath(); - String d = Util.getDigestOf(path); - - File cache = new File(cacheFolder, d); - if(!cache.exists()) { - URL url = new URL("http://updates.jenkins-ci.org/" + path); - FileUtils.copyURLToFile(url,cache); - } - - resp.setContentType(getMimeType(path)); - IOUtils.copy(cache,resp.getOutputStream()); - } - - private String getMimeType(String path) { - int idx = path.indexOf('?'); - if(idx>=0) - path = path.substring(0,idx); - if(path.endsWith(".json")) return "text/javascript"; - return getServletContext().getMimeType(path); - } - - private static volatile JavaNetReverseProxy INSTANCE; - - /** - * Gets the default instance. - */ - public static synchronized JavaNetReverseProxy getInstance() throws Exception { - if(INSTANCE==null) - // TODO: think of a better location --- ideally inside the target/ dir so that clean would wipe them out - INSTANCE = new JavaNetReverseProxy(new File(new File(System.getProperty("java.io.tmpdir")),"jenkins-ci.org-cache2")); - return INSTANCE; - } -} diff --git a/test-harness/src/main/java/org/jvnet/hudson/test/JellyTestSuiteBuilder.java b/test-harness/src/main/java/org/jvnet/hudson/test/JellyTestSuiteBuilder.java deleted file mode 100644 index 4e3ef493aef0f8fc60a88190bb817504dfc757da..0000000000000000000000000000000000000000 --- a/test-harness/src/main/java/org/jvnet/hudson/test/JellyTestSuiteBuilder.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, 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 org.jvnet.hudson.test; - -import junit.framework.TestCase; -import junit.framework.TestResult; -import junit.framework.TestSuite; -import org.apache.commons.io.FileUtils; -import org.dom4j.Document; -import org.dom4j.ProcessingInstruction; -import org.dom4j.io.SAXReader; -import org.jvnet.hudson.test.junit.GroupedTest; -import org.kohsuke.stapler.MetaClassLoader; -import org.kohsuke.stapler.jelly.JellyClassLoaderTearOff; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -/** - * Builds up a {@link TestSuite} for performing static syntax checks on Jelly scripts. - * - * @author Kohsuke Kawaguchi - */ -public class JellyTestSuiteBuilder { - - static Map scan(File resources, String extension) throws IOException { - Map result = new HashMap<>(); - if (resources.isDirectory()) { - for (File f : FileUtils.listFiles(resources, new String[] {extension}, true)) { - result.put(f.toURI().toURL(), f.getAbsolutePath().substring((resources.getAbsolutePath() + File.separator).length())); - } - } else if (resources.getName().endsWith(".jar")) { - String jarUrl = resources.toURI().toURL().toExternalForm(); - JarFile jf = new JarFile(resources); - Enumeration e = jf.entries(); - while (e.hasMoreElements()) { - JarEntry ent = e.nextElement(); - if (ent.getName().endsWith("." + extension)) { - result.put(new URL("jar:" + jarUrl + "!/" + ent.getName()), ent.getName()); - } - } - jf.close(); - } - return result; - } - - /** - * Given a jar file or a class file directory, recursively search all the Jelly files and build a {@link TestSuite} - * that performs static syntax checks. - */ - public static TestSuite build(File res, boolean requirePI) throws Exception { - TestSuite ts = new JellyTestSuite(); - final JellyClassLoaderTearOff jct = new MetaClassLoader(JellyTestSuiteBuilder.class.getClassLoader()).loadTearOff(JellyClassLoaderTearOff.class); - for (Map.Entry entry : scan(res, "jelly").entrySet()) { - ts.addTest(new JellyCheck(entry.getKey(), entry.getValue(), jct, requirePI)); - } - return ts; - } - - private static class JellyCheck extends TestCase { - private final URL jelly; - private final JellyClassLoaderTearOff jct; - private final boolean requirePI; - - JellyCheck(URL jelly, String name, JellyClassLoaderTearOff jct, boolean requirePI) { - super(name); - this.jelly = jelly; - this.jct = jct; - this.requirePI = requirePI; - } - - @Override - protected void runTest() throws Exception { - jct.createContext().compileScript(jelly); - Document dom = new SAXReader().read(jelly); - checkLabelFor(dom); - if (requirePI) { - ProcessingInstruction pi = dom.processingInstruction("jelly"); - if (pi==null || !pi.getText().contains("escape-by-default")) - throw new AssertionError(" is missing in "+jelly); - - } - // TODO: what else can we check statically? use of taglibs? - } - - /** - * Makes sure that <label for=...> is not used inside config.jelly nor global.jelly - */ - private void checkLabelFor(Document dom) { - if (isConfigJelly() || isGlobalJelly()) { - if (!dom.selectNodes("//label[@for]").isEmpty()) - throw new AssertionError("