anthonygauthier / jmeter-elasticsearch-backend-listener

JMeter plugin that lets you send sample results to an ElasticSearch engine to enable live monitoring of load tests.
MIT License
98 stars 76 forks source link

Exception for Java-based tests #50

Closed chbndrhnns closed 4 years ago

chbndrhnns commented 5 years ago

My expectation was that I can specify the required paramters (es.host, es.index) and use your backend listener in a Java-based test script. As I end up with NumberFormatException doing it that way and succeeding when configuring the test via the JMeter GUI, I assume that maybe getDefaultParameters() is not getting called in the Java case?

Here is the exception:

java.lang.IllegalStateException: Failed calling setupTest
    at org.apache.jmeter.visualizers.backend.BackendListener.testStarted(BackendListener.java:339)
    at org.apache.jmeter.visualizers.backend.BackendListener.testStarted(BackendListener.java:292)
    at org.apache.jmeter.engine.StandardJMeterEngine.notifyTestListenersOfStart(StandardJMeterEngine.java:206)
    at org.apache.jmeter.engine.StandardJMeterEngine.run(StandardJMeterEngine.java:381)
    at pannet.jmeter.PerformanceTest.execute(PerformanceTest.java:148)
    at step_definitions.JMeter2.userCreateSoakRequests(JMeter2.java:259)
[...]
Caused by: java.lang.NumberFormatException: null
    at java.lang.Integer.parseInt(Integer.java:542)
    at java.lang.Integer.parseInt(Integer.java:615)
    at io.github.delirius325.jmeter.backendlistener.elasticsearch.ElasticsearchBackendClient.setupTest(ElasticsearchBackendClient.java:81)
    ... 47 more

This is my setup code:

 private BackendListener getBackendListener() {
        backendListener = new BackendListener();
        backendListener.setProperty(BackendListener.TEST_CLASS, BackendListener.class.getName());
        backendListener.setProperty(BackendListener.GUI_CLASS, BackendListenerGui.class.getName());

        Arguments listenerArgs = new Arguments();
        listenerArgs.addArgument("es.host", "localhost", "=");
        listenerArgs.addArgument("es.index", "poc-reporting-elk.perf", "=");
        backendListener.setArguments(listenerArgs);
        backendListener
                .setClassname("io.github.delirius325.jmeter.backendlistener.elasticsearch.ElasticsearchBackendClient");

        return backendListener;
    }
chbndrhnns commented 5 years ago

After trying to put all arguments in Java, I still see the exception and cannot get it to work. Is there something else I am missing here?

anthonygauthier commented 5 years ago

Indeed there seems to be an issue with getDefaultParameter() in that case as your stack trace is returning an error on line 81 of the ElasticSearchBackendClient class. That specific line does the following: this.bulkSize = Integer.parseInt(context.getParameter(ES_BULK_SIZE)); and throws a null exception.

I'll make a SNAPSHOT release with an explicit call to getDefaultParameters() in the setupTest() method.

anthonygauthier commented 5 years ago

@chbndrhnns SNAPSHOT is currently being deployed to maven-central repository. If you don't want to wait for it to be available on Maven. Please add the following JAR to your lib/ext folder (while deleting the old version).

chbndrhnns commented 5 years ago

I see that you are calling getDefaultParameters() now but you are not using the returned values...

So I found out that I get it working if i really specify ALL possible parameters like this:

    private BackendListener getBackendListener() {
        backendListener = new BackendListener();
        backendListener.setProperty(BackendListener.TEST_CLASS, BackendListener.class.getName());
        backendListener.setProperty(BackendListener.GUI_CLASS, BackendListenerGui.class.getName());

        Arguments listenerArgs = new Arguments();
        listenerArgs.addArgument("es.scheme", "http", "=");
        listenerArgs.addArgument("es.host", "localhost");
        listenerArgs.addArgument("es.port", "9200", "=");
        listenerArgs.addArgument("es.index", "poc-reporting-elk.perf", "=");
        listenerArgs.addArgument("es.timestamp", "yyyy-MM-dd'T'HH:mm:ss.SSSZZ", "=");
        listenerArgs.addArgument("es.bulk.size", "100", "=");
        listenerArgs.addArgument("es.timeout.ms", "200", "=");
        listenerArgs.addArgument("es.sample.filter", "", "=");
        listenerArgs.addArgument("es.test.mode", "info", "=");
        listenerArgs.addArgument("es.xpack.user", "abc", "=");
        listenerArgs.addArgument("es.xpack.password", "abc", "=");
        listenerArgs.addArgument("es.parse.req.headers", "false", "=");
        listenerArgs.addArgument("es.parse.res.headers", "false", "=");
        listenerArgs.addArgument("es.aws.endpoint", "", "=");
        listenerArgs.addArgument("es.aws.region", "", "=");
        backendListener.setArguments(listenerArgs);
        backendListener
                .setClassname("io.github.delirius325.jmeter.backendlistener.elasticsearch.ElasticsearchBackendClient");

        return backendListener;
    }
anthonygauthier commented 5 years ago

@chbndrhnns Oh yes, my bad I tried to push it out in a hurry 😆 ! Let me actually use the values of getDefaultParameters.

anthonygauthier commented 5 years ago

