How to make one HTTP request before the scenario?

6,364 views
Skip to first unread message

Dmitry Bedrin

unread,
Apr 18, 2016, 6:45:25 AM4/18/16
to Gatling User Group
Hi guys,

I'm trying to use gatling for testing following use case:
1) Authenticate using REST endpoint /login/ and obtain a session cookie
2) Make 100K requests to other services with this cookie

I would like to make the first request using the gatling API in order to use the same HTTP properties (proxy, e.t.c.)

I can see that build method of PopulationBuilder is private to io.gatling.core and I cannot call it directly

What's the best way to implement it in gatling?



Thanks,
 Dmitry

John Arrowwood

unread,
Apr 18, 2016, 9:46:08 AM4/18/16
to Gatling User Group
I've implemented this very type of thing before.  It's doable.

Assuming you don't want to make 100k requests in serial, you want all your requests to be executed like a normal scenario, so you can take advantage of the traffic shaping abilities of Gatling...

Option 1: Create a thread-safe token cache object.  When you request the token for the first time, it communicates with the server to fetch the token.  Once it has the token, it caches it and on future requests, it returns the cached token.  In the mean time, any calls to the cache looking for a token while the token is being fetched need to block.

Option 2: Fetch the token during scenario build time.  You won't be using Gatling DSL to fetch it, so you will have to implement it differently.

Option 3: Create a Gatling scenario that all it does is request the token, and writes it to a file.  Then you build your test to feed the token from that file.  Then when you launch your test, you launch it using a batch file or shell script which first launches the token-getter scenario, then when it completes, it launches the real test.

Option 3 is the easiest to implement, from a complexity standpoint.  

I've even gone farther, and got access to the database and gave the token a lifetime of 1 year, so I could do it once, and then cache it, and not have to re-run the token-fetching code very often.  But that's because I needed hundreds of thousands of tokens, not just one, and the cost of creating the tokens was significant.

Hope this helps.

Dmitry Bedrin

unread,
Apr 26, 2016, 9:01:45 AM4/26/16
to Gatling User Group
Thanks, John!

I went with option 1 and it worked just fine!

Pavel Golub

unread,
Dec 14, 2017, 10:41:24 AM12/14/17
to Gatling User Group
Dmitry, do you have a code sample how did you do it? I'm pretty new in this area.

вторник, 26 апреля 2016 г., 16:01:45 UTC+3 пользователь Dmitry Bedrin написал:

Pavel Golub

unread,
Dec 15, 2017, 6:30:01 AM12/15/17
to Gatling User Group
I've got this finally working. So leaving code snippet for others

object Scenarios {
 
var tokens: Map[String, String] = Map[String, String]()

 
def searchScenario: ScenarioBuilder = scenario("search-scenario").during(Configuration.TestDuration) {
    feed
(Feeders.userAccount).doIf(session => tokens.get(session("userName").as[String]) == None) {
     
exec(
        http
("Token")
         
.get("tokens/")
         
.basicAuth("${userName}", "${password}")
         
.check(status.is(200))
         
.check(jsonPath("$[*].Id").ofType[String].saveAs("session-token"))
     
).exec(session => {
       
tokens += (session("userName").as[String] -> session("session-token").as[String])
        session
     
})
   
}
     
.feed(Feeders.searchQuery)
     
.exec(http("Search")
       
.get("/search")
       
.queryParam("q", "${q}")
       
.header("Authorization", "Token ${session-token}"))
 
}
}



четверг, 14 декабря 2017 г., 18:41:24 UTC+3 пользователь Pavel Golub написал:

Maksym Max

unread,
Dec 29, 2017, 5:45:25 AM12/29/17
to Gatling User Group
Is it a good way to use Map instead of concurrent version?

Stéphane LANDELLE

unread,
Dec 29, 2017, 11:27:30 AM12/29/17
to gat...@googlegroups.com
It's not :)

Stéphane Landelle
GatlingCorp CEO


--
You received this message because you are subscribed to the Google Groups "Gatling User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gatling+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Łukasz Yabol

unread,
Sep 25, 2018, 9:54:43 AM9/25/18
to Gatling User Group
@Pavel Golub

