Make your Selenium Grid nodes personalized

By Glib Briia on June 6, 2016

A walkthrough on how to make Selenium Grid nodes dedicated for running specific tests.

Selenium provides out-of-the-box feature to be able to redirect specific tests to dedicated nodes by setting:

  • Platform (CapabilityType.PLATFORM)
  • Browser name (CapabilityType.BROWSER_NAME)
  • Browser version (CapabilityType.VERSION)
  • Application name ("applicationName")

All these capabilities are used in DefaultCapabilityMatcher when finding appropriate Grid node for running the tests. It is quite sufficient when the set up differs from node to node, so you can manage tests execution through the means of default capabilities.

But what if there are, lets say, 15 identical instances where Grid nodes are set up on same OS, with same browser, and have same browser version but you still want to dedicate one or several of them to run specific subset of tests?

In this case things become slightly complicated, but it is one off set up, and once done it won’t require changing or updating.

So, to implement that kind of behavior custom capability matcher needs to be created and injected in selenium server itself.

In order to accomplish the goal the following steps need to be performed:

1 Create MyCapabilityMatcher.java:

import java.util.Map;

import org.openqa.grid.internal.utils.DefaultCapabilityMatcher;

public class MyCapabilityMatcher extends DefaultCapabilityMatcher {
    private final String nodeName = "nodeName";
    @Override
    public boolean matches(Map<String, Object> nodeCapability, Map<String, Object> clientCapability) {
        boolean defaultChecks = super.matches(nodeCapability, clientCapability);
        if (!clientCapability.containsKey(nodeName)){
            return defaultChecks;
        }
        return (defaultChecks && nodeCapability.get(nodeName).equals(clientCapability.get(nodeName)));
    }
}

It should extend DefaultCapabilityMatcher.java to gain the default behavior and override only one ‘matches’ method where default checks are performed by Platform, Browser name, Browser version and Application name from DefaultCapabilityMatcher.java and custom check is added for new capability ‘nodeName’ which will be passed from selenium client code while initializing driver.

Another way to go is to implement CapabilityMatcher.java interface directly, but in that way MyCapabilityMatcher.java won’t get the default capabilities matching mechanism.

2 Compile MyCapabilityMatcher.java:

Start the command prompt, change directory to the one where MyCapabilityMatcher.java resides and run:

javac -g MyCapabilityMatcher.java

(-g is optional but will make your debugging easier if you messed something in the .java file)

If everything run successfully MyCapabilityMatcher.class file should be generated.

3 Create Grid hub launching config JSON (HubConfig.json):

{
  "capabilityMatcher": "MyCapabilityMatcher",
  "throwOnCapabilityNotPresent": true
}

Here created capability matcher is specified and throwOnCapabilityNotPresent property, which basically tells the hub to reject the test if no nodes available with given capabilities set instead of queuing and waiting for it to be registered.

Default Grid hub config JSON can be found here DefaultHub.json

4 Create/update NodeConfig.json with new ‘nodeName’ capability :

{
  "capabilities":
      [
        {         "browserName": "firefox", 
                "platform": "WINDOWS", 
                "maxInstances": 8,
                "seleniumProtocol": "WebDriver",        
                "nodeName": "specialNode"                
        },
        {
                "browserName": "firefox",
                "platform": "WINDOWS",
                "maxInstances": 8,
                "seleniumProtocol": "WebDriver",
                "nodeName": "simpleNode"                
        }
      ],
  "configuration": 
        {         
                "nodeTimeout":120,  
                "nodePolling":2000,
                "registerCycle":10000, 
                "register":true,
                "cleanUpCycle":2000,
                "timeout":30000, 
                "maxSession":16,
                "nodeStatusCheckTimeout":10000,
                "downPollingLimit":360000
        } 
}

Node config JSON example can be found here DefaultNodeWebDriver.json

5 Start Grid hub:

java -cp *;. org.openqa.grid.selenium.GridLauncher -role hub -hubConfig HubConfig.json -host your_hub_host_here -port your_hub_port_here

selenium-server-standalone-x.xx.x.jar and MyCapabilityMatcher.class must be placed in the same folder to run the above command successfully or you’ll have to specify the full path to both to include them in classpath.

and start Grid node:

java -jar selenium-server-standalone-x.xx.x.jar -role node  -hub your_hub_url_here -host your_node_host_here -port your_node_port_here -nodeConfig NodeConfig.json -hubHost your_hub_host_here -hubPort your_hub_port_here

6 Finally in your code while initializing driver:

To run tests on ‘simpleNode’:

DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setCapability("nodeName","simpleNode");
WebDriver driver = new RemoteWebDriver(new URL(your_hub_url_here), capabilities);

And to redirect the tests to ‘specialNode’:

DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setCapability("nodeName","specialNode");
WebDriver driver = new RemoteWebDriver(new URL(your_hub_url_here), capabilities);