@chbndrhnns I have uploaded a new JAR this time it is recreating the context (since the context parameters is a private Map and cannot be explicitly reassigned) by doing this: context = new BackendListenerContext(getDefaultParameters());.

Tell me if it works!

https://github.com/delirius325/jmeter-elasticsearch-backend-listener/releases/tag/2.6.3-SNAPSHOT

chbndrhnns commented 5 years ago

Hey, with that snapshot, I get

Caused by: java.lang.IllegalArgumentException: Host name may not be empty
    at org.apache.http.util.Args.containsNoBlanks(Args.java:84)
    at org.apache.http.HttpHost.<init>(HttpHost.java:80)
    at io.github.delirius325.jmeter.backendlistener.elasticsearch.ElasticsearchBackendClient.setupTest(ElasticsearchBackendClient.java:87)

I assume this is because the existing context is overwritten. Shouldn't it be done like this? First, create default context. Second, overwrite the parameters that are passed in from the outside

It seems like I am not able to set any parameters now.

anthonygauthier commented 5 years ago

Yeah, I understand what you mean.. And frankly, I see it that way as well. But I can't seem to find a solution to access and change/add the parameters that are coming from an external source. As I mentioned in an earlier comment, the parameters in context are stored in a private Map which I cannot explicitly change as there is no setParameters() method.

Wouldn't it be easier if I provided a static method in my plugin, say getDefaultValues(), which would return an Arguments and you could then modify it as you see fit?

chbndrhnns commented 5 years ago

I am looking at the influxdb code to understand what they did.

Without fully understanding it as of now, can specify the parameters I want and the rest is taken from the default but the test does not just fail.

Implementing this static method would work but it would make it harder to switch between the influxdb and elasticsearch backend listener as there way of usage differs then.

anthonygauthier commented 5 years ago

They did

@Override
    public Arguments getDefaultParameters() {
        Arguments arguments = new Arguments();
        DEFAULT_ARGS.forEach(arguments::addArgument);
        return arguments;
    }

DEFAULT_ARGS being a private static final Map<String, String> DEFAULT_ARGS I'll implement a similar structure in the next SNAPSHOT

anthonygauthier commented 5 years ago

Hey @chbndrhnns,

So I just switched the parameters declaration to the style they're using in the InfluxDB Backend Listener, let me know if that helps!

https://github.com/delirius325/jmeter-elasticsearch-backend-listener/releases/download/2.6.3-SNAPSHOT/jmeter.backendlistener.elasticsearch-2.6.3-SNAPSHOT.jar

Thanks,

chbndrhnns commented 5 years ago

Hey, there is still a NullPointerException:

Caused by: java.lang.NullPointerException
    at io.github.delirius325.jmeter.backendlistener.elasticsearch.ElasticsearchBackendClient.setupTest(ElasticsearchBackendClient.java:90)
    ... 47 more

I see that context.getParameter() returns null if a parameter is not specified which is the base issue here: I would like to be able to leave out parameters I do not need :)

anthonygauthier commented 5 years ago

I am having issues understanding how the new way of adding the parameters is causing a NullExceptionPointer. I am basically looping through the static parameters and adding them all to the listener.

private static final Map<String, String> DEFAULT_ARGS = new LinkedHashMap<>();
    static {
        DEFAULT_ARGS.put(ES_SCHEME, "http");
        DEFAULT_ARGS.put(ES_HOST, null);
        DEFAULT_ARGS.put(ES_PORT, "9200");
        DEFAULT_ARGS.put(ES_INDEX, null);
        DEFAULT_ARGS.put(ES_TIMESTAMP, "yyyy-MM-dd'T'HH:mm:ss.SSSZZ");
        DEFAULT_ARGS.put(ES_BULK_SIZE, "100");
        DEFAULT_ARGS.put(ES_TIMEOUT_MS, Long.toString(DEFAULT_TIMEOUT_MS));
        DEFAULT_ARGS.put(ES_SAMPLE_FILTER, null);
        DEFAULT_ARGS.put(ES_TEST_MODE, "info");
        DEFAULT_ARGS.put(ES_AUTH_USER, "");
        DEFAULT_ARGS.put(ES_AUTH_PWD, "");
        DEFAULT_ARGS.put(ES_PARSE_REQ_HEADERS, "false");
        DEFAULT_ARGS.put(ES_PARSE_RES_HEADERS, "false");
        DEFAULT_ARGS.put(ES_AWS_ENDPOINT,  "");
        DEFAULT_ARGS.put(ES_AWS_REGION, "");
    }

@Override
    public Arguments getDefaultParameters() {
        Arguments arguments = new Arguments();
        DEFAULT_ARGS.forEach(arguments::addArgument);
        return arguments;
    }

It's as if making a JMeter test-plan from code isn't calling the same methods... Going through the InfluxDB listener and I noticed that my BackendClient was missing a constructor. Not sure if that's the cause of the issue or not, but could be a possible factor. Still investigating.

chbndrhnns commented 5 years ago

Taking a look at https://jmeter.apache.org/api/org/apache/jmeter/visualizers/backend/BackendListenerContext.html#getParameter-java.lang.String-java.lang.String- indicates that the desired default parameter needs to be passed to the getParameter call or null is returned otherwise, or am I wrong?

anthonygauthier commented 5 years ago

That is correct :smile:, which is why I'm trying to fix the issue where the default parameters are not automatically set when creating a test plan from code (as you're doing).