From 9d462acab09508a4d6f5936f4b590be3707b853a Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Tue, 21 Mar 2017 10:43:05 +0100 Subject: [PATCH 1/8] [BUA-925] Creating docker-selenium node with custom capabilities. --- .../DockerSeleniumStarterRemoteProxy.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java index 2b2448db03..81bed543a2 100644 --- a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java +++ b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java @@ -308,6 +308,9 @@ public TestSession getNewSession(Map requestedCapability) { return null; } + // Check and configure specific screen resolution capabilities when they have been passed in the test config. + configureScreenResolutionFromCapabilities(requestedCapability); + LOGGER.log(Level.INFO, LOGGING_PREFIX + "Starting new node for {0}.", requestedCapability); String browserName = requestedCapability.get(CapabilityType.BROWSER_NAME).toString(); @@ -453,6 +456,47 @@ private void createStartupContainers() { }).start(); } + /* + This method will search for a screenResolution capability to be passed when creating a docker-selenium node. + */ + private void configureScreenResolutionFromCapabilities(Map requestedCapability) { + int configuredScreenWidth = env.getIntEnvVariable(ZALENIUM_SCREEN_WIDTH, DEFAULT_SCREEN_WIDTH); + int configuredScreenHeight = env.getIntEnvVariable(ZALENIUM_SCREEN_HEIGHT, DEFAULT_SCREEN_HEIGHT); + + boolean wasConfiguredScreenWidthAndHeightChanged = false; + String[] screenResolutionNames = {"screenResolution", "resolution", "screen-resolution"}; + for (String screenResolutionName : screenResolutionNames) { + if (requestedCapability.containsKey(screenResolutionName)) { + String screenResolution = requestedCapability.get(screenResolutionName).toString(); + try { + int screenWidth = Integer.parseInt(screenResolution.split("x")[0]); + int screenHeight = Integer.parseInt(screenResolution.split("x")[1]); + if (screenWidth > 0 && screenHeight > 0) { + setScreenHeight(screenHeight); + setScreenWidth(screenWidth); + wasConfiguredScreenWidthAndHeightChanged = true; + } else { + setScreenWidth(configuredScreenWidth); + setScreenHeight(configuredScreenHeight); + LOGGER.log(Level.FINE, "One of the values provided for screenResolution is negative, " + + "defaults will be used. Passed value -> " + screenResolution); + } + } catch (Exception e) { + setScreenWidth(configuredScreenWidth); + setScreenHeight(configuredScreenHeight); + LOGGER.log(Level.FINE, "Values provided for screenResolution are not valid integers or " + + "either the width or the height is missing, defaults will be used. Passed value -> " + + screenResolution); + } + } + } + // If the screen resolution parameters were not changed, we just set the defaults again. + if (!wasConfiguredScreenWidthAndHeightChanged) { + setScreenWidth(configuredScreenWidth); + setScreenHeight(configuredScreenHeight); + } + } + private int getNumberOfRunningContainers() { try { List containerList = dockerClient.listContainers(DockerClient.ListContainersParam.allContainers()); From 653793bd5dde7b0673016c9b608dd20e2694bacb Mon Sep 17 00:00:00 2001 From: Leo Gallucci Date: Tue, 21 Mar 2017 10:52:36 +0100 Subject: [PATCH 2/8] [BUA-984] Upgrade SauceConnect 4.4.5 --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index d4aa23c499..588f59a4c9 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -291,8 +291,8 @@ RUN set -x \ # Sauce Connect Tunneling # # ------------------------# # https://docs.saucelabs.com/reference/sauce-connect/ -# Layer size: medium: 12.42 MB -ENV SAUCE_CONN_VER="sc-4.4.4-linux" \ +# Layer size: medium: ~13 MB +ENV SAUCE_CONN_VER="sc-4.4.5-linux" \ SAUCE_CONN_DOWN_URL="https://saucelabs.com/downloads" RUN cd /tmp \ && wget -nv "${SAUCE_CONN_DOWN_URL}/${SAUCE_CONN_VER}.tar.gz" \ From e11f17d8dddd29a0e6e67eeeda6c4cee7eed6b55 Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Tue, 21 Mar 2017 11:44:07 +0100 Subject: [PATCH 3/8] [BUA-925] Improving the capability matcher to match screen resolution. --- .../proxy/DockerSeleniumRemoteProxy.java | 10 ++++++ .../DockerSeleniumStarterRemoteProxy.java | 2 +- .../util/DockerSeleniumCapabilityMatcher.java | 34 +++++++++++++++++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxy.java b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxy.java index b86230b025..2458d636c1 100644 --- a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxy.java +++ b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxy.java @@ -18,6 +18,7 @@ import org.openqa.grid.internal.SessionTerminationReason; import org.openqa.grid.internal.TestSession; import org.openqa.grid.internal.TestSlot; +import org.openqa.grid.internal.utils.CapabilityMatcher; import org.openqa.grid.selenium.proxy.DefaultRemoteProxy; import org.openqa.grid.web.servlet.handler.RequestType; import org.openqa.grid.web.servlet.handler.WebDriverRequest; @@ -64,6 +65,7 @@ public class DockerSeleniumRemoteProxy extends DefaultRemoteProxy { private boolean stopSessionRequestReceived = false; private DockerSeleniumNodePoller dockerSeleniumNodePollerThread = null; private GoogleAnalyticsApi ga = new GoogleAnalyticsApi(); + private CapabilityMatcher capabilityHelper; public DockerSeleniumRemoteProxy(RegistrationRequest request, Registry registry) { super(request, registry); @@ -136,6 +138,14 @@ public TestSession getNewSession(Map requestedCapability) { return null; } + @Override + public CapabilityMatcher getCapabilityHelper() { + if (capabilityHelper == null) { + capabilityHelper = new DockerSeleniumCapabilityMatcher(this); + } + return capabilityHelper; + } + private long getConfiguredIdleTimeout(Map requestedCapability) { long configuredIdleTimeout; try { diff --git a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java index 81bed543a2..59ade62f7c 100644 --- a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java +++ b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java @@ -337,7 +337,7 @@ public void beforeRegistration() { @Override public CapabilityMatcher getCapabilityHelper() { if (capabilityHelper == null) { - capabilityHelper = new DockerSeleniumCapabilityMatcher(); + capabilityHelper = new DockerSeleniumCapabilityMatcher(this); } return capabilityHelper; } diff --git a/src/main/java/de/zalando/tip/zalenium/util/DockerSeleniumCapabilityMatcher.java b/src/main/java/de/zalando/tip/zalenium/util/DockerSeleniumCapabilityMatcher.java index b1283992a7..a541746c3b 100644 --- a/src/main/java/de/zalando/tip/zalenium/util/DockerSeleniumCapabilityMatcher.java +++ b/src/main/java/de/zalando/tip/zalenium/util/DockerSeleniumCapabilityMatcher.java @@ -1,6 +1,8 @@ package de.zalando.tip.zalenium.util; +import de.zalando.tip.zalenium.proxy.DockerSeleniumRemoteProxy; import org.openqa.grid.internal.utils.DefaultCapabilityMatcher; +import org.openqa.grid.selenium.proxy.DefaultRemoteProxy; import org.openqa.selenium.remote.CapabilityType; import java.util.Map; @@ -13,6 +15,13 @@ public class DockerSeleniumCapabilityMatcher extends DefaultCapabilityMatcher { private static final Logger logger = Logger.getLogger(DockerSeleniumCapabilityMatcher.class.getName()); + private DefaultRemoteProxy proxy; + + public DockerSeleniumCapabilityMatcher(DefaultRemoteProxy defaultRemoteProxy) { + super(); + proxy = defaultRemoteProxy; + } + @Override public boolean matches(Map nodeCapability, Map requestedCapability) { logger.log(Level.FINE, ()-> String.format("Validating %s in node with capabilities %s", requestedCapability, @@ -23,18 +32,37 @@ public boolean matches(Map nodeCapability, Map r without the version. If not, we put the requested capability back in the requestedCapability object, so it can be matched by any of the Cloud Testing Providers. */ + boolean browserVersionCapabilityMatches = false; if (requestedCapability.containsKey(CapabilityType.VERSION)) { String requestedVersion = requestedCapability.get(CapabilityType.VERSION).toString(); if ("latest".equalsIgnoreCase(requestedVersion)) { requestedCapability.remove(CapabilityType.VERSION); if (super.matches(nodeCapability, requestedCapability)) { - return true; + browserVersionCapabilityMatches = true; } else { requestedCapability.put(CapabilityType.VERSION, requestedVersion); - return false; } } } - return super.matches(nodeCapability, requestedCapability); + + boolean screenResolutionCapabilityMatches = true; + // This validation is only done for docker-selenium nodes + if (proxy instanceof DockerSeleniumRemoteProxy) { + String[] screenResolutionNames = {"screenResolution", "resolution", "screen-resolution"}; + for (String screenResolutionName : screenResolutionNames) { + if (requestedCapability.containsKey(screenResolutionName)) { + screenResolutionCapabilityMatches = nodeCapability.containsKey(screenResolutionName) && + requestedCapability.get(screenResolutionName).equals(nodeCapability.get(screenResolutionName)); + } + } + } + + // If the browser version has been matched, then implicitly the matcher from the super class has also been + // invoked. + if (browserVersionCapabilityMatches) { + return screenResolutionCapabilityMatches; + } else { + return super.matches(nodeCapability, requestedCapability) && screenResolutionCapabilityMatches; + } } } From 2575b6363791cce172a3eda892db419497e0c931 Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Tue, 21 Mar 2017 15:09:56 +0100 Subject: [PATCH 4/8] [BUA-925] Adding a mark to the capabilities in order to avoid creating too many containers, helps #73 --- .../DockerSeleniumStarterRemoteProxy.java | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java index 59ade62f7c..b5bf817fb5 100644 --- a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java +++ b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java @@ -311,14 +311,33 @@ public TestSession getNewSession(Map requestedCapability) { // Check and configure specific screen resolution capabilities when they have been passed in the test config. configureScreenResolutionFromCapabilities(requestedCapability); - LOGGER.log(Level.INFO, LOGGING_PREFIX + "Starting new node for {0}.", requestedCapability); - String browserName = requestedCapability.get(CapabilityType.BROWSER_NAME).toString(); /* Here a docker-selenium container will be started and it will register to the hub + We check first if a node has been created for this request already. If so, we skip it + but increment the number of times it has been received. In case something went wrong with the node + creation, we remove the mark* after 10 times and we create a node again. + * The mark is an added custom capability */ - startDockerSeleniumContainer(browserName); + String waitingForNode = String.format("waitingFor_%s_Node", browserName.toUpperCase()); + if (!requestedCapability.containsKey(waitingForNode)) { + LOGGER.log(Level.INFO, LOGGING_PREFIX + "Starting new node for {0}.", requestedCapability); + startDockerSeleniumContainer(browserName); + requestedCapability.put(waitingForNode, 1); + } else { + int attempts = (int) requestedCapability.get(waitingForNode); + attempts++; + if (attempts >= 20) { + LOGGER.log(Level.INFO, LOGGING_PREFIX + "Request has waited 20 attempts for a node, something " + + "went wrong with the previous attempts, creating a new node for {0}.", requestedCapability); + startDockerSeleniumContainer(browserName); + requestedCapability.put(waitingForNode, 1); + } else { + requestedCapability.put(waitingForNode, attempts); + LOGGER.log(Level.INFO, LOGGING_PREFIX + "Request waiting for a node new node for {0}.", requestedCapability); + } + } return null; } @@ -491,9 +510,13 @@ private void configureScreenResolutionFromCapabilities(Map reque } } // If the screen resolution parameters were not changed, we just set the defaults again. + // Also in the capabilities, to avoid the situation where a request grabs the node from other request + // just because the platform, version, and browser match. if (!wasConfiguredScreenWidthAndHeightChanged) { setScreenWidth(configuredScreenWidth); setScreenHeight(configuredScreenHeight); + String screenResolution = String.format("%sx%s", getScreenWidth(), getScreenHeight()); + requestedCapability.put("screenResolution", screenResolution); } } From 9eabde4bc24a15d1c596e89ba0ded4991ad7b004 Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Tue, 21 Mar 2017 15:28:30 +0100 Subject: [PATCH 5/8] [BUA-925] Adding documentation on how to use the new screenResolution capability. --- docs/usage_examples.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/usage_examples.md b/docs/usage_examples.md index 72f828e847..b680538018 100644 --- a/docs/usage_examples.md +++ b/docs/usage_examples.md @@ -25,6 +25,7 @@ * [Test name](#test-name) * [Group name](#group-name) * [Idle Timeout](#idle-timeout) + * [Screen resolution](#screen-resolution) ## Initial setup @@ -246,4 +247,16 @@ capability in your test. Example code in Java for the capability (it sets the `i desiredCapabilities.setCapability("idleTimeout", 150); ``` +### Screen resolution +You can pass a custom screen resolution for your test, just include a `screenResolution` with the desired value. E.g. +`screenResolution=1280x1024`. Also supported for the same purpose `resolution` and `screen-resolution`. Example code +in Java for the capability `screenResolution` + + ```java + DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); + desiredCapabilities.setCapability(CapabilityType.BROWSER_NAME, BrowserType.FIREFOX); + desiredCapabilities.setCapability(CapabilityType.PLATFORM, Platform.LINUX); + desiredCapabilities.setCapability("screenResolution", "1280x720"); + ``` + From 423dad946856d1624e2173db5ddb1be002e6c515 Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Tue, 21 Mar 2017 16:51:13 +0100 Subject: [PATCH 6/8] [BUA-925] Adding default screenResolution for requests missing it. --- .../proxy/DockerSeleniumRemoteProxy.java | 4 +- .../DockerSeleniumStarterRemoteProxy.java | 40 ++++++++++++++----- .../util/DockerSeleniumCapabilityMatcher.java | 13 +++++- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxy.java b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxy.java index 2458d636c1..f4ba5eba0d 100644 --- a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxy.java +++ b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxy.java @@ -342,7 +342,7 @@ void copyVideos(final String containerId) throws IOException, DockerException, I IOUtils.copy(tarStream, outputStream); outputStream.close(); Dashboard.updateDashboard(testInformation); - LOGGER.log(Level.INFO, "{0} Video files copies to: {1}", new Object[]{getId(), + LOGGER.log(Level.INFO, "{0} Video files copied to: {1}", new Object[]{getId(), testInformation.getVideoFolderPath()}); } } catch (Exception e) { @@ -409,6 +409,8 @@ public void run() { "thread, stopping thread execution.", e); Thread.currentThread().interrupt(); dockerSeleniumRemoteProxy.ga.trackException(e); + dockerSeleniumRemoteProxy.stopPolling(); + dockerSeleniumRemoteProxy.startPolling(); return; } } diff --git a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java index b5bf817fb5..99ff4e6a30 100644 --- a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java +++ b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java @@ -81,7 +81,9 @@ public class DockerSeleniumStarterRemoteProxy extends DefaultRemoteProxy impleme private static int firefoxContainersOnStartup; private static int maxDockerSeleniumContainers; private static String timeZone; + private static int configuredScreenWidth; private static int screenWidth; + private static int configuredScreenHeight; private static int screenHeight; private static String containerName; private List allocatedPorts = new ArrayList<>(); @@ -110,9 +112,11 @@ private static void readConfigurationFromEnvVariables() { int sWidth = env.getIntEnvVariable(ZALENIUM_SCREEN_WIDTH, DEFAULT_SCREEN_WIDTH); setScreenWidth(sWidth); + setConfiguredScreenWidth(sWidth); int sHeight = env.getIntEnvVariable(ZALENIUM_SCREEN_HEIGHT, DEFAULT_SCREEN_HEIGHT); setScreenHeight(sHeight); + setConfiguredScreenHeight(sHeight); String tz = env.getStringEnvVariable(ZALENIUM_TZ, DEFAULT_TZ); setTimeZone(tz); @@ -263,6 +267,22 @@ protected static void setScreenHeight(int screenHeight) { DockerSeleniumStarterRemoteProxy.screenHeight = screenHeight <= 0 ? DEFAULT_SCREEN_HEIGHT : screenHeight; } + public static int getConfiguredScreenWidth() { + return configuredScreenWidth; + } + + public static void setConfiguredScreenWidth(int configuredScreenWidth) { + DockerSeleniumStarterRemoteProxy.configuredScreenWidth = configuredScreenWidth; + } + + public static int getConfiguredScreenHeight() { + return configuredScreenHeight; + } + + public static void setConfiguredScreenHeight(int configuredScreenHeight) { + DockerSeleniumStarterRemoteProxy.configuredScreenHeight = configuredScreenHeight; + } + @VisibleForTesting protected static void setEnv(final Environment env) { DockerSeleniumStarterRemoteProxy.env = env; @@ -323,13 +343,14 @@ public TestSession getNewSession(Map requestedCapability) { String waitingForNode = String.format("waitingFor_%s_Node", browserName.toUpperCase()); if (!requestedCapability.containsKey(waitingForNode)) { LOGGER.log(Level.INFO, LOGGING_PREFIX + "Starting new node for {0}.", requestedCapability); - startDockerSeleniumContainer(browserName); - requestedCapability.put(waitingForNode, 1); + if (startDockerSeleniumContainer(browserName)) { + requestedCapability.put(waitingForNode, 1); + } } else { int attempts = (int) requestedCapability.get(waitingForNode); attempts++; - if (attempts >= 20) { - LOGGER.log(Level.INFO, LOGGING_PREFIX + "Request has waited 20 attempts for a node, something " + + if (attempts >= 10) { + LOGGER.log(Level.INFO, LOGGING_PREFIX + "Request has waited 10 attempts for a node, something " + "went wrong with the previous attempts, creating a new node for {0}.", requestedCapability); startDockerSeleniumContainer(browserName); requestedCapability.put(waitingForNode, 1); @@ -479,9 +500,6 @@ private void createStartupContainers() { This method will search for a screenResolution capability to be passed when creating a docker-selenium node. */ private void configureScreenResolutionFromCapabilities(Map requestedCapability) { - int configuredScreenWidth = env.getIntEnvVariable(ZALENIUM_SCREEN_WIDTH, DEFAULT_SCREEN_WIDTH); - int configuredScreenHeight = env.getIntEnvVariable(ZALENIUM_SCREEN_HEIGHT, DEFAULT_SCREEN_HEIGHT); - boolean wasConfiguredScreenWidthAndHeightChanged = false; String[] screenResolutionNames = {"screenResolution", "resolution", "screen-resolution"}; for (String screenResolutionName : screenResolutionNames) { @@ -495,8 +513,8 @@ private void configureScreenResolutionFromCapabilities(Map reque setScreenWidth(screenWidth); wasConfiguredScreenWidthAndHeightChanged = true; } else { - setScreenWidth(configuredScreenWidth); - setScreenHeight(configuredScreenHeight); + setScreenWidth(getConfiguredScreenWidth()); + setScreenHeight(getConfiguredScreenHeight()); LOGGER.log(Level.FINE, "One of the values provided for screenResolution is negative, " + "defaults will be used. Passed value -> " + screenResolution); } @@ -513,8 +531,8 @@ private void configureScreenResolutionFromCapabilities(Map reque // Also in the capabilities, to avoid the situation where a request grabs the node from other request // just because the platform, version, and browser match. if (!wasConfiguredScreenWidthAndHeightChanged) { - setScreenWidth(configuredScreenWidth); - setScreenHeight(configuredScreenHeight); + setScreenWidth(getConfiguredScreenWidth()); + setScreenHeight(getConfiguredScreenHeight()); String screenResolution = String.format("%sx%s", getScreenWidth(), getScreenHeight()); requestedCapability.put("screenResolution", screenResolution); } diff --git a/src/main/java/de/zalando/tip/zalenium/util/DockerSeleniumCapabilityMatcher.java b/src/main/java/de/zalando/tip/zalenium/util/DockerSeleniumCapabilityMatcher.java index a541746c3b..e9d0ed72a6 100644 --- a/src/main/java/de/zalando/tip/zalenium/util/DockerSeleniumCapabilityMatcher.java +++ b/src/main/java/de/zalando/tip/zalenium/util/DockerSeleniumCapabilityMatcher.java @@ -1,6 +1,7 @@ package de.zalando.tip.zalenium.util; import de.zalando.tip.zalenium.proxy.DockerSeleniumRemoteProxy; +import de.zalando.tip.zalenium.proxy.DockerSeleniumStarterRemoteProxy; import org.openqa.grid.internal.utils.DefaultCapabilityMatcher; import org.openqa.grid.selenium.proxy.DefaultRemoteProxy; import org.openqa.selenium.remote.CapabilityType; @@ -13,8 +14,7 @@ * The purpose of this class is to let docker-selenium process requests where a capability "version=latest" is present */ public class DockerSeleniumCapabilityMatcher extends DefaultCapabilityMatcher { - private static final Logger logger = Logger.getLogger(DockerSeleniumCapabilityMatcher.class.getName()); - + private final Logger logger = Logger.getLogger(DockerSeleniumCapabilityMatcher.class.getName()); private DefaultRemoteProxy proxy; public DockerSeleniumCapabilityMatcher(DefaultRemoteProxy defaultRemoteProxy) { @@ -46,6 +46,7 @@ public boolean matches(Map nodeCapability, Map r } boolean screenResolutionCapabilityMatches = true; + boolean containsScreenResolutionCapability = false; // This validation is only done for docker-selenium nodes if (proxy instanceof DockerSeleniumRemoteProxy) { String[] screenResolutionNames = {"screenResolution", "resolution", "screen-resolution"}; @@ -53,8 +54,16 @@ public boolean matches(Map nodeCapability, Map r if (requestedCapability.containsKey(screenResolutionName)) { screenResolutionCapabilityMatches = nodeCapability.containsKey(screenResolutionName) && requestedCapability.get(screenResolutionName).equals(nodeCapability.get(screenResolutionName)); + containsScreenResolutionCapability = true; } } + // This is done to avoid having the test run on a node with a configured screen resolution different from + // the global configured one. But not putting it to tests that should go to a cloud provider. + if (!containsScreenResolutionCapability && super.matches(nodeCapability, requestedCapability)) { + String screenResolution = String.format("%sx%s", DockerSeleniumStarterRemoteProxy.getConfiguredScreenWidth(), + DockerSeleniumStarterRemoteProxy.getConfiguredScreenHeight()); + requestedCapability.put("screenResolution", screenResolution); + } } // If the browser version has been matched, then implicitly the matcher from the super class has also been From 0b12a99b55388ba490928f322759e5cd9d428208 Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Tue, 21 Mar 2017 17:09:22 +0100 Subject: [PATCH 7/8] [BUA-925] Forcing container creation when it has been waiting too. long. --- pom.xml | 4 ++-- .../proxy/DockerSeleniumStarterRemoteProxy.java | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index e06368ed23..ce03c516ec 100644 --- a/pom.xml +++ b/pom.xml @@ -52,10 +52,10 @@ 0 8.1.2 4.12 - 2.7.17 + 2.7.18 2.0.0 6.11 - 1.7.24 + 1.7.25 2.19.1 1.8 1.8 diff --git a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java index 99ff4e6a30..8479f580dc 100644 --- a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java +++ b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java @@ -349,10 +349,10 @@ public TestSession getNewSession(Map requestedCapability) { } else { int attempts = (int) requestedCapability.get(waitingForNode); attempts++; - if (attempts >= 10) { - LOGGER.log(Level.INFO, LOGGING_PREFIX + "Request has waited 10 attempts for a node, something " + + if (attempts >= 20) { + LOGGER.log(Level.INFO, LOGGING_PREFIX + "Request has waited 20 attempts for a node, something " + "went wrong with the previous attempts, creating a new node for {0}.", requestedCapability); - startDockerSeleniumContainer(browserName); + startDockerSeleniumContainer(browserName, true); requestedCapability.put(waitingForNode, 1); } else { requestedCapability.put(waitingForNode, attempts); @@ -391,10 +391,14 @@ public float getResourceUsageInPercent() { return 98; } - @VisibleForTesting boolean startDockerSeleniumContainer(String browser) { + return startDockerSeleniumContainer(browser, false); + } + + @VisibleForTesting + boolean startDockerSeleniumContainer(String browser, boolean forceCreation) { - if (validateAmountOfDockerSeleniumContainers()) { + if (validateAmountOfDockerSeleniumContainers() || forceCreation) { String hostIpAddress = "localhost"; From 552f955c117d76d5fb0df2b11c3e55e53c1a2911 Mon Sep 17 00:00:00 2001 From: Diego Molina Date: Tue, 21 Mar 2017 18:21:41 +0100 Subject: [PATCH 8/8] [BUA-925] Adding and fixing unit tests. --- .../DockerSeleniumStarterRemoteProxy.java | 8 +- .../proxy/DockerSeleniumRemoteProxyTest.java | 2 +- .../DockerSeleniumStarterRemoteProxyTest.java | 98 +++++++++++++++++++ .../zalando/tip/zalenium/util/TestUtils.java | 23 +++++ 4 files changed, 126 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java index 8479f580dc..dc36f278d4 100644 --- a/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java +++ b/src/main/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxy.java @@ -268,7 +268,7 @@ protected static void setScreenHeight(int screenHeight) { } public static int getConfiguredScreenWidth() { - return configuredScreenWidth; + return configuredScreenWidth <= 0 ? DEFAULT_SCREEN_WIDTH : configuredScreenWidth; } public static void setConfiguredScreenWidth(int configuredScreenWidth) { @@ -276,7 +276,7 @@ public static void setConfiguredScreenWidth(int configuredScreenWidth) { } public static int getConfiguredScreenHeight() { - return configuredScreenHeight; + return configuredScreenHeight <= 0 ? DEFAULT_SCREEN_HEIGHT : configuredScreenHeight; } public static void setConfiguredScreenHeight(int configuredScreenHeight) { @@ -523,8 +523,8 @@ private void configureScreenResolutionFromCapabilities(Map reque "defaults will be used. Passed value -> " + screenResolution); } } catch (Exception e) { - setScreenWidth(configuredScreenWidth); - setScreenHeight(configuredScreenHeight); + setScreenWidth(getConfiguredScreenWidth()); + setScreenHeight(getConfiguredScreenHeight()); LOGGER.log(Level.FINE, "Values provided for screenResolution are not valid integers or " + "either the width or the height is missing, defaults will be used. Passed value -> " + screenResolution); diff --git a/src/test/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxyTest.java b/src/test/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxyTest.java index dd83d9b8ef..a0474e3edc 100644 --- a/src/test/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxyTest.java +++ b/src/test/java/de/zalando/tip/zalenium/proxy/DockerSeleniumRemoteProxyTest.java @@ -49,7 +49,7 @@ public void setUp() throws DockerException, InterruptedException, IOException { RegistrationRequest request = TestUtils.getRegistrationRequestForTesting(40000, DockerSeleniumRemoteProxy.class.getCanonicalName()); request.getConfiguration().capabilities.clear(); - request.getConfiguration().capabilities.addAll(DockerSeleniumStarterRemoteProxy.getCapabilities()); + request.getConfiguration().capabilities.addAll(TestUtils.getDockerSeleniumCapabilitiesForTesting()); // Creating the proxy proxy = DockerSeleniumRemoteProxy.getNewInstance(request, registry); diff --git a/src/test/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxyTest.java b/src/test/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxyTest.java index 5c3c1ea572..32111eaaba 100644 --- a/src/test/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxyTest.java +++ b/src/test/java/de/zalando/tip/zalenium/proxy/DockerSeleniumStarterRemoteProxyTest.java @@ -26,6 +26,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.times; @@ -127,6 +128,80 @@ public void containerIsStartedWhenBrowserIsSupportedAndLatestIsUsedAsBrowserVers verify(spyProxy, times(1)).startDockerSeleniumContainer(BrowserType.CHROME); } + @Test + public void containerIsStartedWhenScreenResolutionIsProvided() { + // Supported desired capability for the test session + Map supportedCapability = new HashMap<>(); + supportedCapability.put(CapabilityType.BROWSER_NAME, BrowserType.FIREFOX); + supportedCapability.put(CapabilityType.PLATFORM, Platform.ANY); + supportedCapability.put("screenResolution", "1280x760"); + TestSession testSession = spyProxy.getNewSession(supportedCapability); + Assert.assertNull(testSession); + verify(spyProxy, times(1)).startDockerSeleniumContainer(BrowserType.FIREFOX); + Assert.assertEquals(1280, DockerSeleniumStarterRemoteProxy.getScreenWidth()); + Assert.assertEquals(760, DockerSeleniumStarterRemoteProxy.getScreenHeight()); + } + + @Test + public void containerIsStartedWhenResolutionIsProvided() { + // Supported desired capability for the test session + Map supportedCapability = new HashMap<>(); + supportedCapability.put(CapabilityType.BROWSER_NAME, BrowserType.CHROME); + supportedCapability.put(CapabilityType.PLATFORM, Platform.ANY); + supportedCapability.put("resolution", "1300x900"); + TestSession testSession = spyProxy.getNewSession(supportedCapability); + Assert.assertNull(testSession); + verify(spyProxy, times(1)).startDockerSeleniumContainer(BrowserType.CHROME); + Assert.assertEquals(1300, DockerSeleniumStarterRemoteProxy.getScreenWidth()); + Assert.assertEquals(900, DockerSeleniumStarterRemoteProxy.getScreenHeight()); + } + + @Test + public void containerIsStartedWhenCustomScreenResolutionIsProvided() { + // Supported desired capability for the test session + Map supportedCapability = new HashMap<>(); + supportedCapability.put(CapabilityType.BROWSER_NAME, BrowserType.FIREFOX); + supportedCapability.put(CapabilityType.PLATFORM, Platform.ANY); + supportedCapability.put("screen-resolution", "1500x1000"); + TestSession testSession = spyProxy.getNewSession(supportedCapability); + Assert.assertNull(testSession); + verify(spyProxy, times(1)).startDockerSeleniumContainer(BrowserType.FIREFOX); + Assert.assertEquals(1500, DockerSeleniumStarterRemoteProxy.getScreenWidth()); + Assert.assertEquals(1000, DockerSeleniumStarterRemoteProxy.getScreenHeight()); + } + + @Test + public void containerIsStartedWhenNegativeResolutionIsProvidedUsingDefaults() { + // Supported desired capability for the test session + Map supportedCapability = new HashMap<>(); + supportedCapability.put(CapabilityType.BROWSER_NAME, BrowserType.CHROME); + supportedCapability.put(CapabilityType.PLATFORM, Platform.ANY); + supportedCapability.put("resolution", "-1300x800"); + TestSession testSession = spyProxy.getNewSession(supportedCapability); + Assert.assertNull(testSession); + verify(spyProxy, times(1)).startDockerSeleniumContainer(BrowserType.CHROME); + Assert.assertEquals(DockerSeleniumStarterRemoteProxy.getConfiguredScreenWidth(), + DockerSeleniumStarterRemoteProxy.getScreenWidth()); + Assert.assertEquals(DockerSeleniumStarterRemoteProxy.getConfiguredScreenHeight(), + DockerSeleniumStarterRemoteProxy.getScreenHeight()); + } + + @Test + public void containerIsStartedWhenAnInvalidResolutionIsProvidedUsingDefaults() { + // Supported desired capability for the test session + Map supportedCapability = new HashMap<>(); + supportedCapability.put(CapabilityType.BROWSER_NAME, BrowserType.CHROME); + supportedCapability.put(CapabilityType.PLATFORM, Platform.ANY); + supportedCapability.put("screenResolution", "notAValidScreenResolution"); + TestSession testSession = spyProxy.getNewSession(supportedCapability); + Assert.assertNull(testSession); + verify(spyProxy, times(1)).startDockerSeleniumContainer(BrowserType.CHROME); + Assert.assertEquals(DockerSeleniumStarterRemoteProxy.getConfiguredScreenWidth(), + DockerSeleniumStarterRemoteProxy.getScreenWidth()); + Assert.assertEquals(DockerSeleniumStarterRemoteProxy.getConfiguredScreenHeight(), + DockerSeleniumStarterRemoteProxy.getScreenHeight()); + } + @Test public void containerIsStartedWhenFirefoxCapabilitiesAreSupported() { @@ -151,6 +226,29 @@ public void noContainerIsStartedWhenBrowserCapabilityIsAbsent() { verify(spyProxy, never()).startDockerSeleniumContainer(anyString()); } + @Test + public void noContainerIsStartedForAlreadyProcessedRequest() { + Map requestedCapability = new HashMap<>(); + requestedCapability.put(CapabilityType.BROWSER_NAME, BrowserType.CHROME); + requestedCapability.put(CapabilityType.PLATFORM, Platform.LINUX); + requestedCapability.put("waitingFor_CHROME_Node", 1); + TestSession testSession = spyProxy.getNewSession(requestedCapability); + Assert.assertNull(testSession); + verify(spyProxy, times(0)).startDockerSeleniumContainer(anyString()); + } + + @Test + public void containerIsStartedForRequestProcessedMoreThan20Times() { + Map requestedCapability = new HashMap<>(); + requestedCapability.put(CapabilityType.BROWSER_NAME, BrowserType.FIREFOX); + requestedCapability.put(CapabilityType.PLATFORM, Platform.LINUX); + requestedCapability.put("waitingFor_FIREFOX_Node", 21); + TestSession testSession = spyProxy.getNewSession(requestedCapability); + Assert.assertNull(testSession); + verify(spyProxy, times(1)).startDockerSeleniumContainer(anyString(), eq(true)); + } + + /* Tests checking the environment variables setup to have a given number of containers on startup */ diff --git a/src/test/java/de/zalando/tip/zalenium/util/TestUtils.java b/src/test/java/de/zalando/tip/zalenium/util/TestUtils.java index 6e49b4dbac..3f87ba6b1e 100644 --- a/src/test/java/de/zalando/tip/zalenium/util/TestUtils.java +++ b/src/test/java/de/zalando/tip/zalenium/util/TestUtils.java @@ -3,6 +3,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import de.zalando.tip.zalenium.proxy.DockerSeleniumStarterRemoteProxy; import org.apache.commons.io.FileUtils; import org.openqa.grid.common.RegistrationRequest; import org.openqa.grid.internal.utils.configuration.GridNodeConfiguration; @@ -12,13 +13,16 @@ import org.openqa.selenium.Platform; import org.openqa.selenium.remote.BrowserType; import org.openqa.selenium.remote.CapabilityType; +import org.openqa.selenium.remote.DesiredCapabilities; import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; +import java.util.List; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -55,6 +59,25 @@ public static WebDriverRequest getMockedWebDriverRequestStartSession() { return request; } + public static List getDockerSeleniumCapabilitiesForTesting() { + String screenResolution = String.format("%sx%s", DockerSeleniumStarterRemoteProxy.getConfiguredScreenWidth(), + DockerSeleniumStarterRemoteProxy.getConfiguredScreenHeight()); + List dsCapabilities = new ArrayList<>(); + DesiredCapabilities firefoxCapabilities = new DesiredCapabilities(); + firefoxCapabilities.setBrowserName(BrowserType.FIREFOX); + firefoxCapabilities.setPlatform(Platform.LINUX); + firefoxCapabilities.setCapability(RegistrationRequest.MAX_INSTANCES, 1); + firefoxCapabilities.setCapability("screenResolution", screenResolution); + dsCapabilities.add(firefoxCapabilities); + DesiredCapabilities chromeCapabilities = new DesiredCapabilities(); + chromeCapabilities.setBrowserName(BrowserType.CHROME); + chromeCapabilities.setPlatform(Platform.LINUX); + chromeCapabilities.setCapability(RegistrationRequest.MAX_INSTANCES, 1); + chromeCapabilities.setCapability("screenResolution", screenResolution); + dsCapabilities.add(chromeCapabilities); + return dsCapabilities; + } + @SuppressWarnings("ConstantConditions") public static JsonElement getTestInformationSample(String fileName) throws IOException { URL testInfoLocation = TestUtils.class.getClassLoader().getResource(fileName);