How to measure size of response data of multiple http samplers in JMeter. I need to find the overall size of all the responses not for individual responses. I am trying to fetch it through a Beanshell code but it displays the size of the last sample executed:-
import java.util.io.*;
import java.lang.io.*;
int totalsize;
test = prev.getResponseDataAsString().length();
log.info("size is = "+test);
totalsize = totalsize + test;
log.info("totalsize is = "+totalsize);
Thank you.
Use JSR223 code with props and set JMeter property totalsize with 0 at start
props.put("totalsize", Integer.parseInt(prop.get("totalsize")) + test);
Following solution also worked for me on a beanshell post processor:-
import java.util.io.*;
import java.lang.io.*;
test = prev.getResponseDataAsString().length();
log.info("size is = "+test);
text = ctx.getCurrentSampler().getName();
log.info("Sampler name is " +text);
if(text.equalsIgnoreCase("Test Sampler")){
props.put("totalsize",Integer.parseInt("0"));
}else{
props.put("totalsize", (props.get("totalsize")!=null?props.get("totalsize"):0) + test);
}
log.info("totalsize is = "+props.get("totalsize"));
"test" captures the size of each of the sample requests and keeps adding it to the "totalsize". At the end of the execution I am initializing totalsize back to 0.
it's more appropriate to use prev.getBytesAsLong() to get each sampler response size. Take a look at JMeter API
To have combined size of multiple responses you could try grouping needed requests in transaction via Transaction Controller.
Related
I have written below code under beanshall post-processor. But when I am running 1000 threads the files are overwriting existing content instated of appending. It is working for 1-5 threads. Can anyone help me on this?
import org.apache.commons.io.FileUtils;
import java.util.ArrayList;
import java.util.Collections;
File fExceptionLog = new File("${logPath}/ExceptionLog.txt");
String extExceptionData= FileUtils.readFileToString(fExceptionLog);
id=vars.get("id");
try{
String cDatestamp="${__time(yyyyMMddHHmmssSSS)}";
String cResponce = prev.getResponseDataAsString();
String cRequest = prev.getQueryString();
String cResponceCode=prev.getResponseCode();
cTransactionName = prev.getSampleLabel();
cResponseTime = prev.getTime();
cSize = prev.getBytesAsLong();
cIsSuccessful =prev.isSuccessful();
File fRequestLog = new File("${logPath}/RequestLog.txt");
File fHitLog = new File("${logPath}/HitLog.txt");
File fResponceLog = new File("${logPath}/ResponceLog.txt");
File fErrorLog = new File("${logPath}/ErrorLog.txt");
String extHitData = FileUtils.readFileToString(fHitLog);
String extRequestData = FileUtils.readFileToString(fRequestLog);
String extResponceData = FileUtils.readFileToString(fResponceLog);
String extErrorData = FileUtils.readFileToString(fErrorLog);
log.info("cResponceCode"+cResponceCode);
FileUtils.writeStringToFile(fHitLog,extHitData+id+"~"+cDatestamp+"~"+cTransactionName+"~"+cResponceCode+"~"+cResponseTime+"~"+cSize+"~"+cIsSuccessful+"\n");
if(cResponceCode.equals("200")){
FileUtils.writeStringToFile(fRequestLog,extRequestData+id+"~"+cDatestamp+"~"+cTransactionName+"~"+cResponce+"\n");
FileUtils.writeStringToFile(fResponceLog,extResponceData+id+"~"+cDatestamp+"~"+cResponceCode+"~"+cResponce+"\n");
}else{
FileUtils.writeStringToFile(fErrorLog,extErrorData+id+"~"+cDatestamp+"~"+cTransactionName+"~"+cResponce+"\n"+id+"~"+cDatestamp+"~"+cResponceCode+"~"+cResponce+"\n");
}
}catch(Exception e){
FileUtils.writeStringToFile(fExceptionLog,extExceptionData+id+"~"+cDatestamp+"~"+cTransactionName+"~"+e+"\n");
}
You're violating at least 3 JMeter Best Practices
You're referring JMeter Variables like ${logPath} while you should be using vars shorthand instead like vars.get("logPath")
You're using Beanshell while starting from JMeter 3.1 you should be using JSR223 and Groovy
And last but not the least, you yourself introduced a race condition so when several threads will be concurrently writing the same file it will result in data loss. You can put this Beanshell test element (along with the parent Sampler(s)) under the Critical Section Controller, but it will reduce concurrency of the parent sampler(s) to only one at a time
If you need to write some some metrics into a custom file in your own format I would rather recommend consider migrating to the Flexible File Writer which is extremely "flexible" with regards to what values is to store and it accumulates multiple entries in memory and flushes them periodically in batch manner so all the data will be stored without collisions.
You can install Flexible File Writer using JMeter Plugins Manager
I am trying to send HTTP requests using jmeter for which I am using a HTTP sampler. The http requests have a parameter TaskID and these parameters read from a CSV file. I just wanted to make changes on how the HTTP request will be send.
The CSV file looks like this
Time TaskID
9000 42353456
9000 53463464
9000 65475787
9300 42354366
9300 23423535
9600 43545756
9600 53463467
9600 23435346
Now I want to send request based on the Time. For example in Time 9000 there are 3 TaskID. So I want to send 3 HTTP requests with those TaskIDs at a time. Similarly for the other Times as well. Any idea on how to do it?
Update:
I created a minimal working example for one possible solution.
Basically I read the csv in a JSR223 Sampler and group it with following groovy code in "read csv" sampler:
import org.apache.jmeter.services.FileServer
current_dir = FileServer.getFileServer().getBaseDir().replace("\\","/")
csv_lines = new File(current_dir + "/test.csv").readLines()
times = []
csv_lines.each { line ->
line = line.split(",")
time = line[0]
task_id = line[1]
if (vars.getObject(time)){
tasks = vars.getObject(time)
tasks.add(task_id)
vars.putObject(time, tasks)
}
else{
times.add(time)
vars.putObject(time, [task_id])
}
}
times.eachWithIndex { time, i ->
vars.put("time_" + (i+1), time)
}
Notes:
(i+1) is used because the ForEach Controller will not consider the 0th element
I used "," as csv separator and omitted the header line
the "initialize task_ids" sampler holds following code:
.
time = vars.get("time")
tasks = vars.getObject(time)
tasks.eachWithIndex {task, i ->
vars.put(time + "_" + (i+1), task)
}
I hope, this helps!
How can I get an overall PASS/FAIL result for a JMeter thread group without using a post processor on every sampler?
I've tried using a beanshell listener, but it doesn't work for instances where there are multiple samplers inside a transaction controller with "Generate Parent Sample" enabled. In that case, the listener only gets called once per transaction controller and I'm only able to access the result of the last sampler inside the transaction controller.
Edit:
I would like to be able to save a pass/fail value as Jmeter variable or property for the thread group. If one or more components of the thread group fail or return an error, then that would be an overall fail. This variable will then be used for reporting purposes.
My current beanshell listener code:
SampleResult sr = ctx.getPreviousResult();
log.info(Boolean.toString(sr.isSuccessful()));
if (!sr.isSuccessful()){
props.put("testPlanResult", "FAIL");
testPlanResultComment = props.get("testPlanResultComment");
if(testPlanResultComment == ""){
testPlanResultComment = sr.getSampleLabel();
}else {
testPlanResultComment = testPlanResultComment + ", " + sr.getSampleLabel();
}
props.put("testPlanResultComment", testPlanResultComment);
log.info(testPlanResultComment);
}
If you call prev.getParent() you will be able to fetch individual sub-samples via getSubResults() function, something like:
prev.getParent().getSubResults().each {result ->
log.info('Sampler: ' + result.getSampleLabel() + ' Elapsed time: ' + result.getTime() )
}
log.info('Total: ' + prev.getParent().getTime())
Demo:
More information: Apache Groovy - Why and How You Should Use It
I have a TestPlan
Thread-group
HttpSampler
pre-processor
HttpHeaderManager[empty]
HttpRequestDefaults[empty]
Post-processor
I am using a pre-processor script to add headers dynamically to headerManager from reading a json file. it goes well .
import org.apache.jmeter.protocol.http.control.Header
int min = args[0].toInteger()
int max = args[1].toInteger()
int random = min + (int) (Math.random() * ((max - min) + 1));
// here 'inputjson' referring to slurped json object
inputjson.Headers.each{
it.each{ key,value -> sampler.getHeaderManager().add(new Header(key.replace('$random',random.toString()),value.replace('$random',(random+2).toString())));
}
}
the issue is, if a thread loop count is 3, then the set of headers are adding 3 times.
then I added a post processor script
sampler.getHeaderManager().clear()
This time initial[loop-1] run is going fine, next[loop-2] loop is a clear request with no headers. how can I achieve, each request will go with only 1 set of headers
Here is my working example - HeaderManager.clear() did not work, but removing the header by its name did its job.
import org.apache.jmeter.protocol.http.control.Header;
sampler.getHeaderManager().removeHeaderNamed("Authorization");
sampler.getHeaderManager().add(new Header("Authorization", "Bearer " + vars.get("token")));
You can use below code to remove headers programatically - first, getting the headers count and looping till the end of headers count.
int headers_size = sampler.getHeaderManager().size();
log.info("headers_size: "+ headers_size);
while(headers_size > 0) {
log.info("header to be removed:"+ sampler.getHeaderManager().get(0));
sampler.getHeaderManager().remove(0);
headers_size = sampler.getHeaderManager().size();
}
This will done by
adding sampler.setHeaderManager(new HeaderManager()) just before the headerManger add section .
each time a new HeaderManger will get added and will be used. Not sure it is the best solution , but its a working solution.
Don't use the f$%$ing method HeaderManager.clear() which existence I still don't get, and do not do that in a post-processor, better do this in your preprocessor before adding headers to Header Manager.
headerMgr = sampler.getHeaderManager();
while(headerMgr.getHeaders().iterator().hasNext()) {
headerName = headerMgr.getHeaders().iterator().next().getStringValue().split("\\s+")[0];
headerMgr.removeHeaderNamed(headerName);
}
I am trying to run some tests, using jmeters random beanshell post processor, but somehow, randomly it fails to create the numbers and instead posts "variable=${variable_value}" directly in the url.
Here is the sample beanshell post processor code:
import java.util.*;
r = new Random();
b = new Random();
t = new Random();
random_param1 = r.nextInt(415000);
random_param2 = b.nextInt(200);
random_param3 = t.nextInt(25);
vars.put("random_param1",random_param1.toString());
vars.put("random_param2",random_param2.toString());
vars.put("random_param3",random_param3.toString());
And here how I set those for the url:
And the simple test results looks like this:
And this is a failed test request data:
POST test_url
POST data:
param1=%24%7Brandom_param1%7D¶m2=%24%7Brandom_param2%7D¶m3=%24%7Brandom_param3%7D
While the successful ones are like:
POST test_url
POST data:
param1=287341¶m2=107¶m3=20
Any ideas why random generation fails "randomly" like this? Should I use a specific sampler?
EDIT:
Your beanshell code contains an error in the screenshot (so in test plan), you don't set in vars:
random_param2