0
votes

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();
}
2
not related to your question, but ResponseCode.equals("200") == true: usually status 200 indicates success, and you don't have to add == for booleans. So maybeyou meant to have a condition as !ResponseCode.equals("200") (i.e. enter error condition if return code is not 200)?Kiril S.
@KirilS. Thanks. I found and corrected this in my code after my initial posting. I meant to type 'ResponseCode.equals("200") == false'. Does using your '!ResponseCode.equals("200") == true` do the same thing?David
!ResponseCode.equals("200") (without any ==) is the same as ResponseCode.equals("200") == false (equals returns boolean, operator ! inverts its value)Kiril S.
@KirilS. Thanks for the clarification.David

2 Answers

1
votes
  1. There are no ResponseCode, Failure and FailureMessage in the Beanshell PostProcessor, switch to Beanshell Assertion instead.
  2. 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.

0
votes

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.