0

I'm trying to model a scenario where an initial request will provide several different lists of Ids, then a later request needs to submit the values in these lists (if they exist) as part of it's JSON payload. None of the lists is guaranteed to be in the response, and if it isn't, then there is no corresponding entry at all for it in the later JSON.

For example, call 1 might return 3 different lists of Ids that can be saved for later calls...

.check(
  jsonPath("$..manager").findAll.optional.saveAs("managemerIds"),
  jsonPath("$..employee").findAll.optional.saveAs("employeeIds"),
  jsonPath("$..temp").findAll.optional.saveAs("tempIds")      
)

Later I need to submit these as a request body formatted like

{"managers":"${managerIds.jsonStringify()}",
 "employees":"${employeeIds.jsonStringify()}",
 "temps":"${tempIds.jsonStringify()}"}

but if one of the lists of Ids is empty, then it can't be submitted in the JSON at all - ie: if there were no tempId's from the first request, then the JSON payload needs to look like

{"managers":"${managerIds.jsonStringify()}",
 "employees":"${employeeIds.jsonStringify()}"}

I could get this working by using a transformOption on the check to set the session variable to an empty list and then have conditional building of the JSON payload by doing something like

jsonPath("$..temp").findAll.transformOption(ids => ids.orElse(Some(Seq.empty[String])).success).saveAs("tempIds"))

but I was hoping for something more scala idiomatic using Options.

I can generate the required JSON for the body this way with something like

private def createPayload(
    managers: Option[String] = None, 
    employees: Option[String] = None, 
    temps: Option[String] = None) : String = {

        Map("managers" -> managers,
            "employees" -> employees,
            "temps" -> temps
        ).foldLeft(JsObject.empty){ case (result, (key, values)) => {
        values match {
          case Some(ids) => result ++ result.transform((__ \ key).json.put(JsString(ids))).get
          case None => result
      }
    }}.toString()

but I can't work out a way to just pass the option that results from attempting to resolve the session variable

James Warr
  • 2,552
  • 2
  • 7
  • 20

2 Answers2

2

With newer versions of Gatling, it's now possible to use Pebble here is how you can achieve it easily:

  body(PebbleStringBody(
  """
{

    {% if managers %} "managers": [
        {% for value in managers %}
        
            "id":"{{value.id}}"
        {% if loop.last %}{% else %} , {% endif %}
        {% endfor %}
        ]
    {% endif %}
    
}
"""))

Mind the PebbleStringBody instead of the traditional StringBody You can then achieve several operations including conditioning and loop.

EFOE
  • 609
  • 1
  • 10
  • 20
1

so I've come up with a solution that seems to work pretty well - I just had to resolve some session variables in the StringBody function and build the JSON according to requirements.

using the play framework's JSON capabilities is probably overkill though

def contactPeople(managers: Expression[Seq[String]], employees: Expression[Seq[String]], temps: Expression[Seq[String]]: ChainBuilder = {
exec(http(...)
  .post(...)
  .headers(...)
  .body(StringBody(session => 
     Map("managers" -> managers, "employees" -> employees, "temps" -> temps)
     .foldLeft(JsObject.empty){ case (result, (key, values)) => {
         values.apply(session) match {
             case Success(ids) => result ++ result.transform((__ \ key).json.put(Json.toJson[Seq[String]](ids))).get
             case Failure(error) => result
         }
     }}.toString
  ))
  ...
}
James Warr
  • 2,552
  • 2
  • 7
  • 20