Running concurrent scenarios

Hi all,

Hoping someone can make sense for me of how ScenarioBuilder works with ChainBuilder.

I have two “scenarios” each sending a json body to an api endpoint.

My end goal is to have a scenario file of many individual requests (scenarios) and then chain them together with ScenarioBuilder and run as a new scenario of multiple requests.

   ScenarioBuilder create = scenario("Create customer").exec(createCustomer);
   ScenarioBuilder update = scenario("Update customer").exec(createCustomer, updateCustomer);


        {
            setUp(update.injectOpen(rampUsers(config.userCount).during(config.rampDuration))
            ).protocols(config.httpProtocol)
             .assertions(global().failedRequests().percent().lte(5.0));
        }
    }

However, i’m having an issue where it won’t run the second scenario, example above, it will run the createCustomer scenario but ignore the updateCustomer scenario.

I could achieve the same outcome by putting both requests together via ChainBuilder in my scenario file, but I feel like that compromises the DRY principle.

What am I missing?

Sorry, but I don’t get it. create is not configured in your setUp, so there’s no way it gets called.

Is it not called from ‘update’? I have defined two scenarios in update: createCustomer and updateCustomer.

As per this example in the gatling documentation:

ScenarioBuilder users = scenario("Users")
  .exec(search, browse);
ScenarioBuilder admins = scenario("Admins")
  .exec(search, browse, edit);
{
  setUp(users.injectOpen(atOnceUsers(10)).protocols(httpProtocol));
}

Please, keep reading.

Here we set only 10 users,

Then… below, the documentation states:

In our scenario let’s have 10 regular users and 2 admins, and ramp them over 10 seconds so we don’t hammer the server:

setUp(
  users.inject(rampUsers(10).during(10)),
  admins.inject(rampUsers(2).during(10))
).protocols(httpProtocol)

Declaring a scenario is not the same thing as injecting it.

Cheers!

ok but in this example you have search, browse and edit which are 3 separate requests. I want to do the same as this, but in my case it only injects the first request, and doesn’t bother with the second.

search, browse and edit which are 3 separate requests

search, browse and edit and 3 chains. You’re confusing the terms scenarios, chains and requests, so it’s hard to follow.

In your original message, the create defined in ScenarioBuilder create = scenario("Create customer").exec(createCustomer); is never used anywhere, in particular in the setUp, and hence does nothing.

Sorry bad example, this is an example of two different scenarios i want to run, so I’d edit the setUp to include create when i only want to run create and then change it to update when i want it to run createCustomer and updateCustomer.

