Skip to content

Instantly share code, notes, and snippets.

@infomaven
Last active September 10, 2015 22:47
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save infomaven/69132e142b369d8ebfd7 to your computer and use it in GitHub Desktop.
Save infomaven/69132e142b369d8ebfd7 to your computer and use it in GitHub Desktop.
Contains boolean logic to determine which workload will be used . Optimized for Gatling 2.1
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.core.scenario._
import io.gatling.core.structure.PopulatedScenarioBuilder
import scala.concurrent.duration._
class Gatling_WorkloadPicker extends Simulation {
/* The API we are testing has 1 POST and 3 GET endpoints. In this example, we only are considering 3 types of workloads.
1. gets only
2. posts only
3. mixed workload
For simplicity, we are ignoring other http verbs, but they could easily be implemented the same way.
Our API endpoints are fed into Gatling from some external source (like a build server or external file).
- An endpoint having RPS >= 1 is intended to be used.
- RPS < 1 means the endpoint should be SUPPRESSED or SKIPPED
Our primary method of detecting this condition is to compare the RPS total for each type of request (write/read) to the total number of
endpoints that are cataloged at the global level.
For simplicity of testing and running this code example, values are hardcoded
Note: this file is set up to run as a stand-alone Simulation using a local installation of Gatling
*/
// ------writes/POSTs
val writeRequests = List(9) // one POST endpoint configured @ 9 rps
//val writeRequests = List(0.1 ) // uncomment to make this code "skip" running POST calls
val writeCount = writeRequests.length // number of Post endpoints in the catalog (API)
val writeSum = writeRequests.sum // RPS sum for the cataloged Post endpoints
// -------reads/GETs
val readRequests = List( 5, 5, 10) // 3 GET endpoints configured @ 5, 5, 10 rps respectively
// val readRequests = List(0.1,0.1,0.1) // uncomment to make this code "skip" running GET calls
val readCount = readRequests.length // number of Get endpoints in the catalog (API)
val readSum = readRequests.sum // RPS sum for the cataloged Get endpoints
// Characterize the workload according to rps totals found in the Lists (for Get and Post endpoints)
// if neither one of these conditions is triggered, fall back to *mixed* workload
val readsOnly = writeSum < writeCount // extremely low sum for Writes means that this is a READ workload
val writesOnly = readSum < readCount // extremenly low sum for Reads means this is a WRITE workload
val httpConf = http
.baseURL("http://computer-database.herokuapp.com") // Here is the root for all relative URLs
.acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") // Here are the common headers
.doNotTrackHeader("1")
.acceptLanguageHeader("en-US,en;q=0.5")
.acceptEncodingHeader("gzip, deflate")
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
val headers_10 = Map("Content-Type" -> """application/x-www-form-urlencoded""") // Note the headers specific to a given request
//// basic READ request
// GET
object Scenario1 {
val scenario1 = exec( http("request_3")
.get("/computers/6"))
.pause(3)
.exec(http("request_4")
.get("/"))
.pause(2)
}
// GET
object Scenario3 {
val scenario3 = exec(http("request_6")
.get("/computers?p=2"))
.pause(629 milliseconds)
.exec(http("request_7")
.get("/computers?p=3"))
.pause(734 milliseconds)
}
//GET
object Scenario4 {
val scenario4 = exec(http("request_5")
.get("/computers?p=1"))
.pause(670 milliseconds)
.exec(http("request_8")
.get("/computers?p=4"))
.pause(5)
.exec(http("request_9")
.get("/computers/new"))
.pause(1)
}
///// WRITE requests
// POST
object Scenario2 {
val scenario2 = exec(http("request_10")
.post("/computers")
.headers(headers_10)
.formParam("""name""", """Beautiful Computer""")
.formParam("""introduced""", """2012-05-30""")
.formParam("""discontinued""", """""")
.formParam("""company""", """37"""))
}
///// create load injection profiles
val scnWriteWL = scenario( "Writes")
.exec( Scenario2.scenario2 )
.inject( atOnceUsers(writeSum))
val scnReadWL = scenario("Reads")
.exec( Scenario1.scenario1, Scenario3.scenario3, Scenario4.scenario4 )
.inject( atOnceUsers(readSum))
//// fallthrough condition
val scnMixedWL = scenario( "loadMIXED")
.exec( Scenario1.scenario1, Scenario2.scenario2, Scenario3.scenario3, Scenario4.scenario4 )
.inject( atOnceUsers( readSum + writeSum ))
/**
Sets workload composition according to workload characterization.
Receives multiple flag inputs (true/false) and deterines final workload based on the values it receives.
**/
val workload = (readsOnly, writesOnly ) match {
case (true, false) => scnReadWL.protocols( httpConf )
case( false, true) => scnWriteWL.protocols( httpConf )
case( _) => scnMixedWL.protocols( httpConf )
}
setUp(
workload
)
}
package buffer.example
import scala.collection.mutable.ListBuffer
/**
* Created by nadine on 7/28/15.
* This program cotnains supporting objects to encapsulate common settings needed for REST endpoints.
No services are actually called.
* To run this program in REPL, copy and paste the entire thing at scala prompt.
* Then type: BufferExample.main(null)
* Purpose: build a dynamic list of Endpoint objects that can be used as injection steps for a Simulation
*/
object BufferExample extends App {
case class Endpoint( name: String, rps: Double )
def getSubList( nameList: List[String], criteria: String ): List[String] = {
// create new ListBuffer
val nameBuffer: ListBuffer[String] = ListBuffer[String]()
// add elements to ListBuffer that meet the criteria
nameList.foreach( name =>
if( name.contains( criteria )) {
nameBuffer += name
});
nameBuffer.toList
}
//// todo: fix evaluation of Tuple._2 value to work with decimals (it currently only works with Int)
def convertListToEndpoints( nameList: List[ (String, Double ) ], criteria: String): List[Endpoint] = {
// create new ListBuffer
val endpointBuffer: ListBuffer[Endpoint] = ListBuffer[Endpoint]()
// add elements to ListBuffer that meet the criteria
nameList.foreach( entry =>
if( entry._1.contains( criteria ) && (entry._2 >= 1) ) {
val endpoint = Endpoint( entry._1, entry._2 )
endpointBuffer += endpoint
})
endpointBuffer.toList
}
override def main( args: Array[String]) {
val exampleList = List("peakRPSGet1", "peakRPSPost2", "peakRPSPut3", "peakRPSGet4", "peakRPSGet5", "peakRPSDelete6", "peakRPSPost7", "peakRPSPost8", "peakRPSPost9", "peakRPSGet10")
val reads = getSubList(exampleList, "Get")
println("Reads: " + reads)
val posts = getSubList(exampleList, "Post")
val puts = getSubList(exampleList, "Put")
val deletes = getSubList(exampleList, "Delete")
val writes = List(posts, puts, deletes)
println("Writes: " + writes)
///----------
val list2 = List( ("peakRPSGet1", 0.1 ), ("peakRPSPost2", 0.1), ("peakRPSPut3", 0.1), ("peakRPSGet4", 0.1), ("peakRPSGet5", 0.1), ("peakRPSDelete6", 1.0), ("peakRPSPost7", 5.6), ("peakRPSPost8", 0.1))
// list2
val get = convertListToEndpoints( list2, "Get")
val post = convertListToEndpoints( list2, "Post")
val put = convertListToEndpoints( list2, "Put")
val delete = convertListToEndpoints( list2, "Delete")
val mutate = List(post , put , delete)
println( "ReadEndpoints: " + get )
println("WriteEndpoints: " + mutate )
}
}
/*
Another pass at load selection. This time instead of boolean values, we're using in Integer (like someting selected from a menu)
*/
// create injection profiles
val scnTwoProfiles = scenario( "push")
.exec( Scenario2.scenario2 ).inject( rampUsersPerSec(10) to 20 during(5 seconds) , constantUsersPerSec(20) during (20 seconds))
// .exec( Scenario1.scenario1).inject( atOnceUsers(1))
val scnListOfFour = scenario("store")
.exec( Scenario1.scenario1, Scenario3.scenario3, Scenario4.scenario4 )
//.inject( atOnceUsers(3))
.inject( rampUsersPerSec(10) to 20 during(5 seconds) , constantUsersPerSec(20) during (20 seconds))
val scnMixedWL = scenario( "email")
.exec( Scenario1.scenario1 )
// .inject( atOnceUsers(5))
.inject( rampUsersPerSec(10) to 20 during(5 seconds) , constantUsersPerSec(20) during (20 seconds))
val menuId = 5
val workload = (menuId ) match {
case (1) => scnTwoProfiles.protocols( httpConf )
case( 2) => scnListOfFour.protocols( httpConf )
case( _) => scnMixedWL.protocols( httpConf )
}
setUp(
workload
)
}
@infomaven
Copy link
Author

If using this in Gatling 2.2, be alert for class name changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment