Dynamic Test Case Execution on TestGrid: Leveraging Random Device Allocation

You are here:
< All Topics

Overview:

This document outlines the process for executing test cases on TestGrid devices by dynamically allocating the first available device from the pool, rather than binding specific devices to individual test cases. This approach ensures efficient utilization of TestGrid resources, minimizes idle time for devices, and simplifies test case management by eliminating the need for manual device assignment.

By leveraging this dynamic allocation mechanism, test cases are automatically routed to available devices based on their readiness and availability. This process promotes scalability, optimizes test execution workflows, and supports a seamless testing experience in environments with diverse device configurations.

Using the Cap Builder API for Dynamic Device Allocation

To execute test cases on the first available device within TestGrid, the Cap Builder API can be utilized. Below is the syntax for the API request:

curl --location 'https://example.testgrid.io/api/cap-builder' \
--form 'user_token="x9xcdsdfsdfswerwerwerjhkj0zj6"' \
--form 'device_type="android"' \
--form 'project_name="test"' \
--form 'device_name="Galaxy A53 5G"' \
--form 'os_version="14"' \
--form 'device_tag="tag 1"'

Field Details:

  • device_type: Specifies the type of device (e.g., android , ios,or web).
  • project_name: Indicates the project to which the test cases belong.
  • user_token: Authentication token for the user.

Optional Parameters:

  • device_name: (Optional) Specifies a particular device model to refine the search.
  • os_version: (Optional) Defines the OS version for targeted device selection.
  • device_tag: (Optional) Enables filtering by a specific device tag.

If no optional fields are provided, the system will select the first available device that matches the device_type criteria. This flexibility allows for efficient and scalable test execution across the TestGrid infrastructure.

Sample API Response

The API returns a JSON response with the details of the allocated device. Below is an example:

json Android
{
    "status": true,
    "data": {
        "appium_url": "http://example.testgrid.io/appium_xxxx/wd/hub",
        "platform_name": "android",
        "device_name": "Galaxy S20 5G",
        "platform_version": "13",
        "automation_name": "UiAutomator2",
        "udid": "XXXXXXXXX",
        "user_token": "aasdsdffgghkljklkjjhgfddfdsdfsa",
        "system_port": "4011",
        "remote_host": "example.testgrid.io",
        "remote_path": "/wd/hub",
        "remote_port": "xxxxx",
        "project_name": "test"
    }
}

json Web

{
    "status": true,
    "data": {
        "appium_url": "http://example.testgrid.io/browserrunXXXXX/wd/hub",
        "platform_name": "linux",
        "udid": "XXX",
        "user_token": "adhadkhakhskahdkhadhkahdskadhskdh",
        "browser_name": "chrome",
        "project_name": "test"
    }
}

 

Key Response Fields

Mobile Device Response

  • appium_url: URL to connect with Appium for mobile test execution.
  • platform_name: Name of the device platform (e.g., android).
  • device_name: Name of the allocated device.
  • platform_version: Version of the device’s operating system.
  • udid: Unique identifier for the device.
  • system_port: Port for communication with the device.
  • remote_host, remote_path, remote_port: Host, path, and port details for the Appium server.
  • project_name: Name of the project associated with the test case.

Web Response

  • appium_url: URL to connect with Appium for web browser test execution.
  • platform_name: Name of the platform hosting the browser (e.g., linux).
  • udid: Unique identifier for the browser session.
  • browser_name: Name of the browser used for testing (e.g., chrome).
  • project_name: Name of the project associated with the test case.

These responses provide all the necessary details to initiate test execution on either mobile devices or web browsers.

 

Sample Java Code for Web Test Case Execution Using TestGrid

Below is a sample Java code that demonstrates the process of executing a test case on the first available web browser session using the TestGrid Cap Builder API.

 

package all;

import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.ReadContext;
import okhttp3.*;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.IOException;
import java.net.URL;
import java.util.concurrent.TimeUnit;

public class WebAppParallelAutomation extends BaseClass {

    WebDriver driver;
    static String[] search = {"Python", "Java", "Selenium", "Appium", "Nodejs", "Nodered", "IOS", "Android",
            "Docker", "Machine Learning"};

    String userToken = "daskjhfkajfhaskdfhaskfdhaksflhsadkflhf";