These are my chains:

   public static ChainBuilder createCustomer =
                   during(config.testDuration).on(
                     feed(feeders)
                    .exec(http("post-customer-find-create")
                                    .post(config.hostUrl + (testUrl)")
                                    .body(ElFileBody("data/customer_request.json")).asJson()
                                    .check( regex( "customerNumber\":(.*?),\"" ).saveAs("customerId"))
                                    .check(regex("\\{\"id\":\"([^\"]+)\",\"email\":").saveAs("emailId"))
                                    .check(status().is(200)))
                                    .exec(session -> {
                                                System.out.println("Customer ID = " + session.getString("customerId"));
                                                System.out.println("Email ID = " + session.getString("emailId"));
                                                return session;
                                            }
                                    ));


    public static   ChainBuilder updateCustomer =
            during(config.testDuration).on(
                    feed(feeders)
                            .exec(http("put-customer-email-update")
                                    .put(config.hostUrl + "/(testUrl)#{customerId}/emails/#{emailId}")
                                    .body(ElFileBody("data/email_request.json")).asJson()
                                    .check(status().is(200))
                            ));

So the updateCustomer needs the createCustomer to run first so it can take the customerId and emailId and use it.

Again, I might be barking up the wrong tree with what I’m trying to achieve.

Put simply,

I want to have a list of requests and then execute them in a sequence I define as per the ScenarioBuilder.

However, i’m having an issue where it won’t run the second scenario, example above, it will run the createCustomer scenario but ignore the updateCustomer scenario.

How did you reach this conclusion? Because it should work. Can you share your logs?

Note: you really should use jmesPath checks instead of regex for parsing JSON payloads.

1 Like

What are these during(config.testDuration) in your chain builders for?

I think you mix what is an execution Chain, what is a Scenario and what is a Simulation.

I will try to read your code as would do the Gatling application.

  • To setup the simulation, instantiate the scenario “update” and make “userCount” users to be injected each seconds doing that smoothly
  • The “update” scenario is the “createCustomer” chain, then the updateCustomer
  • The “createCustomer” chain is a request you loop during “testDuration”.

And I think this is your “issue”, you want the whole scenario (ie, a virtual user) to be alive during your “testDuration”

Am I correct?

Cheers!

1 Like

I make investigation in this what you give us and created simple demo Simulation to show where you have issue.

Simulation:

package pl.gemiusz;

import io.gatling.javaapi.core.ChainBuilder;
import io.gatling.javaapi.core.ScenarioBuilder;
import io.gatling.javaapi.core.Simulation;
import io.gatling.javaapi.http.HttpProtocolBuilder;

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

public class Case0022Simulation extends Simulation {

    HttpProtocolBuilder httpProtocol =
            http
                    .baseUrl("https://postman-echo.com");

    public static ChainBuilder createCustomer =
            during(5).on(
                            exec(http("GeMi_StatusCodeSimulation_get")
                                    .get("/status/414")
                                    .check(status().is(414).saveAs("GeMi_Status_Code_1"))
                            ).exec(session -> {
                                System.out.println("GeMi_Status_Code_1: " + session.get("GeMi_Status_Code_1").toString());
                                return session;
                            })
            );


    public static   ChainBuilder updateCustomer =
            during(5).on(
                            exec(http("GeMi_StatusCodeSimulation_get_update")
                                    .get("/status/#{GeMi_Status_Code_1}")
                                    .check(status().is(414).saveAs("GeMi_Status_Code_2"))
                            ).exec(session -> {
                                System.out.println("GeMi_Status_Code_2: " + session.get("GeMi_Status_Code_2").toString());
                                return session;
                            })
            );


    ScenarioBuilder update = scenario("Update customer").exec(createCustomer, updateCustomer);


    {
        setUp(update.injectOpen(rampUsers(5).during(1))
        ).protocols(httpProtocol);
    }
}

When you look at output you see loot of

GeMi_Status_Code_1: 414

and afrer some time mix of

GeMi_Status_Code_1: 414
GeMi_Status_Code_1: 414
GeMi_Status_Code_1: 414
GeMi_Status_Code_2: 414
GeMi_Status_Code_1: 414
GeMi_Status_Code_2: 414
GeMi_Status_Code_2: 414
GeMi_Status_Code_2: 414
GeMi_Status_Code_1: 414
GeMi_Status_Code_2: 414
GeMi_Status_Code_1: 414
GeMi_Status_Code_1: 414
GeMi_Status_Code_2: 414

and at end loot of:

GeMi_Status_Code_2: 414

as I understand you want to have always pair of requests:

GeMi_Status_Code_1: 414
GeMi_Status_Code_2: 414

when you look on report you will se what going on:

Global:

createCustomer:

updateCustomer:

What can be wrong:
Using duration in ChainBuilder make a loop of calls for this one chain and after that it’s called another chain and there is another loop of calls.

If you want to achieve one chain and another one after first and same thing again in loop:

GeMi_Status_Code_1: 414
GeMi_Status_Code_2: 414
GeMi_Status_Code_1: 414
GeMi_Status_Code_2: 414
GeMi_Status_Code_1: 414
GeMi_Status_Code_2: 414

you can change code to look like this:

package pl.gemiusz;

import io.gatling.javaapi.core.ChainBuilder;
import io.gatling.javaapi.core.ScenarioBuilder;
import io.gatling.javaapi.core.Simulation;
import io.gatling.javaapi.http.HttpProtocolBuilder;

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

public class Case0022Simulation extends Simulation {

    HttpProtocolBuilder httpProtocol =
            http
                    .baseUrl("https://postman-echo.com");

    public static ChainBuilder createCustomer =
                            exec(http("GeMi_StatusCodeSimulation_get")
                                    .get("/status/414")
                                    .check(status().is(414).saveAs("GeMi_Status_Code_1"))
                            ).exec(session -> {
                                System.out.println("GeMi_Status_Code_1: " + session.get("GeMi_Status_Code_1").toString());
                                return session;
                            });


    public static   ChainBuilder updateCustomer =
                            exec(http("GeMi_StatusCodeSimulation_get_update")
                                    .get("/status/#{GeMi_Status_Code_1}")
                                    .check(status().is(414).saveAs("GeMi_Status_Code_2"))
                            ).exec(session -> {
                                System.out.println("GeMi_Status_Code_2: " + session.get("GeMi_Status_Code_2").toString());
                                return session;
                            });


    ScenarioBuilder update = scenario("Update customer").exec(createCustomer, updateCustomer);


    {
        setUp(update.injectOpen(constantUsersPerSec(1).during(10))
        ).protocols(httpProtocol);
    }
}

1 Like

Thank you for your reply, that helps with the two scenarios running concurrently and behaves as expected, however by using constantUsersPerSec how do I define a ramp and test duration? I’'ve typically used rampUsers and a ramp duration in the past, and occasionally used throttle.

In you question you say about issue with concurrent scenarios so example show where can be bug and how to fix it. If it help set as Solution my previous message.

this was only example, you must prepare Injection as you need.

Yeah i’ve referred to the documentation a lot but I find it difficult to understand the code examples when everything is bundled together, real-world examples, or samples are what my brain tends to understands, I came from LoadRunner so I’m after LoadRunner simplicity levels of run-time settings, i’ll keep experimenting.

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