Load Testing web application with Selenium and TestNG

I’ve used Selenium for while to do verification tests of web applications, recently I discovered a very simple way to use it with TestNG and Maven to do some performance testing. TestNG allows for the use of annotations to allow multi-threading and iterations.

pom.xml:

<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.44.0</version>
<scope>test</scope>
</dependency>
<dependencies>

And as for a simple test to get started with… scripting of steps is available online or could be in a future blog post.

/*
* COPYRIGHT. none
*/
package com.example.selenium;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Simple test example for Selenium
*/
public class SeleniumTest {

private static final Logger LOGGER = LoggerFactory.getLogger(SeleniumTest.class);
/**
* TODO Un-comment or change if needed to set your local path!
*/
@BeforeClass
public void oneTimeSetUp() {
System.out.println(“————————————– init —————————————-“);
//System.setProperty(“webdriver.firefox.bin”,”C:\\path\\to\\firefox.exe”);
}
/**
* NOTE: uses TestNG – behaves differently than JUnit
*/
@Test(invocationCount = 1, threadPoolSize = 5)
public void testLoadApp() {

final String fn = “testLoadApp”;
final String baseUrl = “http://www.giantgeek.com/index.php”;
LOGGER.debug(“[START] Thread Id: {} is started!”, Thread.currentThread().getId());

WebDriver driver = null;
final long start = System.currentTimeMillis();
try{
driver = (WebDriver)new FirefoxDriver();
driver.get(baseUrl);

final String actual = driver.getTitle();
LOGGER.debug(“Page Title is {}”, actual);
final String expected = “GIANTGEEK.COM”;
Assert.assertEquals(actual,expected);
//perform whatever actions, like login, submit form or navigation


}catch(final WebDriverException ex){
LOGGER.warn(fn+":WebDriverException:{}",ex);
}catch(final Exception ex){
LOGGER.warn(fn+":Exception:{}",ex);
}
finally {
final long elapsed = System.currentTimeMillis() - start;
LOGGER.debug("[END] Thread Id: {}, elapsed={}", Thread.currentThread().getId(),elapsed);
if(driver != null){
driver.quit();
}
}
}
}

WARNING: Selenium Tests MAY fail if the browser used for testing is updated in the Operating System. Updating the pom.xml to a newer release usually helps!

REFERENCES:

JSP Copyright tag file example

This is a simple example in .tag files, the concepts can apply to many other uses.

I’ve chosen the following common usage example:

Websites often need to contain copyright date and information in their footer.

Add this to your existing JSP page (or JSPF fragment):


<%@ taglib prefix="webinf" tagdir="/WEB-INF/tags" %>
<webinf:copyrightyear />

Create the .tag file – /WEB-INF/tags/copyrightyear.tag


<%@ tag language="java" isELIgnored="true" trimDirectiveWhitespaces="true" description="dynamically calculates year" %>
&#169;<jsp:expression>java.util.Calendar.getInstance().get(java.util.Calendar.YEAR)</jsp:expression>&#160;<jsp:doBody />

NOTE: I’ve used the <jsp:doBody /> inside the tag file in this example, as such you can also use the following format on your page(s) to use the content between the open and close.


<webinf:copyrightyear>Example</webinf:copyrightyear>

NOTE: if your server supports it, you can also use XML formatted tag file with:

<jsp:directive.tag language="java" isELIgnored="true" trimDirectiveWhitespaces="true" description="dynamically calculates year" />

Eclipse FileSync plugin

I’ve done a lot of front-end java coding over my career,  one particularly annoying aspect is the wait for a build (compile-deploy) cycle in my local developement servers to view or test a small change.  One particularly useful tool that I’ve been using for some time is a FileSync plugin for Eclipse.  It is useful as you can “map” folders from your Eclipse project to a path on your local filesystem, as such the individual files are automatically copied to your server installation.  I’ve personally used this approache with JBoss, Tomcat and WebSphere, but there is no reason that it should not work for other servers.

Renaming JSESSIONID

Older versions of Apache Tomcat, as well as the older servlet specifications required that several configuration values need to be set. With servlet 3, you can now modify the name of the session cookie (as well as the ‘rewriting’ attribute name) in the web.xml file

In web.xml: (servlet 3.x)

<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<name>mysessionid</name><!-- default is jsessionid -->
<http-only>true</http-only>
<!-- secure>true</secure-->
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>

Alternately for Tomcat7, modify TOMCAT_HOME\conf\context.xml:
<Context path="/exampleApp" sessionCookieName="myid">

If you are using spring security, then you should try setting disable-url-rewriting attribute of <http> element to true.

REFERENCES:

Internationalizing JSP with ResourceBundles

Adding multi-language support to JSP based applications is very simple. In this post we will investigate the method that you can use to externalize your text based content.

NOTE: Additional work is required to establish the Locale, format Dates and Numbers or to support other differences such as text-direction.

JSP:

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<fmt:setLocale value="en_US" />
<fmt:setBundle basename="ResourceBundles.TestBundle" scope="request" var="rb" />
<fmt:message bundle="${rb}" key="label.test" />

/src/ResourceBundles/TestBundle.properties:

label.test=test(default)

/src/ResourceBundles/TestBundle_en.properties

label.test=test(en)

/src/ResourceBundles/TestBundle_en_US.properties

label.test=test(en_US)

You can also specify some default Locale information in web.xml if you do not wish to use the in your JSPs.

/WEB-INF/web.xml


<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.locale</param-name>
<param-value>en</param-value>
</context-param>

<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.fallbackLocale</param-name>
<param-value>en</param-value>
</context-param>

Some explanation… in this case we’ve told our JSP that the resources are in the TestBundle properties. As the Locale is set to ‘en_US’ it will first look in the TestBundle_en_US.properties file, if not found it will then look in TestBundle_en.properties and finally in TestBundle.properties. If not found there, the output will generally be in the form ‘???key???‘, in this example: ‘???label.test???‘, my understanding is that this can be suppressed by setting ‘allowNull=true‘ somewhere, but I have never found that setting to date.

REFERENCES:

XML formatted JSP source code

I’ve found that many developers still use the classic coding style on JSP’s, unfortunately this makes it difficult to use some common tools for validation and complicates matters when looking for improperly nested tags in the markup. Migrating the XML formatted JSP markup simplifies matters and makes it possible for developers to quickly identify many problem areas of code within the IDE.

<%@ page language="java" %> = <jsp:page.directive language="java" />

<%@ page contentType="text/html; charset=utf-8" %> = <jsp:page.directive contentType="text/html; charset=utf-8" />

<%@ page import="" %> = <jsp:page.directive import="" />

NOTE: you can combine page.directive’s to a single tag with all attributes.

<% //some scriptlet %> = <jsp:scriptlet>//some scriptlet</jsp:scriptlet>

<%! String somevalue="1"; %> = <jsp:declaration>String somevalue="1";</jsp:declaration>

<%= somevalue %> = <jsp:expression>somevalue</jsp:expression>

<jsp:include page="" />
<jsp:directive.include file="" />

<jsp:useBean id="" scope="" type="" />

<jsp:setProperty name="" />

Unfortunately, there’s one common type of tag that does not have an XML equivalent:

<%@ taglib prefix="c" uri="/WEB-INF/tlds/c.tld" %>

REFERENCES:

Happy coding

JSP Whitespace reduction

I’ve often found that most JSP developers are uncertain as to why their HTML output contains a lot of extra blank-lines, tabs and carriage returns. White space included in the template text of JSP pages is preserved by default. This can have undesirable effects. For example, a carriage return added after a taglib directive would be added to the response output as an extra line. This cruft is known as WhiteSpace, and it is responsible for a lot of wasted bandwidth and many spacing issues in HTML designs.

The challenge:

  • Developers that only use WYSIWYG editors are never even aware of the extra spacing within JSP source code.
  • Developers that work in source code often want to format the markup to allow for better visualization and readability of the source code.
  • Most IDE’s do not show the developers the special characters within the editor environment, external text editors such as NotePad++ and TextPad can be configured to show them.

Here’s a few suggested approaches on removing these, first development items:

  1. Remove comments:
    • Remove any (and all) JSP style comments <%-- comment --%> as each line in them will result in a carriage return being sent to the browser.
    • While you are at it, remove HTML comments <!-- comment --> as they often expose potential attack vectors for individuals trying to hack your website.
  2. Combine your JSP directives, <%@page %> or <jsp:directive.page /> into a single entry.
  3. Open and close all tags on a single line when possible.

Compiler options are possible for some platforms:

  • The page directive on each JSP can contain the argument to tell the compiler to trim the space in individual JSP’s:
    <jsp:directive.page language="java" pageEncoding="utf-8" trimDirectiveWhitespaces="true" />
  • For Tomcat (and others?) web.xml can be edited to contain the following in the jsp-config section:

    <jsp-config>
    <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
    <trim-directive-whitespaces>true</trim-directive-whitespaces>
    </jsp-property-group>
    </jsp-config>
  • For Tomcat (and others?) web.xml can be edited to contain the following for the JSPServlet:

    <init-param>
    <param-name>trimSpaces</param-name>
    <param-value>true</param-value>
    </init-param>
  • The deployment descriptor can also be used to do so by adding a trim-directive-whitespaces element to a jsp-property-group element in the deployment descriptor and set it to true.
  • Some IDE’s expose the attribute, NetBeans 5.5 uses the following:
    1. Open the deployment descriptor file in the editor.
    2. Click the Pages button at the top of the editor.
    3. Select a JSP property group.
    4. Select the Trim Directive Whitespaces checkbox.
    5. Save the deployment descriptor.
  • Custom tag authors can eliminate white space from the output generated by a tag file by setting the trimDirectiveWhiteSpace attribute of the tag directive to true.

JSP Version Matrix for common servers:

Apache Tomcat 7.0.x JSP 2.2
Apache Tomcat 6.0.x JSP 2.1
Apache Tomcat 5.5.x JSP 2.0
Apache Tomcat 4.1.x JSP 1.2
Apache Tomcat 3.3.x JSP 1.1
IBM WebSphere Application Server 7.x JSP 2.x
IBM WebSphere Application Server 6.x JSP 2.0
IBM WebSphere Application Server 5.x JSP 1.2

REFERENCES:

Happy coding!

Custom 404 Page for Tomcat web applications

This is a relatively common problem in JSP based apps as you need to understand the configuration. It’s further complicated if you use Apache HTTPD in front of the Apache Tomcat server to process requests as you need to know where each request is processed.

For this example, we will use the standard 404 error, but you can also intercept other errors for custom pages.

  1. create 404.jsp:

    <% final SimpleDateFormat simpleDate = new SimpleDateFormat("EE MMM dd yyyy hh:mm:ss aa zzz");
    final String dttm = simpleDate.format(new Date()); %>
    <html>
    <title>404 Not Found</title>
    <ul>
    <li>Time: <%= dttm %></li>
    <li>User-Agent: <%= request.getHeader("User-Agent") %></li>
    <li>Server: <%= request.getServerName() %></li>
    <li>Request: <%= request.getRequestURI() %></li>
    <li>Remote: <%= request.getRemoteAddr() %></li>
    <li>Referer: <%= request.getHeader("Referer") %></li>
    </ul>
    </html>
  2. in WEB-INF/web.xml – add the following (NOTE: location within the file is important but outside the scope of this post)

    <error-page>
    <error-code>404</error-code>
    <location>/404.jsp</location>
    </error-page>
  3. You might want to force the HTTP Header to give something other than a ‘404 status’ code, otherwise MSIE will show an unstyled ‘friendly error message’ if the user has not turned off the default setting. Unfortunately, this also means that search engines might index these pages that should not exist.

REF:

Apache Native Client

If you do any development or even production testing with Apache Tomcat, you may have seen the following message in your logs.

“The Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path”

Here’s a quick solution that will leave you with greatly improved performance.

  1. Go to the following URI’s:
  2. Download the appropriate version of tcnative-1.dll
  3. For Windows, place that file in c:\windows\system32\ 
  4. Restart your Tomcat server
  5. You are done!

Cheers

Enabling the Apache2 – Tomcat5 mod_jk Connector

Often you want to use Apache HTTP for static content, yet use Tomcat for JSP and other Java type work.  This is a very common infrastructure for enterprise applications, particularly when using ‘pools’ of servers for performance, redundancy and security.  

In order to accomplish this, all connections need to be handled by the Apache webserver, which will delegate appropriate requests to Tomcat for it to process.

Here’s a simple setup to get you started:

  • First you need to get the connector appropriate to your installation:

    http://tomcat.apache.org/connectors-doc/

  • Next make sure the connector file is in the /conf folder of your Apache installation.

    NOTE: I prefer to use this path and leave the version name to make maintenance and backups easier.

  • Add the following line to httpd.conf

    LoadModule jk_module conf/mod_jk-1.2.26-httpd-2.2.4.so

  • Now, add the following to http.conf

    <IfModule jk_module>
    Include “c:/TOMCATPATH/conf/auto/mod_jk.conf”
    JkWorkersFile conf/workers.properties
    JkLogFile “c:/LOGSPATH/tomcat55_mod_jk.log”
    </IfModule>

  • Add the c:/APACHEPATH/conf/workers.properties file with the following (minimal) contents:

    worker.list=ajp13
    worker.ajp13.port=8009
    worker.ajp13.host=localhost
    worker.ajp13.type=ajp13

  • Finally, restart both Apache and Tomcat
  • The following file should have been created in c:/TOMCATPATH/conf/auto/mod_jk.conf

    ########## Auto generated on …some datetime… ##########

    <IfModule !mod_jk.c>
      LoadModule jk_module “C:/APACHEPATH/conf/mod_jk-1.2.26-httpd-2.2.4.so”
    </IfModule>

    JkWorkersFile “C:/TOMCATPATH/conf/jk/workers.properties”
    JkLogFile “c:/LOGSPATH/mod_jk.log”

    JkLogLevel emerg

    <VirtualHost localhost>
        ServerName localhost

        JkMount /webdav ajp13
        JkMount /webdav/* ajp13

        JkMount /servlets-examples ajp13
        JkMount /servlets-examples/* ajp13

        JkMount /jsp-examples ajp13
        JkMount /jsp-examples/* ajp13

        JkMount /balancer ajp13
        JkMount /balancer/* ajp13

        JkMount /host-manager ajp13
        JkMount /host-manager/* ajp13

        JkMount /tomcat-docs ajp13
        JkMount /tomcat-docs/* ajp13

        JkMount /manager ajp13
        JkMount /manager/* ajp13
    </VirtualHost>

If all went well, you should be able to access  your Tomcat server webapps on the regular HTTP port used by your Apache installation.

Cheers!