    @Test
    public void WebApp1() {
        String device_id = null;
        try {
            device_id = startWebSession();
            reportTestcaseStarted(driver, "WebApp1");

            // Navigate to DemoQA login page
            driver.get("https://demoqa.com/login");
            reportTestStep(driver, "Open DemoQA");

            // Set implicit wait
            driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

            // Execute search operations on Google
            for (int i = 0; i < 1; i++) {
                for (int j = 0; j < 10; j++) {
                    driver.get("https://www.google.com/");
                    driver.findElement(By.name("q")).sendKeys(search[j]);
                    driver.findElement(By.name("q")).sendKeys(Keys.ENTER);
                    Thread.sleep(5000);
                }
            }

            reportTestcasePassed(driver, "Success");
            driver.quit();
            releaseDevice(device_id);
        } catch (Exception e) {
            reportTestcaseFailed(driver, "Failed");
            driver.quit();
            releaseDevice(device_id);
        }
    }

    public String releaseDevice(String device_id) {
        try {
            OkHttpClient client = new OkHttpClient();
            RequestBody body = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("user_token", userToken)
                    .build();

            Request request = new Request.Builder()
                    .url("http://example.testgrid.io/api/user/releasedevice/" + device_id)
                    .method("POST", body)
                    .build();

            Response response = client.newCall(request).execute();
            return response.body().string();
        } catch (Exception e) {
            return null;
        }
    }

    private String startWebSession() throws IOException {
        OkHttpClient client = new OkHttpClient();
        RequestBody body = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("user_token", userToken)
                .addFormDataPart("device_type", "web")
                .addFormDataPart("project_name", "test")
                .build();

        Request request = new Request.Builder()
                .url("http://example.testgrid.io/api/cap-builder")
                .method("POST", body)
                .build();

        Response response = client.newCall(request).execute();
        ReadContext ctx = JsonPath.parse(response.body().string());

        boolean status = ctx.read("$.status");
        if (status) {
            String appiumUrl = ctx.read("$.data.appium_url");
            String platformName = ctx.read("$.data.platform_name");
            String browser_name = ctx.read("$.data.browser_name");
            String udid = ctx.read("$.data.udid");
            String device_id = ctx.read("$.data.device_id");
            String projectName = ctx.read("$.data.project_name");

            DesiredCapabilities capabilities = new DesiredCapabilities();
            capabilities.setCapability("platformName", platformName);
            capabilities.setCapability("browserName", browser_name);
            capabilities.setCapability("tg:udid", udid);
            capabilities.setCapability("tg:userToken", userToken);
            capabilities.setCapability("tg:projectName", projectName);

            driver = new RemoteWebDriver(new URL(appiumUrl), capabilities);
            return device_id;
        } else {
            String message = ctx.read("$.message");
            Assert.fail(message);
            return null;
        }
    }
}

 

Key Highlights:

  1. Dynamic Session Initialization: The startWebSession() method interacts with the Cap Builder API to request the first available browser session.
  2. Test Execution: Example test flows include navigating to a webpage and performing search operations on Google.
  3. Device Release: The releaseDevice() method ensures the device/session is released back to the pool after test completion.
  4. Error Handling: The code includes robust exception handling to manage failures gracefully.

This code is a template for setting up scalable, parallelized web test execution using TestGrid.

 

 

Android App Automation Using TestGrid

Here is a Java example for automating an Android app using TestGrid and Appium. This script demonstrates key aspects like initializing a session, automating app interactions, and releasing the session back to TestGrid:

package all;

import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.ReadContext;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import okhttp3.*;
import org.openqa.selenium.By;
import org.openqa.selenium.ScreenOrientation;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.IOException;
import java.net.URL;

public class AutomationTestingAndroidBroadcom extends BaseClass {

    AppiumDriver driver;

