JMeter BeanShell Assertion encounted "\\" after "" - jmeter

My BeanShell Assertion returns the following result as error:
Assertion error: true
Assertion failure: false
Assertion failure message: org.apache.jorphan.util.JMeterException: Error invoking bsh method: eval
Sourced file: inline evaluation of: `` String sentText = \"Changed the TEXT\"; String receivedText = \"Changed the TEXT\"; . . . '' Token Parsing Error: Lexical error at line 2, column 18. Encountered: "\\" (92), after : ""
I have used a BeanShell PreProcessor to set a property as following and I use it in an edit, which works fine.
${__setProperty(textEdit,\"Changed the TEXT\")}
Then I get the information using a GET call and I use the following regular expression to get that specific information back.
\"edittedText\":(\".*?\")}
Then I use BeanShell Assertion to put the result from that regular expression in the property textEditPost like this. In that BeanShell Assertion I also check if the changed value is the new value.
${__setProperty(textEditPost,${textEditPost})}
String sentText = ${__property(textEdit)};
String receivedText = ${__property(textEditPost)};
if (sentText.equals(receivedText))
{
Failure = false;
}
else
{
Failure = true;
FailureMessage = "The Text does not match, expected: " + sentText + " but found: " + receivedText;
}
I have absolutely no idea where the error on encountering the two backslashes is coming from, as both Strings contain the same data.
Does anyone have an idea why this is happening and a possible solution?

I have found the problem after making some BeanShell Assertions for other things. And I also feel pretty stupid now for not realizing this earlier...
The problem is that the value in the property textEdit is \"Changed the TEXT\" and thus starts with a backslash. Due to this backslash the program has no idea what to do with it when trying to assign it to the String variable sentText or when using the property directly in the if statement.
By placing the property call between quotes the program can properly save it in the String variable. Like this:
${__setProperty(textEditPost,${textEditPost})}
String sentText = "${__property(textEdit)}";
String receivedText = "${__property(textEditPost)}";
if (sentText.equals(receivedText))
{
Failure = false;
}
else
{
Failure = true;
FailureMessage = "The Text does not match, expected: " + sentText + " but found: " + receivedText;
}
I hope this can help others with similar problems too.

Related

How to match EOF condition using antlr 4

I am new to ANTLR and I am currently writing a lexer for cool language in ANTLR 4.
For more about cool language please refer http://theory.stanford.edu/~aiken/software/cool/cool-manual.pdf.
One rule of cool language that I was trying to implement was detecting EOF inside Comments (may be nested) or String Constants and reporting as an error.
This is the rule that I wrote :
ERROR : '(*' (COMMENT|~['(*'|'*)'])*? (~['*)']) EOF {reportError("EOF in comment");}
|'"' (~[\n"])* EOF {reportError("EOF in string");};
fragment COMMENT : '(*' (COMMENT|~['(*'|'*)'])*? '*)'
Here the fragment COMMENT is a recursive rule that I used.
The function reportError used above reports error which is given below:
public void reportError(String errorString){
setText(errorString);
setType(ERROR);
}
But when I run it on the test file given below:
"Test String
It gives the following output :
line 1:0 token recognition error at: '"Test String\n'
#name "helloworld.cl"
Clearly the String with EOF in it was not recognised and ERROR was not detected.
Can someone help me in pointing out where I am going wrong as EOF (and hence, the error rule) is somehow not getting detected by the lexer.
If something is not clear please do mention it.
'"' (~[\n"])* EOF
Here the ~[\n"]* part will stop at the first \n or " or at the end of the file.
If it stops at a ", the rule does not match because the EOF does not match and that's what we want because the string literal is properly terminated.
If it stops at the end of file, then the subsequent EOF will match and you'll get an ERROR token. So that's also what you want.
But if it stops at a \n, the EOF will not match and you won't get an error token even though you'd want one in this case. And since your input ends with a \n, that's exactly the scenario you're running into here. So in addition to EOF, you should also allow for erroneous string literals to end in \n:
'"' (~[\n"])* ('\n' | EOF)
You don't need a dedicated ERROR rule. You can handle that specific situation with an unfinished string directly in your error listener. Your comment rule shouldn't be a fragment however, as it has to recognize a lexeme on its own that must be handled (fragment rules are rather rules to be used in other lexer rules only).
When the lexer reaches a string but cannot finish it due to the end of the input, you can get the offending input from the current lexer state in your error listener. You can then check that to see what exactly wasn't finished, like I do here for 3 quoted text types in MySQL:
void LexerErrorListener::syntaxError(Recognizer *recognizer, Token *, size_t line,
size_t charPositionInLine, const std::string &, std::exception_ptr ep) {
// The passed in string is the ANTLR generated error message which we want to improve here.
// The token reference is always null in a lexer error.
std::string message;
try {
std::rethrow_exception(ep);
} catch (LexerNoViableAltException &) {
Lexer *lexer = dynamic_cast<Lexer *>(recognizer);
CharStream *input = lexer->getInputStream();
std::string text = lexer->getErrorDisplay(input->getText(misc::Interval(lexer->tokenStartCharIndex, input->index())));
if (text.empty())
text = " "; // Should never happen.
switch (text[0]) {
case '/':
message = "Unfinished multiline comment";
break;
case '"':
message = "Unfinished double quoted string literal";
break;
case '\'':
message = "Unfinished single quoted string literal";
break;
case '`':
message = "Unfinished back tick quoted string literal";
break;
default:
// Hex or bin string?
if (text.size() > 1 && text[1] == '\'' && (text[0] == 'x' || text[0] == 'b')) {
message = std::string("Unfinished ") + (text[0] == 'x' ? "hex" : "binary") + " string literal";
break;
}
// Something else the lexer couldn't make sense of (likely there is no rule that accepts this input).
message = "\"" + text + "\" is no valid input at all";
break;
}
owner->addError(message, 0, lexer->tokenStartCharIndex, line, charPositionInLine,
input->index() - lexer->tokenStartCharIndex);
}
}
This code was taken from the parser module in MySQL Workbench.

JMETER Beanshell Read File - Not working - Getting Error Command not found: newBufferedReader( java.io.FileReader )

Below is my complete code that I entered in Jmeter BeanShell Sampler.
BufferedReader fileReader = newBufferedReader(new FileReader("F:/url.txt"));
int counter = 1;
content = fileReader.readLine();
while ((nextLine = fileReader.readLine()) != null)
{
content = content + "\n" + nextLine;
counter++;
}
vars.put("content",content);
I am getting below error when I try to execute, I can see this error in log.info
2019-12-02 11:38:01,431 ERROR o.a.j.u.BeanShellInterpreter: Error invoking bsh method: eval Sourced file: inline evaluation of: ``BufferedReader fileReader = newBufferedReader(new FileReader("F:/url.txt")); int . . . '' : Typed variable declaration : Command not found: newBufferedReader( java.io.FileReader )
2019-12-02 11:38:01,432 WARN o.a.j.p.j.s.BeanShellSampler: Exception executing script. org.apache.jorphan.util.JMeterException: Error invoking bsh method: eval Sourced file: inline evaluation of: ``BufferedReader fileReader = newBufferedReader(new FileReader("F:/url.txt")); int . . . '' : Typed variable declaration : Command not found: newBufferedReader( java.io.FileReader )
I just copy pasted this code from online examples and similarly I tried so many different option to read a file, but it's not working, could someone please help me.
I am using windows machine and jmeter version 5.1
You have a typo in your code, you need to change this:
newBufferedReader
to this:
new newBufferedReader
as the instantiation assumes using Java new operator
P.S. Since JMeter 3.1 users are recommended to user JSR223 Test Elements and Groovy language for scripting, the reasons are in:
Groovy has better performance than Beanshell
Groovy is more modern language which supports all new Java features while with Beanshell you're stuck at Java 1.5 language level
Groovy provides a lot of enhancements over normal Java SDK
assuming all above you can convert your code to this:
vars.put("content", new File("F:/urls.txt").text)
P.P.S. It is also recommended to avoid scripting where possible and use JMeter's built-in components for maximum performance so if you only need to read a file into a JMeter Variable you can consider using __FileToString() function like:
${__FileToString(F:/urls.txt,,content)}
Check out Apache JMeter Functions - An Introduction article for more information on JMeter Functions concept.
I changed the code, and below is the updated code, it works for me, I changed the first line of code, given space between new and BufferedReader.
BufferedReader fileReader = new BufferedReader(new FileReader("F:/url.txt"));
int counter = 1;
content = fileReader.readLine();
while ((nextLine = fileReader.readLine()) != null)
{
content = content + "\n" + nextLine;
counter++;
}
vars.put("content",content);
log.info(content);

Jmeter: How to extract assertion results and use it for my API's

My test plan looks like,
I am running some Http requests with assertion .
I need to check assertion is passed or failed (any built-in variable is available?) .
Need to call/extract assertion result and use it for my next API .
Any one help me on this.
I solved this case using BeanShell Listener by adding the following code and you can call assertion result on jmeter like ${results}
try
{
int results;
if (sampleResult.isSuccessful()) {
log.info("Response Assertion PASSED");
results = 1;
vars.put("results","1");}
else {
log.info("Response Assertion FAILED" );
results = 2;
vars.put("results","2");}
}
catch (Throwable ex) {
log.error("Error in Beanshell", ex);
throw ex;
}
I would suggest adding JSR223 Assertion where you can get parent sampler AssertionResult instance(s) and extract the required information from it like:
def assertionResult = SampleResult.getAssertionResults()[0]
if (assertionResult.isFailure()) {
log.info("Assertion " + assertionResult.getName() + " failed")
log.info(assertionResult.getFailureMessage())
}
Demo:
See How to Use JMeter Assertions in Three Easy Steps article for more information on using assertions. Also avoid using Beanshell as it may cause performance problems, if you need to go for scripting - stick to JSR223 Test Elements
1.Use "Regular Expression Extractor" to extract assertion result.
2.Use BeanShell Sampler to get assertion result,then,use it for your next API.

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.

how to get detailed information about execution of a script in groovy

I found here a very good example of what I want:
Basically to be able to execute a String as a groovy script with an expression, but if the condition is false, I want to show detailed information about why it was evaluated as false.
EDIT
I want an utility method that work like this:
def expression = "model.book.title == \"The Shining\""
def output = magicMethod(expression)
// output.result: the exact result of executing expression
// output.detail: could be a string telling me why this expression returns true or false, similar to de image
I think it may be a combination of Eval.me + assert and to catch the exception in order to get details
Yeah, it works with assert, thanks for the idea #Justin Piper
here is the snippet:
def model = [model:[book:[title:"The Shinning"]]]
def magicMethod= { String exp ->
def out = [:]
out.result = Eval.x(model,"x.with{${exp}}")
try{
if(out.result){
Eval.x(model,"x.with{!assert ${exp}}")
}else{
Eval.x(model,"x.with{assert ${exp}}")
}
}catch(Throwable e){
out.detail = e.getMessage()
}
return out
}
def expression = "model.book.title == \"The Shining\""
def output = magicMethod(expression)
println "result: ${output.result}"
println "detail: ${output.detail}"

Resources