Jmeter: parameterization issue with request Body - jmeter

I am sending the following request with one parameterization parameter ${id} and request looks like
Actual Message:
{"Data":"{\"Source\":\"#include <stdio.h>\\nint main()\\n{\\nint n;\\nprintf(\\\"Enter an integer\\\");\\nscanf(\\\"%d\\\", &n);\\nif (n%2 == 0)\\nprintf(\\\"Even\\\");\\nelse\\nprintf(\\\"Odd\\\");\\nreturn 0;\\n}\",\"Lang\":\"c\",\"callback_url\":\"callback_url_string\",\"cid\":\"159:60719:2667:${id}\"}","Action":"compile","TenantId":"159","UserId":"0","CID":"159:60719:2667:${id}","LanguageId":"25331"}
But while sending the request JMETER is altering the request (removing the few formats like \'s) and sends to the server and server responds with bad request response.
JMETER Sends like:
{"Data":"{\"Source\":\"#include <stdio.h>\nint main()\n{\nint n;\nprintf(\\"Enter an integer\\");\nscanf(\\"%d\\", &n);\nif (n%2 == 0)\nprintf(\\"Even\\");\nelse\nprintf(\\"Odd\\");\nreturn 0;\n}\",\"Lang\":\"c\",\"callback_url\":\"callback_url_string\",\"cid\":\"159:60719:2667:558019\"}","Action":"compile","TenantId":"159","UserId":"0","CID":"159:60719:2667:558019","LanguageId":"25331"}
IF you send above request without parameterization (enter values) then it works fine.
Please let me know how to resolve this issue.

I am assuming this is a POST HTTP request and the body section has this data
could you please point the HTTP body to below relative path starts from bin directory
${__eval(${__FileToString(path/to/payloadfile.txt,,)})}
Now payloadfile.txt can have the actual content still it will evaluate ${ID} and further variables as well.
if that helps dont forget to click answered. Happy to help, Happy Testing
REFINE:
I have used online tools :
first to see the data in the fisrt place is a proper one https://jsonformatter.curiousconcept.com/
I see this
{
"Data":{
"Source":"#include <stdio.h\/>\r\n int main()\r\n {\r\n int n;\r\n printf(\"Enter an integer\");\r\n scanf(\"%d\", &n);\r\n if (n%2 == 0)\r\n printf(\"Even\");\r\n else\r\n printf(\"Odd\");\r\n return 0;\r\n "
},
"Lang":"c",
"callback_url":"callback_url_string",
"cid":"159:60719:2667:${id}",
"Action":"compile",
"TenantId":"159",
"UserId":"0",
"CID":"159:60719:2667:${id}",
"LanguageId":"25331"
}
I separated out C program alone
#include <stdio.h/>
int main()
{
int n;
printf("Enter an integer");
scanf("%d", &n);
if (n%2 == 0)
printf("Even");
else
printf("Odd");
return 0;
}
and applied escape characters using online tool [applied java script escape]
http://www.freeformatter.com/javascript-escape.html#ad-output
output:
#include <stdio.h\/>\r\n int main()\r\n {\r\n int n;\r\n printf(\"Enter an integer\");\r\n scanf(\"%d\", &n);\r\n if (n%2 == 0)\r\n printf(\"Even\");\r\n else\r\n printf(\"Odd\");\r\n return 0;\r\n }
this the one i used and it shown valid json document. if you are not sending valid json document server will throw error. do not select encoding in HTTP sampler

Related

How to upload an image in chunks with client-side streaming gRPC using grpcurl

I have been trying to upload an image in chunks with client side streaming using grpcurl. The service is working without error except that at the server, image data received is 0 bytes.
The command I am using is:
grpcurl -proto image_service.proto -v -d # -plaintext localhost:3010 imageservice.ImageService.UploadImage < out
This link mentions that the chunk data should be base64 encode and so the contents of my out file are:
{"chunk_data": "<base64 encoded image data>"}
This is exactly what I am trying to achieve, but using grpcurl.
Please tell what is wrong in my command and what is the best way to achieve streaming via grpcurl.
I have 2 more questions:
Does gRPC handles the splitting of data into chunks?
How can I first send a meta-data chunk (ImageInfo type) and then the actual image data via grpcurl?
Here is my proto file:
syntax = "proto3";
package imageservice;
import "google/protobuf/wrappers.proto";
option go_package = "...";
service ImageService {
rpc UploadImage(stream UploadImageRequest) returns (UploadImageResponse) {}
}
message UploadImageRequest {
oneof data {
ImageInfo info = 1;
bytes chunk_data = 3;
};
}
message ImageInfo {
string unique_id = 1;
string image_type = 2;
}
message UploadImageResponse {
string url = 1;
}
Interesting question. I've not tried streaming messages with (the excellent) grpcurl.
The documentation does not explain how to do this but this issue shows how to stream using stdin.
I recommend you try it that way first to ensure that works for you.
If it does, then bundling various messages into a file (out) should also work.
Your follow-on questions suggest you're doing this incorrectly.
chunk_data is the result of having split the file into chunks; i.e. each of these base64-encoded strings should be a subset of your overall image file (i.e. a chunk).
your first message should be { "info": "...." }, subsequent messages will be { "chunk_data": "<base64-encoded chunk>" } until EOF.

WebSocket Sampler request data can't parse the variable

I'm trying to use JMeter to test our login API through WebSocket Sampler
But I can't let it parse my variable
Is this a bug or JSON format problem?
enter image description here
the plugin I choose(sorry about the poor description)
https://github.com/maciejzaleski/JMeter-WebSocketSampler
I'm not sure about your escaped quotes (\") - my expection is that these may not parse as JSON.
My solution to this is to add a BeanShell Sampler before the WebSocket Write e.g.
String s = "CONNECT\n" +
"login:${wsToken}\n" +
"passcode:\n" +
"accept-version:1.1,1.0\n" +
"heart-beat:0,0\n" +
"\n" +
'\0' // note: NULL char at end
;
vars.put("wsData", s);
Then in WebSocket Write Sampler - with DataType = "TEXT" set Request Data to
${wsData}
Try using this plugin: https://bitbucket.org/pjtr/jmeter-websocket-samplers/overview.
You can install it using plugin manager found here: https://jmeter-plugins.org/.
I have had no issues constructing JSON with variables in the Websocket request.
Something like this would work:
{ "type": "${type}",
"body": {
"key1": "${variable1}",
"key2": "${variable2}"
}}
So I would think it would solve your issue.
Cheers
edit: typos

Jmeter - How to check if less than 10 stylesheets are loading when I open a web page

I have a requirement where I need to verify that when I open a web page, there should less than 10 stylesheets and less than 20 .js are loading. Is there a way to do this in Jmeter?
It is, but you will need to do some scripting. Example solution:
Add Beanshell Assertion as a child of the HTTP Request you need to test.
Put the following code into the Beanshell Assertion "Script" area:
import org.apache.jmeter.samplers.SampleResult;
int js, css;
js = css = 0;
for (SampleResult subResult : SampleResult.getSubResults()) {
if (subResult.getUrlAsString().endsWith(".css")) {
css++;
} else if (subResult.getUrlAsString().endsWith(".js")) {
js++;
}
}
log.info("JS files: " + js); // you can comment or remove these lines
log.info("CSS files: " + css); // as they do nothing but print the numbers to jmeter.log
if (css > 10 || js > 20) {
Failure = true;
FailureMessage = "Exceeded maximum scripts/styles";
}
If any of the specified thresholds will be met, the sampler will get failed with the relevant message:
More information on conditionally failing JMeter tests: How to Use JMeter Assertions in Three Easy Steps

How to clear header manager programmatically

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);
}

