Wednesday, 27 March 2013

Performance test of GWT Apps using Jmeter

Are you looking for a way to prepare Jmeter tests for GWT based application ?

This blog is for those who is trying to create a jmeter performance test for GWT based application.
The examples are captured when application was running in Jboss server. There could be a variation in the results when different app server is used.

GWT generates a payload which is pretty difficult to interpret. Payload is a data which GWT prepares and sends over the network to the application server where GWT apps is running. Payload is a direct conversion of java hierarchical object structure into text format.

Following are the steps performed to prepare jmeter test for GWT based application.
1) Capture the payloads for every gets and posts.
2) Parse the payload, identify each field of payload.
3) Decide which are dynamically generated data and which are static data.
4) Work on how to automate the dynamically generated data.
5) Specify session information
6) Prepare a jmeter test with threads and loops.
7) Run the performance test.

1) Capture the payloads for every gets and posts.

As said earlier, payload is the data posted from browser to application server. Payloads can be directly captured in jmeter or using a firefox plugin httpfox. Here are the steps for both.

Capturing payloads in jmeter.

1) Right click on WorkBench and select Add --> Non Test Elements --> HTTP Proxy Server.
2) Set some port number which is not in use (9090 in the below example) and click on start.
Upon starting this HTTP Proxy server, jmeter start listening to 9090 port and records all the gets and posts happening in this port.
3) Close all the browser tabs so that no other gets and posts would disturb your activity.
4) Set the above set proxy browser (9090 in this example).Click on OK.
5) Perform the required operation in browser.
6) Verify that the performed operations are captured in jmeter. (Login operation in the below example)
A typical jmeter recording looks like below.

2) Parse the payload, identify each field of payload

 As explained earlier, payload is a data sent in the jmeter request for processing. There could be different kind of data like login data, method data etc. Identifying different jmeter payloads is explained below.

Login data:

Login is the most simple screen and contains most straight forward data. It looks as shown below.

Method data:

This is the most complicated form of data which contains Method name, parameter to the the method, GWT compiler generated code. Again parameter could be string or some number (generally IDs). This is how a simple GWT payload looks.

Method without any parameters:
7|0|4|https://${serverip}:${port}/domain/|4A8FEC11BD605B9C8234F0FB0DA1031A|com.comapany.proj.ui.sf.gwt.client.accessctrl.service.sfAccCtrlService|getUserLoginInfo|1|2|3|4|0|

In the above payload, getUserLoginInfo is a method name (Marked in green), 32 alpha numerical text marked in pink is a GWT compiler generated code.

Method with parameters:

7|2|7|https://192.168.8.123:8443/application/appcustmanagement/|7B34B220B1E6DA85A3616A0062542DD1|com.google.gwt.user.client.rpc.XsrfToken/4254043109|648FD2FDB7D33D80EE10029B8962B279|com.company.application.ui.pricing.gwt.client.applicationService|listServices|Z|1|2|3|4|5|6|1|7|0|

In the above example text marked in yellow is a class name, text marked in green is a method name and text marked in aqua is the input the method.

What is Compiler generated code?
GWT uses this to identify different modules in your application. There will be a unique 32 bit code generated for each of the module. For automating the jmeter test, it is important to know how this code is generated so that this code can be parametrized. Typically, browser identifies this code through cash file which is transferred from app server to client. We would have to do the similar thing.

When you record any transaction in jmeter, there will be a get call to the cache file (say page.nocache.js or some thing of similar name). This is the cache file contains another cash file name which will provide you the compiler code for each module.
There will be 2 files to get the compiler code.
1. page.nocache.js file which contains the module file name. Do a http get operation to this file and write a regular expression to capture the module name.

As you see, I have added a regex extractor to the page.nocache.js operation which stores the module code in a variable tb.
In page.nocache.js file, the module code comes as Rb=ASDGFRE1344FWFGVHT543QWEGHFT6781. This will be in the response of page request.

2. Get the module file and parse 32 bit compiler code.
The response comes as
$moduleBase,'moduleName1','ANCDEHDELEPDNFHE13445TJGLE'
$moduleBase,'moduleName2','124FFTYYH\LEPDNFHE134NY5663'
$moduleBase,'moduleName3','055JDDJHDELEPDNFHE1344RFGRB'
etc.

