//
you're reading...
Grid2

Where did my Test Run ?

medias

Image courtesy : http://www.thetoyshop.com

Since I have seen this question come up every now and then I thought I should perhaps quickly create a post which tells you how to figure out to which Node in a Grid infrastructure did my test get routed to.

So without any further adieu, here’s how you go about doing it.

A few basics :

Whenever you instantiate a RemoteWebDriver or any of its sub class variants such as InternetExplorerDriver FirefoxDriver/ChromeDriver etc., the web driver internally generates an id which is called as a “session id”. WebDriver implementation uses this session id to identify to which browser instance should the actions be routed to. When I say actions I am basically talking about things such as “load a url” (or) “click” on an element etc.,

In the Grid Environment, the Hub uses this session id to also keep a track on to which node was a particular test routed to.

This is the mechanism that we are going to be leveraging on to figure out where did my test get routed to.

So first things first. Lets get hold of the session id after we instantiated a web driver. Luckily for us, the web driver APIs provide a mechanism to extract the session id from a RemoteWebDriver object.

All you would need to do is just call [Java syntax ]

driver.getSessionId()

So now that we have the session Id with us, let us move on.

After that all you would need is to make use of a utility class such as the one below:

package organized.chaos.webdriver;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.openqa.selenium.remote.SessionId;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This demo code was written using Selenium v2.49.0
 */
public class ActiveNodeDeterminer {
    private String gridHostName;
    private int gridPort;

    private static final Logger LOGGER = Logger.getLogger(ActiveNodeDeterminer.class.getCanonicalName());

    /**
     *
     * @param gridHostName - The host where the Grid Hub is running.
     * @param gridPort - The port on which the Grid port is listening to.
     */
    public ActiveNodeDeterminer(String gridHostName, int gridPort) {
        this.gridHostName = gridHostName;
        this.gridPort = gridPort;
    }

    /**
     * @param sessionId - A {@link SessionId} object that represents a valid session.
     * @return - A {@link GridNode} object that represents the node to which the session was routed to.
     */
    public GridNode getNodeInfoForSession(SessionId sessionId) {
        GridNode node = null;
        CloseableHttpClient client = HttpClientBuilder.create().build();
        CloseableHttpResponse response = null;
        try {
            URL url = new URL("http://" + gridHostName + ":" + gridPort + "/grid/api/testsession?session=" + sessionId);
            BasicHttpEntityEnclosingRequest r = new BasicHttpEntityEnclosingRequest("POST", url.toExternalForm());
            response = client.execute(new HttpHost(gridHostName, gridPort), r);
            JsonObject object = extractJson(response.getEntity());
            URL tempUrl = new URL(object.get("proxyId").getAsString());
            node = new GridNode(tempUrl.getHost(), tempUrl.getPort());
        } catch (Exception e) {
            String errorMsg = "Failed to acquire remote webdriver node and port info. Root cause: " + e.getMessage();
            LOGGER.log(Level.SEVERE, errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                LOGGER.log(Level.SEVERE, e.getMessage(), e);
            }
        }
        LOGGER.info("Session " + sessionId + " was routed to " + node.toString());
        return node;
    }

    private JsonObject extractJson(HttpEntity entity) throws IOException {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(entity.getContent()))) {
            StringBuilder builder = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                builder.append(line);
            }
            return new JsonParser().parse(builder.toString()).getAsJsonObject();
        }
    }

    /**
     * A simple POJO (Plain Old Java Object) class that represents a Node in the
     * Selenium Grid environment.
     */
    public static class GridNode {
        private String nodeIp;
        private int nodePort;


        public GridNode(String nodeIp, int nodePort) {
            this.nodeIp = nodeIp;
            this.nodePort = nodePort;
        }

        /**
         * @return - A String that represents the IP Address of the node.
         */
        public String getNodeIp() {
            return this.nodeIp;
        }

        /**
         * @return - An int that represents the port number of the node.
         */
        public int getNodePort() {
            return this.nodePort;
        }

        @Override
        public String toString() {
            return "GridNode [IP='" + nodeIp + "', Port=" + nodePort + "]";
        }
    }
}

That’s it. We now have a mechanism of figuring out to which node was our test code routed to.

Here’s a sample TestNG test that shows how all of this is put together.

package organized.chaos.testng;

import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.Reporter;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import organized.chaos.webdriver.ActiveNodeDeterminer;

import java.net.URL;

public class SampleTest {
    private static final String IP = "localhost";
    private static final int PORT = 4444;

    private RemoteWebDriver driver;
    private ActiveNodeDeterminer determiner = new ActiveNodeDeterminer(IP, PORT);

    @BeforeClass
    public void setup() throws Exception {
        URL url = new URL("http://" + IP + ":" + PORT + "/wd/hub");
        driver = new RemoteWebDriver(url, DesiredCapabilities.firefox());
    }

    @Test
    public void test() {
        Reporter.log("Node : " + determiner.getNodeInfoForSession(driver.getSessionId()), true);
    }

    @AfterClass
    public void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }
}

And here’s the console output of the above test code.

[TestNG] Running:
  temp-testng-customsuite.xml
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Node : GridNode [IP='192.168.1.3', Port=5555]
Jan 15, 2016 9:15:36 PM organized.chaos.webdriver.ActiveNodeDeterminer getNodeInfoForSession
INFO: Session 19f1ef0d-cc65-40bc-8e80-0d579d2e651a was routed to GridNode [IP='192.168.1.3', Port=5555]

===============================================
Default Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================


Process finished with exit code 0

And that’s how this is done 🙂

Hope this post was helpful.

Advertisements

Discussion

One thought on “Where did my Test Run ?

  1. This is a follow up to your barebones Github gist (https://gist.github.com/krmahadevan/1766772)?

    For readers of this post, if you’re looking for versions for other languages, see the gist as there are examples there, although not as fully wrapped in a utility library as in this post.

    Posted by autumnator | January 24, 2016, 4:30 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: