Article Figure 1 Figure 2 Figure 3 Figure 4
Listing 1 Listing 2 Listing 3 Listing 4 jun2006.tar

Platform-Independent Stress Testing from the Command Line

Alan M. Berg

This article will describe the use of various open source tools for scripting without any specific platform dependences. Specifically, I will show how to plumb the Ant [1] and Jmeter [2] tools together via the command line, generating HTML reports. I will also show how to use email, scp, and file renaming. This information should allow you to take the coding further and apply Ant to other problem domains. Platform-independent scripting is a very handy tool in a systems administrator's arsenal.

Ant is a task-based tool that reads in an XML file(s), known as a build file, and performs specific tasks based on the build. Example tasks include the archiving of directory structures, emailing, secure copying, compiling token replacement, deploying Web applications, etc. Ant was originally billed as a tool to take over the role of the make command. However, Ant has spread its roots further to encapsulate whole realms of functionality. The quick growth of tasks can be attributed to the fact that Ant is easily extendable. Tasks are written in Java and can be enabled via the build file.

Ant's built-in features allow the following types of tasks:

    1. Archiving and file. These tasks include: bzip, zip, jar, war, copy, delete, mkdir.

    2. Programming tasks, such as javac, cvs.

    3. Remote tasks, such as FTP, Rexec, Scp, mail, sql.

    4. Logging, such as the record task.

    5. Extensions. Ant tasks are Java classes that are relatively easy to write.

There are numerous examples of contributed tasks; we will take advantage of two of these: the Jmeter and Ant contribution extensions. Note that certain operating system features do exist in Ant, specifically file permission and exec tasks. Please be careful to check these tasks against your target deployments.

Jmeter is a stress-testing and assertion tool. Jmeter has a GUI for building test plans and can be run from the command line or via an extended Ant task. A typical PC can run 500-1000 concurrent threads sending HTTP requests. It is worth noting that for a receiving system a thread can be more active than a typical user. Five hundred threads are probably more like 1500 real users. Jmeter can fire off requests to http, ftp, jdbc (database), soap (http with xml mixed in), LDAP, JMS (message queues), and mail. This list of target protocols is a typical mix for enterprise-wide infrastructures.

Ant, Jmeter, Tomcat, and Apache have been developed under the Apache project [3] umbrella. The Ant and Jmeter tools are written in Java and, thanks to the JVM, can run on any Java-enabled operating system. The supported systems include Solaris, Linux, AIX, HP-UX, BSD, Windows, and Apple.

Stress-Testing Basics

So, you want to hit your systems hard and see what happens. Stress testing is an excellent tool for gaining confidence in a given infrastructure's ability to survive the onset of the end user. In general, there are three scenarios. The first is the acceleration of a burn period for new hardware. On one occasion, I had the pleasure of seeing a system fail five times all due to motherboard issues. By the application of a focused stress test, the motherboard issue would have been found before the hardware had reached production status. Thus stress testing would have avoided a significant number of help desk calls from irate clients.

The second scenario is that of knocking systems that have been patched. Before deploying a patch to production, we first update an acceptance environment and, if required, again hit the systems hard. Logging is vigorously analyzed for those strange exception numbers that occur when systems start to fail. The third and most difficult to achieve situation is that of both stress testing and performing functional tests within a full software cycle. Figure 1 defines one possible solution.

Automated scripts run tests against development, acceptance, and production. The scripts are called via cron jobs or scheduled tasks, and the generated html-formatted results are sent by scp to a directory on a results server. Emails are sent to a distribution list of interested parties. The advantage of automation is the capturing of bogus code, patch, or intermittent errors early on in the cycle. Furthermore, this process provides you, as a systems administrator, with the feeling of orderly control over a potentially chaotic environment. By the end of this article, you should have enough background knowledge to be able to consider the pros and cons of building this structure based on Ant.

What Is to Come?

The source code accompanying this article contains four example build files. The first example sends email and has the purpose of introducing you to the build file structure. The second example archives log files from a directory structure and sends the archive by email. The purpose of the second example is to show how instantaneous it is to script for complex tasks. Further, the example highlights the relevance of using Ant in your environment. The third example is a script that runs a stress test automatically. This example shows how to extend Ant for extra tasks and how to perform basic stress tests. The final example performs a series of stress tests. Here you will learn about iteration through tasks and passing of variables.

Setting Up Your Environment

The following scripts will work with Jmeter 2.1 or above and Ant 1.6 or above. Both packages are downloaded as zip files [4, 5] that once unzipped can be directly run. Java 1.4 is required. Please follow the simple installation instructions contained within the packages.

To run Ant from a cron job, I typically set a couple of environment variables in one file and call the file from a batch file. For example:

file: setenv 

export CVS_RSH=/usr/local/bin/ssh 
export JAVA_HOME=/usr/java 
export ANT_HOME=/opt/usr/ant 
export CLASSPATH=/opt/usr/ant/lib/mail.jar:/opt/usr/ant/ \
  lib/activation.jar 
export PATH=$JAVA_HOME/bin:$ANT_HOME/bin:$PATH 

cronjob batch 
#!/usr/bin/bash 
source /opt/usr/scripts/set_env 
ant -f /opt/usr/scripts/example1.xml ?Dtest.value=45 
          
Note that if you want to extend Ant tasks, you would normally set the extra libraries in a location defined in the CLASSPATH. Further, if you want to pass a value to the build files from the command line, then you would need to follow the convention of ant -Dname=value. Finally, Ant tasks obviously have a lot of power; delete dir, for example, has the same effect as rm -rf. Therefore, it would not be a good idea to run as a privileged user.

Project Basics

Before going further, let's define some basic terminology -- a project defines the whole. A target is a collection of tasks that are grouped together. One target may be to zip all files and then copy the archive to a backup mount; another may be to initiate the directory structure or delete it. Therefore, a project may contain a series of targets. A target in itself may contain a group of tasks. The build file has an XML structure and the tags either are self-contained (e.g., <fileset />) or may enclose other tags (e.g., <fileset></fileset>).

Example 1

Listing 1 enables Ant to send an email. The basic structure is as follows:

Project
     Define some properties
     Target
          Do some tasks
     Target
          Do more tasks

Translating project into Ant syntax:

<project name="example1" default="sendmail">
    
The code fragment states that if we run Ant from the command line, then the sendmail target is called by default. To run another task first, simply add the target name after Ant (e.g., ant targetname). To obtain the full list of targets in a given build file, type ant -projecthelp.

The <property file= "default.properties"/> statement is powerful; it tells Ant to load in the variables from the property file default.properties. The property file has the syntax value=name (e.g., jmeter.host=localhost). To reference the variable within Ant, you would need to enclose the variable with ${} (e.g., ${Jmeter.host}).

The mail task looks pretty straightforward apart from the fileset attribute. This attribute is common to many tasks:

<fileset dir="${log.dir}">
       <include name="**/*.zip"/>
</fileset>
    
In other words, the fileset is the set of files under the ${log.dir} directory and its children as defined by log.dir= in the property file. The set of files should only include zip files.

The mail task uses the fileset attribute to define the files to be sent by mail. The task has a dependency on outside libraries. Download the mail and activation.jar files [6, 7] and add their locations to the CLASSPATH variable.

Example 2

Listing 2 copies all .log files from a given directory structure and places the logs in an archive. For example, the time stamp is placed in the variable today:

<tstamp prefix="today"/>
There are three formats for the time stamp DSTAMP (yyyMMdd), TSTAMP(HHmm) and TODAY (MMMM dd yyyy). To reference the DSTAMP format, we need to use the notation ${today.DSTAMP}.

Copying files is straightforward; however, you may want to map the names or directory structures. Ant can achieve this in multiple ways, such as via mapping(s) within the fileset:

<chainedmapper>
    <flattenmapper/>
    <globmapper from="*.log" to="*_${today.DSTAMP}.log" />
</chainedmapper>
The "chainedmapper" is used to make a composite of other mappers. The "flattenmapper" mapper removes the path information, and the "globmapper" does a simple wild-card mapping and replacing, in the above situation adding a timestamp to the log filenames. For more complex mappings, I would recommend looking at the "regexp" mapper.

Zipping the archive is straightforward:

<zip zipfile="${log.dir}/logs_${today.DSTAMP}.zip" 
  basedir="${log.dir}/${today.DSTAMP}"/>
    
The sending of email occurs by setting the mail.message property and calling example1.xml:

<property name="mail.message" value="Have a nice day 
  ${today.TODAY}" />
<ant antfile="example1.xml"/>
Notice that mail.message is not defined in the default.properties file. Otherwise, the default.properties setting will override the value set.

The Plan

Note that the important theme of this article is the control and iteration of tasks via Ant and that Jmeter stress testing is just one example. If you feel that the details of the Jmeter test plan are not immediately relevant, feel free to skip the next couple of paragraphs.

Like Ant, Jmeter uses an XML configuration, known as a test plan, to define which tests to perform. However, unlike Ant, the plans generally are made via a GUI. In this exercise, we will run a templated test plan. The Ant script will copy the test plan and replace information such as target host and port with parameters stored in the default.properties file. The templated test plan is found under examples/Jmeter/templates/plan.jmx and is best viewed from the GUI. A screen grab is shown in Figure 2. Notice the @PORT@ string. This is one of the tokens that will be stamped.

The plan consists of a number of elements. The top level is a thread group, which defines the number of threads to be run. The child HTTP cookie manager remembers the cookie per thread and returns it if asked by the server. The HTTP user parameter modifier replaces specific parameters in an HTTP request with data from an XML file. This is useful, for example, if you want to log into a server with the parameters user and password.

The data file has an XML structure and needs also to sit under the bin directory of the Jmeter instance. The final component is the HTTP request, which sends a request per thread to a server. Notice the parameters user and pass are left blank and will be filled in from the data file. For convenience, a very brutal Perl script (scripts/make_user.pl) is supplied to generate a data file. Otherwise, you may use the file found under examples/Jmeter/user_data.xml.

Initial Conditions

Setting up the test environment requires installing an example war file under a Servlet container, such as Tomcat or JBoss. The war file can be built by running at the top level of the source code Ant build, then collecting build/war/Jmeter_target.war and deploying. The application is composed of two pages. Index.html is a login form, and parser.jsp sends a message based on the user name and password. The advantage of JSP pages is that you can change the pages on the fly without rebuilding the application.

To define a new Jmeter task in Ant, download the Jmeter library [8]. Add the location of the library to the CLASSPATH.

Example 3

Listing 3 is responsible for running the Jmeter task. However, workflow is required so that we can run the task more than once without overwriting the results or ruining the template. The flow is as follows:

    1. The template is copied to a second directory, and the @@ tokens are replaced with values defined in the default.properties file.

    2. The test plan is carried out, and the results are saved. The results name is made unique by following a convention that includes the parameter used and a time stamp.

    3. An XSL task is run that turns the results into a statistics page.

Within the listing, a new taskdef is needed to allow us to apply the Jmeter task:

<taskdef 
    name="jmeter"
    classpath="../extlib/ant-jmeter.jar"
    classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask"/>
Next, we need to copy the templated test plan to a second directory, replacing the tokens with variables in the properties file. This is achieved by:

<filter token="LOOPS" value="${example.three.loops}"/>
<copy todir="${jmeter.workpad}" filtering="true" overwrite="true>">
Note that overwrite is set to "true" and that the token @LOOPS@ in the test plan will be replaced with the variable example.three.loops from the properties file.

The Jmeter task runs Jmeter and the XSLT task generates the html report. Figure 3 is a screen grab of one such report.

A More Advanced Project

We will use the excellent Ant-contrib library, which can be found at:

http://www.jcraft.com/jsch/index.html 
Please download the library and add to the CLASSPATH. Also, please comment out in default.properties the property example.three.threads.

Example 4

Ramp testing is stress testing with different levels of usage. One of the motivations behind ramp testing is to give an indication of how a system performs under future loads. Figure 4 shows two typical responses to a ramp test. The linear response under load is exactly what you want to see. If a production system is successful and more users wish to visit the application then, with a linear response curve, you will have more time to plan for replacement or additions to your hardware farm. However, with the second response curve, you will have a significantly condensed period to react in. Further, instabilities in response may confuse the underlying cause. In principle, it is better to find out the limitations of your system in acceptance than in production. It costs in short term effort, but generally saves in the middle term.

