Peter
Peter

Reputation: 849

How to pass value between two scenarios in gatling?

I have two scenarios in my script. I want to pass value of "CreateId" to 2nd scenario. I have saved "CreateId" in 1st scenario.

Error says:

No attribute named 'CreateId' is defined

jsonPath($.id).find(0).exists, found nothing

Scenario - 1

val create = scenario("Create")
        .exec(http("post_request_create")
        .post("/api/asdf")
        .headers(headers_10)
        .body(StringBody(session =>s"""{"name": "${randomName()}"}""")).asJSON
        .check(jsonPath("$.id")
        .saveAs("CreateId"))
        )

Scenario - 2

val addTerm = scenario("Add Term")
        .repeat (repeatCount){
        exec(http("Add")

        // NOT WORKING
            //.post("""/api/asdfg/${CreateId}/terms""")

        // NOT WORKING
            .post(session => "/api/asdfg/" + session.get("CreateId").asOption[String] + "/terms")

            .headers(headers_10)
            .body(StringBody(session =>s"""{...somedata...}"""))
            )
        }
val scn = List(create.inject(atOnceUsers(1)),addTerm.inject(nothingFor(10 seconds), atOnceUsers(userCount)))
setUp(scn).protocols(httpProtocol)      

Upvotes: 4

Views: 10480

Answers (4)

Amerousful
Amerousful

Reputation: 2545

I have general solution which can easy to use. There is several steps how to do it.

Create methods which get all session variable from one scenario and another method which set this variables:

import scala.collection.concurrent.{Map => ConcurrentMap}

def passAnotherSession(implicit transferVariable: ConcurrentMap[String, Any]): Expression[Session] =
    (currentSession: Session) => {
      currentSession.setAll(transferVariable)
    }

def saveSessionToVariable(implicit transferVariable: ConcurrentMap[String, Any]): Expression[Session] =
    (currentSession: Session) => {
      val systemKeys = List("gatling.http.ssl.sslContexts", "gatling.http.cache.contentCache", "gatling.http.cache.dns")
      transferVariable ++= currentSession.removeAll(systemKeys: _*).attributes
      currentSession
    }

I defined methods above in my abstract base class which is inherited in all simulations/scenario classes.


Then in my simulations/scenario class I defined mutable map (via implicit) for store session variable:

import scala.collection.concurrent.{Map => ConcurrentMap}

implicit val setUpSession: ConcurrentMap[String, Any] = new TrieMap()

Now let's start using the methods. Below is an example of a scenario that gets the desired variable:

val setUpScenario = scenario(...)
.exec(...) // some action with save desired variable 
.exec(saveSessionToVariable) // this save all session variables to above defined implicit map

And this is already a scenario that needs a variable:

val mainScenario = scenario(...)
.exec(passAnotherSession)    // get variable from setUpScenario
.exec(...)

Upvotes: 0

Oleksii Voropai
Oleksii Voropai

Reputation: 21

Slight modification of @Peter's answer in Java. For some reason the direct modification of the session doesn't work in Java:

.exec(_.set("CreateId", CreateId)) // Set it here

The value set in the session is discarded after leaving the lambda function. I solved this by wrapping the value with a feeder:

    Iterator<Map<String, Object>> createIdFeeder =
    Stream.generate((Supplier<Map<String, Object>>) () -> 
        Collections.singletonMap("CreateId”, CreateId)
    ).iterator();

and adding it to the "Add Term" scenario:

ScenarioBuilder addTerm = scenario("Add Term”)
    .feed(createIdFeeder) // Set it here
    .repeat (repeatCount){

Upvotes: 0

user2006042
user2006042

Reputation: 1

I also got the same issue for token where I need to generate the one token from auth services and need to pass to other API. I followed below steps. Hope this will resolve your problem.

val create = scenario("Create")
        .exec(http("post_request_create")
        .post("/api/asdf")
        .headers(headers_10)
        .body(StringBody(session =>s"""{"name": "${randomName()}"}""")).asJSON
        .check(jsonPath("$.id")
        .saveAs("CreateId"))
        )

then I created

val createId = exec(session => session.set("createdId", createdId));

Let's say create is in different Test object. so created object in calling class.

val test = new Test()

val addTerm = test.createId
    .exec(_.set("CreateId", CreateId)) // Set it here
       .repeat (repeatCount){
        exec(http("Add")
       .post("""/api/asdfg/${CreateId}/terms""")
       .headers(headers_10)
       .body(StringBody(session =>s"""{...somedata...}"""))
            )
        }

val addTermScn = scenario("Add Term ").exec(addTerm)
val testScn = scenario("create").excec(test.create)

setUp(

    testScn.inject(atOnceUsers(1)),
    addTermScn.inject(nothingFor(5),rampUsers(vUsers) during (rampUp seconds)),
    //orderLookup.inject(nothingFor(5),rampUsers(vUsers) during (rampUp seconds))
  ).throttle(
    reachRps(tps) in (rampUp second),
    holdFor(duration minutes)
  ).protocols(httpProtocol)

Upvotes: 0

Peter
Peter

Reputation: 849

Tried with below code and it worked. Hope it helps others.

var CreateId = ""

Scenario - 1

val create = scenario("Create")
        .exec(http("post_request_create")
        .post("/api/asdf")
        .headers(headers_10)
        .body(StringBody(session =>s"""{"name": "${randomName()}"}""")).asJSON
        .check(jsonPath("$.id")
        .saveAs("CreateId"))
        )

        .exec(session => {
            CreateId = session("CreateId").as[String].trim
            println("%%%%%%%%%%% ID =====>>>>>>>>>> " + CreateId)     
            session}       
        )


Scenario - 2

val addTerm = scenario("Add Term")
    .exec(_.set("CreateId", CreateId)) // Set it here
       .repeat (repeatCount){
        exec(http("Add")
       .post("""/api/asdfg/${CreateId}/terms""")
       .headers(headers_10)
       .body(StringBody(session =>s"""{...somedata...}"""))
            )
        }
val scn = List(create.inject(atOnceUsers(1)),addTerm.inject(nothingFor(10 seconds), atOnceUsers(userCount)))
setUp(scn).protocols(httpProtocol)    

Upvotes: 8

Related Questions