Wednesday, November 14, 2012

JMeter


took a while to figure out how to get around to using another one of the immensely simple yet powerful arrows from Apache's amply filled quiver.

The biggest problem with working with Jmeter was that I could not get a head-start. For the uninitiated, it is a load-testing platform developed by Apache.

To start with, ensure you download the latest source code. Fooling around with the one installed with apt-get ensures hours of frustration with no results. The results from internet searches are deceptively informative. Next, well we would prefer having our very own sampler. Why?
 //need to answer this one bro!!

Here we go. First, a little peek into the application I was trying to clobber with requests. A platform to book cabs called pyngcabs was the project. The cab booking was to be done using different clients, to start with, android.
 The Server side code was handled by a team of four writing in Spring and using the akka framework for asynchronously handling calls. This would facilitate a behaviour wherein the cab driver would be given the liberty to choose between cab requests he is given. The flow is as follows :
  1. The customer requests a cab.
  2. Filtered cabs using google maps API are shortlisted with assistance from the customer's GPS.
  3. The cabs are sent the requests.
  4. The cab drivers approve or reject requests. 
  5. The customers are notified of the cab that wishes to accept.
When performing a single test case, the main difference between android and desktop client was the ability to use the awesomely-cool server-to-client notification mechanism using GCM, which although not documented to be guaranteed to receive proved to be nearly as fast and as reliable also without the need for a long living TCP connection with heartbeat messages or other similar mechanism adopted by most notification softwares which can be plugged in with android.

Back to jmeter, so what I wanted was a mechanism to perform requests from a customer, accept/reject one of the requests and notify the same to the customer. A polling based approach which was considered a second-line of defence approach if the GCM message does not arrive till a certain time period,was the path to go with jmeter. So, first we have a HTTP POST where the customer puts in a request. This request was being done using a JSON Object. Hang on!! Load testing would mean multiple customers, multiple users, how does that work? The first thing to notice/ use is a thread group. A thread group allows running a set of threads which would perform similar operations. So, I make two thread groups, one for the customers and one for the cabs. It can be found in add--> threads --> thread groups.
The next thing to do was to add the payload type of the HTTP request we would be sending. In my case, it was a json object and I added the same.A picture, to reduce my words:
Next, to reduce redundancy of our configurations, we add common info like server address, port number and other common variables in the test plan:
//Saving the post
 Next comes the customer thread group. First, I send a HTTP request to the server that I need a cab. For each customer thread that I run, I need to send a unique customer id in the object. Here I made a little script to generate sql INSERT files with serially ordered customer and cab ids and an extension to the same script to create a comma-separated-values file, popularly called csv.

To build a HTTP request, I need to make a JSON object with a value that I fetch from the csv file. For this, we use two things, a CSV data config to read from the csv files and a beanshell pre-processor to generate the JSON object which will be the payload. First, the CSV data config:
The variable names is where we write the name which we will later use in the beanshell pre-processor. In my case, I chose the name custid which is only one var per line. If there are more than one, we need to write them all separated by commas(obviously,it is a csv).Next, we set the delimited as',' without the quotes and the sharing mode as all threads. What is really smart with jmeter is, we never told jmeter about iteration, the thread group takes care of it!! Viola! this simple GUI handles loading different user IDs. Here is the pre-processor for the payload generation:
Do note above that the CSV data config and the beanshell pre-processor are children of the http request. In the beanshell pre-processor, we use the command vars.get("custid") to get the variable custid which we set in the csv config file. We use this and other variables which I have hardcoded for convenience. Once the JSON object has been generated, we need to put it back into the variables. We do it with the command : vars.put("custRequestJSON",toSend.toString()); where the variable name is the part in the double quotes. This variable will be sent with the HTTP request. //saving the post 2 Here is a screenshot of my HTTP request:
I use the var names we set in the test plan and we send a payload as a variable with no name and the value as ${custRequestJSON} which was set in the pre-processor. Now, we are done with sending the request. We follow this with parsing the reply. The reply, in my case has a tripId which I use to query the server to ask whether the trip is scheduled. First the post-processor, to get the tripId:
Next comes polling the server with the trip id which has been put into the variable tripId. For polling, I have used a while controller which keeps running the request till it gets an object where the value for state of the trip is scheduled. I also use a constant timer to space requests so that I do not just keep polling non-stop. I would prefer a near-real scenario wherein I poll somewhere between ~3-5 seconds. Below is the while controller, where I check the value of a variable 'confirmed' and run if not 1( which I set as 0 in the post processor).
Inside this while controller, is another HTTP request, this time a HTTP GET to check the state of the trip and a post-processor to process the state of the trip. Below is the beanshell post-processor part to check the state of the resulting payload.
So, that is half the story. A similar thread group for the cabs was made, where each thread uses a HTTP GET to check for new requests, use a post-processor to randomly accept one of the results and then sends a HTTP PUT with that request id. This is accomplished by an if controller which checks the post-processor. Do let me know if I can help with any queries.