    @Test
    public void AndroidApp1Visual() {
        try {
            // Start the Android session
            startAndroidSession();

            reportTestcaseStarted(driver, "TC01_GoodWeatherGraphsScreen");

            // Allow app installation and launch the app
            waitForSeconds(5);
            AndroidDriver driver1 = (AndroidDriver) driver;

            driver1.installApp("https://api.testgrid.io//wassets/upload/file/1701363450_file_goodweather.apk");
            driver1.activateApp("org.asdtm.goodweather");

            waitForSeconds(5);
            driver1.rotate(ScreenOrientation.PORTRAIT);

            // Handle app interactions
            try {
                driver.findElement(By.xpath("//*[@text='OK']")).click();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

            // Refresh home screen
            WebElement refreshHome = driver.findElement(By.xpath("//android.widget.TextView[@resource-id='org.asdtm.goodweather:id/main_menu_refresh']"));
            refreshHome.click();
            reportTestStep(driver, "Clicked on Refresh");

            // Search for a city
            WebElement searchCityButton = driver.findElement(By.xpath("//android.widget.TextView[@resource-id='org.asdtm.goodweather:id/main_menu_search_city']"));
            searchCityButton.click();
            reportTestStep(driver, "Clicked on Search Button");

            WebElement searchCityView = driver.findElement(By.xpath("//android.support.v7.widget.ar[@resource-id='org.asdtm.goodweather:id/search_view']"));
            searchCityView.click();
            reportTestStep(driver, "Clicked on Search view");

            WebElement searchCityEditText = driver.findElement(By.xpath("//*[@resource-id='org.asdtm.goodweather:id/search_src_text']"));
            searchCityEditText.sendKeys("Atlanta");
            reportTestStep(driver, "Typed on Search view");

            waitForSeconds(5);

            WebElement atlantaText = driver.findElement(By.xpath("//*[@resource-id='org.asdtm.goodweather:id/city_name']"));
            atlantaText.click();
            reportTestStep(driver, "Clicked on Atlanta Text view");

            // Interact with app menu
            WebElement menu = driver.findElement(By.xpath("//android.widget.ImageButton[@content-desc='Open navigation drawer']"));
            menu.click();
            reportTestStep(driver, "Clicked on Menu");

            WebElement closeButton = driver.findElement(By.xpath("//android.widget.CheckedTextView[@text='Graphs']"));
            closeButton.click();
            waitForSeconds(5);
            reportTestStep(driver, "Clicked on Graphs");

            WebElement updateButton = driver.findElement(By.id("org.asdtm.goodweather:id/action_refresh"));
            updateButton.click();
            reportTestStep(driver, "Clicked on Refresh");

            reportTestcasePassed(driver, "Success");
            quitDriver();
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
            try {
                reportTestcaseFailed(driver, "Failed");
                quitDriver();
            } catch (Exception e1) {
                System.out.println(e1.getMessage());
                e1.printStackTrace();
            }
        }
    }

    private void startAndroidSession() throws IOException {
        OkHttpClient client = new OkHttpClient.Builder().build();
        RequestBody body = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("user_token", "askfdhaskfhskdfhsjkfdhskfhsakfhdsa")
                .addFormDataPart("device_type", "android")
                .addFormDataPart("project_name", "test")
                .addFormDataPart("os_version", "14")
                .build();

        Request request = new Request.Builder()
                .url("http://example.testgrid.io/api/cap-builder")
                .method("POST", body)
                .build();

        Response response = client.newCall(request).execute();
        ReadContext ctx = JsonPath.parse(response.body().string());

        if (ctx.read("$.status", Boolean.class)) {
            // Extract capabilities from API response
            String appiumUrl = ctx.read("$.data.appium_url");
            DesiredCapabilities capabilities = new DesiredCapabilities();
            capabilities.setCapability("deviceName", ctx.read("$.data.device_name"));
            capabilities.setCapability("platformVersion", ctx.read("$.data.platform_version"));
            capabilities.setCapability("platformName", ctx.read("$.data.platform_name"));
            capabilities.setCapability("automationName", ctx.read("$.data.automation_name"));
            capabilities.setCapability("udid", ctx.read("$.data.udid"));
            capabilities.setCapability("tg:userToken", ctx.read("$.data.user_token"));
            capabilities.setCapability("tg:projectName", ctx.read("$.data.project_name"));
            capabilities.setCapability("systemPort", ctx.read("$.data.system_port"));
            capabilities.setCapability("uiautomator2ServerLaunchTimeout", "90000");

            driver = new AndroidDriver<>(new URL(appiumUrl), capabilities);
            System.out.println("Session started successfully.");
        } else {
            String message = ctx.read("$.message");
            Assert.fail(message);
        }
    }

    public void quitDriver() {
        driver.quit();
        System.out.println("Driver quit successfully.");
    }

    public void waitForSeconds(int seconds) {
        try {
            Thread.sleep(seconds * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


Key Highlights:

  1. Session Initialization:
    • startAndroidSession() retrieves device details dynamically from the TestGrid Cap Builder API and starts a session using AndroidDriver.
  2. App Automation:
    • The script installs an APK, launches the app, and performs interactions like search and navigation.
  3. Error Handling:
    • Proper exception handling ensures test flow execution is logged and session cleanup happens in case of failures.
  4. Scalability:
    • The script dynamically fetches devices, making it suitable for parallel and distributed testing on TestGrid.

 

 

 

Table of Contents