JMeter Thread Group Not Getting to BeanShell PostProcessor

In my JMeter test plan, I'm trying to write all errors out to a log. I'm using a BeanShell Post-Processor configured as follows
import org.apache.jmeter.services.FileServer;
if (ResponseCode != null && ResponseCode.equals("200") == false) {
Failure = true;
// displays in Results Tree
FailureMessage ="Creation of a new CAE record failed. Response code " + ResponseCode + "." ;
// Static elements
part1 = "Creation of a new record failed. Response code: ";
part2 = ". Sorry!";
// Open File(s)
FileOutputStream f = new FileOutputStream("d:\\error.csv", true);
PrintStream p = new PrintStream(f);
// Write data to file
p.println( part1 + ResponseCode + part2 );
// Close File(s)
p.close();
f.close();
}
I'm trying to do a simple test where the HTTP request is doing a POST that is passing in a json file from c:jmeter/tests/payloads where the directory no longer exists. (let's say someone accidentally deletes it...)
The issue is the test is stopping (see below) and never getting to the BeanShell to write the error out to a log file. I need to capture all error responses, and only error responses.
I'm not sure how to handle this. I've read Jmeter. BeanShell PostProcessor and others, but they doesn't address the issue of what happens when it doesn't get to the BeanShell.
Any help is appreciated!
org.apache.jorphan.util.JMeterStopThreadException: End of sequence
at org.apache.jmeter.functions.FileToString.execute(FileToString.java:105)
at org.apache.jmeter.engine.util.CompoundVariable.execute(CompoundVariable.java:142)
at org.apache.jmeter.engine.util.CompoundVariable.execute(CompoundVariable.java:118)
at org.apache.jmeter.testelement.property.FunctionProperty.getStringValue(FunctionProperty.java:101)
at org.apache.jmeter.testelement.AbstractTestElement.getPropertyAsString(AbstractTestElement.java:274)
at org.apache.jmeter.config.Argument.getValue(Argument.java:146)
at org.apache.jmeter.protocol.http.util.HTTPArgument.getEncodedValue(HTTPArgument.java:236)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sendPostData(HTTPHC4Impl.java:1111)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.handleMethod(HTTPHC4Impl.java:453)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sample(HTTPHC4Impl.java:329)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:74)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1146)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1135)
at org.apache.jmeter.threads.JMeterThread.process_sampler(JMeterThread.java:434)
at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:261)
at java.lang.Thread.run(Unknown Source)
Caused by: java.io.FileNotFoundException: File 'C:\JMeter\test\payloads\Request_1.json' does not exist
at org.apache.commons.io.FileUtils.openInputStream(FileUtils.java:299)
at org.apache.commons.io.FileUtils.readFileToString(FileUtils.java:1711)
at org.apache.commons.io.FileUtils.readFileToString(FileUtils.java:1734)
at org.apache.jmeter.functions.FileToString.execute(FileToString.java:102)
SOLUTION
Based on Dmitri's feedback, I've switched from a Beanshell PostProcessor to Beanshell Assertion. After some tweaking, I got it to work where it now writes only errors (response != 200) to an errors.csv file. Instead of appending the file from a previous run, it overwrites with each run so only the last run's errors are captured.
If anyone thinks my solution could be improved, I'd be happy to receive the feedback. Thanks again to Kiril and Dmitri.
import org.apache.jmeter.services.FileServer;
if (ResponseCode != null && ResponseCode.equals("200") == true) {
SampleResult.setResponseOK();
}
else if (!ResponseCode.equals ("200") == true ) {
Failure = true;
FailureMessage ="Creation of a new record failed. Response code " + ResponseCode + "." ; // displays in Results Tree
print ("Creation of a new record failed: Response code " + ResponseCode + "."); // goes to stdout
log.warn("Creation of a new record failed: Response code " + ResponseCode); // this goes to the JMeter log file
// Static elements or calculations
part1 = "Unable to generate a new record via POST. The response code is: \"";
part2 = "\". \n\n For response code = \'Non-HTTP ressponse\', verify the payload file still exists. \n For response code = 409, check the recordTypeId and recordGrpId combination for validity. \n For response code = 500, verify the database and its host server are reachable. ";
// Open File(s)
FileOutputStream f = new FileOutputStream(FileServer.getFileServer().getBaseDir() + "\\error.csv");
PrintStream p = new PrintStream(f);
// Write data to file
p.println( part1 + ResponseCode + part2 );
// Close File(s)
p.close();
f.close();
}
There are no ResponseCode, Failure and FailureMessage in the Beanshell PostProcessor, switch to Beanshell Assertion instead.
Your ResponseCode.equals("200") clause assumes successful response, error responses usually have response codes > 400
See How to Use BeanShell: JMeter's Favorite Built-in Component guide for comprehensive information on Beanshell scripting in JMeter.
Jmeter overwrites your error.csv file instead of appending to it because you reopen it on every assertion call. Try to open it beforeheand, e.g. in separate Beanshell Sampler in setup thread group:
file = new FileOutputStream("error.csv", true);
bsh.shared.custom_log = new PrintStream(file)
And then use it in your beanshell assertion in a way like:
if (ResponseCode.equals("200")==false) {
bsh.shared.custom_log.println( part1 + ResponseCode + part2 );
}
Btw, AFAIK, you didn't need this part at all, because http responses with code 200 are OK by default:
if (ResponseCode != null && ResponseCode.equals("200") == true) {
SampleResult.setResponseOK();
}
I did't tested the code so there might be typos, but very similar one works for me.
Beanshell shared values are accessed under lock, so beware of possible performance issues if you writes to it heavily. With script like this and fairly short strings (50-100 chars), i'v got ~1k writes per second without significant impact on jmeter perfomance.

Resources