class LoginSimulation extends Simulation { //call the token server with username and password
//save the token as a variable to be used in the call below, extract the token from the response
//the token is to be sent as a header in the call below (as X-Token below)
val httpConf = http
.baseURL(https://coop.ua.com)
.acceptEncodingHeader("""gzip,deflate""")
.baseHeaders(Map("X-Token" -> "1234asdf"))
val scn = scenario("Scenario")
.exec(
http("getProfile")
.get("/user/profile")
.check(status.is(200))
setUp(scn.inject(constantUsersPerSec(5) during (10))).protocols(httpConf)
}
--
You received this message because you are subscribed to the Google Groups "Gatling User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gatling+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
.baseHeaders(Map("X-Token" -> "1234asdf"))
class LoginSimulation extends Simulation {
val httpConf = http
.baseURL(https://low.se)
.acceptEncodingHeader("""gzip,deflate""")
val scn = scenario("Scenario")
.exec(
http("getProfile")
.get("/user/profile")
.check(regex("""<meta content="(.*?)" name="token">""").saveAs("token"))
.exec(
http("getCSomething")
.get("/my/stuff")
.param("token", "${token}")
.
.
.
.
object RESTful {
object GET {
def apply( desc: String, url: String ) =
http( desc )
.get( url )
.headers( Headers.get )
}
object POST {
def apply( desc: String, url: String, body: String ) =
http( desc )
.post( url )
.headers( Headers.post )
.body( StringBody( body ) )
}
object PUT {
def apply( desc: String, url: String, body: String ) =
http( desc )
.put( url )
.headers( Headers.post )
.body( StringBody( body ) )
}
object DELETE {
def apply( desc: String, url: String ) =
http( desc )
.delete( url )
.headers( Headers.get )
}
}
The headers are defined elsewhere, and look like this:
object Headers {
val KEEP_ALIVE = Map( "Keep-Alive" -> "115" )
val XHR = Map( "X-Requested-With" -> "XMLHttpRequest" )
val SENDING_FORM_DATA = Map( "Content-Type" -> "application/x-www-form-urlencoded" )
val SENDING_JSON = Map( "Content-Type" -> "application/json;charset=UTF-8" )
val EXPECTING_JSON_OR_TEXT = Map( "Accept" -> "application/json, text/plain, */*" )
val get = KEEP_ALIVE
val post = KEEP_ALIVE ++ SENDING_JSON
val formPost = KEEP_ALIVE ++ SENDING_FORM_DATA
val ajax = KEEP_ALIVE ++ XHR ++ EXPECTING_JSON_OR_TEXT
val ajaxSend = KEEP_ALIVE ++ XHR ++ SENDING_JSON ++ EXPECTING_JSON_OR_TEXT
}
Then I created an application-specific wrapper for the RESTful object, which adds application-specific headers, like so:
object RTDE {
object GET {
def apply( desc: String, url: String ) =
RESTful.GET( desc, url )
.queryParam( "access_token", ACCESS_TOKEN.value )
}
object POST {
def apply( desc: String, url: String, body: String ) =
RESTful.POST( desc, url, body )
.queryParam( "access_token", ACCESS_TOKEN.value )
}
object PUT {
def apply( desc: String, url: String, body: String ) =
RESTful.PUT( desc, url, body )
.queryParam( "access_token", ACCESS_TOKEN.value )
}
object DELETE {
def apply( desc: String, url: String ) =
RESTful.DELETE( desc, url )
.queryParam( "access_token", ACCESS_TOKEN.value )
}
}
object Terminology {
val path = Config.Endpoint.Services.url + "/terminology"
def getByPath(
desc: Option[String] = None,
path: Option[String] = None,
element: Option[String] = None,
inref: Option[String] = None,
outref: Option[String] = None
) = {
var p: Map[String,Any] = Map()
element.map { x => p += ( "element" -> x )}
inref.map { x => p += ( "inref" -> x )}
outref.map { x => p += ( "outref" -> x )}
RTDE.GET(
desc = desc.getOrElse("Terminology.getByPath"),
url = path + path.getOrElse("/cigna")
)
}
def create(
desc: Option[String] = None,
term: Option[String] = None
) =
RTDE.POST(
desc = desc.getOrElse("Terminology.create"),
url = path,
body = term.getOrElse( TERMINOLOGY_DEFINITION.value )
)
def update(
desc: Option[String] = None,
path: Option[String] = None,
term: Option[String] = None
) =
RTDE.PUT(
desc = desc.getOrElse("Terminology.update"),
url = Terminology.path + path.getOrElse( TERMINOLOGY_PATH.value ),
body = term.getOrElse( TERMINOLOGY_DEFINITION.value )
)
def delete(
desc: Option[String] = None,
path: Option[String] = None
) =
RTDE.DELETE(
desc = desc.getOrElse("Terminology.delete"),
url = Terminology.path + path.getOrElse( TERMINOLOGY_PATH.value )
)
}
This allows me to write my scenarios very simply:
val scn =
scenario( name )
.exec( Login.sequence )
.exec( Service.method )
.exec( Service2.method2( parameters ) )
Still to come: Build reusable chains that represent specific user or application flows, and then the simulation can mix and match various scenarios together.
As Stéphane mentioned, I've also been playing around with creating my own DSL extensions. For example, I have a SessionManagement module that lets me set variables in the session using syntax like this:
scenario( name )
.set( VAR, VALUE ) // value of expression is interpolated and stored in VAR
.set( VAR, $(VAR2) ) // contents of VAR2 are stored in VAR
.set( VAR, VAR2.value ) // contents of VAR2 are stored in VAR
.set( VAR, LIST.random ) // one of the elements of LIST are stored in VAR
.set( VAR ).from( VAR2 ) // contents of VAR2 are stored in VAR
.set( VAR ).to( VALUE ) // value of expression is interpolated and stored in VAR
.set( VAR ).to( $(VAR2) ) // contents of VAR2 are stored in VAR
.set( VAR ).to.value( VALUE ) // value of expression is interpolated and stored in VAR
.set( VAR ).to.value( $(VAR2) ) // contents of VAR2 are stored in VAR
.set( VAR ).to.value.of( VAR2 ) // contents of VAR2 are stored in VAR
.set( VAR ).to.value.of( PATH ).from( VAR2 ) // extract first matching JSON PATH from VAR2
.set( VAR ).to.list.of( PATH ).from( VAR2 ) // extract *ALL* matching JSON PATH from VAR2
.set( VAR ).to.first( SOME_LIST ) // extract the first element from SOME_LIST into VAR
.set( VAR ).to.last( SOME_LIST ) // extract the last element into VAR
.set( VAR ).to.random( SOME_LIST ) // extract any element at random
If you are interested in the code to do that, let me know.
The principles that let me build that kind of DSL could be used to define custom DSL for an application, too. But I opted not to do that for a very good reason. I wanted to be able to use my API wrappers inside of things like .resources( http(), ... ). If you write DSL which extends the chain, you can't (that I know of) use that DSL inside of a resources() method on an HTTP request. And since my application makes restful calls as resources...
val scn = scenario("Scenario")
.baseHeaders(Map("X-Token" -> "1234asdf"))
.feed(csv("memberInfo.csv").random)
.check(jsonPath("$.resultCode").is("SUCCESS"))
.check(jsonPath("$.profile.memberships[0].scanNumber").saveAs("scanNr")))
...
outref<span style="color: #660;" class="styled-by-pret
object SOMETHING {
implicit class AddTokenToHttpRequest( request : T <: AbstractHttpRequestBuilder[T] ) {
def addToken = request.header( "X-Token" -> "${theToken}" )
}
}
// inside your scenario
import SOMETHING._
...
http( url )
.get( path )
.addToken
--
val workflow1Header = Map("username" -> "username", "password" -> "password", "Content-Type" -> "application/json")
val tokenId = "" //workflow1 return tokenId which I would like to use for my workflow2
//Do I need to initialize session variable here? such as tokenIdSession?
val workflowScn = scenario("Admin token")
.exec(http("Workflow1")
.post("/admin token endpoint")
.headers(workflow1Header)
.check(regex("token: (\\d+)").find.saveAs("tokenId"))
)
//I tried to use session here but I kept on getting errors and my scenario is returning this error message "ailed: regex(token: (\d+)).find.exists, found nothing"
setUp(workflowScn.inject(atOnceUsers(1)))
.protocols(newAcctHttpConf)