gatling @ scala.io 2013
DESCRIPTION
GatlingTRANSCRIPT
Gatling 2, What’s up Doc?
by Stéphane Landelle @slandelle
Quick Introduction / Reminder about
What’s Gatling?
• Stress Test Tool
• Scala + Akka +Netty
• Scenarios = code + DSL
Scenario
val scn = scenario("Scala.Io DoS") .repeat(10000) { exec(http("Scala.Io").get("http://scala.io")) } setUp( scn.inject(rampUsers(10000) over 30 seconds) )
Scenario = Actor Workflow
Repeat Actor
Start Actor
Http Request Actor
End Actor
Async Handler Actor
Session
Scenario = Actor Workflow
Repeat Actor
Start Actor
Http Request Actor
End Actor
Async Handler Actor
Session
Scenario = Actor Workflow
Repeat Actor
Start Actor
Http Request Actor
End Actor
Async Handler Actor
Async Handler
Session
Scenario = Actor Workflow
Repeat Actor
Start Actor
Http Request Actor
End Actor
Async Handler Actor
Async Handler
Session
Scenario = Actor Workflow
Repeat Actor
Start Actor
Http Request Actor
End Actor
Async Handler Actor
Session
Scenario = Actor Workflow
Repeat Actor
Start Actor
Http Request Actor
End Actor
Async Handler Actor
Session
Timeline
• Mid 2011: o Start developing Gatling o No Scala background
• End 2012: o Better Scala skills o Community feedback o Need for open APIs
Time to clean this up!
Gatling 2!
• Planned for 2014: o Tons of refactoring o Tons of new features
• Sorry folks, we’re late: o Greater good: stability
• Milestones: o Current M3 o Next M4 november/december
New Expression API
Expression in Gatling 1
type Expression = Session => String implicit def toExpression(s: String): Expression http("Foo").get("https://www.google.fr/search?q=${term}")
Gatling 1 issues o What if “term” is undefined? o What if “term” is of wrong type?
è Unsafe, deal with Exceptions, not generic
repeat("${times}") {} // Expects Int foreach("${seq}”) {} // Expects Seq
Validation
Validation[+T] - map - flatMap
Success[+T] (value: T)
Failure (message: String)
Usage: Building a request
flatMap that s**t!
buildURI(httpAttributes.urlOrURI) .flatMap(configureQueryCookiesAndProxy) .flatMap(configureVirtualHost) .flatMap(configureHeaders) .flatMap(configureRealm)
New Expression API
type Expression[T] = Session => Validation[T] implicit def toExpression[T](s: String): Expression[T]
New Session API
val foo: Validation[T] = session("foo").validate[T] // unsafe: val bar: T = session("foo").as[T] val baz: Option[T] = session("foo").asOption[T]
New Templating API
Templating API in Gatling 1
• (Session => String) / Expression:
o Function o Implicitly compiled EL String
• Scalate SSP
Scalate SSP
o Can have complex logic
o Scala compiler in the background (overhead, proper stop) o Own API, learning curve o Does play well with Session API
Why do we need this anyway?
New Templating API: the EL way
Embedded
// passing an EL String setBody(StringBody("""{ foo: "${foo}", bar: ${bar} }""")
New Templating API: the EL way
External EL based text file
// passing an EL File setBody(ELFileBody("body.txt"))
{ foo: "${foo}", bar: ${bar} }
New Templating API: the EL way
o Simple
o Limited, can’t implement complex logic
Why do we need non-Scala templates anyway?!
We’re not in JSP world!
We have multiline Strings and macros!
String interpolation val jsonTemplate: Expression[String] = session => for { foo <- session("foo").validate[String] bar <- session("bar").validate[Int] } yield s"""{
foo: "$foo", bar: $bar }"""
String interpolation
o Pure Scala o Compile time, not runtime o Standard Scala library
o Requires a bit more Scala skills o Complex logic => intermediate String concatenations
Fastring
https://github.com/Atry/fastring • StringBuilder underneath • Produces Fastrings, not Strings
Fastring val jsonTemplate: Expression[String] = session => for (foos <- session("foos").validate[Seq[String]]) yield
fast"""{ foos = [
${foos.map(foo => fast"""{foo: "$foo"}""").mkFastring("\n")} ]
}""".toString
Checks improvements
Regex check in Gatling 1
è produces Strings è no more than 1 capture group
regex("foo(.*)bar").saveAs("baz")
Issue <form> <input type="hidden" name="foo" value="foo" /> <input type="hidden" name="bar" value="baz" /> </form>
è workaround: 2 regex + manual zip
Tuple support We need:
String (String, String)
(String, String, String) (String, String, String, String)
…
But generic, please…
Type class FTW regex[T](pattern: Expression[String]) (implicit groupExtractor: GroupExtractor[T])
object GroupExtractor { implicit val groupExtractor2: GroupExtractor[(String, String)] = ??? } trait GroupExtractor
regex[(String, String)]("foo(.*)bar(.*)baz")
Also for • headerRegex[T] T of String, Tuple2[String] , Tuple3[String]… • jsonPath[T] T of Int, Long, Double, Float, String, List, Map • XPath? • CSS selectors?
Resource fetching
Gatling 1
HTML page
Resource 1
Resource 2
Resource 3
Sequential workflow
Not how browsers work
HTML page
Resource 1
Resource 2
Resource 3
Parallel workflow
Very complex actually 1. Fetch HTML 2. Fetch HTML embedded resources 3. Fetch some additional resources (CSS @import) 4. Fetch matching CSS rules resources (@font-face, background-image) 5. …
(not accounting for javascript)
è Can’t be perfect without being a browser è Will have to approximate
Kind of scatter-gather pattern
HTML page
ResourceFetcher Actor
Beware of Session reconciliation!
Session + HTML
Fetch resources
New Session
Next
DSL exec( http(“Page").get("http://foo.com") .resources( http(“Ajax1").get("http://foo.com/ajax1"), http(“Ajax2").get("http://foo.com/ajax2") .check(regex("foo(.*)bar").saveAs("baz")) ) )
And many more to come…
Q/A? @GatlingTool
http://gatling-tool.org
https://github.com/excilys/gatling