Ant is somewhat weak in mathematics and iteration, the task for list processes the example.four.thread property and expects a comma-delimited string (e.g., example.four.threads=5,10,15,20,30,40,50). Each element mentioned within <for </for> will be looped through.

<for list="${example.four.threads}" param="threads">
The <sequential> statement forces the code to be run sequentially. If you wish you can also run the tasks in parallel. But that action risks side effects such as race conditions and resource deadlocks.

Within the for loop, we call the antfile example3, which runs an individual Jmeter testplan. The parameter example.three.threads is set to the iterated value:

<ant antfile="example3.xml" target="JmeterTest"  
  inheritall="true" > 
    <property name="example.three.threads" value="@{threads}"/>
</ant>
Note that you will need to comment out the example.three.threads in the property file, or the properties file value will win over the iterated value. Also note the strangeness with the "@" instead of the "$" for threads; you will need to accept this for the task at hand. Sometimes life is just like that.

Now that I've run through the basics, here are a few hints based on my own experience:

    1. Make paths relative. This practice will allow you to keep resources within your build structure and make transport of the structure to other machines easier.

    2. Make your targets as brief and as discreet as possible. You should call one target from another.

    3. Always run as a non-privileged user or some of the more powerful tasks may cause pain if misconfigured.

    4. Resist the temptation to use OS-specific code such as exec. If required, then move into a separate task.

    5. Add meaningful descriptions so that other systems administrators can guess what is going on.

    6. Try to collect often used targets into generic build files.

    7. Use Echo copiously.

    8. Make sure property names are consistent between the build and property files.

    9. Be careful when you overwrite files or clean directories as you will be indirectly affecting other tasks.

    10. Do not get set in your ways. Find excuses to try out new tasks, and this will allow you to expand the applicability of the tool further.

    11. Testing should be done from another server as you may affect the tester by the resources used by the tested.

    12. Let the Jmeter GUI do the configuration work for you.

Looking back to the infrastructure described in Figure 1, we have cycled through all the relevant tasks and approaches from the Ant side apart from the scp task. Code for this would look similar to:

<scp todir="${scp.user}:${scp.pass}@${scp.host}:${scp.rootdir}" \
  trust="true" >
    <fileset dir="${clean_dir}/scp_final"/>
</scp>
    
The task requires the scp dependency library [9].

That brings us to the assertion tests. Jmeter has components for assertion testing. If a particular string or lack of a string is returned from a response, then an error can be raised. Therefore, to render assertion tests from Ant requires no more scripting skills. It is a question of making the correct test plans and templates. However, that said, anteater is an Ant-specific assertion task. If you would like a more direct approach, then this contribution should be your first port of call. Other tasks of interest include ones to deploy and maintain Tomcat and the standard SQL task to connect and manipulate databases. They are many more tasks worth exploring.

Enjoy your experimentations. I wish you luck.

Resources

1. Ant Home -- http://ant.apache.org/

2. Jmeter home -- http://jakarta.apache.org/jmeter/

3. Apache home -- http://www.apache.org

4. Ant download page -- http://ant.apache.org/bindownload.cgi

5. Jmeter download page -- http://jakarta.apache.org/site/downloads/downloads_jmeter.cgi

6. Mail library download page -- http://java.sun.com/products/javamail/

7. Activation download page -- http://java.sun.com/products/javabeans/jaf/index.jsp

8. Jmeter library download page -- http://www.programmerplanet.org/ant-jmeter/

9. Scp dependency library -- http://www.jcraft.com/jsch/index.html

Alan M. Berg has been a lead developer at the Central Computer Services at the University of Amsterdam for the past seven years. He likes to get his hands dirty with the building and gluing of systems. In previous incarnations he was a technical writer, an Internet/Linux course writer, and before that a science teacher. He remains agile by playing computer games with his kids (Nelson and Lawrence) who sadly consistently beat him.