Branching Checks

We are evaluating Gatling here at Hulu. Like others in this thread, we are using Gatling for more than just load. We are using it to validate certain features under load.

The fact that Gatling is in Scala and is a full-featured programming language rather than a GUI based application is good.

We are having some problems with Gatling. We need to do branching logic for checks. By that, I mean we have multiple ways for a response to pass and multiple ways to fail.

As far as I understand, Gatling only has one linear set of checks for each request:

  
exec (
  http("GET url")
  .get("/path")
  .check(
    xpath("//tag1"),
    xpath("//tag2"),
    xpath("//tag3"),

  )
)

Currently the way that it works is that if the check for xpath(“//tag1”) passes then xpath(“//tag2”) can run, if that passes, then “tag3” can run.

What we need is branching of the checks. I propose two different notations:

/* Simple if Pass Parent - then check children in block */
xpath("//tag1") {
  xpath("//tag1A"),
  xpath("//tag1B"),
  xpath("//tag1C"),
},

/* Case Pass / Fail / Other - Check children block */
xpath("//tag2") {
  case check if check.passed => {
    xpath("//tag2PASS1")
    xpath("//tag2PASS2")
    xpath("//tag2PASS3")
  }
  case check if check.failed => {
    xpath("//tag2FAILED1")
    xpath("//tag2FAILED2")
    xpath("//tag2FAILED3")
  }
  case check if session("foo").as[String] == "FOO" => {
    xpath("//tag2/foo_is_FOO1")
    xpath("//tag2/foo_is_FOO2")
    xpath("//tag2/foo_is_FOO3")
  }
}

Also, there were functions on the check class that don’t seem to do what I want:

  /* Things that don't quite work */
  xpath("//tag3")
    .onSuccess({
      xpath("//tag3ON_SUCCESS1")
      xpath("//tag3ON_SUCCESS2")
      xpath("//tag3ON_SUCCESS3")
    })
    .onFailure({
      xpath("//tag3ON_FAILURE1")
      xpath("//tag3ON_FAILURE2")
      xpath("//tag3ON_FAILURE3")
    })
)

Eventually, we need to see what passed and what failed in the test output:


---- Errors --------------------------------------------------------------------

Hi Emmanuel,

Such checks could be useful, but the design is actually a bit complex:

  • When there’s multiple checks, Gatling only reports the first failed one, but actually tries all of them, and save as many data as possible (ie all successful checks with saveAs are honored, even when they come after a failed one). What would be the behavior with branched checks then?
  • The general logic in Gatling DSL is that components are resolved once, when the scenario is built. Your suggestions based on pattern matching that return checks are not possible, because it would violate this principle and require to build checks at runtime. We need a DSL where the branching is either static, or isolated from the check, ie the most rich yet complex form has to be something like ((Session, parent’s Validation[CheckResult]) => Boolean, Check), and then maybe have more simple overloads.

Thoughts?

Hi,

I Use my “feature” HttpConditionnalCheck to do this.
A first check store some infos in session
Then following check can be performed depending the result of a nearly Expression[Boolean].

Check my thread : https://groups.google.com/forum/#!topic/gatling/Go1dkWm9fH8

By overriding the HttpConditionnalCheck class, I can add logic to not fail on a particular check, by using some stored infos in session, for exemple.

I’m looking at your implimentation but, it isn’t compiling for me. I’m missing HttpConditionalCheckBuilder. It isn’t in the gatling sources nor the code the other thread.

I’m still looking at kicking it around and making it work as it’s closer to what I need than JMeter.

Hi,

Here is my class HttpConditionalCheckBuilder :

class HttpConditionalCheckBuilder(condition: (Session, Response) => Validation[Boolean], nestedCheck: HttpCheck)
extends DefaultFindCheckBuilder[HttpCheck, Response, Response, Response](
(wrapped: Check[Response]) => new HttpConditionalCheck(wrapped, condition, nestedCheck), dummyPreparer, dummyExtractor) {

}

It use dummyPreparer and dummExtractor vals which are defined in the code I supplied before.

val dummyExtractor: Expression[Extractor[Response, Response]] = new HttpDummyExtractor().expression
class HttpDummyExtractor extends Extractor[Response, Response] {
  def name = "dummy"
  def arity = "dummy"
  def apply(prepared: Response): Validation[Option[Response]] = { Success(Option(prepared)) }
}
trait Extractor[P, X] {
  def name: String
  def arity: String
  def apply(prepared: P): Validation[Option[X]]
}

DummyExtractor extends Extractor and neither of them have the expression method / member.

Is that something you added?

You have to import this : import io.gatling.core.session._

Or I think replacing the line by this may do the trick, but not tested yet. : val dummyExtractor: Expression[Extractor[Response, Response]] = new ExpressionWrapper(new HttpDummyExtractor()).expression
ExpressionWrapper is an implicit class, so the wrapper was built implictly by the compiler.