Write regex to get this module name and store it in a variable. Later this variable is used as the module name for the corresponding module request.

As you see in the above screen shot, unique compiler generated code of customer module is stored in code1 variable. I would be using code1 variable when ever I am accessing customer module.

3) Decide which are dynamically generated data and which are static data:

When a request is sent from browser to the server, payload includes both static and dynamic data. Static data could be some string which is being passed in the request, say some thing similar to login details. Dynamic data are those which keeps changing like id of any object. Such details might be generated locally by java script or they might have been captured in the response from the previous operation. Consider a simple Save and edit operation. During save operation you would pass all static data which might give a unique id of saved data in the response. During edit operation, we might have to send this id in the request representing which is the row we are editing. When a web page is representing multiple classes, say for example User information details, address details, contact details, in the edit operation, you might have to pass ids of user info, address info and contact info if you are editing these details. When web page is integrating multiple classes like this, it becomes tedious to identify which id is belonging to which object. Following are some of the simple techniques to identify the ids.
1. Record a payload in jmeter, glance through the payload request, map it to the corresponding id in the database tables, and parametrize such ids.
2. If the ids are numerical numbers through database sequence, set the starting sequence of all the tables as different numbers. Say in the above example, customer table starting sequence is set to 100, contact table starting sequence is set to 1000 and contact sequence is set to 5000. In such case, in jmeter recorded payload, we can easily identify which id belongs to which object. Parametrize such ids.

Alternative tool to glance at request/response payload:
You can install httpfox plugin of firefox which also gives each request and response details. This is helpful to edit the existing jmeter test plan where you just have to copy the payload from httpfox, parametrize it and add it in the jmeter request.

4) Work on how to automate the dynamically generated data.

You should not be recording the request and response every time you need to run the tests. The test plan should be created once and run as many times in as many servers. To achieve this, parametrization is necessary. Parametrization can take place in several places. It could in the response of previous request, it could through a SQL query, it could be through separate API call etc. The simple way to parametrize such data is through using regular expression extractor or any other post processor. I will not be talking much about this as this could be found in any of jmeter documentation.

5) Specify session information

When the login id and password of a page is submitted to the server, a unique session id will be generated which will then be used by the application  for tracking the session. This session is mostly used when your application has to go through authentication to perform the operation. This session id can be found in the URL section of the post operation. Following is one of the way a session id can be captured for your application.


As shows above, a regular expression extractor is used to get the session information. Once the session id is captured, it should be used in the HTTP Header manager of all the succeeding steps which requires session. It is as depicted below.




6) Prepare a jmeter test with threads and loops.

I am not going to explain this as this is a part of basic jmeter concepts.

7) Run the performance test.

5 comments:

  1. Nice and very interesting blog.
    As you show parsing GWTRPC payloads can be very hard if not impossible making it difficult to make test really dynamic and realistic.
    Hopefully, we provide a GWTRPC plugin for JMeter which allows:
    - Recording of GWTRPC application through CORE Jmeter
    - Request and response Transformation to XML for easy variabilisation
    - Easy scripting and debugging through View Results Tree Renderers

    See this blog for more details:
    - http://www.ubik-ingenierie.com/blog/load-testing-gwt-rpc-applications-with-ubik-load-pack-plugin-for-jmeter/
    - http://www.ubik-ingenierie.com/blog/boost-productivity-load-testing-gwt-with-jmeter/
    @ubikloadpack
    https://plus.google.com/+Ubikloadpack

    ReplyDelete
  2. Very good and usefull blog...

    But I have problems extracting the 32 bit compiler code within my Regular Expression Extractor. Could you please explain this part with some more details?


    Thank you in advance...

    ReplyDelete
    Replies
    1. Regular expressions are quiet simple, should not matter how many bits you have. You need to see how data is being returned for your request and you can do that by having tree result listener in jmeter. Depending on that, you will have to write regex. Refer to any regex document.

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. There is no difference between pictures in s640 and s1600 folders. So images are blurry :(

    ReplyDelete