JMeter and DWR

Testing a web application with JMeter is easy, but when your application uses AJAX (with DWR, for instance) and sessions, it can be a complex task.

I’ve developed an application with DWR and i want to test the performance. DWR is one of the coolest project to make an AJAX applications, IMHO.
The first aproach with JMeter is to save a set of requests to reproduce later, but those requests are asociated with a session. So, if i run concurrently those requests in several threads:

  • i don’t test what i want. I want one session per thread
  • maybe i obtain inconsistent data

To record a set of request, we have to:

  • In Test Plan add a Config Element/HTTP Request Defaults
  • In HTTP Request Defaults set a value to Server Name or IP, Port Number and Protocol
  • This is necesary to chage easily the host and port of all request. If you don’t use a HTTP Request Defaults, every request recorded will have a host and port value, and if you want to test another host you have to chane a lot of values.

  • In Test Plan add a Thread Group
  • In this Thread Group add a Logic Controler/Recording Controller
  • It is a simple container for the requests. ;)

  • In WorkBench add a Non-Test Elements/HTTP Proxy Server
  • In HTTP Proxy Server set Port, Target Controller and Pattern to Include
  • In HTTP Proxy Server add a Timer/Gaussian Random Timer
  • In the Gaussian Timer, set the Constant Delay Offset to ${T}
  • This record the time between every request with a random deviation. It’s very important to try to reproduce the user experience.

view JMeter screencast

In this screencast i introduced HTTP Cookie Manager and a listener item that didn’t be included in the above explanation. It will be used in stress time to let JMeter manage cookies to store JSESSIONID value of every thread (synthetic user) and view the results.

Now, it’s time to deploy your application and configure your browser to use the JMeter proxy.

view proxy screencast

Easy, isn’t it?

Try 1

Then, my next step was recording several users and grow up the JMeter config file. I’ve created several thread groups, one per concurrent user with distinct session IDs (remember to close the browser between every recording to clean cookies). But .., with six or seven users the files was almost 6 MB, it may vary in your project and the complexity of the user requests.

JMeter is a really cool application, but with this kind of file sizes, it needs a lot of memory. I’ve got a lot of OutOfMemoryExceptions and decided to record every new user from scratch to later merge in only one project file.

This was not a success experience, i only could get less than ten users and, the JMeter can’t use those big files, and i wasted a lot of time recording every new user, so …

Try 2

Regenerate a new session ID per thread. This seems to be easy, i have a lot of experience with xpath, and i can extract a portion of a html with it. First i created a .jsp to print the session ID:

<html>
<body>
<sessionid><%=session.getId()%></sessionid>
</body>
</html>

At the beginning of the user recording, i request this .jsp, and the i attach a Post Processor/XPath Extractor in this HTTP Request, with this values:

  • Reference Name: USERSESSIONID
  • XPath query: /html/body/sessionid/text()

Now i only have to replace the session IDs ocurrences in the JMeter config file (.jmx) with:

${USERSESSIONID}

I used jEdit to replace, only have to find the ID like E4B1B20074F2106ED330B98387EAF8E5 and replace all with the above text.

But … DWR needs another sessionid (script session id) and the JMeter failed :(

Try 3

I thought i could get DWR script session id like the session id, but minutes ago of reading the DWR code, i discover that engine.js have this values in JavaScript variables. Instead using XPath extractor y used a Regular Expresion extractor.

In the engine.js HTTP Request, attach two Regular Expresion Post Processor with:

  • Reference Name: HTTPSESSIONID
  • Regular Expression: DWREngine._httpSessionId = “(.*)”;
  • Template: $1$
  • Reference Name: SCRIPTSESSIONID
  • Regular Expression: DWREngine._scriptSessionId = “(.*)”;
  • Template: $1$

regexp

Then you have to replace the values like Try 2 in the DWR requests:

[...]
<stringProp name="Argument.value">1
httpSessionId=${HTTPSESSIONID}
scriptSessionId=${SCRIPTSESSIONID}
page=/smartcv2/Edit.do
c0-scriptName=MainForm
c0-methodName=setValue
c0-id=5943_1159885700394
c0-param0=string:biologicalDescriptors.dateOfBirth
c0-param1=string:October%2015%2C%201979</stringProp>
[...]

Check the .jmx file twice before loading in JMeter and if you have problems, use a TCP Monitor to see the HTTP traffic. Axis and Eclipse + WTP come with one (also netbeans, but i’ve not used yet).

See here the addendum for DWR 2.0RC2

7 Comments so far

  1. Joe Walker on October 18th, 2006

    Thanks Jorge - I’m not to familiar with JMeter, but I’ve added a link from the DWR “Around the web” page: http://getahead.ltd.uk/dwr/elsewhere .

  2. Mare on November 10th, 2006

    Didn’t have time to re-create the test from your tutorial, but if it turns out to be successful, I’ll start worshiping you! Had so much trouble with testing dwr…..

  3. Kumar Pandey on November 11th, 2006

    I don’t understand how this will work. DWR is expecting a post with like so

    callCount=1
    page=/smartcv2/Edit.do

    It seem to parse each line and form a map. In the case above callCount is a param key and rest of the string is value so I’m getting callCount is not a number error.

    The newline post is causing lot of grief to use tools like JMeter in dwr. Why couldn’t this data is passed as normal key value pairs?

  4. Kumar Pandey on November 11th, 2006

    OK, my apology. Jorge’s steps actually works.
    Provided you don’t edit the javaservice post request key value param from the Jmeter UI.
    This will screw up the new line.
    As he suggested just edit the xml file to replace the session id with the variable from regular expression extraction.

    I see the following being posted now -

    callCount=1
    page=/demo/dwr.html
    httpSessionId=B399078721DD4C38FE3AB4BD793F975B
    scriptSessionId=E46E1F4BE9B1582B0DAE07A69D859D50
    c0-scriptName=SearchService
    c0-methodName=getResults
    c0-id=0
    c0-param0=boolean:false
    c0-param1=string:A
    batchId=0

  5. Peter Odéus on April 16th, 2007

    Any editor may screw up the new line :-( . Having an editor with a unix style default setting (notepad on WinXp), I spent some time before figuring that out. So to be safe, switch to hex mode in your editor to make sure 0d 0a (or was it the other way around ;-) ) are in place.

    /Peter Odéus

  6. Peter Odéus on April 16th, 2007

    … or on second thought, jMeter seems to be bearing the responsibility; every time I choose “save” in jMeter and then switch to the reloaded file in my editor, it simply shows the current line-break style that the file currently has. So I have to manually set it to windows style in order to enforce 0d 0a line breaks.

    Maybe another approach would be to, in jMeter, add a couple of \r\n (after all, it’s a java app), in the request parameter value. I’ll try it tomorrow…

  7. Peter Odéus on April 17th, 2007

    Ahh, finally. In the jMeter GUI, as a child element to the test plan; add a Edit - Add - Config Element - User Defined Variables. Add a name, e.g. CRLF, and a value: ${__javaScript(’\r\n’)}
    Then you alter the request parameter such that it becomes like: 1${CRLF}page=/jmeterTemplate.html${CRLF}scriptSessionId=${SCRIPTSESSIONID}${CRLF}c0-scriptName=dwrQuoteRequestService${CRLF}c0-methodName=doService${CRLF}c0-id=0${CRLF}c0-param0=string:${CRLF}c0-param1=string:${CRLF}c0-param2=boolean:false${CRLF}c0-param3=boolean:false${CRLF}c0-param4=boolean:false${CRLF}batchId=0
    Good luck
    :D
    /Peter Odéus

Leave a reply