99 Bottles of JMeter on the wall

I’ve recently had to do some performance testing on a couple of our new web services. I know of a few handy open source tools available for this. Tsung, Grinder and JMeter spring to mind. I find that I can get up and running in JMeter quicker than I can with the other tools and it tends to be the one I use most. One of the web services I wanted to test required some dynamic content to be generated in the body of the HTTP POST. Normally I’ve been able to get away with using the standard counters and config variables provided by JMeter, but this time I needed a bit more control. Luckily, JMeter allows you to do some scripted preprocessing of HTTP requests and I was able to use this to generate dynamic content within JMeter. I found the JMeter documentation to be a bit lacking in this area, so I created this blog post to give a quick explanation of how I managed to do this.

I’ve created a demo project that you can follow along with to see how it all works. Download the source code here: https://github.com/groodt/99bottles-jmeter Follow the README on GitHub to get everything setup and running. All you need is git, Python and JMeter. Open up the file “Test Plan.jmx” in JMeter to follow along.

The demo
The demo project is a simple web service that parses JSON payloads and prints a modified version of the “99 Bottles of beer on the wall” song onto the console. The JSON payload looks something like this:

{“drink”:”beer”, “bottles”:”99″, “date”:”1321024778956″, “thread”:”4″}

The server then parses these payloads and prints them out to the console:

JMeter then aggregates the response times in the summary report:

The HTTP POST
If you navigate to the “HTTP Request” node in the example you can see the JSON POST body being constructed:

The variables ${drink}, ${bottles}, ${date} and ${thread} are generated dynamically by a script that JMeter executes for each request.

The BSF PreProcessor
The BSF PreProcessor is run before each HTTP request to generate the dynamic content mentioned earlier. The BSF PreProcessor allows you to run Javascript, Python, Tcl and a few other languages inside JMeter. I decided to write my script in Javascript.

If you navigate to the “BSF PreProcessor” node in the example you can see the script that is used:

The Javascript
The simple Javascript basically places 4 variables in scope that are then available for JMeter.

// Calculate number
var count=vars.get("count");
var bottles=99-count;
vars.put("bottles",bottles);

// Calculate drink
var random=new Packages.java.util.Random();
var number = random.nextInt(4);
var drink = vars.get("drink"+number);
vars.put("drink", drink);

// Calculate date
var date=new Packages.java.util.Date().getTime();
vars.put("date",date);

// Calculate thread
var thread=ctx.getThreadNum();
vars.put("thread",thread);
  • In lines 1 to 4, the counter is read from JMeter then 99 is subtracted and the value is placed into scope under the name “bottles”.
  • In lines 6 to 10, a random number from 0 upto 4, it then uses this number as a lookup into the names of drinks (beer, wine, mead, cider) defined in the JMeter General Variables. It then stores this value in a variable named “drink”. It makes uses of java.util.Random to generate the random integer.
  • In lines 12 to 14, java.util.Date is used to generate a timestamp in milliseconds. This value is stored in a variable named “date”.
  • In lines 16 to 18, the JMeter thread number is read from the JMeter context and then stores this value into a variable named “thread”.

Executing Java libraries within the scripts
If you noticed in the scripts above, the Java libraries are exposed in JMeter under Packages.*. This allows you to execute any of the Java standard libraries or Java code in the classpath of JMeter. I think you can also write your own Java code and place it in the JMeter classpath and expose it in the same way.

Putting it all together
Putting all of that together gives you a handy way of doing reasonably complex performance testing in JMeter and I hope you find it useful.

6 thoughts on “99 Bottles of JMeter on the wall

  1. Thanks for sharing Greg. Its awesome of you to go the extra mile and provide the follow-along source on github.

    Q: Did you happen to look into how JMeter’s javascript capabilities can be further expanded?

    For example, if someone wants to use the JSON.stringify(myObject, replacer); method in the BSF PreProcessor … then where can the source (https://github.com/douglascrockford/JSON-js) javascript be dragged & dropped … such that it will be like using the methods out of the box?

  2. I’ve not specifically looked into expanding the javascript capabilities. I think the idea of the BSF preprocessors is to use the core features of javascript for simple tweaks. Im not entirely sure if additional scripts can be loaded into the JMeter javascript runtime (powered by Rhino), but it would be interesting to investigate this. I imagine that you would need to call the global “load()” function provided by Rhino, but Im not sure where the scripts would be loaded from on disk. It might be that they simply need to be in the same directory as the *.jmx file.

    I think the preprocessors are meant to be lightweight, so you would need to avoid using logic or dependencies that might slow down the actual performance tests too much.

    If you specifically need JSON.stringify then this is available in the nightly build of JMeter (2.7-SNAPSHOT or greater) or you can download Rhino 1.7R3 (https://www.mozilla.org/rhino/download.html) and replace the js.jar in your existing JMeter 2.6 distribution.

  3. Thanks for great post. It worth mentioning that BSF / Javascript interpreters are initialized each time they’re being accessed. Also none of language which are provided by BSF scripting enging don’t implement Compilable interface. It means that each time script called it’ll be executed by script engine causing resources consumption and performance degradation. It’s recommended to use JSR223 Sampler and Groovy language as it can be compiled into Java code and gives performance nearly the same as native Java function or custom sampler. See Beanshell vs JSR223 vs Java JMeter Scripting performance comparison benchmark for more details.

Leave a Reply