Measuring Tridion UI Performance Using Selenium and JMeter

Recently, one of our clients wanted to capture the performance metrics of Tridion in scaled environments and they had some interesting questions for us:  metrics
1. How long does a Tridion item—for example, a component, page, etc.—take to load in a browser?
2. How long does it take to save and check-in a Tridion item through the browser?                                                                                                   
The client, having updated Tridion to Web 8.5 from 2013, was interested in measuring the performance of Web 8.5 under user load for auditing purposes and identifying bottlenecks, if any, in the system.  A lot of browser automation tools are available in the market, but we needed a tool that is cost-effective, open source, provides support for writing test scripts in Java and offers great support for browser automation of dynamic websites. We chose Selenium for these reasons. For the similar reasons of being cost-effective and open source—in addition to providing support for running test scripts in non-GUI mode, thereby saving a lot of resources and supporting remote execution of test scripts, JMeter was chosen as the load testing tool. In this post, I will demonstrate how Selenium and JMeter were used in gathering performance metrics in Tridion CMS.                

Why Selenium

Since the requirements focused on knowing the client-side performance as opposed to server-side, Selenium WebDriver was used to automate browser interactions and measure performance through their Java API. Measuring the load time of dynamic pages is also easy with Selenium Webdriver, making it possible to gather the performance of Tridion’s dynamic content in addition to their static content.

Why JMeter

We used JMeter to simulate multiple user load and measure performance under that load, and we integrated the Selenium script with JMeter to capture the performance metrics. The captured metrics helped DevOps discover any bottlenecks and identify ways to optimize and tune the system for better performance.

Setting up the Selenium 2.0 Java project

Setting up a Selenium 2.0 Java project is simple. Create a Maven Java project and configure the pom.xml to get the Selenium 2.0 Java libraries and all of its dependencies. Also, the pom.xml should be configured in a way so that the project can be packaged as a JAR file. We also used Apache Commons Lang library as it provides convenient APIs for timings. Your pom.xml should have the dependencies shown below:                                                               
<dependency> 
  <groupId>org.seleniumhq.selenium</groupId> 
  <artifactId>selenium-java</artifactId> 
  <version>3.141.59</version> 
  </dependency> 
<dependency> 
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId> 
  <version>3.8.1</version> 
</dependency>
The next example shown is a Java Method that uses Selenium 2.0 Java API to measure the page load time of a Tridion component on the Chrome browser. For the Selenium WebDriver to drive the Chrome browser, the ChromeDriver binary needs to be placed somewhere on the machine where the script is run. The Java method takes in two parameters—component URL and the name of the first schema field—and returns a string with the initial and the fully loaded page time. A component gets loaded in two stages. First, the ribbon toolbar and other menu items are loaded. Next, the content field values are loaded dynamically. So, we define the initial page load time as the time it takes for the ribbon toolbar to display and the fully loaded page time is the time it takes for all content fields to load. We have emulated this in Selenium by waiting for the item toolbar to load in the DOM to measure the initial page load time, and waiting to see if a div element with id ‘SchemaBasedFields’ is injected by JavaScript dynamically to measure the fully loaded page time.
Although the example below is specific to measuring the load time of a Tridion component on the Chrome browser, it could be easily extended to other Tridion items and browsers through third-party drivers, plugins, and bindings.                                                                                   
package com.ad.selenium.loadtesting.test; 

import org.apache.commons.lang3.time.StopWatch; 
import org.openqa.selenium.By; 
import org.openqa.selenium.JavascriptExecutor; 
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver; 
import org.openqa.selenium.support.ui.ExpectedCondition; 
import org.openqa.selenium.support.ui.ExpectedConditions; 
import org.openqa.selenium.support.ui.WebDriverWait;
 
/** 
 * The TridionPageLoadTimer class contains methods for timing automated Tridion 
 * UI browswser page loads. It uses the Selenium WebDriver to drive the Chrome 
 * browser, and gather metrics of the Tridion UI. It contains methods to measure 
 * performance of the various phases of page load times of the Tridion items.
 * @author Content Bloom 
 * @version 1.0 
 *
 */
public class TridionPageLoadTimer { 
    private static final String CHROME_DRIVER_PATH = "C:\\Temp\\chromedriver.exe";
    private static final String ITEM_TOOLBAR_ID = "ItemToolbar"; 
    private static final String SCHEMA_FIELDS_ID = "SchemaBasedFields"; 

