Using Feeder to dynamically generate different JWT tokens for VUs

Gatling version: 3.13.1
Gatling flavor: java
Gatling build tool: maven

code snippet: calls custom function JwtGenerator.getTokenAsString to generate JWT token
End point converts JWT to access token, returns access token in response.
Save access token as “admintoken”

ChainBuilder getToken =
          
            exec(http("GetToken")
                    .get("https://test.com/token")
                    .queryParam("token", String -> computerdatabase.JwtGenerator.getTokenAsString("mykey","mykeyId"))
                    .check(status().is(200))
                    .check(jsonPath("$.access_token").exists().saveAs("admintoken"))
            );

Problem: all VU will reuse same access token

Solution: use feeder csv file to cycle through list of keys and keyIds

FeederBuilder.Batchable<String> mykeys =
            csv("mykeys.csv").circular();

ChainBuilder get =
            //let's give proper names, as they are displayed in the report
            exec(http("Setup")
                    .get("/"))
                    .feed(keyPair)
                    .exec(http("GetToken")
                            .get("https://test.com/token")
                            .queryParam("token",String -> computerdatabase.JwtGenerator.getTokenAsString("#accountId","#keyId"))
                            .check(status().is(200))
                            .check(jsonPath("$.access_token").exists().saveAs("token"))
            );

Problem: can only use EL code such as #accountID and #keyID in gatling DSL methods.
Soluion: I assume I can use session api to get #accountId and #keyID values and input those values into my custom function, such as:

ChainBuilder get =
            //let's give proper names, as they are displayed in the report
            exec(http("Setup")
                    .get("/"))
                    .feed(keyPair)
                     .exec(session => session.get("accountId", computerdatabase.JwtGenerator.getTokenAsString(session("Count").as[String]))))

However, I get compliation errors:

[ERROR] /java/computerdatabase/advancedsimulation.java:[53,140]
‘;’ expected
&
illegal start of expression

exec(session => session

You have a syntax error. Java uses -> light arrows for functions, not => strong ones like Scala or Kotlin.

1 Like

Thanks for the quick response @slandelle. Your answer cleared up that compilation error.

Now that I know I am on the right track, I am trying something based on this example, in documentation:

// passing a reference to a function
Function<Session, String> f =
    session -> "/foo/" + session.getString("param").toLowerCase(Locale.getDefault());
exec(http("name").get(f));

In my case, I added the Function after the FeederBuilder

FeederBuilder.Batchable<String> keyPair =
            csv("keyIds.csv").circular();
Function<Session, String> f =
        session -> session.getString("keyId");

my imports are:

package computerdatabase;
import static computerdatabase.PerfTestConfig.*;

import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;

import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;

But, now I get this compilation error:
cannot find symbol
[ERROR] symbol: class Function
[ERROR] location: class computerdatabase.advancedsimulation

Solution:
import java.util.function.Function;

I have the feeling that you’re trying to code Java without using a proper IDE such as IntelliJ IDEA. If you’re indeed not, you should try it, it would really help you.

1 Like

I am using IntelliJ IDEA 2023 Ultimate Edition
but, I am not a Java developer.

And still struggling to get things working
Example code works perfectly

Function<Session, String> g =
            session -> session.getString("keyId");
Function<Session, String> f =
            session -> session.getString("accountId");
    // 1b. Add ChainBuilder:
    ChainBuilder setup =
            //give proper names, as they are displayed in the report
            exec(http("Setup")
                    .get("/"))
                    .feed(keyPair)
                    .exec(http("keyId").get(g)   //passed by reference VERIFIED: 

But, when I try to pass the keyId string into my custom function:

 ChainBuilder getToken =
            exec(http("GetToken")
                    .get("https://mytest.com/token")
                    .queryParam("assertion",String -> computerdatabase.JwtGenerator.getTokenAsString(f,g))  //compiler ERROR: cannot convert Function to String
                    .queryParam("assertion",String -> computerdatabase.JwtGenerator.getTokenAsString(session -> session.getString("accountId"),session -> session.getString("keyId")))  //compiler ERROR: incompatible types: String is not a functional interface
                    .check(status().is(200))
                    .check(jsonPath("$.access_token").exists().saveAs("token"))
            );

I guess I am passing a function into my custom function? Not sure what the best solution is or if there is a solution…

keyId does have the correct values, from csv file!!! Just no idea how to plug them as string input to my JwtGenerator.getTokenAsString function.

OUTPUT:

keyId: No baseUrl defined but provided url is relative : test1 1 (12.50%)

keyId: No baseUrl defined but provided url is relative : test2 1 (12.50%)

This is how your function should work:

.queryParam("assertion",session ->JwtGenerator.getTokenAsString(session.getString("accountId"), session.getString("keyId")))

No baseUrl defined but provided url is relative

Unrelated issue, and the error message is clear.
Gatling needs to know where to send the requests, so if you pass relative urls and not absolute ones (like you do in get("/")), you must define a default baseUrl in the protocol, see doc: Gatling HTTP protocol reference - protocol configuration

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.