Jmeter - How to escape % as special character in Jmeter - jmeter

I have a script where in my request I use as:
"requirements": [
{
"key": "SITEID",
"operand": "%",
"value": "1,202,209"
}
]
I got exception like:
java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern - Error at index 0 in: "","
at java.net.URLDecoder.decode(URLDecoder.java:232) ~[?:?]
at java.net.URLDecoder.decode(URLDecoder.java:142) ~[?:?]
at org.apache.jmeter.protocol.http.visualizers.RequestViewHTTP.decodeQuery(RequestViewHTTP.java:336) ~[ApacheJMeter_http.jar:5.4.3]
at org.apache.jmeter.protocol.http.visualizers.RequestViewHTTP.getQueryMap(RequestViewHTTP.java:290) ~[ApacheJMeter_http.jar:5.4.3]
at org.apache.jmeter.protocol.http.visualizers.RequestViewHTTP.setSamplerResult(RequestViewHTTP.java:216) ~[ApacheJMeter_http.jar:5.4.3]
at org.apache.jmeter.visualizers.RequestPanel.setSamplerResult(RequestPanel.java:116) ~[ApacheJMeter_components.jar:5.4.3]
at org.apache.jmeter.visualizers.SamplerResultTab.setupTabPane(SamplerResultTab.java:238) ~[ApacheJMeter_components.jar:5.4.3]
at org.apache.jmeter.visualizers.ViewResultsFullVisualizer.valueChanged(ViewResultsFullVisualizer.java:385) ~[ApacheJMeter_components.jar:5.4.3]
at org.apache.jmeter.visualizers.ViewResultsFullVisualizer.valueChanged(ViewResultsFullVisualizer.java:363) ~[ApacheJMeter_components.jar:5.4.3]
at javax.swing.JTree.fireValueChanged(JTree.java:2967) ~[?:?]
at javax.swing.JTree$TreeSelectionRedirector.valueChanged(JTree.java:3456) ~[?:?]
What should be done in order to escape the % sign?

If you're using "Parameters" section - tick "URL Encode" box
If you're adding the JSON to URL directly - wrap it into __urlencode() function like:
${__urlencode({"requirements":[{"key":"SITEID"\,"operand":"%"\,"value":"1\,202\,209"}]})}
Make sure that you really need to use HTTP GET method as the request body looks more like to be a POST one
You may also need to add a HTTP Header Manager and configure it to send Content-Type header with the value of application/json

Related

jmeter+influxdb Backend Listener: howto specify password?

I use Jmeter Backend Listener url:
influxdbUrl = http://XX.XXX.XX.XXX:8086/write?db=JMeter&u=jusr&p=C-UBBC-"<
I get an error:
java.lang.IllegalStateException: Failed calling setupTest Caused by: java.net.URISyntaxException: Illegal character in query at index 76: http://XX.XXX.XX.XXX:8086/write?db=JMeter&u=jusr&p=C-UBBC-"<
Problem in special characters in password: C-UBBC-"<
How to fix it?
Not every character is allowed in an URL, you can use alphanumeric and few special ones, in particular ; , / ? : # & = + $ - _ . ! ~ * ' ( ) #. Everything else needs to be percent-encoded
Wrap your password into __urlencode() function and it should resolve your issue.
More information on JMeter Functions concept: Apache JMeter Functions - An Introduction

Curl/GraphQL command failing with 200

