├── .gitignore ├── Jenkinsfile ├── LICENSE ├── UPDATE-HTMLUNITDRIVER-README.md ├── UPDATE-SELENIUM-README.md ├── dist-server-standalone ├── local_m2 │ └── org │ │ └── seleniumhq │ │ └── selenium │ │ ├── htmlunit-driver-standalone │ │ ├── 2.33.3 │ │ │ ├── htmlunit-driver-standalone-2.33.3.jar │ │ │ └── htmlunit-driver-standalone-2.33.3.pom │ │ └── maven-metadata-local.xml │ │ └── selenium-server-standalone │ │ ├── 3.141.59 │ │ ├── selenium-server-standalone-3.141.59.jar │ │ └── selenium-server-standalone-3.141.59.pom │ │ └── maven-metadata-local.xml └── pom.xml ├── images └── selenium.svg ├── pom.xml ├── readme.md └── src ├── main ├── java │ └── hudson │ │ └── plugins │ │ └── selenium │ │ ├── .gitignore │ │ ├── ComputerListenerImpl.java │ │ ├── ConfigurationBuilder.java │ │ ├── HubHolder.java │ │ ├── HubLauncher.java │ │ ├── HubParams.java │ │ ├── HubParamsCallable.java │ │ ├── JenkinsCapabilityMatcher.java │ │ ├── PluginImpl.java │ │ ├── RemoteControlLauncher.java │ │ ├── RemoteRunningStatus.java │ │ ├── RestartListenerImpl.java │ │ ├── SeleniumHolder.java │ │ ├── SeleniumTestSlot.java │ │ ├── SeleniumTestSlotGroup.java │ │ ├── actions │ │ ├── SeleniumActions.java │ │ ├── SeleniumConfigurationAction.java │ │ └── ServiceManagementAction.java │ │ ├── callables │ │ ├── GetConfigurations.java │ │ ├── PropertyUtils.java │ │ ├── RemoteStopSelenium.java │ │ ├── RemoveSeleniumServer.java │ │ ├── RetrieveAvailablePort.java │ │ ├── RunningRemoteGetterCallable.java │ │ ├── RunningRemoteSetterCallable.java │ │ ├── SeleniumCallable.java │ │ ├── SeleniumConstants.java │ │ ├── StopSeleniumServer.java │ │ ├── hub │ │ │ └── StopHubCallable.java │ │ └── running │ │ │ └── RemoteGetConfigurations.java │ │ ├── configuration │ │ ├── ConfigurationDescriptor.java │ │ ├── CustomRCConfiguration.java │ │ ├── CustomWDConfiguration.java │ │ ├── DirectJsonInputConfiguration.java │ │ ├── FileConfiguration.java │ │ ├── SeleniumNodeConfiguration.java │ │ ├── browser │ │ │ ├── AbstractSeleniumBrowser.java │ │ │ ├── BrowserDescriptor.java │ │ │ ├── EdgeDriverServerUtils.java │ │ │ ├── IeDriverServerUtils.java │ │ │ ├── NodeUtils.java │ │ │ ├── selenium │ │ │ │ ├── ChromeBrowser.java │ │ │ │ ├── EdgeBrowser.java │ │ │ │ ├── FirefoxBrowser.java │ │ │ │ ├── IEBrowser.java │ │ │ │ ├── OperaBrowser.java │ │ │ │ └── SeleniumBrowser.java │ │ │ └── webdriver │ │ │ │ ├── ChromeBrowser.java │ │ │ │ ├── DriverRequiredWebDriverBrowser.java │ │ │ │ ├── EdgeBrowser.java │ │ │ │ ├── FirefoxBrowser.java │ │ │ │ ├── HTMLUnitBrowser.java │ │ │ │ ├── IEBrowser.java │ │ │ │ ├── OperaBrowser.java │ │ │ │ ├── SafariBrowser.java │ │ │ │ └── WebDriverBrowser.java │ │ └── global │ │ │ ├── SeleniumGlobalConfiguration.java │ │ │ ├── hostname │ │ │ ├── HostnameResolver.java │ │ │ ├── HostnameResolverDescriptor.java │ │ │ ├── JenkinsRootHostnameResolver.java │ │ │ └── StaticHostnameResolver.java │ │ │ └── matcher │ │ │ ├── MatchAllMatcher.java │ │ │ ├── MatchNoneMatcher.java │ │ │ ├── NodeLabelMatcher.java │ │ │ └── SeleniumConfigurationMatcher.java │ │ └── process │ │ ├── ProcessArgument.java │ │ ├── ProcessKeyListArgument.java │ │ ├── SeleniumJarRunner.java │ │ ├── SeleniumProcess.java │ │ ├── SeleniumProcessUtils.java │ │ └── SeleniumRunOptions.java ├── resources │ ├── IEDriverServer_32.exe │ ├── IEDriverServer_64.exe │ ├── MicrosoftWebDriver.exe │ └── hudson │ │ └── plugins │ │ └── selenium │ │ ├── Messages.properties │ │ ├── PluginImpl │ │ ├── _infotable.jelly │ │ ├── add.jelly │ │ ├── computers.jelly │ │ ├── conf_sidepanel.jelly │ │ ├── config.jelly │ │ ├── configurations.jelly │ │ ├── console.jelly │ │ ├── help-browserTimeout.html │ │ ├── help-exclusionPatterns.html │ │ ├── help-hubLogLevel.html │ │ ├── help-newSessionWaitTimeout.html │ │ ├── help-port.html │ │ ├── help-throwOnCapabilityNotPresent.html │ │ ├── help-timeout.html │ │ ├── index.jelly │ │ ├── index.properties │ │ └── sidepanel.jelly │ │ ├── actions │ │ ├── ServiceManagementAction │ │ │ ├── index.jelly │ │ │ └── sidepanel.jelly │ │ └── _infotable.jelly │ │ └── configuration │ │ ├── CustomRCConfiguration │ │ ├── config.jelly │ │ ├── config_summary.jelly │ │ ├── help-display.html │ │ ├── help-port.html │ │ ├── help-rcBrowserSessionReuse.html │ │ ├── help-rcBrowserSideLog.html │ │ ├── help-rcBrowserSideLog_ja.html │ │ ├── help-rcDebug.html │ │ ├── help-rcDebug_ja.html │ │ ├── help-rcFirefoxProfileTemplate.html │ │ ├── help-rcFirefoxProfileTemplate_ja.html │ │ ├── help-rcTrustAllSSLCerts.html │ │ ├── help-rcTrustAllSSLCerts_ja.html │ │ └── help_en.html │ │ ├── CustomWDConfiguration │ │ ├── config.jelly │ │ ├── config_summary.jelly │ │ ├── help-display.html │ │ ├── help-port.html │ │ └── help_en.html │ │ ├── DirectJsonInputConfiguration │ │ ├── config.jelly │ │ ├── config_summary.jelly │ │ ├── help-config.html │ │ ├── help-jvmArgs.html │ │ ├── help-seleniumArgs.html │ │ └── help_en.html │ │ ├── FileConfiguration │ │ ├── config.jelly │ │ ├── config_summary.jelly │ │ ├── help-configURL.html │ │ └── help_en.html │ │ ├── browser │ │ ├── AbstractSeleniumBrowser │ │ │ ├── config.jelly │ │ │ ├── help-maxInstances.html │ │ │ └── help-version.html │ │ ├── selenium │ │ │ ├── ChromeBrowser │ │ │ │ ├── config.jelly │ │ │ │ └── help-driverBinaryPath.html │ │ │ ├── EdgeBrowser │ │ │ │ ├── config.jelly │ │ │ │ └── help-driverBinaryPath.html │ │ │ ├── FirefoxBrowser │ │ │ │ ├── config.jelly │ │ │ │ └── help-binaryPath.html │ │ │ ├── IEBrowser │ │ │ │ ├── config.jelly │ │ │ │ ├── help-driverBinaryPath.html │ │ │ │ └── help-forbid64bitDriver.html │ │ │ └── OperaBrowser │ │ │ │ ├── config.jelly │ │ │ │ └── help-binaryPath.html │ │ └── webdriver │ │ │ ├── ChromeBrowser │ │ │ ├── config.jelly │ │ │ └── help-driverBinaryPath.html │ │ │ ├── EdgeBrowser │ │ │ ├── config.jelly │ │ │ └── help-driverBinaryPath.html │ │ │ ├── FirefoxBrowser │ │ │ ├── config.jelly │ │ │ └── help-binaryPath.html │ │ │ ├── HTMLUnitBrowser │ │ │ ├── config.jelly │ │ │ └── help-maxInstances.html │ │ │ ├── IEBrowser │ │ │ ├── config.jelly │ │ │ ├── help-driverBinaryPath.html │ │ │ └── help-forbid64bitDriver.html │ │ │ ├── OperaBrowser │ │ │ ├── config.jelly │ │ │ └── help-binaryPath.html │ │ │ └── SafariBrowser │ │ │ └── config.jelly │ │ └── global │ │ ├── SeleniumGlobalConfiguration │ │ ├── delete.jelly │ │ ├── delete.properties │ │ ├── index.jelly │ │ └── sidepanel.jelly │ │ ├── hostname │ │ ├── JenkinsRootHostnameResolver │ │ │ ├── config.jelly │ │ │ └── help_en.html │ │ └── StaticHostnameResolver │ │ │ ├── config.jelly │ │ │ └── help_en.html │ │ └── matcher │ │ ├── MatchAllMatcher │ │ ├── config.jelly │ │ └── help_en.html │ │ ├── MatchNoneMatcher │ │ ├── config.jelly │ │ └── help_en.html │ │ └── NodeLabelMatcher │ │ ├── config.jelly │ │ └── help_en.html └── webapp │ ├── 16x16 │ ├── MicrosoftEdge.png │ ├── chrome.png │ ├── firefox.png │ ├── internet explorer.png │ ├── opera.png │ └── safari.png │ ├── 24x24 │ ├── internet-web-browser.png │ └── selenium.png │ ├── 48x48 │ └── selenium.png │ ├── css │ ├── images │ │ ├── animated-overlay.gif │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png │ │ ├── ui-icons_222222_256x240.png │ │ ├── ui-icons_2e83ff_256x240.png │ │ ├── ui-icons_454545_256x240.png │ │ ├── ui-icons_888888_256x240.png │ │ └── ui-icons_cd0a0a_256x240.png │ ├── jquery-ui-1.10.4.custom.css │ └── selenium.css │ └── js │ ├── jquery-1.10.2.js │ └── jquery-ui-1.10.4.custom.js └── test └── java └── hudson └── plugins └── selenium └── SeleniumTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | work 3 | .classpath 4 | .project 5 | .settings 6 | *.iml 7 | *.ipr 8 | *.iws 9 | .idea 10 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | buildPlugin() -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2008-, Kohsuke Kawaguchi, Richard Lavoie and a number of other of contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /UPDATE-HTMLUNITDRIVER-README.md: -------------------------------------------------------------------------------- 1 | Updating htmlunit driver standalone is done in these steps: 2 | 3 | 1. Bump htmlunit driver version number in dist-server-standalone/pom.xml 4 | 2. Remove folder dist-server-standalone/local_m2 5 | 3. Run mvn install in dist-server-standalone/ 6 | 4. Bump htmlunit-driver-standalone version number in pom.xml 7 | 6. Check in changes, and don't forget to also check in the updated htmlunit-driver-standalone jar in local_m2 8 | -------------------------------------------------------------------------------- /UPDATE-SELENIUM-README.md: -------------------------------------------------------------------------------- 1 | Updating selenium standalone server is done in these steps: 2 | 3 | 1. Bump selenium server standalone version number in dist-server-standalone/pom.xml 4 | 2. Remove folder dist-server-standalone/local_m2 5 | 3. Run mvn install in dist-server-standalone/ 6 | 4. Bump selenium standalone server version number in pom.xml 7 | 5. Check all selenium dependencies (selenium team is working to move third-party dependencies out of the selenium package) 8 | 6. Check in changes, and don't forget to also check in the updated selenium-server-standalone jar in local_m2 9 | -------------------------------------------------------------------------------- /dist-server-standalone/local_m2/org/seleniumhq/selenium/htmlunit-driver-standalone/2.33.3/htmlunit-driver-standalone-2.33.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/dist-server-standalone/local_m2/org/seleniumhq/selenium/htmlunit-driver-standalone/2.33.3/htmlunit-driver-standalone-2.33.3.jar -------------------------------------------------------------------------------- /dist-server-standalone/local_m2/org/seleniumhq/selenium/htmlunit-driver-standalone/2.33.3/htmlunit-driver-standalone-2.33.3.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | org.seleniumhq.selenium 6 | htmlunit-driver-standalone 7 | 2.33.3 8 | POM was created from install:install-file 9 | 10 | -------------------------------------------------------------------------------- /dist-server-standalone/local_m2/org/seleniumhq/selenium/htmlunit-driver-standalone/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.seleniumhq.selenium 4 | htmlunit-driver-standalone 5 | 6 | 2.33.3 7 | 8 | 2.33.3 9 | 10 | 20181213181504 11 | 12 | 13 | -------------------------------------------------------------------------------- /dist-server-standalone/local_m2/org/seleniumhq/selenium/selenium-server-standalone/3.141.59/selenium-server-standalone-3.141.59.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/dist-server-standalone/local_m2/org/seleniumhq/selenium/selenium-server-standalone/3.141.59/selenium-server-standalone-3.141.59.jar -------------------------------------------------------------------------------- /dist-server-standalone/local_m2/org/seleniumhq/selenium/selenium-server-standalone/3.141.59/selenium-server-standalone-3.141.59.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | org.seleniumhq.selenium 6 | selenium-server-standalone 7 | 3.141.59 8 | POM was created from install:install-file 9 | 10 | -------------------------------------------------------------------------------- /dist-server-standalone/local_m2/org/seleniumhq/selenium/selenium-server-standalone/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.seleniumhq.selenium 4 | selenium-server-standalone 5 | 6 | 3.141.59 7 | 8 | 3.141.59 9 | 10 | 20181213181504 11 | 12 | 13 | -------------------------------------------------------------------------------- /dist-server-standalone/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | fake 7 | fake 8 | pom 9 | ${selenium.version} 10 | 11 | fake 12 | 13 | 14 | 3.141 15 | 3.141.59 16 | 2.33.3 17 | UTF-8 18 | 19 | 20 | 21 | 22 | 23 | org.apache.maven.plugins 24 | maven-antrun-plugin 25 | 1.7 26 | 27 | 28 | install 29 | 30 | run 31 | 32 | 33 | 34 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-install-plugin 52 | 2.5.1 53 | 54 | 55 | selenium-server-standalone 56 | install 57 | 58 | install-file 59 | 60 | 61 | ${project.build.directory}/selenium-server-standalone-${selenium.version}.jar 62 | org.seleniumhq.selenium 63 | selenium-server-standalone 64 | ${selenium.version} 65 | jar 66 | 67 | local_m2 68 | 69 | 70 | 71 | htmlunit-driver-standalone 72 | install 73 | 74 | install-file 75 | 76 | 77 | ${project.build.directory}/htmlunit-driver-standalone-${htmlunit.driver.version}.jar 78 | org.seleniumhq.selenium 79 | htmlunit-driver-standalone 80 | ${htmlunit.driver.version} 81 | jar 82 | 83 | local_m2 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |

:warning: Plugin requires Java8 :warning:

