Search code examples
javaauthenticationjwtperformance-testinggatling

Gatling: How to share dynamic authentication between virtual users?


Using Gatling (in Java), I would like to run a performance test against a backend needing some authentication via bearer token (JWT). The token expires after 5 minutes, so I'll need to renew it, if the test runs longer than that (which is the intention).

This is the way it's working for now:

HttpProtocolBuilder httpProtocol = http.baseUrl("http://my.url/v1/")
    .authorizationHeader((session) -> session.getString("AuthToken"))
    .check(status().in(200, 401).saveAs("status"));

private String getAuthentication() {
  // retrieves and returns a new, valid authentication token via HttpURLConnection
  // this method has been proven to work correctly
}

ScenarioBuilder scn = scenario("My scenario")
    .repeat(100).on(
        exec(http("My HTTP call").get("/my/endpoint"))
            .pause(1)
            .doIfOrElse((session -> session.getInt("status") == 401))
            .then(
                exec(session -> {
                    System.out.println("Got status 401 - retrieving new token");
                    return session.set("AuthToken", getAuthentication());
             }))
            .orElse(
                exec(session -> {
                    System.out.println("Got status: " + session.getInt("status"));
                    return session;
                })
            )
        );

    {
        setUp(
            scn.injectClosed(
                rampConcurrentUsers(5).to(40).during(1200), constantConcurrentUsers(40).during(600))
        ).protocols(httpProtocol);
    }

I'm OK with this solution, but I see the getAuthentication calls occurring too often, resulting in the authentication backend being called more often than necessary. I suppose this is due to the virtual users running in their own threads and the synchronization via the session variable does not happen (fast enough).

So, is there any smart way to have the authentification happen only one time, when needed, and share the token with all users?

Some things I thought of:

  • Using the synchronized Java keyword on getAuthentication - did not change anything
  • Creating a new Java Thread that will fetch a new authentication automatically every 4:30 minutes and write the new token to a variable which can then be accessed by the authorizationHeader call. Didn't try this yet as it seems a rather poor solution to me.

I have been searching around, as it seems, there are some more people facing the same challenge, but I haven't found any applicable solution there.

Bonus question: Is there any way to not count the 401 responses in the final statistics? :)

Many thanks in advance!


Solution

  • Performing some blocking operation (UrlConnection, synchronized) from Gatling's own threads is a very very bad idea. You're going to stall the whole engine.

    Instead, you should update your shared token preemptively as you've described from a background task:

    • either a dedicated Java thread if you want to stick to the blocking UrlConnection
    • or a distinct Gatling scenario if you're willing to drop UrlConnection.

    Note: this question has been asked several times on the Gatling community forum and you'll find some examples there for the latter solution.