Typically in JMeter we would use a ${variableName} notation. However JMeter only replaces these values when the the ${variableName} is within the script itself , not when it is referenced in some other file. As the user wants to use a separate (template) file which is added to the HTTP request, this technique wont work.
One option to consider is whether we could generate all the files we need before we run the test. this is possible for example when the dynamic data is a set of id's that is accessible say from a database. In this case the better (in the more efficient sense) is to have a initialisation step (perhaps as part of the build or as a separate step in Jmeter) to create all the files that the test would need. Once this is done it is easy to make the JMeter script pick one file (usually using the CSV DataSet Config).
However this isnt always possible. In the question above , the Order ID could be dynamically generated by the system under test in ways that might not be predictable. In this case we cannot generate the files in advance. We have to extend JMeter.
The cleaner more elegant way to do this would be to write a custom pre-processor of some sort because it sounds as if this functionality could be reused in some other context (or extend the HTTPSampler). But we will choose the quick and dirty way of writing a BeanShell preprocessor that does this for us.
Briefly the solution will
a. Have a template XML file. We will use @variableName@ within the file for what we want replaced. We will currently only support replacing a single variable (but it is easy to support multiple variables).
b. We will configure the HTTPSampler to use a generated file. At runtime a pre - processor will read the template file and generate this new file. This new file will be read and posted by JMeter
The Structure of the test is shown below
The HTTP Sampler adds a currently non existent file to be posted. This is the file the Pre Processor will create. The name of the file is varied based on the ThreadNumber (we could have added timestamps etc as well) so that each thread will get its own file name
We use user defined variables to define the location of the temp file, the regex that we want to run on the file and the replacement value.
The BeanShell pre-processor
import java.io.BufferedReader;
import org.apache.jmeter.protocol.http.util.HTTPFileArg;
import java.io.File;
import java.io.FileInputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.nio.channels.Channels;
//read the file as string
FileInputStream stream = new FileInputStream(new File(vars.get("templatePath")));
String fileAsString = "";
try {
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
fileAsString = Charset.defaultCharset().decode(bb).toString();
}
finally {
stream.close();
}
//perform the replacement
fileAsString = fileAsString.replaceAll(vars.get("replaceRegex"), vars.get(vars.get("variableName")));
//assumes first file
HTTPFileArg arg = sampler.getHTTPFiles()[0];
//write it out to the file we want
FileChannel fout = new FileOutputStream(arg.getPath()).getChannel();
BufferedWriter bf = new BufferedWriter(Channels.newWriter(fout, Charset.defaultCharset().name()));
bf.write(fileAsString);
bf.close();
Disclaimer : File Reading writing snippets swiped from Google, you can probably make it more efficient.- Briefly the snippet reads the template file(location defined as a variable) as a String (using the default charset , if you deal with multiple languages you might want to force this to UTF-8).
- It then runs the replacement using a regex (also a variable) and the subsitution value (also a variable which for this example we have just spoofed)
- Finally it writes the file(assuming default charset , again you could force this to be UTF-8). To determine the location of the file , it reads the location from the HTTPSampler. This is currently set as the first file , but we could have used a name or any other technique.
Sample JMX available here
17 comments:
hii need some help in installing jmeterwith env variables and also help about bean shell post processor. . it is howing bean shell intrepretor error . . if any solution is know kindly let me know thanks
mail the jmeter mailing list. You probably have a syntax eerror in your bean shell
Interpretor not found error got resolved by changing the bean shell jar file.
I am using a JMS point to point from which response has to be parsed and written to a file.
I am able to create a file from bean shell post processor and write a string variable
I want to know how to get the response and store in string
Also provide me some details on how to use
vars.get()
vars.put()
getResponseData()
I am totally new to jmeter. .
Thanks to u :)
Look at
http://jakarta.apache.org/jmeter/api/index.html
Class is JMeterVariables (vars), HTTPSampleResult(SampleResult)
get and put are fairly straight forward
vars.put("key","value");
you can do use it as
vars.get("key") or ${key} anywhere later in JMeter (like HTTP Sampler).
The other method gets the response of the Sample the post processor is attached to
Thanks for the information. I ll try and let u know the results . .:)
hi it worked fine today , i used getResponse dsta to get the response :)
Now the next step i hv to parse it and store to a file
i guess jmeter has inbuilt sax parser jar. . But i dunno hw to parse using it.
since you dont actually say what you want to do it is hard to advise. java has a built in XML parser so you could use that. However Jmeter can write data to file using listerners as well as extract data using XPATH post processor and Regex Post processor which should be sufficient most of the time instead of writing your own code
hi i have a doubt using vars.put("key",value). it works fine if "value" is a string. But when i try to pass a integer value, i am not able to get it.
ex. int a = 5;
int b = "response";
vars.put("key1",a);
vars.put("key2",b);
i am able to get "b" value by using
vars.get(key2);
but not get a value by
vars.get(key1);
if i convert the int into string then i am able to retrive.
vars.put("key3",a.toString());
then i am able to retrive.
any idea of how to retrive integer value as it is . .
Look at the javadoc
http://jakarta.apache.org/jmeter/api/org/apache/jmeter/threads/JMeterVariables.html
There is a method
put(String, String)
and there is putObject(String, object)
If you only intend using this in BSH then you could use putObject, but my recommendation would be to use
ex. int a = 5;
int b = "response";
vars.put("key1",String.valueOf(a));
To retrieve as int use something like
a =
Integer.parseInt(vars.get("key1"));
Thanks a lot , ur sugesstions were very helpful.
Hi . . hv u used switch controller. .
it it possible to give value using ${Var} in switch.. it works fine with integer
ex Switch
value = 2 it selects component with name 2.
but when i use bean shell preprocessor
int a = 5;
switch
value ${a} it deosnt work
Also in components reference it is given Non numeric values are also accepted but case sensitive.
it also doesn work . . If u hv any sugessions , it ll be helpful ty
variable values work - However it says element (so any sampler) - it wont work for pre Processors.
Also use debug sampler to inspect whether your variable is set correctly
Hi
I have 3 kind of users which will be determined from inputs from csv file.
For ex
input.csv has
Name sex age Address someIndicator
Naveen M 12 xxx " A "
Kumar M 20 asd " A"
Latha F 68 sda " B"
Saravanan M 20 asd " A"
Sam F 68 sda " C"
Say based on someIndicator
we have to pass certain parameters to a JMS request
For this i hv used bean shell preprocessor
String tempReq = null;
if(${someIndicator}==A){
tempReq = "Value<\param1>"+
"Value<\param2>"+
"Value<\param3>";
}
else if(${someIndicator}==B){
tempReq = "Value<\param4>"+
"Value<\param5>"+
"Value<\param6>";
}
else if(${someIndicator}==C){
tempReq = "Value<\param7>"+
"Value<\param8>"+
"Value<\param9>";
}
Instead of specifying the value directly
I want to keep as property with default valaue so that dynamically it can be changed.
For this i would prefer to have separate property file for each indicator
is it possible to select diff property file for each user based on input from csv.
Hello,
Very interesting work, Deepak! (as usual)
Does this method needs to save the files? (as you configured them into the sampler config: "data_${whatever}.xml")
I am confused as why do you need to configure a different file than the template because I would assume all the changes should be done in memory.
@Anonymous
I am confused as why do you need to configure a different file than the template because I would assume all the changes should be done in memory.
As far as I know the HTTPSamplerBase (which is the base class for all HTTPSamplers) does not give you a way to specify the file contents in its public API. if I wanted to do this , I'd probably have to change some internal JMeter code, something I don't want to do.
Which means that I have to write the file somewhere.
@navin
you should send your queries to the Jmeter mailing list, i do not check the comments on this blog frequently.
So suppose you have two CSV files
Naveen M 12 xxx " A "
Kumar M 20 asd " B"
and another
A,p1,p2,p3
B,p4,p5,p6
The easy way is to write a program that converts CSV file 1 into
Naveen, M ,12, xxx, " A ",p1,p2,p3
Kumar, M ,20, asd, " B",p4,p5,p6
And call this before your test (either through jmeter or external to it.).
Everything else needs a little bit of programming and will never be as efficient as pre processing the files into the format you want.
Post a Comment