2 | 3 | `Guide for updating selenium version is found in update-selenium-readme.md` 4 |
`Guide for updating htmlunit driver version is found in update-htmlunitdriver-readme.md` 5 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/.gitignore: -------------------------------------------------------------------------------- 1 | /PluginImpl.java 2 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/ComputerListenerImpl.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import hudson.Extension; 4 | import hudson.model.TaskListener; 5 | import hudson.model.Computer; 6 | import hudson.plugins.selenium.actions.ServiceManagementAction; 7 | import hudson.slaves.ComputerListener; 8 | import hudson.slaves.OfflineCause; 9 | 10 | import javax.annotation.Nonnull; 11 | import java.io.IOException; 12 | import java.io.Serializable; 13 | 14 | /** 15 | * When a new slave is connected, launch a selenium RC. 16 | * 17 | * @author Kohsuke Kawaguchi 18 | * @author Richard Lavoie 19 | */ 20 | @Extension 21 | public class ComputerListenerImpl extends ComputerListener implements Serializable { 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | /** 26 | * Starts a selenium Grid node remotely. 27 | */ 28 | @Override 29 | public void onOnline(Computer c, final TaskListener listener) throws IOException, InterruptedException { 30 | PluginImpl.startSeleniumNode(c, listener, null); 31 | } 32 | 33 | @Override 34 | public void onOffline(@Nonnull Computer c, OfflineCause cause) { 35 | try { 36 | new ServiceManagementAction(c).doStop(null); 37 | } catch (Throwable e) { 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/ConfigurationBuilder.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import com.beust.jcommander.JCommander; 4 | import hudson.remoting.Channel; 5 | import org.openqa.grid.internal.cli.GridHubCliOptions; 6 | import org.openqa.grid.internal.cli.GridNodeCliOptions; 7 | import org.openqa.grid.internal.utils.configuration.GridHubConfiguration; 8 | import org.openqa.grid.internal.utils.configuration.GridNodeConfiguration; 9 | import org.openqa.grid.selenium.GridLauncherV3; 10 | 11 | /** 12 | * Converts String[] args to Selenium Grid configuration objects using {@link JCommander} 13 | */ 14 | public class ConfigurationBuilder { 15 | 16 | public static GridNodeConfiguration buildNodeConfig(String[] args) { 17 | GridNodeCliOptions nodeOptions = new GridNodeCliOptions(); 18 | JCommander.newBuilder().addObject(nodeOptions).build().parse(args); 19 | return new GridNodeConfiguration(nodeOptions); 20 | } 21 | 22 | public static GridHubConfiguration buildHubConfig(String[] args, Integer port) { 23 | GridHubCliOptions cliOptions = new GridHubCliOptions(); 24 | JCommander.newBuilder().addObject(cliOptions).build().parse(args); 25 | GridHubConfiguration config = new GridHubConfiguration(cliOptions); 26 | config.port = port; 27 | config.capabilityMatcher = new JenkinsCapabilityMatcher(Channel.current(), config.capabilityMatcher); 28 | return config; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/HubHolder.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import org.openqa.grid.web.Hub; 4 | 5 | /** 6 | * Used inside Hub JVM to hold the reference to the running {@link Hub} 7 | * 8 | * @author Richard Lavoie 9 | */ 10 | public class HubHolder { 11 | 12 | private static Hub hub; 13 | 14 | private HubHolder() {} 15 | 16 | public static Hub getHub() { 17 | return hub; 18 | } 19 | 20 | public static void setHub(Hub hub) { 21 | HubHolder.hub = hub; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/HubLauncher.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import jenkins.security.MasterToSlaveCallable; 4 | import org.jfree.util.Log; 5 | import org.openqa.grid.internal.utils.configuration.GridHubConfiguration; 6 | import org.openqa.grid.web.Hub; 7 | 8 | import java.util.logging.Level; 9 | import java.util.logging.Logger; 10 | 11 | /** 12 | * Starts the selenium grid server. 13 | * 14 | * This callable blocks until the server is shut down and thus generally never returns. 15 | * 16 | * @author Kohsuke Kawaguchi 17 | */ 18 | public class HubLauncher extends MasterToSlaveCallable { 19 | 20 | /** 21 | * 22 | */ 23 | private static final long serialVersionUID = 5658971914841423874L; 24 | 25 | private final int port; 26 | private final String[] args; 27 | private final Level logLevel; 28 | 29 | public HubLauncher(int port, String[] args, Level logLevel) { 30 | this.port = port; 31 | this.args = args; 32 | this.logLevel = logLevel; 33 | } 34 | 35 | public Void call() { 36 | try { 37 | Logger log = Logger.getLogger(HubLauncher.class.getName()); 38 | log.log(Level.OFF, "Grid hub starting with log level " + logLevel.getName()); 39 | log.log(Level.OFF, "Grid Hub preparing to start on port " + port); 40 | 41 | GridHubConfiguration c = ConfigurationBuilder.buildHubConfig(args, port); 42 | Hub hub = new Hub(c); 43 | hub.start(); 44 | HubHolder.setHub(hub); 45 | 46 | StringBuilder arguments = new StringBuilder(); 47 | for (String arg : args) { 48 | arguments.append(" ").append(arg); 49 | } 50 | log.log(Level.OFF, "Grid Hub started on port " + port + " with args:" + arguments.toString()); 51 | configureLoggers(); 52 | } catch (Exception e) { 53 | Log.error("An error occurred while starting the hub", e); 54 | } 55 | 56 | return null; 57 | } 58 | 59 | private void configureLoggers() { 60 | Logger.getLogger("org.openqa").setLevel(logLevel); 61 | Logger.getLogger("org.seleniumhq").setLevel(logLevel); 62 | Logger.getLogger("com.thoughtworks.selenium").setLevel(logLevel); 63 | Logger.getLogger("org.apache.commons.httpclient").setLevel(logLevel); 64 | Logger.getLogger("hudson.plugins.selenium").setLevel(logLevel); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/HubParams.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import java.io.Serializable; 4 | import java.net.URL; 5 | 6 | public class HubParams implements Serializable { 7 | private static final long serialVersionUID = 3813168118997469056L; 8 | 9 | private String host =""; 10 | private Integer port = -1; 11 | private boolean isActive = false; 12 | 13 | public HubParams() { 14 | this("", -1, false); 15 | } 16 | 17 | public HubParams(URL host, boolean isActive) { 18 | this.host = host.getHost(); 19 | this.port = host.getPort(); 20 | this.isActive = isActive; 21 | } 22 | 23 | public HubParams(String host, Integer port, boolean isActive) { 24 | this.host = host; 25 | this.port = port; 26 | this.isActive = isActive; 27 | } 28 | 29 | public boolean isActive() { 30 | return isActive; 31 | } 32 | 33 | public boolean isNotActiveOn(String masterHostName, int masterPort) { 34 | return isActive && !(port == masterPort && host.equalsIgnoreCase(masterHostName)); 35 | } 36 | 37 | public String getHost() { 38 | return host; 39 | } 40 | 41 | public Integer getPort() { 42 | return port; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/HubParamsCallable.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import jenkins.security.MasterToSlaveCallable; 4 | 5 | class HubParamsCallable extends MasterToSlaveCallable { 6 | 7 | /** 8 | * 9 | */ 10 | private static final long serialVersionUID = -4136171068376050199L; 11 | 12 | public HubParams call() throws Throwable { 13 | if (HubHolder.getHub() == null) { 14 | return new HubParams(); 15 | } 16 | return new HubParams(HubHolder.getHub().getUrl(), true); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/JenkinsCapabilityMatcher.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import antlr.ANTLRException; 4 | import hudson.model.Label; 5 | import hudson.model.Node; 6 | import hudson.remoting.Channel; 7 | import jenkins.model.Jenkins; 8 | import jenkins.security.MasterToSlaveCallable; 9 | import org.apache.commons.lang.StringUtils; 10 | import org.openqa.grid.internal.utils.CapabilityMatcher; 11 | import org.openqa.selenium.MutableCapabilities; 12 | 13 | import java.io.IOException; 14 | import java.util.Map; 15 | import java.util.logging.Level; 16 | import java.util.logging.Logger; 17 | 18 | /** 19 | * {@link CapabilityMatcher} that adds "jenkins:label" support. 20 | * 21 | * @author Kohsuke Kawaguchi 22 | */ 23 | public class JenkinsCapabilityMatcher implements CapabilityMatcher { 24 | 25 | private static final Logger LOGGER = Logger.getLogger(JenkinsCapabilityMatcher.class.getName()); 26 | /** 27 | * Can be used as a capability when WebDriver requests a node from Grid. The value is a boolean expression over labels to select the desired node 28 | * to run the test. 29 | */ 30 | public static final String LABEL = "jenkins:label"; 31 | 32 | /** 33 | * RC uses this to register, to designate its origin. 34 | */ 35 | public static final String NODE_NAME = "jenkins:nodeName"; 36 | 37 | /** 38 | * Node name of the master computer 39 | */ 40 | public static final String MASTER_NAME = "(master)"; 41 | 42 | private final CapabilityMatcher base; 43 | 44 | private final Channel master; 45 | 46 | public JenkinsCapabilityMatcher(Channel master, CapabilityMatcher base) { 47 | this.master = master; 48 | this.base = base; 49 | } 50 | 51 | public boolean matches(Map currentCapability, Map requestedCapability) { 52 | LOGGER.log(Level.INFO, "CURRENT : " + currentCapability.toString()); 53 | LOGGER.log(Level.INFO, "REQUEST : " + requestedCapability.toString()); 54 | 55 | if (!base.matches(currentCapability, requestedCapability)) { 56 | return false; 57 | } 58 | 59 | Object label = requestedCapability.get(LABEL); 60 | Object reqNode = requestedCapability.get(NODE_NAME); 61 | String nodeName = (String) currentCapability.get(NODE_NAME); 62 | 63 | if (label == null && reqNode == null) { 64 | return true; 65 | } 66 | 67 | LOGGER.log(Level.INFO, "NODE : " + reqNode + " - " + nodeName); 68 | 69 | boolean nodeMatch; 70 | 71 | if (reqNode != null && nodeName != null) { 72 | LOGGER.log(Level.INFO, "BOTH NOT NULL"); 73 | nodeMatch = nodeName.equals(reqNode); 74 | } else nodeMatch = reqNode == null; 75 | 76 | if (label == null) { 77 | return nodeMatch; 78 | } 79 | 80 | String labelExpr = label.toString(); 81 | if (labelExpr.trim().length() == 0) { 82 | LOGGER.log(Level.INFO, "returning node match"); 83 | return nodeMatch; // treat "" as null 84 | } 85 | 86 | try { 87 | return nodeMatch && master.call(new LabelMatcherCallable(nodeName, labelExpr)); 88 | } catch (IOException e) { 89 | LOGGER.log(Level.INFO, "Failed to communicate with master for capability matching", e); 90 | } catch (ANTLRException e) { 91 | LOGGER.log(Level.INFO, "Invalid label expression: " + label, e); 92 | } catch (InterruptedException e) { 93 | LOGGER.log(Level.INFO, "Failed to communicate with master for capability matching", e); 94 | } 95 | return false; 96 | } 97 | 98 | private static class LabelMatcherCallable extends MasterToSlaveCallable { 99 | 100 | private static final long serialVersionUID = 1L; 101 | 102 | /** 103 | * Checks if the given node satisfies the label expression. 104 | */ 105 | private final String nodeName; 106 | 107 | private final String labelExpr; 108 | 109 | public LabelMatcherCallable(String nodeName, String labelExpr) { 110 | this.nodeName = nodeName.equals(MASTER_NAME) ? "" : nodeName; 111 | this.labelExpr = labelExpr; 112 | } 113 | public Boolean call() throws ANTLRException { 114 | Node n = Jenkins.getInstance().getNode(nodeName); 115 | if (n == null) 116 | return false; 117 | return Label.parseExpression(labelExpr).matches(n); 118 | } 119 | 120 | } 121 | 122 | public static void enhanceCapabilities(MutableCapabilities capabilities, String node) { 123 | String nodeName = StringUtils.isEmpty(node) ? JenkinsCapabilityMatcher.MASTER_NAME : node; 124 | capabilities.setCapability(JenkinsCapabilityMatcher.NODE_NAME, nodeName); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/RemoteControlLauncher.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import hudson.plugins.selenium.callables.PropertyUtils; 4 | import hudson.plugins.selenium.callables.SeleniumConstants; 5 | import hudson.remoting.Channel; 6 | import jenkins.security.MasterToSlaveCallable; 7 | import org.openqa.grid.common.RegistrationRequest; 8 | import org.openqa.grid.internal.utils.SelfRegisteringRemote; 9 | import org.openqa.selenium.MutableCapabilities; 10 | import org.openqa.selenium.remote.server.SeleniumServer; 11 | 12 | import java.util.logging.Level; 13 | import java.util.logging.Logger; 14 | 15 | /** 16 | * Launches Selenium RC. 17 | * 18 | *

19 | * This callable is run on the JVM dedicated to selenium RC. 20 | * 21 | * @author Kohsuke Kawaguchi 22 | * @author Richard Lavoie 23 | */ 24 | public class RemoteControlLauncher extends MasterToSlaveCallable { 25 | 26 | private static final Logger LOGGER = Logger.getLogger(RemoteControlLauncher.class.getName()); 27 | 28 | /** 29 | * 30 | */ 31 | private static final long serialVersionUID = -6502768962889139192L; 32 | 33 | private final String[] args; 34 | private final String nodeName; 35 | 36 | public RemoteControlLauncher(String nodeName, String[] args) { 37 | this.nodeName = nodeName; 38 | this.args = args; 39 | } 40 | 41 | // because this method is called asynchronously and no one waits for the completion, 42 | // exception needs to be reported explicitly. 43 | public Void call() throws Exception { 44 | try { 45 | RegistrationRequest c = new RegistrationRequest(ConfigurationBuilder.buildNodeConfig(args), nodeName); 46 | 47 | for (MutableCapabilities dc : c.getConfiguration().capabilities) { 48 | JenkinsCapabilityMatcher.enhanceCapabilities(dc, nodeName); 49 | } 50 | SelfRegisteringRemote remote = new SelfRegisteringRemote(c); 51 | remote.setRemoteServer(new SeleniumServer(c.getConfiguration())); 52 | PropertyUtils.setProperty(SeleniumConstants.PROPERTY_INSTANCE, remote); 53 | remote.startRemoteServer(); 54 | remote.startRegistrationProcess(); 55 | 56 | Channel.current().waitForProperty(SeleniumConstants.PROPERTY_LOCK); 57 | return null; 58 | } catch (Exception e) { 59 | LOGGER.log(Level.SEVERE, e.getMessage(), e); 60 | throw e; 61 | } catch (Error e) { 62 | LOGGER.log(Level.SEVERE, e.getMessage(), e); 63 | throw e; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/RemoteRunningStatus.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import hudson.plugins.selenium.callables.SeleniumConstants; 4 | import hudson.plugins.selenium.process.SeleniumRunOptions; 5 | import hudson.remoting.Channel; 6 | 7 | import java.io.Serializable; 8 | import java.util.concurrent.atomic.AtomicBoolean; 9 | 10 | public class RemoteRunningStatus implements Serializable { 11 | 12 | /** 13 | * 14 | */ 15 | private static final long serialVersionUID = -5791953423035014104L; 16 | 17 | private AtomicBoolean running = new AtomicBoolean(false); 18 | 19 | transient private Channel jvmChannel; 20 | 21 | private SeleniumRunOptions options; 22 | 23 | private String currentStatus; 24 | 25 | public RemoteRunningStatus(Channel channel, SeleniumRunOptions options) { 26 | jvmChannel = channel; 27 | this.options = options; 28 | currentStatus = SeleniumConstants.STARTING; 29 | } 30 | 31 | public boolean isRunning() { 32 | return running.get(); 33 | } 34 | 35 | public void setRunning(boolean val) { 36 | running.set(val); 37 | } 38 | 39 | public void start() { 40 | running.set(true); 41 | } 42 | 43 | public SeleniumRunOptions getOptions() { 44 | return options; 45 | } 46 | 47 | public Channel getSeleniumChannel() { 48 | return jvmChannel; 49 | } 50 | 51 | public void setStatus(String status) { 52 | currentStatus = status; 53 | } 54 | 55 | public String getStatus() { 56 | return currentStatus; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/RestartListenerImpl.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Computer; 5 | import hudson.model.RestartListener; 6 | import hudson.plugins.selenium.actions.ServiceManagementAction; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * Created by mobrockers on 24-4-2016. 12 | */ 13 | @Extension 14 | public class RestartListenerImpl extends RestartListener { 15 | 16 | @Override 17 | public boolean isReadyToRestart() throws IOException, InterruptedException { 18 | 19 | for (Computer c : PluginImpl.getPlugin().getComputers().keySet()) { 20 | try { 21 | new ServiceManagementAction(c).doStop(null); 22 | } catch (Throwable e) { 23 | } 24 | } 25 | 26 | return true; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/SeleniumHolder.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import org.openqa.grid.internal.utils.SelfRegisteringRemote; 4 | 5 | public final class SeleniumHolder { 6 | 7 | public static SelfRegisteringRemote seleniumInstance; 8 | 9 | private SeleniumHolder() {} 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/SeleniumTestSlot.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium; 2 | 3 | import org.apache.commons.lang3.builder.EqualsBuilder; 4 | import org.apache.commons.lang3.builder.HashCodeBuilder; 5 | import org.kohsuke.stapler.export.Exported; 6 | import org.kohsuke.stapler.export.ExportedBean; 7 | import org.openqa.grid.internal.RemoteProxy; 8 | import org.openqa.grid.internal.TestSlot; 9 | 10 | import java.io.Serializable; 11 | import java.net.URL; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.Map.Entry; 15 | 16 | /** 17 | * Selenium Remote Control instance. 18 | * 19 | *

20 | * This class is used to expose RC data to the remoting API, as well as using this from index.jelly rendering of {@link PluginImpl}. 21 | * 22 | * @author Kohsuke Kawaguchi 23 | */ 24 | @ExportedBean 25 | public class SeleniumTestSlot implements Comparable, Serializable { 26 | 27 | private static final long serialVersionUID = 1L; 28 | 29 | private static final Map ENV_MAPPING = new HashMap(); 30 | /** 31 | * is anything running? 32 | */ 33 | private final boolean isReserved; 34 | private final URL host; 35 | private final Map capabilities; 36 | 37 | public SeleniumTestSlot(TestSlot testSlot) { 38 | RemoteProxy proxy = testSlot.getProxy(); 39 | host = proxy.getRemoteHost(); 40 | capabilities = toCapabilities(testSlot); 41 | isReserved = testSlot.getSession() != null; 42 | } 43 | 44 | private Map toCapabilities(TestSlot testSlot) { 45 | Map r = new HashMap(); 46 | for (Entry e : testSlot.getCapabilities().entrySet()) { 47 | r.put(e.getKey(), e.getValue().toString()); 48 | } 49 | return r; 50 | } 51 | 52 | @Exported 53 | public String getHost() { 54 | return host.getHost(); 55 | } 56 | 57 | @Exported 58 | public int getPort() { 59 | return host.getPort(); 60 | } 61 | 62 | @Exported 63 | public Map getCapabilities() { 64 | return capabilities; 65 | } 66 | 67 | @Exported 68 | public boolean isReserved() { 69 | return isReserved; 70 | } 71 | 72 | public String getStatus() { 73 | if (isReserved) 74 | return "In use"; 75 | else 76 | return "Idle"; 77 | } 78 | 79 | static { 80 | ENV_MAPPING.put("*iexplore", "internet explorer"); 81 | ENV_MAPPING.put("*firefox", "firefox"); 82 | ENV_MAPPING.put("*googlechrome", "chrome"); 83 | ENV_MAPPING.put("*opera", "opera"); 84 | ENV_MAPPING.put("*MicrosoftEdge", "Microsoft Edge"); 85 | } 86 | 87 | public String getBrowserName() { 88 | return getCapabilities().get("browserName"); 89 | } 90 | 91 | public String getUnifiedBrowserName() { 92 | String browser = getCapabilities().get("browserName"); 93 | String unified = ENV_MAPPING.get(browser); 94 | return unified != null ? unified : browser; 95 | } 96 | 97 | public int compareTo(SeleniumTestSlot that) { 98 | int r = this.getHost().compareTo(that.getHost()); 99 | if (r != 0) 100 | return r; 101 | return this.getPort() - that.getPort(); 102 | } 103 | 104 | @Override 105 | public boolean equals(Object o) { 106 | if (this == o) return true; 107 | 108 | if (o == null || getClass() != o.getClass()) return false; 109 | 110 | SeleniumTestSlot that = (SeleniumTestSlot) o; 111 | 112 | return new EqualsBuilder() 113 | .append(isReserved, that.isReserved) 114 | .append(host, that.host) 115 | .append(capabilities, that.capabilities) 116 | .isEquals(); 117 | } 118 | 119 | @Override 120 | public int hashCode() { 121 | return new HashCodeBuilder(17, 37) 122 | .append(isReserved) 123 | .append(host) 124 | .append(capabilities) 125 | .toHashCode(); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/SeleniumTestSlotGroup.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium; 5 | 6 | import java.io.Serializable; 7 | import java.net.URL; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.TreeMap; 12 | 13 | import org.apache.commons.lang3.builder.EqualsBuilder; 14 | import org.apache.commons.lang3.builder.HashCodeBuilder; 15 | import org.kohsuke.stapler.export.Exported; 16 | import org.kohsuke.stapler.export.ExportedBean; 17 | 18 | /** 19 | * @author Richard Lavoie 20 | * 21 | */ 22 | @ExportedBean 23 | public class SeleniumTestSlotGroup implements Comparable, Serializable { 24 | 25 | /** 26 | * 27 | */ 28 | private static final long serialVersionUID = 8967484262051147802L; 29 | 30 | private URL host; 31 | 32 | private List slots = new ArrayList(); 33 | 34 | public SeleniumTestSlotGroup(URL host) { 35 | this.host = host; 36 | } 37 | 38 | public List getSlots() { 39 | return slots; 40 | } 41 | 42 | public void addTestSlot(SeleniumTestSlot slot) { 43 | this.slots.add(slot); 44 | } 45 | 46 | public String getHostAndPort() { 47 | return host.toExternalForm(); 48 | } 49 | 50 | @Exported 51 | public String getHost() { 52 | return host.getHost(); 53 | } 54 | 55 | @Exported 56 | public int getPort() { 57 | return host.getPort(); 58 | } 59 | 60 | private static class BusyCounter { 61 | 62 | int free = 0; 63 | int count = 0; 64 | } 65 | 66 | public String getSummary() { 67 | Map counters = new TreeMap(); 68 | 69 | for (SeleniumTestSlot slot : slots) { 70 | String browser = slot.getBrowserName(); 71 | BusyCounter c = counters.get(browser); 72 | if (c == null) { 73 | c = new BusyCounter(); 74 | counters.put(browser, c); 75 | } 76 | c.count++; 77 | if (!slot.isReserved()) { 78 | c.free++; 79 | } 80 | } 81 | 82 | StringBuilder sb = new StringBuilder(); 83 | for (Map.Entry entry : counters.entrySet()) { 84 | BusyCounter counter = entry.getValue(); 85 | sb.append(entry.getKey()).append(" ").append(counter.free).append("/").append(counter.count).append(", "); 86 | } 87 | 88 | return sb.substring(0, sb.length() - 2); 89 | } 90 | 91 | public int compareTo(SeleniumTestSlotGroup that) { 92 | int r = this.getHost().compareTo(that.getHost()); 93 | if (r != 0) 94 | return r; 95 | return this.getPort() - that.getPort(); 96 | } 97 | 98 | @Override 99 | public boolean equals(Object o) { 100 | if (this == o) return true; 101 | 102 | if (o == null || getClass() != o.getClass()) return false; 103 | 104 | SeleniumTestSlotGroup that = (SeleniumTestSlotGroup) o; 105 | 106 | return new EqualsBuilder() 107 | .append(host, that.host) 108 | .append(slots, that.slots) 109 | .isEquals(); 110 | } 111 | 112 | @Override 113 | public int hashCode() { 114 | return new HashCodeBuilder(17, 37) 115 | .append(host) 116 | .append(slots) 117 | .toHashCode(); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/actions/SeleniumActions.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.actions; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Action; 5 | import hudson.model.TransientComputerActionFactory; 6 | import hudson.model.Computer; 7 | import hudson.plugins.selenium.PluginImpl; 8 | 9 | import java.util.Collection; 10 | import java.util.Collections; 11 | 12 | @Extension 13 | public class SeleniumActions extends TransientComputerActionFactory { 14 | 15 | @Override 16 | public Collection createFor(Computer target) { 17 | 18 | // If user has admin privileges, let the user access selenium node configurations through the node 19 | if (PluginImpl.getPlugin().isAdmin()) { 20 | 21 | return Collections.singletonList(new ServiceManagementAction(target)); 22 | } else { 23 | 24 | return Collections.EMPTY_LIST; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/actions/SeleniumConfigurationAction.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.actions; 2 | 3 | import hudson.Extension; 4 | import hudson.model.ManagementLink; 5 | 6 | @Extension 7 | public class SeleniumConfigurationAction extends ManagementLink { 8 | 9 | public String getIconFileName() { 10 | return "/plugin/selenium/24x24/selenium.png"; 11 | } 12 | 13 | public String getDisplayName() { 14 | return "Selenium configurations"; 15 | } 16 | 17 | public String getUrlName() { 18 | return "selenium/configurations"; 19 | } 20 | 21 | public String getDescription() { 22 | return "Selenium node configurations"; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/actions/ServiceManagementAction.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.actions; 2 | 3 | import hudson.model.Action; 4 | import hudson.model.Computer; 5 | import hudson.plugins.selenium.PluginImpl; 6 | import hudson.plugins.selenium.callables.GetConfigurations; 7 | import hudson.plugins.selenium.configuration.global.SeleniumGlobalConfiguration; 8 | import hudson.plugins.selenium.process.SeleniumRunOptions; 9 | import hudson.util.StreamTaskListener; 10 | import org.kohsuke.stapler.HttpResponse; 11 | import org.kohsuke.stapler.HttpResponses; 12 | import org.kohsuke.stapler.QueryParameter; 13 | 14 | import javax.servlet.ServletException; 15 | import java.io.IOException; 16 | import java.io.OutputStreamWriter; 17 | import java.util.Collections; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | 23 | public class ServiceManagementAction implements Action { 24 | 25 | private static final Logger LOGGER = Logger.getLogger(ServiceManagementAction.class.getName()); 26 | 27 | private Computer computer; 28 | 29 | public ServiceManagementAction(Computer c) { 30 | computer = c; 31 | } 32 | 33 | public String getIconFileName() { 34 | return "/plugin/selenium/24x24/selenium.png"; 35 | } 36 | 37 | public String getDisplayName() { 38 | return "Selenium node Management"; 39 | } 40 | 41 | public String getUrlName() { 42 | return "selenium"; 43 | } 44 | 45 | public HttpResponse doRestart(@QueryParameter String conf) throws IOException, ServletException { 46 | PluginImpl.getPlugin().validateAdmin(); 47 | doStop(conf); 48 | doStart(conf); 49 | return HttpResponses.forwardToPreviousPage(); 50 | } 51 | 52 | public HttpResponse doStop(@QueryParameter String conf) { 53 | PluginImpl.getPlugin().validateAdmin(); 54 | PluginImpl.getPlugin().getConfiguration(conf).stop(computer); 55 | return HttpResponses.forwardToPreviousPage(); 56 | } 57 | 58 | public HttpResponse doStart(@QueryParameter String conf) { 59 | PluginImpl.getPlugin().validateAdmin(); 60 | try { 61 | PluginImpl.startSeleniumNode(computer, new StreamTaskListener(new OutputStreamWriter(System.out)), conf); 62 | } catch (Exception e) { 63 | LOGGER.log(Level.SEVERE, e.getMessage(), e); 64 | } 65 | return HttpResponses.forwardToPreviousPage(); 66 | } 67 | 68 | public Computer getComputer() { 69 | return computer; 70 | } 71 | 72 | public Map getConfigurations() { 73 | PluginImpl.getPlugin().validateAdmin(); 74 | try { 75 | return computer.getNode().getRootPath().getChannel().call(new GetConfigurations()); 76 | } catch (Exception e) { 77 | return Collections.emptyMap(); 78 | } 79 | } 80 | 81 | public List getMatchingConfigurations() { 82 | PluginImpl.getPlugin().validateAdmin(); 83 | return PluginImpl.getPlugin().getGlobalConfigurationForComputer(computer); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/GetConfigurations.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.callables; 2 | 3 | import hudson.plugins.selenium.process.SeleniumRunOptions; 4 | 5 | import java.util.Map; 6 | 7 | import jenkins.security.MasterToSlaveCallable; 8 | 9 | public class GetConfigurations extends MasterToSlaveCallable, Exception> { 10 | 11 | /** 12 | * 13 | */ 14 | private static final long serialVersionUID = 8710676054398822727L; 15 | 16 | @SuppressWarnings( "unchecked" ) 17 | public Map call() throws Exception { 18 | return PropertyUtils.getProperty(SeleniumConstants.PROPERTY_STATUS); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/PropertyUtils.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.callables; 2 | 3 | import hudson.remoting.ChannelProperty; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | public final class PropertyUtils { 10 | 11 | private static Map properties = new ConcurrentHashMap(); 12 | 13 | private PropertyUtils() {} 14 | 15 | public static T getProperty(ChannelProperty property) { 16 | return property.type.cast(properties.get(property.displayName)); 17 | } 18 | 19 | public static void setProperty(ChannelProperty property, Object object) { 20 | properties.put(property.displayName, object); 21 | } 22 | 23 | @SuppressWarnings( { "unchecked", "rawtypes" } ) 24 | public static T getMapProperty(ChannelProperty property, String key) { 25 | ChannelProperty cp = new ChannelProperty(Map.class, property.displayName); 26 | Map map = getProperty(cp); 27 | if (map == null) { 28 | return null; 29 | } 30 | return (T) map.get(key); 31 | } 32 | 33 | @SuppressWarnings( { "rawtypes", "unchecked" } ) 34 | public static void setMapProperty(ChannelProperty property, String key, Object object) { 35 | ChannelProperty cp = new ChannelProperty(Map.class, property.displayName); 36 | Map map = getProperty(cp); 37 | if (map == null) { 38 | map = new HashMap(); 39 | setProperty(cp, map); 40 | } 41 | map.put(key, object); 42 | setProperty(cp, map); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/RemoteStopSelenium.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.callables; 2 | 3 | import hudson.remoting.Channel; 4 | 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | import jenkins.security.MasterToSlaveCallable; 9 | 10 | import org.openqa.grid.internal.utils.SelfRegisteringRemote; 11 | 12 | public class RemoteStopSelenium extends MasterToSlaveCallable { 13 | 14 | /** 15 | * 16 | */ 17 | private static final long serialVersionUID = -5448989386458342771L; 18 | 19 | public String call() throws Exception { 20 | Logger log = Logger.getLogger(SelfRegisteringRemote.class.getName()); 21 | 22 | Logger.getLogger("org").setLevel(Level.ALL); 23 | 24 | log.fine("instances " + PropertyUtils.getProperty(SeleniumConstants.PROPERTY_INSTANCE)); 25 | SelfRegisteringRemote srr = PropertyUtils.getProperty(SeleniumConstants.PROPERTY_INSTANCE); 26 | String url = getRemoteURL(srr); 27 | srr.stopRemoteServer(); 28 | 29 | Channel.current().setProperty(SeleniumConstants.PROPERTY_LOCK, new Object()); 30 | return url; 31 | } 32 | 33 | private String getRemoteURL(SelfRegisteringRemote srr) { 34 | String host = (String) srr.getConfiguration().host; 35 | Integer port = (Integer) srr.getConfiguration().port; 36 | return "http://" + host + ":" + port; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/RemoveSeleniumServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.callables; 5 | 6 | import jenkins.security.MasterToSlaveCallable; 7 | 8 | import java.util.Map; 9 | 10 | /** 11 | * @author Richard Lavoie 12 | * 13 | */ 14 | public class RemoveSeleniumServer extends MasterToSlaveCallable { 15 | 16 | /** 17 | * 18 | */ 19 | private static final long serialVersionUID = 6048096509551676769L; 20 | 21 | /** 22 | * Name of the configuration associated to the channel to stop. 23 | */ 24 | private String name; 25 | 26 | public RemoveSeleniumServer(String config) { 27 | this.name = config; 28 | } 29 | 30 | /** 31 | * 32 | */ 33 | public Void call() throws Exception { 34 | Map configs = PropertyUtils.getProperty(SeleniumConstants.PROPERTY_STATUS); 35 | configs.remove(name); 36 | return null; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/RetrieveAvailablePort.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.callables; 2 | 3 | import jenkins.security.MasterToSlaveCallable; 4 | 5 | import java.net.ServerSocket; 6 | 7 | public class RetrieveAvailablePort extends MasterToSlaveCallable { 8 | 9 | /** 10 | * 11 | */ 12 | private static final long serialVersionUID = 8030109206143148731L; 13 | 14 | private int port; 15 | 16 | public RetrieveAvailablePort(int port) { 17 | this.port = port; 18 | } 19 | 20 | public Integer call() throws Exception { 21 | 22 | // this is potentially unsafe way to figure out a free port number, but it's far easier 23 | // than patching Selenium 24 | ServerSocket ss = new ServerSocket(port); 25 | int newport = ss.getLocalPort(); 26 | ss.close(); 27 | return newport; 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/RunningRemoteGetterCallable.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.callables; 2 | 3 | import hudson.plugins.selenium.RemoteRunningStatus; 4 | import jenkins.security.MasterToSlaveCallable; 5 | 6 | /** 7 | * Callable that returns a property set on the channel 8 | * 9 | * @author Richard Lavoie 10 | */ 11 | public class RunningRemoteGetterCallable extends MasterToSlaveCallable { 12 | 13 | /** 14 | * 15 | */ 16 | private static final long serialVersionUID = -3519905249359789575L; 17 | 18 | private String config; 19 | 20 | public RunningRemoteGetterCallable(String conf) { 21 | config = conf; 22 | } 23 | 24 | public RemoteRunningStatus call() throws Exception { 25 | return (RemoteRunningStatus) PropertyUtils.getProperty(SeleniumConstants.PROPERTY_STATUS).get(config); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/RunningRemoteSetterCallable.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.callables; 2 | 3 | import hudson.plugins.selenium.RemoteRunningStatus; 4 | import jenkins.security.MasterToSlaveCallable; 5 | 6 | /** 7 | * Callable that returns a property set on the channel 8 | * 9 | * @author Richard Lavoie 10 | */ 11 | public class RunningRemoteSetterCallable extends MasterToSlaveCallable { 12 | 13 | /** 14 | * 15 | */ 16 | private static final long serialVersionUID = -3519905249359789575L; 17 | 18 | private String config; 19 | 20 | private String status; 21 | 22 | public RunningRemoteSetterCallable(String conf, String status) { 23 | config = conf; 24 | this.status = status; 25 | } 26 | 27 | public Void call() throws Exception { 28 | ((RemoteRunningStatus) PropertyUtils.getMapProperty(SeleniumConstants.PROPERTY_STATUS, config)).setStatus(status); 29 | return null; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/SeleniumCallable.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.callables; 2 | 3 | import hudson.FilePath; 4 | import hudson.model.TaskListener; 5 | import hudson.plugins.selenium.RemoteControlLauncher; 6 | import hudson.plugins.selenium.RemoteRunningStatus; 7 | import hudson.plugins.selenium.process.ProcessArgument; 8 | import hudson.plugins.selenium.process.SeleniumProcessUtils; 9 | import hudson.plugins.selenium.process.SeleniumRunOptions; 10 | import hudson.remoting.Channel; 11 | import hudson.remoting.VirtualChannel; 12 | import jenkins.MasterToSlaveFileCallable; 13 | import org.apache.commons.lang.ArrayUtils; 14 | 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.Arrays; 19 | import java.util.List; 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | 23 | public class SeleniumCallable extends MasterToSlaveFileCallable { 24 | 25 | /** 26 | * 27 | */ 28 | private static final long serialVersionUID = 2047557797415325512L; 29 | 30 | private static final String ROLE_PARAM = "-role"; 31 | 32 | private static final String ROLE_NODE_VALUE = "node"; 33 | 34 | private static final String HUB_PARAM = "-hub"; 35 | 36 | private static final Logger LOGGER = Logger.getLogger(SeleniumCallable.class.getName()); 37 | 38 | private FilePath seleniumJar; 39 | private FilePath htmlUnitDriverJar; 40 | private long seleniumJarTimestamp; 41 | private long htmlUnitDriverJarTimestamp; 42 | private String nodeName; 43 | private SeleniumRunOptions options; 44 | private String config; 45 | 46 | private TaskListener listener; 47 | 48 | private String[] defaultArgs; 49 | 50 | public SeleniumCallable(FilePath seleniumJar, FilePath htmlUnitDriverJar, String nodehost, String masterName, int masterPort, String nodeName, TaskListener listener, 51 | String confName, SeleniumRunOptions options) throws InterruptedException, IOException { 52 | this.seleniumJar = seleniumJar; 53 | seleniumJarTimestamp = seleniumJar.lastModified(); 54 | this.htmlUnitDriverJar = htmlUnitDriverJar; 55 | htmlUnitDriverJarTimestamp = htmlUnitDriverJar.lastModified(); 56 | this.nodeName = nodeName; 57 | this.options = options; 58 | this.listener = listener; 59 | config = confName; 60 | defaultArgs = new String[] { 61 | ROLE_PARAM, ROLE_NODE_VALUE, 62 | HUB_PARAM, "http://" + masterName + ":" + masterPort + "/wd/hub" }; 63 | } 64 | 65 | public String invoke(File f, VirtualChannel channel) throws IOException { 66 | RemoteRunningStatus status = PropertyUtils.getMapProperty(SeleniumConstants.PROPERTY_STATUS, config); 67 | 68 | if (status != null && status.isRunning()) { 69 | return null; 70 | } 71 | 72 | File localSeleniumJar = new File(f, seleniumJar.getName()); 73 | File localHtmlUnitDriverJar = new File(f, htmlUnitDriverJar.getName()); 74 | if (localSeleniumJar.lastModified() != seleniumJarTimestamp) { 75 | try { 76 | seleniumJar.copyTo(new FilePath(localSeleniumJar)); 77 | localSeleniumJar.setLastModified(seleniumJarTimestamp); 78 | } catch (InterruptedException e) { 79 | throw new IOException("Failed to copy grid jar", e); 80 | } 81 | } 82 | if (localHtmlUnitDriverJar.lastModified() != htmlUnitDriverJarTimestamp) { 83 | try { 84 | htmlUnitDriverJar.copyTo(new FilePath(localHtmlUnitDriverJar)); 85 | localHtmlUnitDriverJar.setLastModified(htmlUnitDriverJarTimestamp); 86 | } catch (InterruptedException e) { 87 | throw new IOException("Failed to copy htmlunit driver jar", e); 88 | } 89 | } 90 | 91 | try { 92 | 93 | listener.getLogger().println("Creating selenium node VM"); 94 | Channel jvm = SeleniumProcessUtils.createSeleniumRCVM(localSeleniumJar, localHtmlUnitDriverJar, listener, options.getJVMArguments(), options.getEnvironmentVariables()); 95 | status = new RemoteRunningStatus(jvm, options); 96 | status.setStatus(SeleniumConstants.STARTING); 97 | 98 | List arguments = new ArrayList(options.getSeleniumArguments().size()); 99 | for (ProcessArgument arg : options.getSeleniumArguments()) { 100 | arguments.addAll(arg.toArgumentsList()); 101 | } 102 | 103 | Object[] allArgs = ArrayUtils.addAll(defaultArgs, arguments.toArray(new String[arguments.size()])); 104 | 105 | listener.getLogger().println("Starting the selenium node process. Args: " + Arrays.toString(allArgs)); 106 | jvm.callAsync(new RemoteControlLauncher(nodeName, (String[])allArgs)); 107 | status.setStatus(SeleniumConstants.STARTED); 108 | status.setRunning(true); 109 | } catch (Exception t) { 110 | if(status == null){ 111 | status = new RemoteRunningStatus(null, options); 112 | } 113 | status.setRunning(false); 114 | status.setStatus(SeleniumConstants.ERROR); 115 | LOGGER.log(Level.WARNING, "Selenium node launch failed", t); 116 | listener.getLogger().println( "Selenium node launch failed" + t.getMessage()); 117 | 118 | throw new IOException("Selenium node launch interrupted", t); 119 | } 120 | PropertyUtils.setMapProperty(SeleniumConstants.PROPERTY_STATUS, config, status); 121 | 122 | return config; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/SeleniumConstants.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.callables; 2 | 3 | import hudson.remoting.ChannelProperty; 4 | 5 | import java.util.Map; 6 | 7 | import org.openqa.grid.internal.utils.SelfRegisteringRemote; 8 | 9 | public class SeleniumConstants { 10 | 11 | @SuppressWarnings( "rawtypes" ) 12 | public static final ChannelProperty PROPERTY_STATUS = new ChannelProperty(Map.class, "selenium.status"); 13 | 14 | public static final ChannelProperty PROPERTY_LOCK = new ChannelProperty(Object.class, "selenium.lock"); 15 | 16 | public static final ChannelProperty PROPERTY_INSTANCE = new ChannelProperty( 17 | SelfRegisteringRemote.class, "instance"); 18 | 19 | public static final String STARTING = "Starting"; 20 | public static final String STARTED = "Started"; 21 | public static final String RESTARTING = "Restarting"; 22 | public static final String STOPPING = "Stopping"; 23 | public static final String STOPPED = "Stopped"; 24 | 25 | public static final String ERROR = "Error"; 26 | 27 | private SeleniumConstants() {} 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/StopSeleniumServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.callables; 5 | 6 | import jenkins.security.MasterToSlaveCallable; 7 | import hudson.plugins.selenium.RemoteRunningStatus; 8 | import hudson.remoting.Callable; 9 | 10 | /** 11 | * @author Richard Lavoie 12 | * 13 | */ 14 | public class StopSeleniumServer extends MasterToSlaveCallable { 15 | 16 | /** 17 | * 18 | */ 19 | private static final long serialVersionUID = 6048096509551676769L; 20 | 21 | /** 22 | * Name of the configuration associated to the channel to stop. 23 | */ 24 | private String name; 25 | 26 | public StopSeleniumServer(String config) { 27 | this.name = config; 28 | } 29 | 30 | /** 31 | * 32 | */ 33 | public String call() throws Exception { 34 | RemoteRunningStatus rs = getRunningStatus(); 35 | rs.setStatus("Stopping"); 36 | String url = callOnSubProcess(new RemoteStopSelenium(), null); 37 | rs.setStatus("Stopped"); 38 | rs.setRunning(false); 39 | rs.getSeleniumChannel().close(); 40 | return url; 41 | } 42 | 43 | private RemoteRunningStatus getRunningStatus() { 44 | return (RemoteRunningStatus) PropertyUtils.getMapProperty(SeleniumConstants.PROPERTY_STATUS, name); 45 | } 46 | 47 | private T callOnSubProcess(Callable call, T defaultValue) throws Exception { 48 | RemoteRunningStatus opt = PropertyUtils.getMapProperty(SeleniumConstants.PROPERTY_STATUS, name); 49 | if (opt == null) 50 | return defaultValue; 51 | return opt.getSeleniumChannel().call(call); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/hub/StopHubCallable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.callables.hub; 5 | 6 | import hudson.plugins.selenium.HubHolder; 7 | import jenkins.security.MasterToSlaveCallable; 8 | 9 | import java.util.logging.Logger; 10 | 11 | /** 12 | * @author Richard Lavoie 13 | * 14 | */ 15 | public class StopHubCallable extends MasterToSlaveCallable { 16 | 17 | /** 18 | * 19 | */ 20 | private static final long serialVersionUID = -8923286239409381397L; 21 | 22 | private static final Logger LOGGER = Logger.getLogger(StopHubCallable.class.getName()); 23 | /* 24 | * (non-Javadoc) 25 | * @see hudson.remoting.Callable#call() 26 | */ 27 | public Void call() throws Exception { 28 | if (HubHolder.getHub() == null){ 29 | LOGGER.warning("Hub is not running. Nothing to stop."); 30 | return null; 31 | } 32 | 33 | HubHolder.getHub().getRegistry().stop(); 34 | HubHolder.getHub().stop(); 35 | HubHolder.setHub(null); 36 | return null; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/callables/running/RemoteGetConfigurations.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.callables.running; 2 | 3 | import hudson.plugins.selenium.callables.PropertyUtils; 4 | import hudson.plugins.selenium.callables.SeleniumConstants; 5 | import jenkins.security.MasterToSlaveCallable; 6 | 7 | import java.util.Collections; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | public class RemoteGetConfigurations extends MasterToSlaveCallable, Exception> { 12 | 13 | /** 14 | * 15 | */ 16 | private static final long serialVersionUID = 4826936469266107568L; 17 | 18 | @SuppressWarnings( { "unchecked", "rawtypes" } ) 19 | public Set call() throws Exception { 20 | Map map = PropertyUtils.getProperty(SeleniumConstants.PROPERTY_STATUS); 21 | if (map != null) 22 | return map.keySet(); 23 | return Collections.emptySet(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/ConfigurationDescriptor.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration; 2 | 3 | import hudson.model.Descriptor; 4 | 5 | public abstract class ConfigurationDescriptor extends Descriptor { 6 | 7 | // define additional constructor parameters if you want 8 | protected ConfigurationDescriptor(Class clazz) { 9 | super(clazz); 10 | } 11 | 12 | protected ConfigurationDescriptor() { 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/CustomRCConfiguration.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Computer; 5 | import hudson.model.Descriptor; 6 | import hudson.plugins.selenium.callables.RetrieveAvailablePort; 7 | import hudson.plugins.selenium.configuration.browser.selenium.ChromeBrowser; 8 | import hudson.plugins.selenium.configuration.browser.selenium.FirefoxBrowser; 9 | import hudson.plugins.selenium.configuration.browser.selenium.IEBrowser; 10 | import hudson.plugins.selenium.configuration.browser.selenium.SeleniumBrowser; 11 | import hudson.plugins.selenium.configuration.browser.selenium.SeleniumBrowser.SeleniumBrowserDescriptor; 12 | import hudson.plugins.selenium.process.SeleniumRunOptions; 13 | import hudson.util.FormValidation; 14 | import org.kohsuke.stapler.DataBoundConstructor; 15 | import org.kohsuke.stapler.QueryParameter; 16 | import org.kohsuke.stapler.export.Exported; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | public class CustomRCConfiguration extends SeleniumNodeConfiguration { 22 | 23 | /** 24 | * 25 | */ 26 | private static final long serialVersionUID = 140690678989633328L; 27 | 28 | private int port = 4444; 29 | private boolean rcBrowserSideLog; 30 | private boolean rcDebug; 31 | private boolean rcTrustAllSSLCerts; 32 | private boolean rcBrowserSessionReuse; 33 | private Integer timeout = -1; 34 | private String rcLog; 35 | private List browsers = new ArrayList(); 36 | 37 | private CustomRCConfiguration() { 38 | super(null); 39 | browsers.add(new IEBrowser(1, "", "", false)); 40 | browsers.add(new FirefoxBrowser(5, "", "")); 41 | browsers.add(new ChromeBrowser(5, "", "")); 42 | } 43 | 44 | @DataBoundConstructor 45 | public CustomRCConfiguration(int port, boolean rcBrowserSideLog, boolean rcDebug, boolean rcTrustAllSSLCerts, boolean rcBrowserSessionReuse, 46 | Integer timeout, String rcLog, List browsers, String display) { 47 | super(display); 48 | this.port = port; 49 | this.rcBrowserSideLog = rcBrowserSideLog; 50 | this.rcDebug = rcDebug; 51 | this.rcTrustAllSSLCerts = rcTrustAllSSLCerts; 52 | this.rcBrowserSessionReuse = rcBrowserSessionReuse; 53 | this.rcLog = rcLog; 54 | this.timeout = timeout; 55 | this.browsers = browsers; 56 | 57 | } 58 | 59 | @Exported 60 | public String getRcLog() { 61 | return rcLog; 62 | } 63 | 64 | @Exported 65 | public boolean getRcBrowserSideLog() { 66 | return rcBrowserSideLog; 67 | } 68 | 69 | @Exported 70 | public boolean getRcDebug() { 71 | return rcDebug; 72 | } 73 | 74 | @Exported 75 | public boolean getRcTrustAllSSLCerts() { 76 | return rcTrustAllSSLCerts; 77 | } 78 | 79 | @Exported 80 | public boolean getRcBrowserSessionReuse() { 81 | return rcBrowserSessionReuse; 82 | } 83 | 84 | @Exported 85 | public int getPort() { 86 | return port; 87 | } 88 | 89 | @Exported 90 | public Integer getTimeout() { 91 | return timeout; 92 | } 93 | 94 | @Exported 95 | public List getBrowsers() { 96 | return browsers; 97 | } 98 | 99 | @Extension 100 | public static class DescriptorImpl extends ConfigurationDescriptor { 101 | 102 | @Override 103 | public String getDisplayName() { 104 | return "Custom RC node configuration"; 105 | } 106 | 107 | public CustomRCConfiguration getDefault() { 108 | return new CustomRCConfiguration(); 109 | } 110 | 111 | public static List> getBrowserTypes() { 112 | List> lst = new ArrayList>(); 113 | for (SeleniumBrowserDescriptor b : SeleniumBrowser.all()) { 114 | lst.add(b); 115 | } 116 | return lst; 117 | } 118 | 119 | public FormValidation doCheckTimeout(@QueryParameter String value) { 120 | try { 121 | Integer i = Integer.parseInt(value); 122 | if (i >= -1) { 123 | return FormValidation.ok(); 124 | } 125 | } catch (NumberFormatException nfe) { 126 | 127 | } 128 | return FormValidation.error("Must be an integer greater than or equal to -1."); 129 | } 130 | 131 | } 132 | 133 | @Override 134 | public SeleniumRunOptions initOptions(Computer c) { 135 | SeleniumRunOptions opt = super.initOptions(c); 136 | 137 | opt.addOptionIfSet("-log", getRcLog()); 138 | 139 | try { 140 | opt.addOptionIfSet("-port", c.getChannel().call(new RetrieveAvailablePort(getPort()))); 141 | } catch (Exception e) { 142 | // an error occured, not adding the port option 143 | } 144 | 145 | if (getRcBrowserSideLog()) { 146 | opt.addOption("-browserSideLog"); 147 | } 148 | if (getRcDebug()) { 149 | opt.addOption("-debug"); 150 | } 151 | if (getRcTrustAllSSLCerts()) { 152 | opt.addOption("-trustAllSSLCertificates"); 153 | } 154 | if (getRcBrowserSessionReuse()) { 155 | opt.addOption("-browserSessionReuse"); 156 | } 157 | if (getTimeout() != null && getTimeout() > -1) { 158 | opt.addOption("-timeout"); 159 | opt.addOption(getTimeout().toString()); 160 | } 161 | 162 | for (SeleniumBrowser b : browsers) { 163 | b.initOptions(c, opt); 164 | } 165 | 166 | return opt; 167 | } 168 | 169 | public String getIcon() { 170 | return "/plugin/selenium/24x24/internet-web-browser.png"; 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/CustomWDConfiguration.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Computer; 5 | import hudson.model.Descriptor; 6 | import hudson.plugins.selenium.callables.RetrieveAvailablePort; 7 | import hudson.plugins.selenium.configuration.browser.webdriver.ChromeBrowser; 8 | import hudson.plugins.selenium.configuration.browser.webdriver.FirefoxBrowser; 9 | import hudson.plugins.selenium.configuration.browser.webdriver.IEBrowser; 10 | import hudson.plugins.selenium.configuration.browser.webdriver.WebDriverBrowser; 11 | import hudson.plugins.selenium.configuration.browser.webdriver.WebDriverBrowser.WebDriverBrowserDescriptor; 12 | import hudson.plugins.selenium.process.SeleniumRunOptions; 13 | import hudson.util.FormValidation; 14 | import org.kohsuke.stapler.DataBoundConstructor; 15 | import org.kohsuke.stapler.QueryParameter; 16 | import org.kohsuke.stapler.export.Exported; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | 23 | public class CustomWDConfiguration extends SeleniumNodeConfiguration { 24 | 25 | private static final Logger LOGGER = Logger.getLogger(CustomWDConfiguration.class.getName()); 26 | 27 | /** 28 | * 29 | */ 30 | private static final long serialVersionUID = -1357952133882786829L; 31 | 32 | private int port = 4444; 33 | private Integer maxSession = 5; 34 | private Integer timeout = -1; 35 | 36 | private List browsers = new ArrayList(); 37 | 38 | private CustomWDConfiguration() { 39 | super(null); 40 | browsers.add(new IEBrowser(1, "", "", false)); 41 | browsers.add(new FirefoxBrowser(5, "", "")); 42 | browsers.add(new ChromeBrowser(5, "", "")); 43 | } 44 | 45 | @DataBoundConstructor 46 | public CustomWDConfiguration(int port, Integer timeout, List browsers, String display, Integer maxSession) { 47 | super(display); 48 | this.port = port; 49 | this.timeout = timeout; 50 | this.browsers = browsers; 51 | this.maxSession = maxSession; 52 | } 53 | 54 | @Exported 55 | public int getPort() { 56 | return port; 57 | } 58 | 59 | @Exported 60 | public Integer getTimeout() { 61 | return timeout; 62 | } 63 | 64 | @Exported 65 | public Integer getMaxSession() { return maxSession; } 66 | 67 | @Exported 68 | public List getBrowsers() { 69 | return browsers; 70 | } 71 | 72 | @Extension 73 | public static class DescriptorImpl extends ConfigurationDescriptor { 74 | 75 | @Override 76 | public String getDisplayName() { 77 | return "Custom web driver node configuration"; 78 | } 79 | 80 | public CustomWDConfiguration getDefault() { 81 | return new CustomWDConfiguration(); 82 | } 83 | 84 | public static List> getBrowserTypes() { 85 | List> lst = new ArrayList>(); 86 | for (WebDriverBrowserDescriptor b : WebDriverBrowser.all()) { 87 | lst.add(b); 88 | } 89 | return lst; 90 | } 91 | 92 | public FormValidation doCheckTimeout(@QueryParameter String value) { 93 | try { 94 | Integer i = Integer.parseInt(value); 95 | if (i >= -1) { 96 | return FormValidation.ok(); 97 | } 98 | } catch (NumberFormatException nfe) { 99 | 100 | } 101 | return FormValidation.error("Must be an integer greater than or equal to -1."); 102 | } 103 | 104 | public FormValidation doCheckMaxSession(@QueryParameter String value) { 105 | try { 106 | Integer i = Integer.parseInt(value); 107 | if (i >= 1) { 108 | return FormValidation.ok(); 109 | } 110 | } catch (NumberFormatException nfe) { 111 | 112 | } 113 | return FormValidation.error("Must be an integer greater than or equal to 1."); 114 | } 115 | } 116 | 117 | @Override 118 | public SeleniumRunOptions initOptions(Computer c) { 119 | SeleniumRunOptions opt = super.initOptions(c); 120 | try { 121 | opt.addOptionIfSet("-port", c.getChannel().call(new RetrieveAvailablePort(getPort()))); 122 | } catch (Exception e) { 123 | LOGGER.log(Level.SEVERE, "an error occured, not adding the port option", e); 124 | } 125 | 126 | if (getTimeout() != null && getTimeout() > -1) { 127 | opt.addOption("-timeout"); 128 | opt.addOption(getTimeout().toString()); 129 | } 130 | 131 | if (getMaxSession() != null && getMaxSession() > 0) { 132 | opt.addOption("-maxSession"); 133 | opt.addOption(getMaxSession().toString()); 134 | } 135 | 136 | for (WebDriverBrowser b : browsers) { 137 | b.initOptions(c, opt); 138 | } 139 | 140 | return opt; 141 | } 142 | 143 | public String getIcon() { 144 | return "/plugin/selenium/24x24/internet-web-browser.png"; 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/DirectJsonInputConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.configuration; 5 | 6 | import hudson.Extension; 7 | import hudson.FilePath; 8 | import hudson.model.Computer; 9 | import hudson.plugins.selenium.process.SeleniumRunOptions; 10 | import hudson.remoting.VirtualChannel; 11 | import hudson.util.FormValidation; 12 | import jenkins.MasterToSlaveFileCallable; 13 | import org.apache.commons.io.IOUtils; 14 | import org.apache.commons.lang.StringUtils; 15 | import org.json.JSONObject; 16 | import org.kohsuke.stapler.DataBoundConstructor; 17 | import org.kohsuke.stapler.QueryParameter; 18 | import org.kohsuke.stapler.export.Exported; 19 | 20 | import java.io.ByteArrayInputStream; 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.io.StringReader; 24 | import java.util.Map.Entry; 25 | import java.util.Properties; 26 | import java.util.logging.Logger; 27 | 28 | /** 29 | * @author Richard Lavoie 30 | * 31 | */ 32 | public class DirectJsonInputConfiguration extends SeleniumNodeConfiguration { 33 | 34 | private static final Logger LOGGER = Logger.getLogger(FileConfiguration.class.getName()); 35 | 36 | /** 37 | * 38 | */ 39 | private static final long serialVersionUID = 4521592447812296365L; 40 | 41 | /** 42 | * JSON formatted configuration 43 | */ 44 | private String config; 45 | 46 | /** 47 | * JVM arguments. 48 | */ 49 | private String jvmArgs; 50 | 51 | private String seleniumArgs; 52 | 53 | /** 54 | */ 55 | @DataBoundConstructor 56 | public DirectJsonInputConfiguration(String display, String config, String jvmArgs, String seleniumArgs) { 57 | super(display); 58 | if (config.startsWith("\"")) { 59 | this.config = config.substring(1, config.length() - 1); 60 | } else { 61 | this.config = config; 62 | } 63 | this.jvmArgs = jvmArgs; 64 | this.seleniumArgs = seleniumArgs; 65 | } 66 | 67 | @Exported 68 | public String getConfig() { 69 | return config; 70 | } 71 | 72 | @Exported 73 | public String getJvmArgs() { 74 | return jvmArgs; 75 | } 76 | 77 | @Exported 78 | public String getSeleniumArgs() { 79 | return seleniumArgs; 80 | } 81 | 82 | @Extension 83 | public static class DescriptorImpl extends ConfigurationDescriptor { 84 | 85 | @Override 86 | public String getDisplayName() { 87 | return "JSON configuration"; 88 | } 89 | 90 | public FormValidation doCheckConfig(@QueryParameter( "config" ) String config) { 91 | FormValidation notEmpty = FormValidation.validateRequired(config); 92 | if (!notEmpty.equals(FormValidation.ok())) { 93 | return notEmpty; 94 | } 95 | try { 96 | // We don't want to validate the fields, even RegistrationRequest doesn't ... It just ignores the unknown fields. 97 | return FormValidation.ok(); 98 | } catch (Exception e) { 99 | return FormValidation.error("Invalid JSON input."); 100 | } 101 | } 102 | } 103 | 104 | @Override 105 | public SeleniumRunOptions initOptions(Computer computer) { 106 | SeleniumRunOptions opt = super.initOptions(computer); 107 | try { 108 | 109 | final String filename = "selenium-temp-config-" + System.currentTimeMillis() + ".json"; 110 | 111 | if (jvmArgs != null) { 112 | Properties p = new Properties(); 113 | p.load(new StringReader(jvmArgs.replace("\\", "\\\\"))); 114 | for (Entry e : p.entrySet()) { 115 | opt.getJVMArguments().put(e.getKey().toString(), e.getValue().toString()); 116 | } 117 | } 118 | 119 | if (seleniumArgs != null) { 120 | for (Object l : IOUtils.readLines(new StringReader(seleniumArgs))) { 121 | String line = (String) l; 122 | line = line.trim(); 123 | if (line.contains(" ")) { 124 | String[] keyValue = StringUtils.split(line, " ", 2); 125 | opt.addOptionIfSet(keyValue[0], keyValue[1]); 126 | } else { 127 | opt.addOption(line); 128 | } 129 | } 130 | } 131 | 132 | String fullPath = computer.getNode().getRootPath().act(new MasterToSlaveFileCallable() { 133 | 134 | /** 135 | * 136 | */ 137 | private static final long serialVersionUID = -288688398601004624L; 138 | 139 | public String invoke(File f, VirtualChannel channel) throws IOException { 140 | File conf = new File(f, filename); 141 | 142 | FilePath urlConf = new FilePath(conf); 143 | try { 144 | urlConf.copyFrom(new ByteArrayInputStream(config.getBytes())); 145 | } catch (InterruptedException e) { 146 | throw new IOException("Failed to write configuration to " + filename, e); 147 | } 148 | 149 | return conf.getAbsolutePath(); 150 | } 151 | }); 152 | 153 | opt.addOptionIfSet("-nodeConfig", fullPath); 154 | 155 | return opt; 156 | } catch (Exception e) { 157 | LOGGER.fine("Cannot write the specified configuration on the node. " + e.getMessage()); 158 | return null; 159 | } 160 | } 161 | 162 | public String getIcon() { 163 | return "/images/24x24/document.png"; 164 | } 165 | 166 | } 167 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/FileConfiguration.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration; 2 | 3 | import hudson.Extension; 4 | import hudson.FilePath; 5 | import hudson.model.Computer; 6 | import hudson.plugins.selenium.process.SeleniumRunOptions; 7 | import hudson.remoting.VirtualChannel; 8 | import jenkins.MasterToSlaveFileCallable; 9 | import org.kohsuke.stapler.DataBoundConstructor; 10 | import org.kohsuke.stapler.export.Exported; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.net.URL; 15 | import java.util.logging.Logger; 16 | 17 | public class FileConfiguration extends SeleniumNodeConfiguration { 18 | 19 | /** 20 | * 21 | */ 22 | private static final long serialVersionUID = 5068212020001695128L; 23 | 24 | private static final Logger LOGGER = Logger.getLogger(FileConfiguration.class.getName()); 25 | 26 | private String configURL; 27 | 28 | @DataBoundConstructor 29 | public FileConfiguration(String configURL, String display) { 30 | super(display); 31 | this.configURL = configURL; 32 | } 33 | 34 | @Exported 35 | public String getConfigURL() { 36 | return configURL; 37 | } 38 | 39 | @Extension 40 | public static class DescriptorImpl extends ConfigurationDescriptor { 41 | 42 | @Override 43 | public String getDisplayName() { 44 | return "File configuration"; 45 | } 46 | } 47 | 48 | @Override 49 | public SeleniumRunOptions initOptions(Computer c) { 50 | SeleniumRunOptions opt = super.initOptions(c); 51 | try { 52 | final String filename = "selenium-temp-config-" + System.currentTimeMillis() + ".json"; 53 | 54 | String fullPath = c.getNode().getRootPath().act(new MasterToSlaveFileCallable() { 55 | 56 | /** 57 | * 58 | */ 59 | private static final long serialVersionUID = -288688398601004624L; 60 | 61 | public String invoke(File f, VirtualChannel channel) throws IOException { 62 | File conf = new File(f, filename); 63 | 64 | FilePath urlConf = new FilePath(conf); 65 | try { 66 | urlConf.copyFrom(new URL(configURL)); 67 | } catch (InterruptedException e) { 68 | throw new IOException("Failed to retrieve configuration from " + configURL, e); 69 | } 70 | 71 | return conf.getAbsolutePath(); 72 | } 73 | }); 74 | 75 | opt.addOptionIfSet("-nodeConfig", fullPath); 76 | 77 | return opt; 78 | } catch (Exception e) { 79 | LOGGER.fine("Cannot download the specified configuration file on the node. " + e.getMessage()); 80 | return null; 81 | } 82 | } 83 | 84 | public String getIcon() { 85 | return "/images/24x24/document.png"; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/SeleniumNodeConfiguration.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration; 2 | 3 | import hudson.DescriptorExtensionList; 4 | import hudson.model.Computer; 5 | import hudson.model.Describable; 6 | import hudson.model.Node; 7 | import hudson.plugins.selenium.process.SeleniumJarRunner; 8 | import hudson.plugins.selenium.process.SeleniumRunOptions; 9 | import jenkins.model.Jenkins; 10 | import org.kohsuke.stapler.export.Exported; 11 | import org.kohsuke.stapler.export.ExportedBean; 12 | 13 | import java.io.Serializable; 14 | 15 | @ExportedBean 16 | public abstract class SeleniumNodeConfiguration extends SeleniumJarRunner implements Describable, Serializable { 17 | 18 | /** 19 | * 20 | */ 21 | private static final long serialVersionUID = -6869016011243891909L; 22 | 23 | private String displayName = null; 24 | 25 | private String display; 26 | 27 | /** 28 | */ 29 | public SeleniumNodeConfiguration(String display) { 30 | this.display = display; 31 | } 32 | 33 | public ConfigurationDescriptor getDescriptor() { 34 | return (ConfigurationDescriptor) Jenkins.getInstance().getDescriptor(getClass()); 35 | } 36 | 37 | public static DescriptorExtensionList all() { 38 | return Jenkins.getInstance().getDescriptorList(SeleniumNodeConfiguration.class); 39 | } 40 | 41 | public static DescriptorExtensionList allExcept(Node current) { 42 | return Jenkins.getInstance().getDescriptorList(SeleniumNodeConfiguration.class); 43 | } 44 | 45 | public SeleniumRunOptions initOptions(Computer c) { 46 | SeleniumRunOptions opts = new SeleniumRunOptions(); 47 | 48 | opts.setEnvVar("DISPLAY", display); 49 | 50 | return opts; 51 | } 52 | 53 | public String getDisplayName() { 54 | if (displayName == null) { 55 | String name = getClass().getSimpleName(); 56 | StringBuilder b = new StringBuilder(name.length()); 57 | b.append(name.charAt(0)); 58 | for (int i = 1; i < name.length(); i++) { 59 | if (Character.isUpperCase(name.charAt(i))) { 60 | b.append(" "); 61 | } 62 | b.append(name.charAt(i)); 63 | } 64 | displayName = b.toString(); 65 | } 66 | return displayName; 67 | } 68 | 69 | @Exported 70 | public String getDisplay() { 71 | return display; 72 | } 73 | 74 | public String getIcon() { 75 | return "/images/24x24/gear.png"; 76 | } 77 | 78 | public String getIconAltText() { 79 | return getDescriptor().getDisplayName(); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/AbstractSeleniumBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser; 2 | 3 | import hudson.ExtensionPoint; 4 | import hudson.model.Describable; 5 | import hudson.model.Computer; 6 | import hudson.plugins.selenium.process.SeleniumRunOptions; 7 | 8 | import java.io.Serializable; 9 | import java.util.ArrayList; 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import org.apache.commons.lang.StringUtils; 15 | import org.kohsuke.stapler.export.Exported; 16 | import org.kohsuke.stapler.export.ExportedBean; 17 | import org.openqa.grid.common.SeleniumProtocol; 18 | 19 | @ExportedBean 20 | public abstract class AbstractSeleniumBrowser & Describable> implements ExtensionPoint, Serializable { 21 | 22 | /** 23 | * 24 | */ 25 | private static final long serialVersionUID = -1895158524568642537L; 26 | 27 | transient protected final String paramBrowserName = "browserName"; 28 | 29 | transient protected final String paramMaxInstances = "maxInstances"; 30 | 31 | transient protected final String paramVersion = "version"; 32 | 33 | transient protected final String paramSeleniumProtocol = "seleniumProtocol"; 34 | 35 | private int maxInstances = 0; 36 | private String version; 37 | private SeleniumProtocol protocol; 38 | private String name; 39 | 40 | protected AbstractSeleniumBrowser(SeleniumProtocol protocol, int instances, String version, String name) { 41 | if (protocol == null) { 42 | throw new NullPointerException(); 43 | } 44 | 45 | maxInstances = instances; 46 | this.version = version; 47 | this.protocol = protocol; 48 | this.name = name; 49 | } 50 | 51 | @Exported 52 | public int getMaxInstances() { 53 | return maxInstances; 54 | } 55 | 56 | @Exported 57 | public String getVersion() { 58 | return version; 59 | } 60 | 61 | @Exported 62 | public String getName() { 63 | return name; 64 | } 65 | 66 | @Exported 67 | public String getProtocol() { 68 | return protocol.toString(); 69 | } 70 | 71 | /** 72 | * Combine the key and value on the key=value form and add that form in the options list 73 | * 74 | * @param options 75 | * List on which to add the key=value pair 76 | * @param key 77 | * Key option 78 | * @param value 79 | * Value option 80 | */ 81 | protected static void combine(List options, String key, Object value) { 82 | if (value != null && !StringUtils.isBlank(value.toString())) { 83 | options.add(key + "=" + value.toString().replace("\"", "\\\"")); 84 | } 85 | } 86 | 87 | protected static void combine(Map args, String key, String value) { 88 | if (!StringUtils.isBlank(value)) { 89 | args.put(key, value); 90 | } 91 | } 92 | 93 | public void initOptions(Computer c, SeleniumRunOptions opt) { 94 | opt.getJVMArguments().putAll(getJVMArgs()); 95 | opt.addOptionIfSet("-browser", StringUtils.join(initBrowserOptions(c, opt), ",")); 96 | } 97 | 98 | protected List initBrowserOptions(Computer c, SeleniumRunOptions options) { 99 | List args = new ArrayList(); 100 | combine(args, paramSeleniumProtocol, protocol); 101 | combine(args, paramBrowserName, getName()); 102 | combine(args, paramMaxInstances, maxInstances); 103 | combine(args, paramVersion, version); 104 | return args; 105 | } 106 | 107 | protected Map getJVMArgs() { 108 | return Collections.emptyMap(); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/BrowserDescriptor.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser; 2 | 3 | import hudson.model.Describable; 4 | import hudson.model.Descriptor; 5 | import hudson.util.FormValidation; 6 | 7 | import org.kohsuke.stapler.QueryParameter; 8 | 9 | public abstract class BrowserDescriptor & Describable> extends Descriptor { 10 | 11 | // define additional constructor parameters if you want 12 | protected BrowserDescriptor(Class clazz) { 13 | super(clazz); 14 | } 15 | 16 | protected BrowserDescriptor() { 17 | } 18 | 19 | public abstract int getMaxInstances(); 20 | 21 | public FormValidation doCheckMaxInstances(@QueryParameter String value) { 22 | return FormValidation.validatePositiveInteger(value); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/EdgeDriverServerUtils.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser; 2 | 3 | import hudson.model.Computer; 4 | import org.apache.commons.lang3.StringUtils; 5 | 6 | import java.net.URL; 7 | 8 | public class EdgeDriverServerUtils { 9 | 10 | private EdgeDriverServerUtils() { 11 | } 12 | 13 | private static final String EDGE_DRIVER_NAME = "MicrosoftWebDriver.exe"; 14 | 15 | public static String uploadEdgeDriverIfNecessary(Computer computer, String serverBinary) { 16 | if (StringUtils.isBlank(serverBinary)) { 17 | String serverPath; 18 | NodeUtils.OsType nodeOs = NodeUtils.getNodeOS(computer); 19 | switch (nodeOs) { 20 | case WINDOWS_64: 21 | case WINDOWS_32: 22 | URL url = IeDriverServerUtils.class.getClassLoader().getResource(EDGE_DRIVER_NAME); 23 | serverPath = NodeUtils.uploadFileToNode(computer, url, EDGE_DRIVER_NAME); 24 | break; 25 | default: 26 | return serverBinary; 27 | } 28 | return serverPath; 29 | } 30 | return serverBinary; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/IeDriverServerUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.configuration.browser; 5 | 6 | import hudson.model.Computer; 7 | import org.apache.commons.lang3.StringUtils; 8 | 9 | import java.net.URL; 10 | 11 | /** 12 | * @author Richard Lavoie 13 | * 14 | */ 15 | public final class IeDriverServerUtils { 16 | 17 | private IeDriverServerUtils() { 18 | } 19 | 20 | public static String uploadIEDriverIfNecessary(Computer computer, String serverBinary, boolean forbid64bitDriver) { 21 | if (StringUtils.isBlank(serverBinary)) { 22 | String driverName; 23 | NodeUtils.OsType nodeOs = NodeUtils.getNodeOS(computer); 24 | switch (nodeOs) { 25 | case WINDOWS_64: 26 | if (forbid64bitDriver) { 27 | driverName = "IEDriverServer_64.exe"; 28 | break; 29 | } 30 | case WINDOWS_32: 31 | driverName = "IEDriverServer_32.exe"; 32 | break; 33 | default: 34 | return serverBinary; 35 | } 36 | URL url = IeDriverServerUtils.class.getClassLoader().getResource(driverName); 37 | return NodeUtils.uploadFileToNode(computer, url, "IEDriverServer.exe"); 38 | } else { 39 | return serverBinary; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/NodeUtils.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser; 2 | 3 | import hudson.Functions; 4 | import hudson.model.Computer; 5 | import hudson.remoting.RemoteInputStream; 6 | import hudson.remoting.VirtualChannel; 7 | import hudson.util.IOUtils; 8 | import jenkins.MasterToSlaveFileCallable; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.net.URL; 14 | 15 | public class NodeUtils { 16 | 17 | enum OsType { 18 | WINDOWS_32, 19 | WINDOWS_64, 20 | OTHER, 21 | NOT_DEFINED 22 | } 23 | 24 | static OsType getNodeOS(Computer computer) { 25 | try { 26 | return computer.getNode().getRootPath().act(new MasterToSlaveFileCallable() { 27 | private static final long serialVersionUID = -726600253548951419L; 28 | 29 | public OsType invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { 30 | if (!Functions.isWindows()) { 31 | return OsType.OTHER; 32 | } 33 | Process p = Runtime.getRuntime().exec("cmd /c if defined ProgramFiles(x86) ( exit 1 ) else ( exit 0 )"); 34 | int exitValue = p.waitFor(); 35 | 36 | return exitValue == 1 ? OsType.WINDOWS_64 : OsType.WINDOWS_32; 37 | } 38 | }); 39 | } catch (IOException | InterruptedException e) { 40 | e.printStackTrace(); 41 | } 42 | return OsType.NOT_DEFINED; 43 | } 44 | 45 | 46 | public static String uploadFileToNode(Computer computer, URL url, String outputFileName) { 47 | try { 48 | final InputStream is = new RemoteInputStream(url.openStream(), RemoteInputStream.Flag.GREEDY); 49 | return computer.getNode().getRootPath().act(new MasterToSlaveFileCallable() { 50 | private static final long serialVersionUID = 4508849758404950847L; 51 | 52 | public String invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { 53 | File out = new File(f, outputFileName); 54 | if (out.exists()) { 55 | out.delete(); 56 | } 57 | IOUtils.copy(is, out); 58 | return out.getAbsolutePath(); 59 | } 60 | }); 61 | } catch (IOException | InterruptedException e) { 62 | e.printStackTrace(); 63 | } 64 | return null; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/selenium/ChromeBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.selenium; 2 | 3 | import hudson.Extension; 4 | import hudson.util.FormValidation; 5 | import org.apache.commons.lang.StringUtils; 6 | import org.kohsuke.stapler.DataBoundConstructor; 7 | import org.kohsuke.stapler.QueryParameter; 8 | import org.kohsuke.stapler.export.Exported; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | public class ChromeBrowser extends SeleniumBrowser { 14 | 15 | /** 16 | * 17 | */ 18 | private static final long serialVersionUID = 2L; 19 | 20 | private transient final String chromeDriverProperty = "webdriver.chrome.driver"; 21 | 22 | private String driverBinaryPath; 23 | 24 | @DataBoundConstructor 25 | public ChromeBrowser(int maxInstances, String version, String driverBinaryPath) { 26 | super(maxInstances, version, "*googlechrome"); 27 | this.driverBinaryPath = driverBinaryPath; 28 | } 29 | 30 | @Exported 31 | public String getDriverBinaryPath() { 32 | return driverBinaryPath; 33 | } 34 | 35 | @Override 36 | public Map getJVMArgs() { 37 | Map args = new HashMap(); 38 | combine(args, chromeDriverProperty, getDriverBinaryPath()); 39 | return args; 40 | } 41 | 42 | @Extension 43 | public static class DescriptorImpl extends SeleniumBrowserDescriptor { 44 | 45 | public int getMaxInstances() { 46 | return 5; 47 | } 48 | 49 | @Override 50 | public String getDisplayName() { 51 | return "Chrome"; 52 | } 53 | 54 | public FormValidation doCheckDriverBinaryPath(@QueryParameter String value) { 55 | if (StringUtils.isBlank(value)) { 56 | return FormValidation 57 | .warning("Must not be empty unless it is already defined from a previous chrome browser definition or already defined in the path"); 58 | } 59 | return FormValidation.ok(); 60 | } 61 | } 62 | 63 | // Backwards compatibility since 2.4.1 64 | @Deprecated 65 | transient private String server_binary; 66 | @Deprecated 67 | public String getServer_binary() { 68 | return server_binary; 69 | } 70 | 71 | public Object readResolve() { 72 | 73 | if (server_binary != null) { 74 | 75 | this.driverBinaryPath = server_binary; 76 | } 77 | return this; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/selenium/EdgeBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.selenium; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Computer; 5 | import hudson.plugins.selenium.configuration.browser.EdgeDriverServerUtils; 6 | import hudson.plugins.selenium.process.SeleniumRunOptions; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.kohsuke.stapler.DataBoundConstructor; 9 | import org.kohsuke.stapler.export.Exported; 10 | 11 | public class EdgeBrowser extends SeleniumBrowser { 12 | 13 | /** 14 | * 15 | */ 16 | private static final long serialVersionUID = 2L; 17 | 18 | private String driverBinaryPath; 19 | 20 | private transient final String edgeDriverProperty = "webdriver.edge.driver"; 21 | 22 | @DataBoundConstructor 23 | public EdgeBrowser(int maxInstances, String version, String driverBinaryPath) { 24 | super(maxInstances, version, "*MicrosoftEdge"); 25 | this.driverBinaryPath = driverBinaryPath; 26 | } 27 | 28 | @Exported 29 | public String getDriverBinaryPath() { 30 | return driverBinaryPath; 31 | } 32 | 33 | @Override 34 | public void initOptions(Computer c, SeleniumRunOptions opt) { 35 | String serverPath = EdgeDriverServerUtils.uploadEdgeDriverIfNecessary(c, getDriverBinaryPath()); 36 | if (serverPath != null) { 37 | opt.getJVMArguments().put(edgeDriverProperty, serverPath); 38 | } 39 | opt.addOptionIfSet("-browser", StringUtils.join(initBrowserOptions(c, opt), ",")); 40 | } 41 | 42 | @Extension 43 | public static class DescriptorImpl extends SeleniumBrowserDescriptor { 44 | 45 | public int getMaxInstances() { 46 | return 1; 47 | } 48 | 49 | @Override 50 | public String getDisplayName() { 51 | return "Microsoft Edge"; 52 | } 53 | } 54 | 55 | // Backwards compatibility since 2.4.1 56 | @Deprecated 57 | transient private String server_binary; 58 | @Deprecated 59 | public String getServer_binary() { 60 | return server_binary; 61 | } 62 | 63 | public Object readResolve() { 64 | 65 | if (server_binary != null) { 66 | 67 | this.driverBinaryPath = server_binary; 68 | } 69 | return this; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/selenium/FirefoxBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.selenium; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Computer; 5 | import hudson.plugins.selenium.process.SeleniumRunOptions; 6 | import org.kohsuke.stapler.DataBoundConstructor; 7 | import org.kohsuke.stapler.export.Exported; 8 | 9 | import java.util.List; 10 | 11 | public class FirefoxBrowser extends SeleniumBrowser { 12 | 13 | /** 14 | * 15 | */ 16 | private static final long serialVersionUID = 1180910636911313608L; 17 | 18 | private transient final String paramBinaryPath = "firefox_binary"; 19 | 20 | private String binaryPath; 21 | 22 | @DataBoundConstructor 23 | public FirefoxBrowser(int maxInstances, String version, String binaryPath) { 24 | super(maxInstances, version, "*firefox"); 25 | this.binaryPath = binaryPath; 26 | } 27 | 28 | @Exported 29 | public String getBinaryPath() { 30 | return binaryPath; 31 | } 32 | 33 | @Override 34 | public List initBrowserOptions(Computer c, SeleniumRunOptions options) { 35 | List args = super.initBrowserOptions(c, options); 36 | combine(args, paramBinaryPath, getBinaryPath()); 37 | return args; 38 | } 39 | 40 | @Extension 41 | public static class DescriptorImpl extends SeleniumBrowserDescriptor { 42 | 43 | public int getMaxInstances() { 44 | return 5; 45 | } 46 | 47 | @Override 48 | public String getDisplayName() { 49 | return "Firefox"; 50 | } 51 | } 52 | 53 | // Backwards compatibility since 2.4.1 54 | @Deprecated 55 | transient private String binary_path; 56 | @Deprecated 57 | public String getBinary_path() { 58 | return binary_path; 59 | } 60 | 61 | public Object readResolve() { 62 | 63 | if (binary_path != null) { 64 | 65 | this.binaryPath = binary_path; 66 | } 67 | return this; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/selenium/IEBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.selenium; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Computer; 5 | import hudson.plugins.selenium.configuration.browser.IeDriverServerUtils; 6 | import hudson.plugins.selenium.process.SeleniumRunOptions; 7 | 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.kohsuke.stapler.DataBoundConstructor; 10 | import org.kohsuke.stapler.export.Exported; 11 | 12 | public class IEBrowser extends SeleniumBrowser { 13 | 14 | /** 15 | * 16 | */ 17 | private static final long serialVersionUID = 2L; 18 | 19 | private String driverBinaryPath; 20 | 21 | private transient boolean forbid64bitDriver; 22 | 23 | private transient final String ieDriverProperty = "webdriver.ie.driver"; 24 | 25 | @DataBoundConstructor 26 | public IEBrowser(int maxInstances, String version, String driverBinaryPath, boolean forbid64bitDriver) { 27 | super(maxInstances, version, "*iexplore"); 28 | this.driverBinaryPath = driverBinaryPath; 29 | this.forbid64bitDriver = forbid64bitDriver; 30 | } 31 | 32 | @Exported 33 | public String getDriverBinaryPath() { 34 | return driverBinaryPath; 35 | } 36 | 37 | @Exported 38 | public boolean getForbid64bitDriver() { 39 | return forbid64bitDriver; 40 | } 41 | 42 | @Override 43 | public void initOptions(Computer c, SeleniumRunOptions opt) { 44 | String serverPath = IeDriverServerUtils.uploadIEDriverIfNecessary(c, getDriverBinaryPath(), getForbid64bitDriver()); 45 | if (serverPath != null) { 46 | opt.getJVMArguments().put(ieDriverProperty, serverPath); 47 | } 48 | opt.addOptionIfSet("-browser", StringUtils.join(initBrowserOptions(c, opt), ",")); 49 | } 50 | 51 | @Extension 52 | public static class DescriptorImpl extends SeleniumBrowserDescriptor { 53 | 54 | public int getMaxInstances() { 55 | return 1; 56 | } 57 | 58 | @Override 59 | public String getDisplayName() { 60 | return "Internet Explorer"; 61 | } 62 | } 63 | 64 | // Backwards compatibility since 2.4.1 65 | @Deprecated 66 | transient private String server_binary; 67 | @Deprecated 68 | public String getServer_binary() { 69 | return server_binary; 70 | } 71 | 72 | public Object readResolve() { 73 | 74 | if (server_binary != null) { 75 | 76 | this.driverBinaryPath = server_binary; 77 | } 78 | return this; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/selenium/OperaBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.selenium; 2 | 3 | import hudson.Extension; 4 | import org.kohsuke.stapler.DataBoundConstructor; 5 | import org.kohsuke.stapler.export.Exported; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class OperaBrowser extends SeleniumBrowser { 11 | 12 | /** 13 | * 14 | */ 15 | private static final long serialVersionUID = 2L; 16 | 17 | private transient final String paramBinaryPath = "opera.binary"; 18 | 19 | private String binaryPath; 20 | 21 | @DataBoundConstructor 22 | public OperaBrowser(int maxInstances, String version, String binaryPath) { 23 | super(maxInstances, version, "*opera"); 24 | this.binaryPath = binaryPath; 25 | } 26 | 27 | @Exported 28 | public String getBinaryPath() { 29 | return binaryPath; 30 | } 31 | 32 | @Override 33 | public Map getJVMArgs() { 34 | Map args = new HashMap(); 35 | combine(args, paramBinaryPath, getBinaryPath()); 36 | return args; 37 | } 38 | 39 | @Extension 40 | public static class DescriptorImpl extends SeleniumBrowserDescriptor { 41 | 42 | public int getMaxInstances() { 43 | return 1; 44 | } 45 | 46 | @Override 47 | public String getDisplayName() { 48 | return "Opera"; 49 | } 50 | } 51 | 52 | // Backwards compatibility since 2.4.1 53 | @Deprecated 54 | transient private String browser_binary; 55 | @Deprecated 56 | public String getBrowser_binary() { 57 | return browser_binary; 58 | } 59 | 60 | public Object readResolve() { 61 | 62 | if (browser_binary != null) { 63 | 64 | this.binaryPath = browser_binary; 65 | } 66 | return this; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/selenium/SeleniumBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.selenium; 2 | 3 | import hudson.DescriptorExtensionList; 4 | import hudson.model.Describable; 5 | import hudson.model.Descriptor; 6 | import hudson.plugins.selenium.configuration.browser.AbstractSeleniumBrowser; 7 | import hudson.plugins.selenium.configuration.browser.BrowserDescriptor; 8 | import jenkins.model.Jenkins; 9 | import org.openqa.grid.common.SeleniumProtocol; 10 | 11 | public abstract class SeleniumBrowser extends AbstractSeleniumBrowser implements Describable { 12 | 13 | /** 14 | * 15 | */ 16 | private static final long serialVersionUID = 412877504468641135L; 17 | 18 | protected SeleniumBrowser(int instances, String version, String name) { 19 | super(SeleniumProtocol.Selenium, instances, version, name); 20 | } 21 | 22 | @SuppressWarnings( "unchecked" ) 23 | public Descriptor getDescriptor() { 24 | return Jenkins.getInstance().getDescriptor(getClass()); 25 | } 26 | 27 | public static DescriptorExtensionList all() { 28 | return Jenkins.getInstance().getDescriptorList(SeleniumBrowser.class); 29 | } 30 | 31 | public static abstract class SeleniumBrowserDescriptor extends BrowserDescriptor { 32 | 33 | public abstract int getMaxInstances(); 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/webdriver/ChromeBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.webdriver; 2 | 3 | import hudson.Extension; 4 | import hudson.util.FormValidation; 5 | import org.apache.commons.lang.StringUtils; 6 | import org.kohsuke.stapler.DataBoundConstructor; 7 | import org.kohsuke.stapler.QueryParameter; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | public class ChromeBrowser extends DriverRequiredWebDriverBrowser { 13 | 14 | /** 15 | * 16 | */ 17 | private static final long serialVersionUID = 2L; 18 | 19 | /** 20 | * System property to specify the chrome binary location. Could be done through a tool installer and probably moved into the chromedriver plugin. 21 | */ 22 | private transient final String chromeDriverProperty = "webdriver.chrome.driver"; 23 | 24 | @DataBoundConstructor 25 | public ChromeBrowser(int maxInstances, String version, String driverBinaryPath) { 26 | super(maxInstances, version, "chrome", driverBinaryPath); 27 | } 28 | 29 | @Override 30 | public Map getJVMArgs() { 31 | Map args = new HashMap(); 32 | combine(args, chromeDriverProperty, getDriverBinaryPath()); 33 | return args; 34 | } 35 | 36 | @Extension 37 | public static class DescriptorImpl extends WebDriverBrowserDescriptor { 38 | 39 | public int getMaxInstances() { 40 | return 5; 41 | } 42 | 43 | @Override 44 | public String getDisplayName() { 45 | return "Chrome"; 46 | } 47 | 48 | public FormValidation doCheckDriverBinaryPath(@QueryParameter String value) { 49 | if (StringUtils.isBlank(value)) { 50 | return FormValidation 51 | .warning("Must not be empty unless it is already defined from a previous chrome browser definition or already defined in the path"); 52 | } 53 | return FormValidation.ok(); 54 | } 55 | } 56 | 57 | // Backwards compatibility 58 | @Deprecated 59 | transient private String server_binary; 60 | 61 | @Deprecated 62 | public String getServer_binary() { 63 | 64 | return server_binary; 65 | } 66 | 67 | // Deal with converting old persisted data to new fields 68 | public Object readResolve() { 69 | 70 | if (server_binary != null) { 71 | 72 | setDriverBinaryPath(server_binary); 73 | } 74 | return this; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/webdriver/DriverRequiredWebDriverBrowser.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.configuration.browser.webdriver; 5 | 6 | import org.kohsuke.stapler.export.Exported; 7 | 8 | /** 9 | * This is an abstract object that holds the driver binary for selenium browsers that use a separate driver binary 10 | * to communicate with the browser : IE, Chrome, Edge, Opera, HTMLUnit (provided). 11 | * 12 | * HTMLUnit is provided in plugin as this is a jar, not a binary file, and thus not as easily added. 13 | * 14 | * @author Richard Lavoie 15 | * 16 | */ 17 | public abstract class DriverRequiredWebDriverBrowser extends WebDriverBrowser { 18 | 19 | /** 20 | * 21 | */ 22 | private static final long serialVersionUID = 2L; 23 | 24 | /** 25 | * Path to the server binary used to communicate with the browser. 26 | */ 27 | private String driverBinaryPath; 28 | 29 | /** 30 | * 31 | * @param instances 32 | * Number of instances to run of this browser type session. 33 | * @param version 34 | * Version of the browser to use. 35 | * @param name 36 | * Name of the browser 37 | * @param driverBinaryPath 38 | * Path to the driver binary that communicate with the browser 39 | */ 40 | public DriverRequiredWebDriverBrowser(int instances, String version, String name, String driverBinaryPath) { 41 | super(instances, version, name); 42 | this.driverBinaryPath = driverBinaryPath; 43 | } 44 | 45 | public void setDriverBinaryPath(String driverBinaryPath) { 46 | 47 | this.driverBinaryPath = driverBinaryPath; 48 | } 49 | 50 | @Exported 51 | public String getDriverBinaryPath() { 52 | 53 | return driverBinaryPath; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/webdriver/EdgeBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.webdriver; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Computer; 5 | import hudson.plugins.selenium.configuration.browser.EdgeDriverServerUtils; 6 | import hudson.plugins.selenium.process.SeleniumRunOptions; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.kohsuke.stapler.DataBoundConstructor; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | public class EdgeBrowser extends DriverRequiredWebDriverBrowser { 14 | 15 | /** 16 | * 17 | */ 18 | private static final long serialVersionUID = 4134783568959523121L; 19 | 20 | private transient final String edgeDriverProperty = "webdriver.edge.driver"; 21 | 22 | @DataBoundConstructor 23 | public EdgeBrowser(int maxInstances, String version, String driverBinaryPath) { 24 | super(maxInstances, version, "MicrosoftEdge", driverBinaryPath); 25 | } 26 | 27 | @Override 28 | public Map getJVMArgs() { 29 | Map args = new HashMap(); 30 | 31 | combine(args, edgeDriverProperty, getDriverBinaryPath()); 32 | return args; 33 | } 34 | 35 | @Override 36 | public void initOptions(Computer c, SeleniumRunOptions opt) { 37 | String driverPath = EdgeDriverServerUtils.uploadEdgeDriverIfNecessary(c, getDriverBinaryPath()); 38 | if (driverPath != null) { 39 | opt.getJVMArguments().put(edgeDriverProperty, driverPath); 40 | } 41 | opt.addOptionIfSet("-browser", StringUtils.join(initBrowserOptions(c, opt), ",")); 42 | } 43 | 44 | @Extension 45 | public static class DescriptorImpl extends WebDriverBrowserDescriptor { 46 | 47 | public int getMaxInstances() { 48 | return 1; 49 | } 50 | 51 | @Override 52 | public String getDisplayName() { 53 | return "Microsoft Edge"; 54 | } 55 | } 56 | 57 | // Backwards compatibility since 2.4.1 58 | @Deprecated 59 | transient private String server_binary; 60 | 61 | @Deprecated 62 | public String getServer_binary() { 63 | 64 | return server_binary; 65 | } 66 | 67 | public Object readResolve() { 68 | 69 | if (server_binary != null) { 70 | 71 | setDriverBinaryPath(server_binary); 72 | } 73 | return this; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/webdriver/FirefoxBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.webdriver; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Computer; 5 | import hudson.plugins.selenium.process.SeleniumRunOptions; 6 | import org.kohsuke.stapler.DataBoundConstructor; 7 | import org.kohsuke.stapler.export.Exported; 8 | 9 | import java.util.List; 10 | 11 | public class FirefoxBrowser extends WebDriverBrowser { 12 | 13 | /** 14 | * 15 | */ 16 | private static final long serialVersionUID = 1451746845341944745L; 17 | 18 | private transient final String paramBinaryPath = "firefox_binary"; 19 | 20 | private String binaryPath; 21 | 22 | @DataBoundConstructor 23 | public FirefoxBrowser(int maxInstances, String version, String binaryPath) { 24 | super(maxInstances, version, "firefox"); 25 | this.binaryPath = binaryPath; 26 | } 27 | 28 | @Exported 29 | public String getBinaryPath() { 30 | return binaryPath; 31 | } 32 | 33 | @Override 34 | public List initBrowserOptions(Computer c, SeleniumRunOptions options) { 35 | List args = super.initBrowserOptions(c, options); 36 | combine(args, paramBinaryPath, getBinaryPath()); 37 | return args; 38 | } 39 | 40 | @Extension 41 | public static class DescriptorImpl extends WebDriverBrowserDescriptor { 42 | 43 | public int getMaxInstances() { 44 | return 5; 45 | } 46 | 47 | @Override 48 | public String getDisplayName() { 49 | return "Firefox"; 50 | } 51 | 52 | } 53 | 54 | // Backwards compatibility since 2.4.1 55 | @Deprecated 56 | transient private String binary_path; 57 | @Deprecated 58 | public String getBinary_path() { return binary_path; } 59 | 60 | public Object readResolve() { 61 | 62 | if (binary_path != null) { 63 | 64 | this.binaryPath = binary_path; 65 | } 66 | 67 | return this; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/webdriver/HTMLUnitBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.webdriver; 2 | 3 | import hudson.Extension; 4 | 5 | import org.kohsuke.stapler.DataBoundConstructor; 6 | 7 | public class HTMLUnitBrowser extends WebDriverBrowser { 8 | 9 | /** 10 | * 11 | */ 12 | private static final long serialVersionUID = 7089526214694718987L; 13 | 14 | @DataBoundConstructor 15 | public HTMLUnitBrowser(int maxInstances) { 16 | super(maxInstances, null, "htmlunit"); 17 | } 18 | 19 | @Extension 20 | public static class DescriptorImpl extends WebDriverBrowserDescriptor { 21 | 22 | public int getMaxInstances() { 23 | return 1; 24 | } 25 | 26 | @Override 27 | public String getDisplayName() { 28 | return "HTMLUnit"; 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/webdriver/IEBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.webdriver; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Computer; 5 | import hudson.plugins.selenium.configuration.browser.IeDriverServerUtils; 6 | import hudson.plugins.selenium.process.SeleniumRunOptions; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.kohsuke.stapler.DataBoundConstructor; 9 | import org.kohsuke.stapler.export.Exported; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | public class IEBrowser extends DriverRequiredWebDriverBrowser { 15 | 16 | /** 17 | * 18 | */ 19 | private static final long serialVersionUID = -241845413478474187L; 20 | 21 | private transient final String ieDriverProperty = "webdriver.ie.driver"; 22 | 23 | private transient boolean forbid64bitDriver; 24 | 25 | @DataBoundConstructor 26 | public IEBrowser(int maxInstances, String version, String driverBinaryPath, boolean forbid64bitDriver) { 27 | super(maxInstances, version, "internet explorer", driverBinaryPath); 28 | this.forbid64bitDriver = forbid64bitDriver; 29 | } 30 | 31 | @Override 32 | public Map getJVMArgs() { 33 | Map args = new HashMap(); 34 | 35 | combine(args, ieDriverProperty, getDriverBinaryPath()); 36 | return args; 37 | } 38 | 39 | @Override 40 | public void initOptions(Computer c, SeleniumRunOptions opt) { 41 | String driverPath = IeDriverServerUtils.uploadIEDriverIfNecessary(c, getDriverBinaryPath(), getForbid64bitDriver()); 42 | if (driverPath != null) { 43 | opt.getJVMArguments().put(ieDriverProperty, driverPath); 44 | } 45 | opt.addOptionIfSet("-browser", StringUtils.join(initBrowserOptions(c, opt), ",")); 46 | } 47 | 48 | @Extension 49 | public static class DescriptorImpl extends WebDriverBrowserDescriptor { 50 | 51 | public int getMaxInstances() { 52 | return 1; 53 | } 54 | 55 | @Override 56 | public String getDisplayName() { 57 | return "Internet Explorer"; 58 | } 59 | } 60 | 61 | // Backwards compatibility since 2.4.1 62 | @Deprecated 63 | transient private String server_binary; 64 | 65 | @Deprecated 66 | public String getServer_binary() { 67 | 68 | return server_binary; 69 | } 70 | 71 | public Object readResolve() { 72 | 73 | if (server_binary != null) { 74 | 75 | setDriverBinaryPath(server_binary); 76 | } 77 | return this; 78 | } 79 | 80 | @Exported 81 | public boolean getForbid64bitDriver() { 82 | return forbid64bitDriver; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/webdriver/OperaBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.webdriver; 2 | 3 | import hudson.Extension; 4 | import org.kohsuke.stapler.DataBoundConstructor; 5 | import org.kohsuke.stapler.export.Exported; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class OperaBrowser extends WebDriverBrowser { 11 | 12 | /** 13 | * 14 | */ 15 | private static final long serialVersionUID = 2L; 16 | 17 | private transient final String paramBinaryPath = "opera.binary"; 18 | 19 | private String binaryPath; 20 | 21 | @DataBoundConstructor 22 | public OperaBrowser(int maxInstances, String version, String binaryPath) { 23 | super(maxInstances, version, "opera"); 24 | this.binaryPath = binaryPath; 25 | } 26 | 27 | @Exported 28 | public String getBinaryPath() { 29 | return binaryPath; 30 | } 31 | 32 | @Override 33 | public Map getJVMArgs() { 34 | Map args = new HashMap(); 35 | combine(args, paramBinaryPath, getBinaryPath()); 36 | return args; 37 | } 38 | 39 | @Extension 40 | public static class DescriptorImpl extends WebDriverBrowserDescriptor { 41 | 42 | public int getMaxInstances() { 43 | return 1; 44 | } 45 | 46 | @Override 47 | public String getDisplayName() { 48 | return "Opera"; 49 | } 50 | } 51 | 52 | // Backwards compatibility since 2.4.1 53 | @Deprecated 54 | transient private String browser_binary; 55 | @Deprecated 56 | public String getBrowser_binary() { 57 | return browser_binary; 58 | } 59 | 60 | public Object readResolve() { 61 | 62 | if (browser_binary != null) { 63 | 64 | this.binaryPath = browser_binary; 65 | } 66 | return this; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/webdriver/SafariBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.webdriver; 2 | 3 | import hudson.Extension; 4 | 5 | import org.kohsuke.stapler.DataBoundConstructor; 6 | 7 | public class SafariBrowser extends WebDriverBrowser { 8 | 9 | /** 10 | * 11 | */ 12 | private static final long serialVersionUID = 5425432330259522911L; 13 | 14 | @DataBoundConstructor 15 | public SafariBrowser(int maxInstances, String version) { 16 | super(maxInstances, version, "safari"); 17 | } 18 | 19 | @Extension 20 | public static class DescriptorImpl extends WebDriverBrowserDescriptor { 21 | 22 | public int getMaxInstances() { 23 | return 1; 24 | } 25 | 26 | public String getDisplayName() { 27 | return "Safari"; 28 | } 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/browser/webdriver/WebDriverBrowser.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.browser.webdriver; 2 | 3 | import hudson.DescriptorExtensionList; 4 | import hudson.model.Describable; 5 | import hudson.model.Descriptor; 6 | import hudson.plugins.selenium.configuration.browser.BrowserDescriptor; 7 | import hudson.plugins.selenium.configuration.browser.AbstractSeleniumBrowser; 8 | import jenkins.model.Jenkins; 9 | 10 | import org.openqa.grid.common.SeleniumProtocol; 11 | 12 | public abstract class WebDriverBrowser extends AbstractSeleniumBrowser implements Describable { 13 | 14 | /** 15 | * 16 | */ 17 | private static final long serialVersionUID = -1666042840629819766L; 18 | 19 | protected WebDriverBrowser(int instances, String version, String name) { 20 | super(SeleniumProtocol.WebDriver, instances, version, name); 21 | } 22 | 23 | @SuppressWarnings( "unchecked" ) 24 | public Descriptor getDescriptor() { 25 | return Jenkins.getInstance().getDescriptor(getClass()); 26 | } 27 | 28 | public static DescriptorExtensionList all() { 29 | return Jenkins.getInstance().getDescriptorList(WebDriverBrowser.class); 30 | } 31 | 32 | public static abstract class WebDriverBrowserDescriptor extends BrowserDescriptor { 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/global/SeleniumGlobalConfiguration.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.global; 2 | 3 | import hudson.DescriptorExtensionList; 4 | import hudson.model.Computer; 5 | import hudson.model.Describable; 6 | import hudson.model.Descriptor; 7 | import hudson.model.Failure; 8 | import hudson.model.TaskListener; 9 | import hudson.plugins.selenium.PluginImpl; 10 | import hudson.plugins.selenium.configuration.ConfigurationDescriptor; 11 | import hudson.plugins.selenium.configuration.SeleniumNodeConfiguration; 12 | import hudson.plugins.selenium.configuration.global.matcher.SeleniumConfigurationMatcher; 13 | import hudson.plugins.selenium.configuration.global.matcher.SeleniumConfigurationMatcher.MatcherDescriptor; 14 | import hudson.util.FormValidation; 15 | import jenkins.model.Jenkins; 16 | import org.kohsuke.stapler.DataBoundConstructor; 17 | import org.kohsuke.stapler.QueryParameter; 18 | import org.kohsuke.stapler.StaplerRequest; 19 | import org.kohsuke.stapler.StaplerResponse; 20 | import org.kohsuke.stapler.export.Exported; 21 | import org.kohsuke.stapler.export.ExportedBean; 22 | 23 | import java.io.IOException; 24 | import java.io.Serializable; 25 | import java.util.concurrent.ExecutionException; 26 | 27 | @ExportedBean 28 | public class SeleniumGlobalConfiguration implements Serializable, Describable { 29 | 30 | /** 31 | * 32 | */ 33 | private static final long serialVersionUID = -8366478398033252973L; 34 | 35 | private String name; 36 | 37 | private SeleniumConfigurationMatcher matcher; 38 | 39 | private SeleniumNodeConfiguration configuration; 40 | 41 | @DataBoundConstructor 42 | public SeleniumGlobalConfiguration(String name, SeleniumConfigurationMatcher matcher, SeleniumNodeConfiguration configuration) { 43 | this.name = name; 44 | this.matcher = matcher; 45 | this.configuration = configuration; 46 | } 47 | 48 | public void start(Computer computer, TaskListener listener) throws IOException, InterruptedException, ExecutionException { 49 | if (matcher != null && matcher.match(computer.getNode())) { 50 | configuration.start(computer, listener, name); 51 | } 52 | } 53 | 54 | public void stop(Computer computer) { 55 | if (matcher != null && matcher.match(computer.getNode())) { 56 | configuration.stop(computer, name); 57 | } 58 | } 59 | 60 | /** 61 | */ 62 | public void remove(Computer computer) { 63 | PluginImpl.getPlugin().validateAdmin(); 64 | configuration.remove(computer, name); 65 | } 66 | 67 | /** 68 | * Returns the name of the configuration 69 | * 70 | */ 71 | @Exported 72 | public String getName() { 73 | return name; 74 | } 75 | 76 | public String getMatcherSummary() { 77 | return matcher.getSummary(); 78 | } 79 | 80 | @Exported 81 | public SeleniumConfigurationMatcher getMatcher() { 82 | return matcher; 83 | } 84 | 85 | @Exported 86 | public SeleniumNodeConfiguration getConfiguration() { 87 | return configuration; 88 | } 89 | 90 | public String getDisplayName() { 91 | return configuration.getDescriptor().getDisplayName(); 92 | } 93 | 94 | public void doDoDelete(StaplerRequest req, StaplerResponse rsp) throws Exception { 95 | PluginImpl.getPlugin().validateAdmin(); 96 | PluginImpl.getPlugin().removeGlobalConfigurations(name); 97 | rsp.sendRedirect("../../configurations"); 98 | } 99 | 100 | public Descriptor getDescriptor() { 101 | return Jenkins.getInstance().getDescriptorByType(DescriptorImpl.class); 102 | } 103 | 104 | public static final class DescriptorImpl extends Descriptor { 105 | 106 | @Override 107 | public String getDisplayName() { 108 | return null; 109 | } 110 | 111 | public FormValidation doCheckName(@QueryParameter String name) { 112 | return FormValidation.validateRequired(name); 113 | } 114 | 115 | } 116 | 117 | public void doCommitEdit(StaplerRequest req, StaplerResponse rsp) throws Exception { 118 | PluginImpl.getPlugin().validateAdmin(); 119 | SeleniumGlobalConfiguration conf = req.bindJSON(SeleniumGlobalConfiguration.class, req.getSubmittedForm()); 120 | if (null == conf.getName() || conf.getName().trim().equals("")) { 121 | throw new Failure("You must specify a name for the configuration"); 122 | } 123 | 124 | PluginImpl.getPlugin().replaceGlobalConfigurations(name, conf); 125 | 126 | rsp.sendRedirect2("../../configuration/"+conf.getName()); 127 | } 128 | 129 | public DescriptorExtensionList getConfigTypes() { 130 | return SeleniumNodeConfiguration.all(); 131 | } 132 | 133 | public DescriptorExtensionList getMatcherTypes() { 134 | return SeleniumConfigurationMatcher.all(); 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/global/hostname/HostnameResolver.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.configuration.global.hostname; 5 | 6 | import hudson.DescriptorExtensionList; 7 | import hudson.ExtensionPoint; 8 | import hudson.model.Describable; 9 | import jenkins.model.Jenkins; 10 | 11 | import java.io.Serializable; 12 | 13 | /** 14 | * This extension point exists to be able to configure selenium to resolve a hostname and publish it to it's nodes and the status view. 15 | * 16 | * @author Richard Lavoie 17 | * 18 | */ 19 | public abstract class HostnameResolver implements Describable, ExtensionPoint, Serializable { 20 | 21 | /** 22 | * 23 | */ 24 | private static final long serialVersionUID = -3819154151335977152L; 25 | 26 | /** 27 | * Retrieve the hostname to use 28 | * 29 | * @return Host name. 30 | */ 31 | public abstract String retrieveHost(); 32 | 33 | public HostnameResolverDescriptor getDescriptor() { 34 | return (HostnameResolverDescriptor) Jenkins.getInstance().getDescriptor(getClass()); 35 | } 36 | 37 | public static DescriptorExtensionList all() { 38 | return Jenkins.getInstance().getDescriptorList(HostnameResolver.class); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/global/hostname/HostnameResolverDescriptor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.configuration.global.hostname; 5 | 6 | import hudson.model.Descriptor; 7 | 8 | /** 9 | * @author Richard Lavoie 10 | * 11 | */ 12 | public abstract class HostnameResolverDescriptor extends Descriptor { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/global/hostname/JenkinsRootHostnameResolver.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.configuration.global.hostname; 5 | 6 | import hudson.Extension; 7 | import jenkins.model.Jenkins; 8 | import org.kohsuke.stapler.DataBoundConstructor; 9 | 10 | import java.net.MalformedURLException; 11 | import java.net.URL; 12 | 13 | /** 14 | * @author Richard Lavoie 15 | * 16 | */ 17 | public class JenkinsRootHostnameResolver extends HostnameResolver { 18 | 19 | /** 20 | * 21 | */ 22 | private static final long serialVersionUID = 7865004453289102894L; 23 | 24 | @DataBoundConstructor 25 | public JenkinsRootHostnameResolver() { 26 | } 27 | 28 | 29 | public String retrieveHost() { 30 | String rootUrl = Jenkins.getInstance().getRootUrl(); 31 | if (rootUrl == null) 32 | return "localhost"; 33 | URL url; 34 | try { 35 | url = new URL(rootUrl); 36 | } catch (MalformedURLException e) { 37 | return null; 38 | } 39 | return url.getHost(); 40 | } 41 | 42 | @Extension 43 | public static final class JenkinsHostnameRetrieverDescriptor extends HostnameResolverDescriptor { 44 | 45 | @Override 46 | public String getDisplayName() { 47 | return "Use jenkins URL, as defined in the global configuration"; 48 | } 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/global/hostname/StaticHostnameResolver.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.configuration.global.hostname; 5 | 6 | import hudson.Extension; 7 | import org.kohsuke.stapler.DataBoundConstructor; 8 | 9 | /** 10 | * @author Richard Lavoie 11 | * 12 | */ 13 | public class StaticHostnameResolver extends HostnameResolver { 14 | 15 | /** 16 | * 17 | */ 18 | private static final long serialVersionUID = -6854399632708036684L; 19 | 20 | private String hostname; 21 | 22 | @DataBoundConstructor 23 | public StaticHostnameResolver(String hostname) { 24 | this.hostname = hostname; 25 | } 26 | 27 | public String retrieveHost() { 28 | return hostname; 29 | } 30 | 31 | public String getHostname() { 32 | return hostname; 33 | } 34 | 35 | @Extension 36 | public static final class StaticHostnameRetrieverDescriptor extends HostnameResolverDescriptor { 37 | 38 | @Override 39 | public String getDisplayName() { 40 | return "Use a fixed hostname"; 41 | } 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/global/matcher/MatchAllMatcher.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.global.matcher; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Node; 5 | 6 | import org.kohsuke.stapler.DataBoundConstructor; 7 | 8 | @Extension 9 | public class MatchAllMatcher extends SeleniumConfigurationMatcher { 10 | 11 | /** 12 | * 13 | */ 14 | private static final long serialVersionUID = -2499088801959956260L; 15 | 16 | @DataBoundConstructor 17 | public MatchAllMatcher() { 18 | 19 | } 20 | 21 | public boolean match(Node node) { 22 | return true; 23 | } 24 | 25 | @Extension 26 | public static class DescriptorImpl extends MatcherDescriptor { 27 | 28 | @Override 29 | public String getDisplayName() { 30 | return "Match all nodes"; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/global/matcher/MatchNoneMatcher.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.global.matcher; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Node; 5 | 6 | import org.kohsuke.stapler.DataBoundConstructor; 7 | 8 | /** 9 | * This matcher always return false. Useful to disable a configuration but not remove it. 10 | * 11 | * @author Richard Lavoie 12 | * 13 | */ 14 | @Extension 15 | public class MatchNoneMatcher extends SeleniumConfigurationMatcher { 16 | 17 | /** 18 | * 19 | */ 20 | private static final long serialVersionUID = 3110742193312586293L; 21 | 22 | @DataBoundConstructor 23 | public MatchNoneMatcher() { 24 | 25 | } 26 | 27 | public boolean match(Node node) { 28 | return false; 29 | } 30 | 31 | @Extension 32 | public static class DescriptorImpl extends MatcherDescriptor { 33 | 34 | @Override 35 | public String getDisplayName() { 36 | return "Match no nodes"; 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/global/matcher/NodeLabelMatcher.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.global.matcher; 2 | 3 | import antlr.ANTLRException; 4 | import hudson.Extension; 5 | import hudson.model.AutoCompletionCandidates; 6 | import hudson.model.Label; 7 | import hudson.model.Node; 8 | import hudson.model.labels.LabelAtom; 9 | import hudson.util.FormValidation; 10 | import jenkins.model.Jenkins; 11 | import org.kohsuke.stapler.DataBoundConstructor; 12 | import org.kohsuke.stapler.QueryParameter; 13 | import org.kohsuke.stapler.export.Exported; 14 | 15 | import java.util.List; 16 | 17 | @Extension 18 | public class NodeLabelMatcher extends SeleniumConfigurationMatcher { 19 | 20 | /** 21 | * 22 | */ 23 | private static final long serialVersionUID = -7254869163456438031L; 24 | 25 | private String labelExpr; 26 | 27 | public NodeLabelMatcher() { 28 | 29 | } 30 | 31 | @DataBoundConstructor 32 | public NodeLabelMatcher(String label) { 33 | this.labelExpr = label; 34 | } 35 | 36 | public boolean match(Node node) { 37 | if (node == null) 38 | return false; 39 | try { 40 | return Label.parseExpression(labelExpr).matches(node); 41 | } catch (ANTLRException e) { 42 | } 43 | return false; 44 | } 45 | 46 | @Exported 47 | public String getLabel() { 48 | return labelExpr; 49 | } 50 | 51 | @Extension 52 | public static class DescriptorImpl extends MatcherDescriptor { 53 | 54 | @Override 55 | public String getDisplayName() { 56 | return "Match nodes from a label expression"; 57 | } 58 | 59 | public FormValidation doCheckLabel(@QueryParameter String value) { 60 | return FormValidation.validateRequired(value); 61 | } 62 | 63 | /** 64 | * Returns a list of auto completion candidates. 65 | * 66 | * @return candidates 67 | */ 68 | public AutoCompletionCandidates doAutoCompleteLabel() { 69 | AutoCompletionCandidates candidates = new AutoCompletionCandidates(); 70 | List masterNodeList = Jenkins.getInstance().getNodes(); 71 | for (Node node : masterNodeList) { 72 | try { 73 | for (LabelAtom atom : Label.parseExpression(node.getLabelString()).listAtoms()) { 74 | candidates.add(atom.getName()); 75 | } 76 | } catch (ANTLRException e) { 77 | // invalid expression, skipped 78 | } 79 | } 80 | return candidates; 81 | } 82 | 83 | } 84 | 85 | public String getSummary() { 86 | return getDescriptor().getDisplayName() + " (Expression = '" + labelExpr + "' )"; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/configuration/global/matcher/SeleniumConfigurationMatcher.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.configuration.global.matcher; 2 | 3 | import hudson.DescriptorExtensionList; 4 | import hudson.ExtensionPoint; 5 | import hudson.model.Describable; 6 | import hudson.model.Descriptor; 7 | import hudson.model.Node; 8 | import jenkins.model.Jenkins; 9 | 10 | import java.io.Serializable; 11 | 12 | public abstract class SeleniumConfigurationMatcher implements ExtensionPoint, Describable, Serializable { 13 | 14 | /** 15 | * 16 | */ 17 | private static final long serialVersionUID = -8723977886089297294L; 18 | 19 | public abstract boolean match(Node node); 20 | 21 | public static DescriptorExtensionList all() { 22 | return Jenkins.getInstance().getDescriptorList(SeleniumConfigurationMatcher.class); 23 | } 24 | 25 | public abstract static class MatcherDescriptor extends Descriptor { 26 | 27 | } 28 | 29 | public MatcherDescriptor getDescriptor() { 30 | return (MatcherDescriptor) Jenkins.getInstance().getDescriptorOrDie(getClass()); 31 | } 32 | 33 | public String getSummary() { 34 | return getDescriptor().getDisplayName(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/process/ProcessArgument.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.process; 5 | 6 | import java.io.Serializable; 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | 10 | /** 11 | * @author Richard Lavoie 12 | * 13 | */ 14 | public class ProcessArgument implements Serializable { 15 | 16 | /** 17 | * 18 | */ 19 | private static final long serialVersionUID = 176693180466734322L; 20 | private String value; 21 | 22 | public ProcessArgument(String argumentValue, boolean quote) { 23 | // not yet implemented 24 | throw new UnsupportedOperationException(); 25 | } 26 | 27 | public ProcessArgument(String argumentValue) { 28 | this.value = argumentValue; 29 | } 30 | 31 | public String toString() { 32 | return value; 33 | } 34 | 35 | /** 36 | */ 37 | public Collection toArgumentsList() { 38 | return Collections.singletonList(value); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/process/ProcessKeyListArgument.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.process; 5 | 6 | import org.apache.commons.lang.StringUtils; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | /** 13 | * @author Richard Lavoie 14 | * 15 | */ 16 | public class ProcessKeyListArgument extends ProcessArgument { 17 | 18 | /** 19 | * 20 | */ 21 | private static final long serialVersionUID = -138813439927716198L; 22 | 23 | private List values; 24 | 25 | /** 26 | */ 27 | public ProcessKeyListArgument(String keyArgument, String... values) { 28 | super(keyArgument); 29 | this.values = Arrays.asList(values); 30 | } 31 | 32 | public void addArgument(String value) { 33 | values.add(value); 34 | } 35 | 36 | public List toArgumentsList() { 37 | List rets = new ArrayList(values.size() + 1); 38 | rets.addAll(super.toArgumentsList()); 39 | rets.addAll(values); 40 | return rets; 41 | } 42 | 43 | public String toString() { 44 | return super.toString() + " " + StringUtils.join(values, " "); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/process/SeleniumJarRunner.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.process; 5 | 6 | import hudson.FilePath; 7 | import hudson.model.Computer; 8 | import hudson.model.TaskListener; 9 | import hudson.plugins.selenium.HubHolder; 10 | import hudson.plugins.selenium.PluginImpl; 11 | import hudson.plugins.selenium.callables.*; 12 | import jenkins.security.MasterToSlaveCallable; 13 | import org.openqa.grid.internal.GridRegistry; 14 | import org.openqa.grid.internal.RemoteProxy; 15 | 16 | import java.io.IOException; 17 | import java.util.Iterator; 18 | 19 | /** 20 | * @author Richard Lavoie 21 | * 22 | */ 23 | public abstract class SeleniumJarRunner implements SeleniumProcess { 24 | 25 | public abstract SeleniumRunOptions initOptions(Computer c); 26 | 27 | public void start(Computer computer, TaskListener listener, String name) throws IOException, InterruptedException { 28 | PluginImpl p = PluginImpl.getPlugin(); 29 | 30 | final FilePath seleniumJar = new FilePath(SeleniumProcessUtils.findStandAloneServerJar()); 31 | final FilePath htmlUnitDriverJar = new FilePath(SeleniumProcessUtils.findHtmlUnitDriverJar()); 32 | final String nodeName = computer.getName(); 33 | final String masterName = PluginImpl.getMasterHostName(); 34 | 35 | String nodehost = computer.getHostName(); 36 | 37 | SeleniumRunOptions opts = initOptions(computer); 38 | 39 | if (opts != null) { 40 | opts.addOptionIfSet("-host", nodehost); 41 | computer.getNode().getRootPath() 42 | .act(new SeleniumCallable(seleniumJar, htmlUnitDriverJar, nodehost, masterName, p.getPort(), nodeName, listener, name, opts)); 43 | } 44 | } 45 | 46 | /** 47 | */ 48 | public void remove(Computer computer, String name) { 49 | stop(computer, name); 50 | try { 51 | computer.getNode().getRootPath().act(new RemoveSeleniumServer(name)); 52 | } catch (Exception e) { 53 | 54 | } 55 | } 56 | 57 | /* 58 | * (non-Javadoc) 59 | * @see hudson.plugins.selenium.configuration.SeleniumRunner#stop(hudson.model.Computer) 60 | */ 61 | public void stop(Computer computer, String name) { 62 | FilePath path = computer.getNode().getRootPath(); 63 | if (path != null) { 64 | try { 65 | final String url = computer.getNode().getRootPath().act(new StopSeleniumServer(name)); 66 | PluginImpl.getPlugin().getHubChannel().call(new MasterToSlaveCallable() { 67 | 68 | /** 69 | * 70 | */ 71 | private static final long serialVersionUID = -5805313572457450300L; 72 | private String remoteUrl = url; 73 | 74 | public Void call() throws Exception { 75 | GridRegistry registry = HubHolder.getHub().getRegistry(); 76 | if (registry != null) { 77 | Iterator it = registry.getAllProxies().iterator(); 78 | while (it.hasNext()) { 79 | RemoteProxy proxy = it.next(); 80 | if (remoteUrl.equals(proxy.getRemoteHost().toString())) { 81 | registry.removeIfPresent(proxy); 82 | } 83 | } 84 | } 85 | return null; 86 | } 87 | 88 | }); 89 | } catch (Exception e) { 90 | try { 91 | computer.getNode().getRootPath().act(new RunningRemoteSetterCallable(name, SeleniumConstants.ERROR)); 92 | } catch (Exception e1) { 93 | } 94 | } 95 | } 96 | 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/process/SeleniumProcess.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package hudson.plugins.selenium.process; 5 | 6 | import hudson.model.Computer; 7 | import hudson.model.TaskListener; 8 | 9 | import java.io.IOException; 10 | 11 | /** 12 | * This interface specifies the operation necessary for a selenium process to run on a given computer 13 | * 14 | * @author Richard Lavoie 15 | * 16 | */ 17 | public interface SeleniumProcess { 18 | 19 | void start(Computer computer, TaskListener listener, String configName) throws IOException, InterruptedException; 20 | 21 | void stop(Computer computer, String name); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/hudson/plugins/selenium/process/SeleniumRunOptions.java: -------------------------------------------------------------------------------- 1 | package hudson.plugins.selenium.process; 2 | 3 | import org.springframework.util.StringUtils; 4 | 5 | import java.io.Serializable; 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * This is only a bean that contains the JVM settings and the selenium arguments to start 13 | * 14 | * @author Richard Lavoie 15 | * 16 | */ 17 | public final class SeleniumRunOptions implements Serializable { 18 | 19 | /** 20 | * 21 | */ 22 | private static final long serialVersionUID = -5571585840451096944L; 23 | 24 | private List arguments; 25 | 26 | private Map jvmArgs; 27 | 28 | private Map envVars; 29 | 30 | public SeleniumRunOptions() { 31 | arguments = new ArrayList(); 32 | jvmArgs = new HashMap(); 33 | envVars = new HashMap(); 34 | } 35 | 36 | /** 37 | * Returns the selenium process arguments 38 | * 39 | * @return List of arguments 40 | */ 41 | public List getSeleniumArguments() { 42 | return arguments; 43 | } 44 | 45 | /** 46 | * Returns the jvm arguments that needs to be given to the RcVM class (-D options mostly) 47 | * 48 | * @return Map of key/value options to be given to the jvm starting selenium 49 | */ 50 | public Map getJVMArguments() { 51 | return jvmArgs; 52 | } 53 | 54 | /** 55 | * Add an option to the selenium process' command line arguments list 56 | * 57 | * @param option 58 | * Option to add 59 | */ 60 | public void addOption(String option) { 61 | arguments.add(new ProcessArgument(option)); 62 | } 63 | 64 | /** 65 | * Add an option only if the value is set : not null and length not zero 66 | * 67 | * @param option Option to set 68 | * @param value Value of the option 69 | */ 70 | public void addOptionIfSet(String option, Object value) { 71 | if (value != null && StringUtils.hasText(value.toString())) { 72 | arguments.add(new ProcessKeyListArgument(option, value.toString())); 73 | } 74 | } 75 | 76 | public Map getEnvironmentVariables() { 77 | return envVars; 78 | } 79 | 80 | /** 81 | * Sets the environment variables to the specified value. If the value is null, the environment variable is removed. 82 | * 83 | * @param key 84 | * Variable name 85 | * @param value 86 | * Variable value 87 | */ 88 | public void setEnvVar(String key, String value) { 89 | if (value != null && !value.equals("")) { 90 | envVars.put(key, value); 91 | } 92 | } 93 | 94 | public static SeleniumRunOptions merge(SeleniumRunOptions options1, SeleniumRunOptions options2) { 95 | if (options1 == null && options2 == null) 96 | return null; 97 | SeleniumRunOptions newOpts = new SeleniumRunOptions(); 98 | addAllOptions(newOpts, options1); 99 | addAllOptions(newOpts, options2); 100 | 101 | return newOpts; 102 | } 103 | 104 | private static void addAllOptions(SeleniumRunOptions newOpts, SeleniumRunOptions options) { 105 | if (options == null) { 106 | return; 107 | } 108 | for (ProcessArgument arg : options.arguments) { 109 | newOpts.arguments.add(arg); 110 | } 111 | for (Map.Entry arg : options.jvmArgs.entrySet()) { 112 | newOpts.jvmArgs.put(arg.getKey(), arg.getValue()); 113 | } 114 | for (Map.Entry arg : options.envVars.entrySet()) { 115 | newOpts.envVars.put(arg.getKey(), arg.getValue()); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/resources/IEDriverServer_32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/resources/IEDriverServer_32.exe -------------------------------------------------------------------------------- /src/main/resources/IEDriverServer_64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/resources/IEDriverServer_64.exe -------------------------------------------------------------------------------- /src/main/resources/MicrosoftWebDriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/resources/MicrosoftWebDriver.exe -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/Messages.properties: -------------------------------------------------------------------------------- 1 | AdminPermission=This permission allows to restart selenium processes if required 2 | PermissionGroup=Selenium -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/_infotable.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 21 | 24 | 25 | 28 | 29 | 30 | 31 |
TypeDelete${%Name}Matching typeDescription summary
14 | ${c.iconAltText} 15 | 17 | 18 | 19 | 20 | 22 | ${c.name} 23 | ${c.matcherSummary} 26 | 27 |
32 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/add.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

New configuration

7 | 8 | 9 | 10 | 11 | 14 | 17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 |
25 |
26 |
27 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/computers.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | 25 | 26 | 27 | 30 | 31 | 32 | 48 | 49 | 50 |
${%Name}Matching configurations
17 | ${c.iconAltText} 19 | 23 | (master) 24 | 28 | ${c.displayName} 29 | 33 | 34 | 35 | 36 | 37 | 41 | 44 | 45 | 46 |
38 | ${c.configuration.iconAltText} 40 | 42 | ${conf.name} 43 |
47 |
51 |
52 |
53 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/conf_sidepanel.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ${%You need to restart hub and than all configurations/nodes in order to apply settings for Selenium Hub.} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 |
45 |
46 |
47 |
48 |
49 |
50 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/configurations.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/console.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

 7 |             
8 | 9 |
10 | 11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/help-browserTimeout.html: -------------------------------------------------------------------------------- 1 |
2 | Starting from selenium v2.21.0 3 |
Controls how long the browser is allowed to hang (value in seconds) 4 |
5 | The grid does not act on this value by itself, but passes the value on to the nodes, which do. 6 | Should be higher than the socket lock timeout (45 seconds) and generally higher than values used in 7 | webDriver.manage().timeouts() 8 |

9 | See also 10 |
https://code.google.com/p/selenium/wiki/Grid2 11 |
12 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/help-exclusionPatterns.html: -------------------------------------------------------------------------------- 1 |
2 | A comma separated list of java.util.Regex patterns. If a node has a label that matches one of the patterns in the 3 | list it will be excluded from the grid.

4 | Example: winxp\d,macos.* will exclude all nodes with labels like winxp1, winxp2, macostiger, 5 | macosleopard etc

6 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/help-hubLogLevel.html: -------------------------------------------------------------------------------- 1 |
2 | Selenium Hub can create excessive amount of log messages in the 3 | $JENKINS_HOME/selenium.log on INFO level. Set this to 4 | SEVERE level to reduce the Selenium Hub Disk usage. 5 | The changes will be applied on the next Jenkins start. 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/help-newSessionWaitTimeout.html: -------------------------------------------------------------------------------- 1 |
2 | Time in ms after which a new test waiting for a node to become available will 3 | time out.When that happens, the test will throw an exception before starting 4 | a browser. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/help-port.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the TCP port where Selenium Grid Hub accepts connections from your tests that use Selenium. 3 | Selenium Grid uses 4444 as the default by convention. This port also needs to be accessible from 4 | Selenium RCs, as that's how they communicate with the grid hub. 5 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/help-throwOnCapabilityNotPresent.html: -------------------------------------------------------------------------------- 1 |
2 | If enabled, the hub will reject test requests right away if no proxy is currently registered 3 | that can host that capability. Disable to have the request queued until a node 4 | supporting the capability is added to the grid. 5 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/help-timeout.html: -------------------------------------------------------------------------------- 1 |
2 | Controls how long (value in seconds) the client is allowed to be gone before the session is reclaimed. 3 | Typically takes care of the client crashes. Working together with cleanup cycle (default is 5sec). 4 | Worst case scenario, a session can be idle for timeout + cleanup cycle before the timeout is detected. 5 |
6 | When elapsed the browser will be released for another test to use. 7 | To remove the timeout completely, specify -timeout 0 and the hub will never release the node. 8 | (Can be used when doing step-by-step debugging of client code) 9 |
10 | Default value is 30sec. 11 |
12 | Replaces the -nodeTimeout parameter starting from selenium v2.21.0 13 |

14 | See also: 15 |
https://code.google.com/p/selenium/wiki/Grid2 16 |
https://code.google.com/p/selenium/wiki/RemoteWebDriverServer 17 |
18 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/index.properties: -------------------------------------------------------------------------------- 1 | MissingMasterUrlConfiguration=We were unable to determine the hostname to use for the node to connect to the HUB. Please config Selenium HUB hostname so that Jenkins can launch Selenium RCs. 2 | RunningAt=Running at {0}:{1,number,####}. 3 | ConnectFrom1=Selenium 1 clients should connect as follow: 4 | ConnectFrom2=Selenium 2 clients should connect as follow: 5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/PluginImpl/sidepanel.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/actions/ServiceManagementAction/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Selenium 8 | Configuration 9 |

10 | ${context.setVariable("computer", context.parent.getVariable("from").name.equals("") ? "(master)" : context.parent.getVariable("from").name)} 11 |

Running configurations

12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 33 | 39 | 45 | 61 | 62 | 63 | 64 |
${%Name}${%Status}${%Environment variables}${%JVM options}${%Selenium options}${%Service actions}
${c.key}${c.value.status} 28 | 29 | ${a.key}=${a.value} 30 |
31 |
32 |
34 | 35 | ${a.key}=${a.value} 36 |
37 |
38 |
40 | 41 | ${a} 42 |
43 |
44 |
46 |
47 | 48 | 49 | 50 |
51 |
52 | 53 | 54 | 55 |
56 |
57 | 58 | 59 | 60 |
65 | 66 |

Matching configurations

67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 81 | 84 | 85 | 88 | 102 | 103 | 104 |
Type${%Name}Matching typeDescription summaryActions
79 | ${c.iconAltText} 80 | 82 | ${c.name} 83 | ${c.matcherSummary} 86 | 87 | 89 | 90 |
91 | 92 | 93 | 94 |
95 | 96 |
97 | 98 | 99 | 100 |
101 |
105 |
106 |
107 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/actions/ServiceManagementAction/sidepanel.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/actions/_infotable.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 21 | 24 | 25 | 28 | 29 | 30 | 31 |
TypeDelete${%Name}Matching typeDescription summary
14 | ${c.iconAltText} 15 | 17 | 18 | 19 | 20 | 22 | ${c.name} 23 | ${c.matcherSummary} 26 | 27 |
32 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 34 | 35 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/config_summary.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ${b.maxInstances} instances of ${b.descriptor.displayName} (version : 5 | ${b.version == null || b.version.equals("") ? "Not specified" : b.version}) 6 |
7 |
8 |
9 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-display.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the DISPLAY environment variables so the remote execution can run browsers on a headless server 3 | that has an in-memory X11 server running, XVFB for example. 4 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-port.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the prefered TCP port where this selenium node should accept connections from your tests that use Selenium. 3 | Selenium Grid uses 4444 as the default by convention. If this port is in use already, it will use another random 4 | port. 5 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-rcBrowserSessionReuse.html: -------------------------------------------------------------------------------- 1 |
2 | Stops re-initialization and spawning of the browser between tests. 3 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-rcBrowserSideLog.html: -------------------------------------------------------------------------------- 1 |
2 | Enable this option to see more detailed log messages from the Javascript executed by Selenium Core (browser side). 3 | This option can be used in combination with -log to write the log messages to a file. 4 | See also http://seleniumhq.org/docs/05_selenium_rc.html#server-options 5 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-rcBrowserSideLog_ja.html: -------------------------------------------------------------------------------- 1 |
2 | このオプションを設定すると、Selenium Core(ブラウザ側)で実行されたJavascriptからのより詳細なログメッセージが参照できるようになります。 3 | このオプションと-logを組み合わせて、ファイルにログメッセージを出力することもできます。 4 | http://seleniumhq.org/docs/05_selenium_rc.html#server-optionsを参照してください。 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-rcDebug.html: -------------------------------------------------------------------------------- 1 |
2 | Use this option to get DEBUG level messages in the node console. 3 | This option can be used in combination with -log to write the log messages to a file. 4 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-rcDebug_ja.html: -------------------------------------------------------------------------------- 1 |
2 | このオプションを設定すると、ノードコンソールにDEBUGレベルのメッセージを取り込めるようになります。 3 | このオプションと-logを組み合わせて、ファイルにログメッセージを出力することもできます。 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-rcFirefoxProfileTemplate.html: -------------------------------------------------------------------------------- 1 |
2 | The location of the profile to be used when launching Firefox instances. 3 | See also http://seleniumhq.org/docs/05_selenium_rc.html#server-options 4 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-rcFirefoxProfileTemplate_ja.html: -------------------------------------------------------------------------------- 1 |
2 | Firefoxインスタンスの起動時に使用するプロファイルの場所を設定してください。 3 | http://seleniumhq.org/docs/05_selenium_rc.html#server-optionsを参照してください。 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-rcTrustAllSSLCerts.html: -------------------------------------------------------------------------------- 1 |
2 | Forces the Selenium proxy to skip SSL certificate check and trust all SSL certificates. 3 | Useful when you are using self-signed certificates for testing. 4 | 5 | Note that this option requires a browser running in 6 | the proxy injection mode. 7 | Example browsers are *pifirefox for *firefox and *piiexplore for *iexplore 8 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help-rcTrustAllSSLCerts_ja.html: -------------------------------------------------------------------------------- 1 |
2 | Selenium ProxyがSSLサーバ証明書のチェックをスキップして、すべてのSSLサーバ証明書をTrust扱いします。 3 | これは、テスト用に自己署名証明書(self-signed certificates)を用いているときに役立ちます。 4 | 5 | このオプションを使用する場合は、 6 | proxy injection modeで動作するブラウザが必要になるので注意してください。 7 | 例えば、*firefox用には*pifirefox、*iexplore用には*piiexploreを使用します。 8 |
9 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomRCConfiguration/help_en.html: -------------------------------------------------------------------------------- 1 | Custom configuration defining manually alot of command line parameters normally sent when manually starting a selenium node without a json config file -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomWDConfiguration/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomWDConfiguration/config_summary.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ${b.maxInstances} instances of ${b.descriptor.displayName} (version : 5 | ${b.version == null || b.version.equals("") ? "Not specified" : b.version}) 6 |
7 |
8 |
9 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomWDConfiguration/help-display.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the DISPLAY environment variables so the remote execution can run browsers on a headless server 3 | that has an in-memory X11 server running, XVFB for example. 4 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomWDConfiguration/help-port.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the prefered TCP port where this selenium node should accept connections from your tests that use Selenium. 3 | Selenium Grid uses 4444 as the default by convention. If this port is in use already, it will use another random 4 | port. 5 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/CustomWDConfiguration/help_en.html: -------------------------------------------------------------------------------- 1 | Custom configuration defining manually a lot of command line parameters normally sent when manually starting a selenium node without a json config file -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/DirectJsonInputConfiguration/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/DirectJsonInputConfiguration/config_summary.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | Config : 4 |
5 |         ${it.config}
6 |     
7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/DirectJsonInputConfiguration/help-config.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the JSON config to use for the selenium node. 3 | This config will be written to disk and the file path will be passed to the grid with the -nodeConfig parameter. 4 | See Grid2 and DefaultNode.json 6 | on how to specify a JSON input. 7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/DirectJsonInputConfiguration/help-jvmArgs.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the JVM system properties that will be set. 3 | This is useful to specify webdriver.ie.driver and webdriver.chrome.driver properties. 4 | The expected format is key=value, one per line. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/DirectJsonInputConfiguration/help-seleniumArgs.html: -------------------------------------------------------------------------------- 1 |
2 | Specify additionnal selenium arguments that will be given to the selenium process. 3 | One setting per line. For example : 4 |
5 |     -host ip
6 |     -debug
7 |     
8 |
9 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/DirectJsonInputConfiguration/help_en.html: -------------------------------------------------------------------------------- 1 | Specify a JSON configuration. -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/FileConfiguration/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/FileConfiguration/config_summary.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | Config file : ${it.configURL} 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/FileConfiguration/help-configURL.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the file location of the JSON format config file to setup your node. 3 | This file must have json extension and will be passed to the grid with the -nodeConfig parameter. 4 | This config file path can be configured with any scheme 5 | the URL java class understands. (file:, http:, ftp:, etc.) 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/FileConfiguration/help_en.html: -------------------------------------------------------------------------------- 1 | Specify a configuration that fetches the config file from a remote or local URL. -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/AbstractSeleniumBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/AbstractSeleniumBrowser/help-maxInstances.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the maximum number of instances this browser can handle at the same time. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/AbstractSeleniumBrowser/help-version.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the browser version. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/ChromeBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/ChromeBrowser/help-driverBinaryPath.html: -------------------------------------------------------------------------------- 1 |
2 | Path to the chromedriver executable. This needs to be set only once as it 3 | defines a global property. If you set it in multiple browser definition, the latest 4 | will be used. If you use the Jenkins 5 | chromedriver plugin, 6 | the path will be $JENKINS_HOME/tools/chromedriver/chromedriver.ext 7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/EdgeBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/EdgeBrowser/help-driverBinaryPath.html: -------------------------------------------------------------------------------- 1 |
2 | Path to Edge browser executable. 3 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/FirefoxBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/FirefoxBrowser/help-binaryPath.html: -------------------------------------------------------------------------------- 1 |
2 | Path to Firefox browser executable. 3 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/IEBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/IEBrowser/help-driverBinaryPath.html: -------------------------------------------------------------------------------- 1 |
2 | Path to the IE driver executable. This needs to be set only once as it 3 | defines a global property. If you set it in multiple browser definition, the latest 4 | will be used. 5 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/IEBrowser/help-forbid64bitDriver.html: -------------------------------------------------------------------------------- 1 |
2 | Sometimes 32 bit IE driver should be used for 64 bit OS. 3 | If you set it, 32 bit driver will be uploaded to slave even if 64 bit OS is used. 4 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/OperaBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/selenium/OperaBrowser/help-binaryPath.html: -------------------------------------------------------------------------------- 1 |
2 | Path to opera browser executable. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/ChromeBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/ChromeBrowser/help-driverBinaryPath.html: -------------------------------------------------------------------------------- 1 |
2 | Path to the chromedriver executable. This needs to be set only once as it 3 | defines a global property. If you set it in multiple browser definitions, the latest 4 | will be used. If you use the Jenkins 5 | chromedriver plugin, 6 | the path will be $JENKINS_HOME/tools/chromedriver/chromedriver.ext 7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/EdgeBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/EdgeBrowser/help-driverBinaryPath.html: -------------------------------------------------------------------------------- 1 |
2 | Path to the Edge driver executable. This needs to be set only once as it 3 | defines a global property. If you set it in multiple browser definition, the latest 4 | will be used. 5 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/FirefoxBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/FirefoxBrowser/help-binaryPath.html: -------------------------------------------------------------------------------- 1 |
2 | Path to Firefox browser executable. 3 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/HTMLUnitBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/HTMLUnitBrowser/help-maxInstances.html: -------------------------------------------------------------------------------- 1 |
2 | Specify the maximum number of instances this browser can handle at the same time. Default to 5. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/IEBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/IEBrowser/help-driverBinaryPath.html: -------------------------------------------------------------------------------- 1 |
2 | Path to the IE driver executable. This needs to be set only once as it 3 | defines a global property. If you set it in multiple browser definition, the latest 4 | will be used. 5 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/IEBrowser/help-forbid64bitDriver.html: -------------------------------------------------------------------------------- 1 |
2 | Sometimes 32 bit IE driver should be used for 64 bit OS. 3 | If you set it, 32 bit driver will be uploaded to slave even if 64 bit OS is used. 4 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/OperaBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/OperaBrowser/help-binaryPath.html: -------------------------------------------------------------------------------- 1 |
2 | Path to opera browser executable. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/browser/webdriver/SafariBrowser/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/SeleniumGlobalConfiguration/delete.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | ${%delete_confirm(it.name)} 8 | 9 | 10 |
11 |
12 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/SeleniumGlobalConfiguration/delete.properties: -------------------------------------------------------------------------------- 1 | delete_confirm=Are you sure about deleting the configuration ''{0}''? -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/SeleniumGlobalConfiguration/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

${it.descriptor.displayName}

7 | 8 | 9 | 10 | 11 | 12 | 15 | 18 | 19 |
20 |
21 | 22 |
23 |
24 |
25 |
26 |
27 |
28 |
-------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/SeleniumGlobalConfiguration/sidepanel.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/hostname/JenkinsRootHostnameResolver/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/hostname/JenkinsRootHostnameResolver/help_en.html: -------------------------------------------------------------------------------- 1 | This retriever will use the hostname defined in the "Jenkins URL" field. -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/hostname/StaticHostnameResolver/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/hostname/StaticHostnameResolver/help_en.html: -------------------------------------------------------------------------------- 1 | This will use the specified hostname to tell the node where to connect to the hub -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/matcher/MatchAllMatcher/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/matcher/MatchAllMatcher/help_en.html: -------------------------------------------------------------------------------- 1 | Apply this configuration on all nodes -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/matcher/MatchNoneMatcher/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/matcher/MatchNoneMatcher/help_en.html: -------------------------------------------------------------------------------- 1 | Don't apply this configuration on any node -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/matcher/NodeLabelMatcher/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/hudson/plugins/selenium/configuration/global/matcher/NodeLabelMatcher/help_en.html: -------------------------------------------------------------------------------- 1 | Apply this configuration on all nodes matching the specified label expression -------------------------------------------------------------------------------- /src/main/webapp/16x16/MicrosoftEdge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/16x16/MicrosoftEdge.png -------------------------------------------------------------------------------- /src/main/webapp/16x16/chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/16x16/chrome.png -------------------------------------------------------------------------------- /src/main/webapp/16x16/firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/16x16/firefox.png -------------------------------------------------------------------------------- /src/main/webapp/16x16/internet explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/16x16/internet explorer.png -------------------------------------------------------------------------------- /src/main/webapp/16x16/opera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/16x16/opera.png -------------------------------------------------------------------------------- /src/main/webapp/16x16/safari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/16x16/safari.png -------------------------------------------------------------------------------- /src/main/webapp/24x24/internet-web-browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/24x24/internet-web-browser.png -------------------------------------------------------------------------------- /src/main/webapp/24x24/selenium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/24x24/selenium.png -------------------------------------------------------------------------------- /src/main/webapp/48x48/selenium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/48x48/selenium.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/animated-overlay.gif -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /src/main/webapp/css/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/selenium-plugin/63e2d642d480810a43c6d8bf93bfb4a6d7704567/src/main/webapp/css/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /src/main/webapp/css/selenium.css: -------------------------------------------------------------------------------- 1 | #proxies { 2 | margin-top: 25px; 3 | } 4 | 5 | .ui-state-active { 6 | background: #AAA url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x !important; 7 | } 8 | 9 | #proxies .browser-category { 10 | margin: 5px; 11 | } 12 | 13 | .session-busy { 14 | opacity: 0.4; 15 | filter:alpha(opacity=40); 16 | } 17 | 18 | .ui-accordion-header { 19 | font-size: 11px !important; 20 | } 21 | 22 | .nobreak { 23 | white-space: nowrap; 24 | } 25 | 26 | .binfo { 27 | margin: 0 3px; 28 | } 29 | 30 | .actions form { 31 | display: inline-block; 32 | } 33 | 34 | .ui-button.ui-state-default { 35 | border: #999 solid 1px; 36 | } 37 | 38 | .ui-button-text { 39 | background-color: #ddd; 40 | 41 | } 42 | 43 | .configuration-info { 44 | font-size: 11px; 45 | } 46 | 47 | .options-title { 48 | font-size: 14px; 49 | font-weight: 600; 50 | padding: 5px; 51 | } --------------------------------------------------------------------------------