I am trying to write a shell script that executes a curl against a GraphQL API and I've never interacted with GQL before. I am getting some strange errors and although I understand this community doesn't have access to the GQL server I was hoping someone could take a look at the script and make sure I'm not doing anything flagrantly wrong syntax-wise (both in the shell script layer as well as the GQL query itself).
My script:
#!/bin/bash
BSEE_WEB_SERVER_DNS=https://mybsee.example.com
BSEE_API_KEY=abc123
siteId=1
scanConfigId=456
runScanQuery='mutation CreateScheduleItem { create_schedule_item(input: {site_id: "$siteId" scan_configuration_ids: "$scanConfigId"}) { schedule_item { id } } }'
runScanVariables='{ "input": "site_id": $scanId }}'
runScanOperationName='CreateScheduleItem'
curl -i --request POST \
--url $BSEE_WEB_SERVER_DNS/graphql/v1 \
--header "Authorization: $BSEE_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"query":"$runScanQuery","variables":{$runScanVariables},"operationName":"${runScanOperationName}"}'
And the output when I run the script off the terminal:
HTTP/2 200
<OMITTED RESPONSE HEADERS>
{"errors":[{"message":"Invalid JSON : Unexpected character (\u0027$\u0027 (code 36)): was expecting double-quote to start field name, Line 1 Col 38","extensions":{"code":3}}]}%
I am omitting the HTTP response headers for security and brevity reasons.
I am wondering if my use of quotes/double-quotes is somehow wrong, or if there is anything about the nature of the GQL query itself (via curl) that looks off to anyone.
I verified with the team that manages the server that the HTTP 200 OK response code is correct. 200 shows that the request succeeded to the GQL API, but that GQL is responding with this error to indicate the query itself is incorrect.
We need to modify the GraphQL bits and fix the bash string quoting.
runScanQuery GraphQL operation
Fix the GraphQL syntax. Use a GraphQL operation name CreateScheduleItem with variables $site_id in the arguments input: { site_id: $siteId, scan_configuration_ids: $scanConfigId:
mutation CreateScheduleItem($site_id: String!, $scanConfigId: String!) {
create_schedule_item(
input: { site_id: $siteId, scan_configuration_ids: $scanConfigId }
) {
schedule_item {
id
}
}
}
runScanVariables: JSON
Our mutation expects two variables, which GraphQL will substitute into CreateScheduleItem($site_id: String!, $scanConfigId: String!). Provide the GraphQL variables as JSON. Here is the expected output after bash variable substitution:
{ "$site_id": "1", "$scanConfigId": "456" }
Get the bash quoting right
Finally, translate the inputs into bash-friendly syntax:
runScanQuery='mutation CreateScheduleItem($site_id: String!, $scanConfigId: String!) { create_schedule_item(input: {site_id: $siteId scan_configuration_ids: $scanConfigId}) { schedule_item { id } } }'
runScanVariables='{"$site_id":"'"$siteId"'","$scanConfigId":"'"$scanConfigId"'"}' # no spaces!
runScanOperationName='CreateScheduleItem'
data='{"query":"'"$runScanQuery"'","variables":'$runScanVariables',"operationName":"'"$runScanOperationName"'"}'
Check our bash formats. Paste the terminal output into a code-aware editor like VSCode. Expect the editor to parse the output correctly.
echo $runScanQuery # want string in graphql format
echo $runScanVariables # want JSON
echo $data # want JSON
Edit: add a public API example
Here's a complete working example using the public Star Wars API:
#!/bin/bash
filmId=1
data='{"query":"query Query($filmId: ID) { film(filmID: $filmId) { title }}","variables":{"filmId":"'"$filmId"'"}}'
curl --location --request POST 'https://swapi-graphql.netlify.app/.netlify/functions/index' \
--header 'Content-Type: application/json' \
--data "$data"
Responds with {"data":{"film":{"title":"A New Hope"}}}.
In GraphQL it's normal to always have 200 status code; client must check response body searching for failures.
The reason is simple: In REST, http is part of the protocol and status code has semantics but in GraphQL http is not part of the protocol, you can have GraphQL over serveral transport protocols:
http: typical scenario docs
WebSocket: does not provide any "status code like" payload. sample
MQTT: does not provide any "status code like" payload
...
The only way that server tells you something (even failures) is the body.
In your case I suggest you jq to parse json via bash script searching error property.
Your error is completely unrelated to GraphQL. You really have wrong JSON.
Error message says Unexpected character (\u0027$\u0027 (code 36)): was expecting double-quote to start field name, Line 1 Col 38",
You can replace escaped \u0027 with apostrophe and you will get
Unexpected character ('$' (code 36)): was expecting double-quote to start field name, Line 1 Col 38",
So it hates dollar sign at position 38 in what you send as data to curl
data='{"query":"'"$runScanQuery"'","variables":'$runScanVariables'
^
this
First - all field names and values in JSON should be wrapped with double quotes, not single.
Second - if you want curl to expand env variable, put it to double quotes, not single.

Getting Content is not allowed in prolog when running in Java

I am facing Content is not allowed in prolog exception when I run my xxx.jmx file from Java (Jmeter 5.0).
I tested the jmx in the GUI mode and everything works fine and in the Java I am just following the standard way to call the jmx file and execute it.
The jmx just have some normal stuff. Sending HTTP request and validate the expected and received XML (I am using this snipped to validate):
import org.apache.commons.io.FileUtils
expect = FileUtils.readFileToString(new File('some_path'))
XmlParser parser = new XmlParser()
expectedXML = new XmlSlurper().parseText(expect)
actualXML = new XmlSlurper().parseText(prev.getResponseDataAsString())
if (expectedXML != actualXML) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage('Mismatch between expected and actual XML \n'+ prev.getResponseDataAsString())
and the stack trace:
2018/10/24 15:18:03,386 12675 [ERROR ] [Thread Group 1-1] (JSR223Assertion.java:52) – Problem in JSR223 script: Validate resposne
javax.script.ScriptException: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.
at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:320)
at org.codehaus.groovy.jsr223.GroovyCompiledScript.eval(GroovyCompiledScript.java:72)
at javax.script.CompiledScript.eval(CompiledScript.java:92)
at org.apache.jmeter.util.JSR223TestElement.processFileOrScript(JSR223TestElement.java:221)
at org.apache.jmeter.assertions.JSR223Assertion.getResult(JSR223Assertion.java:49)
at org.apache.jmeter.threads.JMeterThread.processAssertion(JMeterThread.java:901)
at org.apache.jmeter.threads.JMeterThread.checkAssertions(JMeterThread.java:892)
at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:565)
at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:486)
at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:253)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
at groovy.util.XmlSlurper.parse(XmlSlurper.java:207)
at groovy.util.XmlSlurper.parse(XmlSlurper.java:260)
at groovy.util.XmlSlurper.parseText(XmlSlurper.java:286)
at groovy.util.XmlSlurper$parseText.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at Script1.run(Script1.groovy:9)
at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:317)
... 10 more
UPDATE 1:
The problem of using Response Assertion is it cannot ignore the space or tab. So if the format is not exactly the same when I use equal will always fail. Any ideas how to ignore these things by using Response Assertion?
UPDATE 2:
I found out that the issue is not related to the BOM. Is becasue if I run the jmx from my Java application:
prev.getResponseDataAsString()
above function always return:
${__FileToString(${inputFilePath},,)}
but not the actual response. This function is come from the body data of the HTTP Request sampler!!!!!! If I give the acutal body there then I am able to run the jmx...... Any idea how to deal with this dynamic body data?
It might be the case your "expected" XML file contains BOM and it causes your code failure.
BOM is basically 3 first bytes so you can remove them using code like:
def expect = FileUtils.readFileToString(new File('some_path')).getBytes().flatten()
1.upto(3) {
expect.remove(0)
}
XmlParser parser = new XmlParser()
def expectedXML = parser.parseText(new String(expect.toArray(new Byte[0])))
The rest of your code should work fine.
Check out The Groovy Templates Cheat Sheet for JMeter article to learn more Groovy tips and tricks.
Also be informed that in majority of cases it's easier to use Response Assertion or when it comes to XML - XPath Assertion, Java code will work faster than Groovy in any case.