The first request is executed only once? 
I have a similar problem, I need to grab some data first and then reused it until now I kept a static list but it's changing too often.
I did a similar thing

object  FiltersTest{

def getFilters(duration:Duration)= {
exec(
http("Get filter from metadata")
.get("/api/v2/metadata?Tenant=" + Tenants.Flex)
.check(status.is(200))
.check(jsonPath("$..filtersDescriptors..name").findAll.saveAs("filterList"))
)
    .during(duration, exitASAP = false) {
foreach("${filterList}", "filter") {
exec(
http("Get filter ${filter}")
.get("/api/v2/filter-value/${filter}?startDate=" + Constants.startDate + "&endDate=" + Constants.startDate + "&PyraCloudTenant=" + Tenants.Flex)
.check(status.is(200))
.check(jsonPath("$..key").count.greaterThan(0))
).pause(Constants.pauseDuration)
}
}
}
}

But the first request is executed the same number of times as the foreach inside during{} block. 

I'm missing something ? 
I know that I could save it to file as John mentioned but it's a little bit stupid in my opinion. 

Regards 
Lukasz

Julia

unread,
Sep 25, 2018, 5:38:55 PM9/25/18
to Gatling User Group
Hi Lukasz,
I think with your code example you need to input 1 user in setup, then it will fetch filterList once, and then generate the number of requests of length of filterList.

Łukasz Yabol

unread,
Sep 26, 2018, 6:24:23 AM9/26/18
to Gatling User Group
Thank's Julia, 
True I was running it for a number of users, with one user I get what I expected. 

But it means that first request will be executed for each user, not exactly what I need. 

So we back to saving in the file it's a pity that gatling doesn't have run once option and you have to do 
workarounds :( 

Regards

Stéphane LANDELLE

unread,
Sep 26, 2018, 6:53:33 AM9/26/18
to gat...@googlegroups.com

--
You received this message because you are subscribed to the Google Groups "Gatling User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gatling+u...@googlegroups.com.

Łukasz Yabol

unread,
Sep 26, 2018, 7:17:59 AM9/26/18
to Gatling User Group
Hi Stéphane,

I know that there is before method but still, it required to write custom code or in v3 this will change and it will be possible to use DSL ? 

Regards 

Stéphane LANDELLE

unread,
Sep 26, 2018, 7:19:22 AM9/26/18
to gat...@googlegroups.com
Still works the same way.

Stéphane Landelle
GatlingCorp CTO


Julia

unread,
Sep 26, 2018, 8:54:38 AM9/26/18
to Gatling User Group

You can try to divide your requests to separate ChainBuilder objects and pass the values between two sessions by saving fetched list to external object:
.exec { session =>
 someExternalVar
= session("fetchedAttribute")
session
}

And then setting it as a session attribute:
.exec(_.set("attributeToBeUsedAfter", someExternalVar))

Then you can have different number of users for them. I think this scheme is good enough for authorisation (fetching token), but for similar situation as yours I use saving to files and running simulations in sequence, as you can use standard csv feeder then.

Lukáš Lukyer

unread,
Jul 26, 2019, 6:33:50 AM7/26/19
to Gatling User Group
Hi all, I managed to do what you want but only in hacky way:

val initStarted = new AtomicBoolean(false)
val initCompleteLatch = new CountDownLatch(1)
scenario("myScenario")
    .doIf(_ => initStarted.getAndSet(true) == false) {
      exec(http("first")
        .get("/endpoint")
        .check(status.is(200),
          jsonPath("$..response.id").findAll.saveAs("reponseVariable")
        )
      ).exec { session =>
        reponseVariable = session("reponseVariable").as[String]
        initCompleteLatch.countDown()
        session
      }
    }
    .exec { session =>
      initCompleteLatch.await()
      session.set("reponseVariable", reponseVariable)
    }
    .exec(http("second")
      .post("/another/endpoint/{responseVariable}")
      .body(...)
      .check(status.is(200))
    )

Hope it helps :) It can chain serveral requests, passthrough response along, and ensures first request is send only once. 

Btw it was so disappointing about Gatling that one have to do such dirty hacks to achieve so common thing :( 
Reply all
Reply to author
Forward
0 new messages