Search code examples
javajsondatetimejmeterbeanshell

Jmeter BeanShell assertion parsing and comparing UTC datetime from json


There is a specific requirement where i need to compare previous datetime version to updated datetime version from a json response in jmeter

Below is my previous response :

{
    "state":
    {
        "errorDetails":
        [
        ]
    },
    "results":
    [
        {
            "state":
            {
                "errorDetails":
                [
                ]
            },
            "id":"someNumber1",
            "version":"2017-11-23T15:25:20.154+00:00",
            "referenceId":"1234"
        }
    ]
}

And the updated response :

{
    "state":
    {
        "errorDetails":
        [
        ]
    },
    "results":
    [
        {
            "state":
            {
                "errorDetails":
                [
                ]
            },
            "id":"someNumber1",
            "version":"2017-11-23T15:25:22+00:00",
            "referenceId":"1234"
        }
    ]
}

And I am extracting versions via JSON Extractor and passing it to below BeanShell assertion as :

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

try{
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");  
    long created = sdf.parse(vars.get("noteVersion")).getTime();
    long updated = sdf.parse(vars.get("updatedNoteVersion")).getTime();
    if ( updated > created){
    SampleResult.setResponseMessage("PASSED");
    }else{
    SampleResult.setResponseMessage("FAIL");
    }
}
catch (Exception ex){
    log.warn("Error in my script", ex);
    throw ex; // elsewise JMeter will "swallow" the above exception
}

However I am unable to parse the datetime and stuck with below error :

java.text.ParseException: Unparseable date: "2017-11-23T15:25:20.154+00:00"
    at java.text.DateFormat.parse(Unknown Source) ~[?:1.8.0_31]
    at sun.reflect.GeneratedMethodAccessor77.invoke(Unknown Source) ~[?:?]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_31]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_31]
    at bsh.Reflect.invokeMethod(Reflect.java:134) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.Reflect.invokeObjectMethod(Reflect.java:80) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.Name.invokeMethod(Name.java:858) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.BSHMethodInvocation.eval(BSHMethodInvocation.java:75) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.BSHPrimarySuffix.doSuffix(BSHPrimarySuffix.java:103) ~[bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.BSHPrimaryExpression.eval(BSHPrimaryExpression.java:80) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.BSHPrimaryExpression.eval(BSHPrimaryExpression.java:47) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.BSHVariableDeclarator.eval(BSHVariableDeclarator.java:86) ~[bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.BSHTypedVariableDeclaration.eval(BSHTypedVariableDeclaration.java:84) ~[bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.BSHBlock.evalBlock(BSHBlock.java:130) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.BSHBlock.eval(BSHBlock.java:80) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.BSHBlock.eval(BSHBlock.java:46) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.BSHTryStatement.eval(BSHTryStatement.java:86) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.Interpreter.eval(Interpreter.java:645) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.Interpreter.eval(Interpreter.java:739) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at bsh.Interpreter.eval(Interpreter.java:728) [bsh-2.0b5.jar:2.0b5 2005-06-12 04:50:41]
    at sun.reflect.GeneratedMethodAccessor34.invoke(Unknown Source) ~[?:?]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_31]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_31]
    at org.apache.jmeter.util.BeanShellInterpreter.bshInvoke(BeanShellInterpreter.java:166) [ApacheJMeter_core.jar:3.3 r1808647]
    at org.apache.jmeter.util.BeanShellInterpreter.eval(BeanShellInterpreter.java:189) [ApacheJMeter_core.jar:3.3 r1808647]
    at org.apache.jmeter.util.BeanShellTestElement.processFileOrScript(BeanShellTestElement.java:151) [ApacheJMeter_core.jar:3.3 r1808647]
    at org.apache.jmeter.assertions.BeanShellAssertion.getResult(BeanShellAssertion.java:105) [ApacheJMeter_components.jar:3.3 r1808647]
    at org.apache.jmeter.threads.JMeterThread.processAssertion(JMeterThread.java:812) [ApacheJMeter_core.jar:3.3 r1808647]
    at org.apache.jmeter.threads.JMeterThread.checkAssertions(JMeterThread.java:803) [ApacheJMeter_core.jar:3.3 r1808647]
    at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:525) [ApacheJMeter_core.jar:3.3 r1808647]
    at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:424) [ApacheJMeter_core.jar:3.3 r1808647]
    at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:255) [ApacheJMeter_core.jar:3.3 r1808647]

Adding to this I was able to achieve the same for a normal datetime requirement as yyyy-MM-DD HH:mm:ss - (2017-11-23 15:25:20)

Can anyone help me for this


Solution

  • My suggestion for you is you give up on the long outdated SimpleDateFormat and friends and use java.time, the modern Java date and time API also known as JSR-310, instead. It’s generally much nicer to work with and in your particular case has a couple of nice advantages as we shall see.

        String noteVersion = "2017-11-23T15:25:20.154+00:00";
        String updatedNoteVersion = "2017-11-23T15:25:22+00:00";
    
        OffsetDateTime created = OffsetDateTime.parse(noteVersion);
        OffsetDateTime updated = OffsetDateTime.parse(updatedNoteVersion);
        if (updated.isAfter(created)) {
            System.out.println("PASSED");
        } else {
            System.out.println("FAILED");
        }
    

    With the datatime version strings from your question the code snippet prints

    PASSED
    

    First advantage: The datetime format from your JSON is ISO 8601, a standard format for exchange of date and time information as text, among other places often used in JSON. The java.time classes including OffsetDateTime parse this format as their default, that is without any explicit format specification. No need to worry whether the offset is Z or XXX or something else.

    Second advantage: ISO 8601 is flexible enough to allow that times come with or without milliseconds, so the parsing works for both your previous and your updated datetime (with SimpleDateFormat you would have needed two SimpleDateFormat instances).

    Question: Can I use the modern API with my Java version?

    If using at least Java 6, you can.