Error handling with curl and elasticsearch

I'm currently developing bash scripts that use elasticsearch and I need a good error-handling.
In this situation I try to add a document to elasticsearch and check if the operation succeeded.
At first I naively tried this :
response=$(curl -XPOST 'http://localhost:9200/indexation/document' -d '
{
"content":"'"$txt"'",,
"date_treatment":"'"$(date +%Y-%m-%d)"'"
}') && echo ok || echo fail
But curl doesn't work that way and still returns success (0 - which is actually logical) even though the json request is obviously incorrect (note the double comma on line 3) and elasticsearch displays errors.
So the answer isn't there. Now I think I should analyze the variable $response to catch errors (grep ?). I post this question to get hints or solutions on the way to do this in a reliable way and to make sure I'm not missing an obvious solution (maybe a curl option I don't know ?).
Additional useful things
Parsing JSON with Unix tools
Examples of the content of $response :
success :
{
"_id": "AVQz7Fg0nF90YvJIX_2C",
"_index": "indexation",
"_shards": {
"failed": 0,
"successful": 1,
"total": 1
},
"_type": "document",
"_version": 1,
"created": true
}
error :
{
"error": {
"caused_by": {
"reason": "json_parse_exception: Unexpected character (',' (code 44)): was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name\n at [Source: org.elasticsearch.common.io.stream.InputStreamStreamInput#139163f; line: 3, column: 17]",
"type": "json_parse_exception"
},
"reason": "failed to parse",
"root_cause": [
{
"reason": "json_parse_exception: Unexpected character (',' (code 44)): was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name\n at [Source: org.elasticsearch.common.io.stream.InputStreamStreamInput#139163f; line: 3, column: 17]",
"type": "json_parse_exception"
}
],
"type": "mapper_parsing_exception"
},
"status": 400
}
A simple workaround is to use the -f/--fail option.
As per documentation :
(HTTP) Fail silently (no output at all) on server errors. This is
mostly done to better enable scripts etc to better deal with failed
attempts. In normal cases when an HTTP server fails to deliver a
document, it returns an HTML document stating so (which often also
describes why and more). This flag will prevent curl from outputting
that and return error 22.
This method is not fail-safe and there are occasions where
non-successful response codes will slip through, especially when
authentication is involved (response codes 401 and 407).
example:
response=$(curl -XPOST 'http://localhost:9200/indexation/document' -d '
{
"content":"'"$txt"'",,
"date_treatment":"'"$(date +%Y-%m-%d)"'"
}' -f ) && echo ok || echo fail

JMeter: Body & File content

The WebAPI request has a POST method which expects Content body. I've tried to use both Parameters and Body options but I receive error responses - 'Invalid Request' with 400 Status code, etc.
JMeter request Sample Content Body:
{
"ParamA": 111,
"ParamB": "Char String",
"ParamC": "VarType"
}
OR
{ "ParamA": 111, "ParamB": "Char String", "ParamC": "VarType"}
Listener Request:
POST data:
--8vpH3B6WcV4f1La46_wccVi4c25lrLJaGcN--
Listener Response:
{"message":"The request is invalid.","modelState":{"value":["An error
has occurred."]}}
Any insight into viable options? Eventually, I'm planning on reading the Body string from a .csv file so I can parameterize the request. Reading from a .CSV file only reads the first line of the request body - for example: '{'
Any help would be greatly appreciated.
Best,
Ray
HTTP Request
Request
Uncheck in HTTP request the option:
Use multipart/form data for POST
Also check your CSV does not contain some data that contains the CSV separator which is '\t' by default.
Ensure it doesn't by changing separator to '|' for example if you're sure your JSON will never contain it.

Resources