Gatling EL stringToExpression is not working as expected for grpc

Hi, I am trying to create my gRPC payload by reading data from a csv file(it has guestID and category as columns) but I see ${guestID} is being passed to my service instead of the actual value in csv file. I think EL is unable to interpret it at runtime. I also have “import io.gatling.core.Predef.stringToExpression” in my script. How can I achieve this? Am I doing something wrong here? Any help is appreciated. (payload is a RequestContext object which takes in metadata, keys and items. metadata is a map, keys is a Seq of ContextKey and items is empty Seq. ContextKey contains string guestID or category and type).

val scn2: ScenarioBuilder = scenario("gRPC call - 50 users repeated 100 times")
  .feed(csv("testtext.csv").circular)
  .exec(
    grpc("gRPC request with test message")
      .rpc(RecommenderGrpc.METHOD_GET_RECOMMENDATIONS)
      .payload(RequestContext.of(metadata = Map("test" -> "test"),
        keys = Seq(ContextKey.of("${guestID}",Type.GUEST),
          ContextKey.of("${category}",Type.CATEGORY)), items = Seq())
      )
  )

Please carefully read the documentation: Gatling Expression Language is not some that can magically work in your own custom code, only when passed to Gatling DSL methods.

https://gatling.io/docs/current/session/expression_el/

Yeah exactly.

If you need a way to use EL parser freely in your code outside Gatling DSL, use helper object:

`

import io.gatling.core.session._
import io.gatling.core.session.el._

object ELParser {

def apply(string: String, session: Session): Any = asOption(string, session).get

def asOption(string: String, session: Session): Option[Any] = {
val expression = string.el[Any]
expression(session).toOption
}
}

`

To use it you always need the current user session instance:

`
// simple var
val id = ELParser("${call_id}", session)

// nested object
val organizationId = ELParser("${organization_data.id}", session).asInstanceOf[String]

// any EL function works
val exists = ELParser("${call_data.recording_data.transcript.exists()}", session).asInstanceOf[Boolean]

// or return option to prevent exception if key not found
val language = ELParser.asOption("${call_data.recording_data.language}", session).asInstanceOf[Option[String]]

`

Cheers!

I’m not convinced using the EL parser explicitly to manually turn Gatling EL Strings into functions is a good thing.
I recommend using the programmatic Session API instead.

// simple var
val id: Expression[String] = session => session(“call_id”).as[String]

For simple vars - agreed, but for nested objects session API becomes “casting hell”… :frowning:

Hi Adam,

I don’t think that’s the case.
Using for comprehension, it can be achieved with one line per session attribute access without callback hell indentation.
For an example, see my answer for this question on stackoverflow.

Regards,
George

Hi George,

you are still referencing simple variable here:

`

session("category").validate[String] // "category" is the first-level key in session bag

`

What if you’d need some nested value, say an equivalent of below EL string?

`

"${category.games.education(n).name}" // get the name for the n-th game in education category, given "n" is a counter name in a loop

`

EL resolves this in one liner, manual extraction would not look so nice :wink:
Or maybe there is a one liner solution without using EL I’m not aware of?

Cheers,
Adam

Hi Adam,

I see what you mean now. I thought you were talking about the nested flatMap (what for comprehension desugars to) for multiple session attribute accesses.
I guess trying to write that nested access succinctly manually will result in bad Scala code, as the EL compiler has to do quite a few dynamic type checking behind the scenes.

Regards,
George