    /** 
    * Get the measured the initial page load time and the completed page 
    * load time of a Tridion Component. 
    * @return A string containing the initial page load time of a Component in a 
    * Tridion CM instance and the load time after loading all schema
    * fields of the Component. 
    */
    public String getComponentLoadTime(String componentUrl, final String firstSchemaField){ 
        // Include the location of the ChromeDriver to webdriver.chrome.driver 
        System.setProperty("webdriver.chrome.driver", CHROME_DRIVER_PATH); 
        WebDriver webDriver = new ChromeDriver(); 
        double initialPageLoadTime_Seconds = 0.0D; 
        double finalPageLoadTime_Seconds = 0.0D;
        try { 
            // Initialize initialPageLoad and finalPageLoad for timing 
            // page loads at different phases. 
            StopWatch initialPageLoadTime = new StopWatch(); 
            StopWatch fullyLoadedPageTime = new StopWatch();
            initialPageLoadTime.start(); 
            fullyLoadedPageTime.start(); 
            webDriver.get(componentUrl); 
            WebDriverWait wait = new WebDriverWait(webDriver, 30000); 

            // Wait until the item toolbar of the Component is located.
            // This determines the initial page load time. 
            wait.until(ExpectedConditions.presenceOfElementLocated(By.id( ITEM_TOOLBAR_ID))); 
            initialPageLoadTime.stop();
   
            // Wait until all schema fields are located. This determines the page is fully loaded.
            wait.until(new ExpectedCondition<Boolean>() { 
                public Boolean apply(WebDriver driver) {
                    String content = (String) ((JavascriptExecutor)driver).
                        executeScript("return document.getElementById('"+ SCHEMA_FIELDS_ID+"').textContent"); 
                    if(content.contains(firstSchemaField)) { 
                        return true; 
                    } else { 
                        return false; 
                    } 
                }
            });         
            fullyLoadedPageTime.stop();

            // Get the initial and fully loaded page time.
            long initialPageLoadTime_ms = initialPageLoadTime.getTime(); 
            initialPageLoadTime_Seconds = initialPageLoadTime_ms / 1000.0d;
            long finalPageLoadTime_ms = fullyLoadedPageTime.getTime(); 
            finalPageLoadTime_Seconds = finalPageLoadTime_ms / 1000.0d;
        } 
        catch (Exception ex){
           ex.printStackTrace();
        } 
        finally{ 
           webDriver.close();
           webDriver.quit(); 
        }  
        return "Initial page load time: " + initialPageLoadTime_Seconds + " seconds. Total page load time: " + finalPageLoadTime_Seconds + " seconds.";
     } 
}

JMeter set up

Download and extract Apache JMeter 5.0 binary from https://jmeter.apache.org/download_jmeter.cgi. The JMeter’s /bin folder contains the Windows Batch File jmeter.bat, which opens the GUI. You can have your test plan created here to simulate user load and determine the page load time of a component using the Selenium WebDriver Java project JAR built with Maven as described above. The JAR needs to be dropped in JMeter’s /lib folder so the methods available in the JAR can be leveraged in JMeter. 

BeanShell sampler script

JMeter provides support for Java code in test plans using the BeanShell sampler. The image below is the script in BeanShell that returns the initial and final page load time of a Tridion component. The script uses the TridionPageLoadTimer class  getComponentLoadTime() shown above to return the page load time of a Tridion component with the URL as http://localhost:81/WebUI/item.aspx?tcm=16#id=tcm:18-994 and the first Schema field as ‘heading’.

This last GIF shows a test plan containing the BeanShell sampler script, executed under light load (2 users) to measure the page load time of a component. The page load times of the component are then displayed in the Command Prompt. 

jmeterIt is relatively easy to have Selenium integrated with JMeter and have page load times measured under user load. Of course, the example shown in this article is pretty simple, but it should help you get up and running with Selenium and JMeter’s functionality.  The example can also be easily extended to measure the page load times of other Tridion items under a more heavy load and measure the performance of operations such as saving an item, checking-in an item, etc.                                                                                                                                                                                                                                                    I hope that this post about performance testing using Selenium and JMeter can be of use in your own testing projects,  and has given you some insight into Selenium and JMeter. If you do try the project above or try using Selenium and JMeter for any other performance testing, let us know how it goes! We’d love to hear about it. Leave a comment down below or contact us at info@contentbloom.com. We’re looking forward to hearing from you.

 

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>