Writing Performance Tests in Grinder using a Framework
Here we do two additional things. After creating an instance of LoginTask, we create an array of name-value pairs and assign it to loginCredentials. We then create a new property for this particular instance of LoginTask called loginCredentials, and set the value of that property to the array we just defined. The reason we do this is because we’re going to be refering to this array in our parameterizing method. Then, we actually define the parameterizing method. In the method, we choose a name-value pair out of the array using the current thread number as an index. We then use the username and password in the name-value pair as our login credentials. What we’re essentially doing is modifying the username and password parameters for request number 201 in the appLogin2 method of LoginTask. The neat thing is that you can put whatever logic you want inside the parameterizing method. You could even read from a file if you wanted to.
Finally, here is one more example. It’s a bit more complicated, but see if you can figure out what it’s trying to do. I’m providing a link to it (grinder-frameworked,py) since it’s a little long. The code is commented so that should help
: I hope this demonstrates the power and flexibility of the testing framework. Now you’re ready to write your own tests using this framework! But before that, you’ll need to know how to translate the data from TCPProxy.
Using xmlToJython.pl
xmlToJython.pl is a handy script that I wrote, that translates XML header data from TCPProxy into a Jython class. Before you use it, you need to have TCPProxy return XML data instead of Jython. You will need to create a new shellscript:
#!/bin/bash . setGrinderEnv.sh java -cp $CLASSPATH net.grinder.TCPProxy -http $GRINDERPATH/etc/httpToXML.xsl -console > grinder.xml
Then, you’ll need to use xmlToJython.pl to convert the XML file into Jython. The syntax for xmlToJython.pl is this:
xmlToJython.pl input.xml [output.py]
The output file is optional. If one is not provided, the script just outputs to STDOUT. The script requires that the XML::Simple module has been installed. The easiest way to do that is through cpan (a commandline tool to install Perl modules). I’m going to see if I can compile the script into a binary so that you don’t have to jump through hoops to use it.
A few more tips… xmlToJython.pl has a feature that lets you make your generated script a bit nicer to read. In the code samples above, you’ll notice that the methods had nice names like “appLogin1″ instead of “page1″, and that the description strings for the tests were actually informative instead of just “GET /somefile.html”. Here’s how you can do that: When you start up TCPProxy, you’ll notice that you can add comments. If you make sure that your very first comment is of the form:
@NameOfTaskClass pageMethodName:Description of Task
Then, your recorded class will be called NameOfTaskClass, your page methods will start with pageMethodName, and your test descriptions will have “Description of Task” prepended to them. Typically you should only need that very first comment since you’re only recording one discrete task.
Popularity: 100% [?]
Dear vivin
Happy onam to you. we are a group of students from cochin who are currently building a web portal on kerala. in which we wish to include a kerala blog roll with links to blogs maintained by malayali’s or blogs on kerala.
you could find our site here: http://enchantingkerala.org
the site is currently being constructed and will be finished by 1st of sep 2009.
we wish to include your blog located here
http://vivin.net/
we’ll also have a feed fetcher which updates the recently updated blogs from among the listed blogs thus generating traffic to your recently posted entries.
If you are interested in listing your site in our blog roll; kindly include a link to our site in your blog in the prescribed format and send us a reply to enchantingkerala.org@gmail.com and we’ll add your blog immediatly.
pls use the following format to link to us
Kerala
hoping to hear from you soon.
warm regards
Biby Cletus
Hi,
I was evaluating Grinder tool..
If the Tester Runner method is big . i mean if Testrunner class exceeds certain length then i am unable to run the test and the tool is throwing following exception…
As a workaround we can divide the script into more than once script but the problem here is how can i call one script in other…?? could you help me..
Thanks In Advance
Kamalakar
@kamalakar
That’s strange – I’ve never run into that issue before. What is the exception you’re getting? You might consider putting each one into a class of its own and since they’re callable, you might be able to call them split them into separate classes and then write a wrapper that calls them? I think you’ll probably have better luck on the grinder-use mailing list – have you asked your question on there?
I have read some of your posts and find your style of writing very interersting. Salute you on how neatly the articles are presented.
@Avinash Mangipudi
Thanks Avinash!
I get following error for all import statements of my framework scripts (ImportError: no module named sci).
This goes away if I compile all my dependent scripts and add jar to classpath of agent. But then I cant parameterize methods in those dependent scripts as they are already classes.
How do I solve this?
I tried settting PYTHONPATH, passing python.home in grinder.properties. nothing seems to work for me.
I found out the issue. I had to put my script sources folder in Jython registry file.@Mukes Nair
@Mukesh Nair
Sorry I didn’t get back to you sooner. I didn’t check my email until now! I’m glad that you were able to fix the issue. I wasn’t clear on your initial problem though. Did you have problems importing the actual scripts (that you created using the framework) themselves?
Hi ,
I am trying to use torque framework , facing problem with the scenario class.
As scenario class showing error at following code.
” urlDict = property(getUrlDict, setUrlDict)” because my eclipse is unable to find property import.
i have jython 2.1 with me. it seems the property import is not available on the jython 2.1
Could you please help me wat might be the problem..?
Thanks
Kamalakar
I need a a way to share some data between tasks..
How can i do this?
Do we need to add other prop in the scenario class
@kamalakar
Hi
i am able to fix this error.. the problem is with my environment
Actually i am using GrinderStone its eclipse plugin for Grinder Tool.
Thanks
Kamalakar
@kamalakar
Sorry I wasn’t able to get to you sooner! Glad you were able to fix the issue – it did sound like an environment problem.
What data are you trying to share between tasks?Tasks are discrete entities that should have nothing in common with each other. Hence, they shouldn’t be sharing state-data. However, they can share input data (from a common resource – like a file).
suppose consider following usecase:
1.login is one task: after user got logged in we will get a userid .
2.second task :
— Here the request in this task need the userid from the previous task.
So, we need a global parameters that can be accessible throughout the scenario.
Could you suggest me how we can achieve . I have one approach in my mind.
— Add another param like ‘urlDict’ in the Scenario Class . what do you say.?
Thanks
Kamalakar
@kamalakar
In this case I’d parameterize the usernames and userId’s and link them to the thread number. You’d have to do this even if you were testing a pure Grinder-script that didn’t use the framework.
I have another issue to resolve. Any help will be appreciated. Lets take a scenario of a billing counter like of BestBuy. The associate will log in and load the billing screen. Then he will enter items and print receipt for a customer. Then for the next customer and so on. Here I have classified tasks in the scenario as follows
1. Login Task
2. Load Billing Screen Task
3. Enter Items Task
4.Print receipt Task
5. Logout task
Now in the run I want to run tasks 1, 2 and 5 only once. I want to repeat 3 and 4.
How do I do this?
Thanks
Mukesh
@Mukesh Nair
I’m assuming that you know how many times you need to repeat tasks 3 and 4? You can simply create n “Enter Items” tasks and n “Print receipt” tasks (through a loop perhaps, and maybe have an array for each, for example enterItemsTaskArray and printReceiptTaskArray).
When you build your scenario, you add Task 1 and 5, then iterate through both arrays at the same time and them to the scenario (so you’d add one “Enter items” task and then one “Print receipt” task). After you’re done you add Task 5.
Actually I don’t know how many times I will be repeating 3 and 4. I found another way to tackle the issue. Like this.
class TestRunner:
def __init__(self):
log(“initializing scenario %s” % self.__class__.__name__)
myScenario.initialize()
def __call__(self):
log(“running scenario %s” % self.__class__.__name__)
myScenario.run()
def __del__(self):
log(“finalizing scenario %s” % self.__class__.__name__)
myScenario.finalize()
@Mukesh Nair
so my scenario will look like:
myScenario.addInitTask(loginTask)
myScenario.addInitTask(loadPackScreenTask)
myScenario.addTask(scanShipmentTask)
myScenario.addTask(newCaseTask)
myScenario.addTask(scanItemTask)
myScenario.addTask(closeContainerTask)
myScenario.addFinalTask(logoutTask)
I think this should solve my current issue.
@Mukesh Nair
That would work as well. I’m assuming that you’re using meta-programming and extending the Scenario class at runtime?
Even if you didn’t know how many times you’d be repeating it, as in let’s say that it will be repeated a random number of times, you can add a random number of items to the arrays. But I do like your solution. It’s a little more elegant.
I have a problem of data getting mixed up between threads. Look at the log below.
initially thread-1 had value 100000019. Once thread -0 got the value 100000024, i printed out values again. Now both threads have the same value.
I decompiled one of the class files and I found that self is declared as:
static final py self;
Did you face similar issue?
11/20/09 10:56:09 AM (thread 1 run 0 test 101): self.parameters["SelectStationAndScanShipment2"]["201"]["BarcodeData"] 100000019
11/20/09 10:56:09 AM (thread 0 run 0 test 101): suggestedShipments ['100000019', '100000024']
11/20/09 10:56:09 AM (thread 0 run 0 test 101): self.parameters["SelectStationAndScanShipment2"]["201"]["BarcodeData"] 100000024
11/20/09 10:56:09 AM (thread 1 run 0 test 4201): http://10.10.20.80:7099/smcfs/console/exuipack.exui -> 200 OK, 365 bytes
11/20/09 10:56:09 AM (thread 1 run 0 test 4201): sleeping for 29 ms
11/20/09 10:56:09 AM (thread 0 run 0 test 4201): http://10.10.20.80:7099/smcfs/console/exuipack.exui -> 200 OK, 919 bytes
11/20/09 10:56:09 AM (thread 0 run 0 test 4201): sleeping for 31 ms
11/20/09 10:56:09 AM (thread 1 run 0 test 4301): http://10.10.20.80:7099/smcfs/console/exuipack.exui -> 200 OK, 244 bytes
11/20/09 10:56:09 AM (thread 1 run 0 test 4301): sleeping for 34 ms
11/20/09 10:56:09 AM (thread 0 run 0 test 4301): http://10.10.20.80:7099/smcfs/console/exuipack.exui -> 200 OK, 244 bytes
11/20/09 10:56:09 AM (thread 0 run 0 test 4301): sleeping for 30 ms
11/20/09 10:56:09 AM (thread 1 run 0 test 4401): http://10.10.20.80:7099/smcfs/console/exuipack.exui -> 200 OK, 919 bytes
11/20/09 10:56:09 AM (thread 0 run 0 test 4401): http://10.10.20.80:7099/smcfs/console/exuipack.exui -> 200 OK, 919 bytes
11/20/09 10:56:09 AM (thread 1 run 0 test 4401): sleeping for 63 ms
11/20/09 10:56:09 AM (thread 0 run 0 test 4401): sleeping for 60 ms
11/20/09 10:56:09 AM (thread 1 run 0 test 4501): http://10.10.20.80:7099/smcfs/console/exuipack.exui -> 200 OK, 341 bytes
11/20/09 10:56:09 AM (thread 1 run 0 test 4600): self.parameters["SelectStationAndScanShipment2"]["201"]["BarcodeData"] 100000024
11/20/09 10:56:09 AM (thread 0 run 0 test 4501): http://10.10.20.80:7099/smcfs/console/exuipack.exui -> 200 OK, 341 bytes
11/20/09 10:56:09 AM (thread 0 run 0 test 4600): self.parameters["SelectStationAndScanShipment2"]["201"]["BarcodeData"] 100000024
@Mukesh Nair
How are you parameterizing the data? Are you doing it based on the thread number?
@vivin
am setting data in the task itself using one method call to a utility script, like below
def SelectStationAndScanShipment2(self):
“”"Selecting station and scanning shipment POST exuipack.exui (request 201).”"”
self.parameters["SelectStationAndScanShipment2"]["201"]["BarcodeData"] = self.StringUtil.getAPickedShipmentNumber(self.parameters["SelectStationAndScanShipment2"]["201"]["OrganizationCode"])
self.log(“self.parameters[\"SelectStationAndScanShipment2\"][\"201\"][\"BarcodeData\"] %s” % self.parameters["SelectStationAndScanShipment2"]["201"]["BarcodeData"])
@Mukesh Nair
I recommend not modifying the actual task. What you want to do is create a parameterizing method that sets the values in the parameters dictionary for you. Check out my examples in this post.
@vivin
i wanna show you a grinder xml which is not producing correct url in the task created by the perl script. I directly created grinder script using proxy. I can see a lot of arguements witht he url. But when it is converted using using the perl script into a task, all the arguements are missing. let me know where to send the related files so that you can take a look. I haven’t looked into perl yet. So I thought you could resolve it faster.
@Mukesh Nair
Is it a POST or a GET? I can take a look at it. I DM’ed you my email on twitter. So just send me the XML and I’ll take a look at it.
[...] alerted me to a problem with the Perl conversion script (that converts the XML produced by the Grinder [...]
Pingback by An update to the Grinder testing-framework | Rough Book | December 7, 2009
Hi Vivin,
Here i need your help. I am working in web application and i wanna to test the load of the application. For this i am using the grinder tool and under stand all the things except properties file of grinder framework. Is it possible to run more than one script or divide the scripts in threads on same time. Here i can explain you through example. Suppose we have 4 scripts and want 4 scripts are equally divided in 100 user’s. is it possible?
@vicky
I looked around for ways to run multiple scripts and I ran into this post here that says you can do it by making each script as a separate property and not space delimited. So what you need to do is divide the load (and select a user) based on the thread number. Script 1 will use user1-user25 (if the thread number is between 1 and 25), script 2 will use user26-user50 (if the thread number is between 26 and 50). This basically means that you need to have 100 threads.
The Perl file under the link on page 9 is not the same as the one you packaged in the ZIP.
@Marcel
Thanks for pointing that out Marcel; I’ll fix it!
@Mukesh Nair
Could you show the details about it. I have the same problem.
Hi vivin.
I have a question about the using of regex. Since grinder just allows to compile regex within the runner, how do i parse http results in torqueo tasks? I didn’t get any valuable answers in the internet so far. Do you have any advices? Would be great, thx!
@muellae
Sorry for taking so long to respond. I was pretty busy with school and work. There is no way (as of now) to have access to the HTTP results. It’s abstracted away inside the tasks. What you could do, is modify the autogenerated task-files themselves and get access to the result that way.
The reason that the result is not provided (and possibly cannot be provided per the current design) is that a task consists of one or more requests. So it doesn’t make sense to talk about the “result” of a task. A task represents an abstract unit.
Hi vivin!
Thanks for your answer. I actually meant a http request only and was not able to parse it. The problem was, that it’s hardly (or even not?) possible to use the python regex lib in jython. I’m now just using the java regex library and it works like a charm.
Thanks anyway for your answer! You did a great job with torqueo, it’s a great tool which helped me a lot.
@muellae
I’m glad you find my tool helpful!
Glad to know you figured it out. Also, thank you for your kind words
Hi Vivin,
Thanks for describing the test framework. Its nice to see the way u maintained the tutorials for Grinder. Have few queries on implementing few features related to Grinder.
1. How to call a user defined function
2. How to monitor server side metrics like CPU,memory and Disk etc.
3. Do we have an option to add users dynamically.
Do u have any monitoring template available
Thanks
Sattish.