880 likes | 1.44k Views
Performance testing with Gatling. Intro/Agenda. Performance testing overview Gatling overview Gatling test structure Gatling API Gatling Recorder Gatling DSL Gatling reports. Performance testing. Performance testing. Measure response time under workload
E N D
Intro/Agenda • Performance testing overview • Gatling overview • Gatling test structure • Gatling API • Gatling Recorder • Gatling DSL • Gatling reports
Performance testing • Measure response time under workload • Load, Stress, Soak, Spike testing • Find bottlenecks • Satisfy impatient customers • Increase conversion rate • Sustain company reputation
Approach • Set proper goals • Choose tools • Try the tools • Implement scenarios • Prepare environments • Run and measure
Gatling Firepower
Gatling • Thousands of concurrent users • Users are not threads, but actors • Asynchronous concurrency • Scala • Akka • Netty • Recorder (HTTP Proxy and HAR) • Extensions (Maven, Gradle, Jenkins)
1 thread = 1 user * * http://www.slideshare.net/ZeroTurnaround/stephane-landelleblastyourappwithgatling
Blocking I/O * * http://www.slideshare.net/ZeroTurnaround/stephane-landelleblastyourappwithgatling
Actors Model • Mathematical model used in parallel computing • Actor is autonomous computational unit • No shared resources, no shared state • Asynchronous message passing • Mailbox to buffer incoming messages • React on received messages
HTTP GET Request Define constant variable Variable name Method of HTTP Request object Request URI val myHttpGetRequest = http("Open home page").get("/home") Create HTTP Request object Request name
HTTP Protocol URL is prepended to any HTTP request Application URL Create HTTP Protocol object val myHttpProtocol = http.baseURL("http://localhost:81")
Scenario Create Scenario object Scenario name Execute HTTP Request Already created HTTP Request object val myScenario = scenario("Browse Home").exec(myHttpGetRequest) .pause(2).exec(myReq2) Pause between requests Pause time in seconds Execute more HTTP Requests
setUp Gatling Simulation base method Scenario object method Number of users Already created HTTP Protocol object setUp(myScenario.inject(atOnceUsers(10))).protocols(myHttpProtocol) Already created Scenario object Injection profile Configure protocol
Simulation class Import Gatling API classes Gatling base simulation class import io.gatling.core.Predef._import io.gatling.http.Predef._class MySimulation extends Simulation {} Simulation class name
Gatling simulation import io.gatling.core.Predef._import io.gatling.http.Predef._class MySimulation extends Simulation {val myHttpProtocol = http.baseURL("http://localhost:81") .inferHtmlResources()val myHttpGetRequest = http("Open home page").get("/home")val myLoginRequest = http("Open login page").get("/login")val myScenario = scenario("Browse Home") .exec(myHttpGetRequest).pause(2) .exec(myLoginRequest) setUp(myScenario.inject(atOnceUsers(10))).protocols(myHttpProtocol)}
Recorded simulation import io.gatling.core.Predef._import io.gatling.http.Predef._class RecordedSimulation extends Simulation {val httpProtocol = http .baseURL("http://localhost:9000") .inferHtmlResources()val scn = scenario("RecordedSimulation") .exec(http("request_0") .get("/products")) .pause(5) .exec(http("request_1") .get("/products?q=SearchString")) setUp(scn.inject(atOnceUsers(1))) .protocols(httpProtocol)}
Gatling DSL Domain Specific Language
Gatling DSL • Feeders • csv, ssv, tsv, jsonFile, jsonUrl, jdbcFeeder • queue, random, circular • Checks • responseTimeInMillis, latencyInMillis, status, currentLocation • header, headerRegex • bodyString, bodyBytes, regex, xpath, jsonPath, css • Check actions • find, findAll, count, saveAs • is, not, exits, notExists, in, optional
Gatling DSL (2) • Execution control • doIf, doIfOrElse, doSwitch, doSwitchOrElse, randomSwitch • repeat, foreach, during, asLongAs, forever • tryMax, exitBlockOnFail, exitHereIfFailed • Assertions • responseTime, allRequests, requestsPerSec • min, max, mean, stdDev, percentile1, percentile2 • lessThan, greaterThan, between, is, in, assert • Injection profiles • nothingFor, atOnceUsers, rampUsers over, rampUsers during
Session • A virtual user’s state • stores all simulation user’s data • Map[String, Any] • Write data • using Feeders • extract and save from response • programmatically with Session API • Read data • using Gatling Expression Language • programmatically with Session API
ANY STIONS?
Thank you! Lyudmil Latinov Senior Automation QA Xoomworks Bulgaria https://github.com/llatinov/sample-performance-with-gatling Blog: AutomationRhapsody.com www.qachallengeaccepted.com
Bonus slides Offline bonus slides
CSV Feeder Read CSV file CSV file name Start over once file is read Access in random order Access modifier search_terms.csv search_termprodproduct1hellosearchTerm1hello hello private val csvFeeder = csv("search_terms.csv").circular.random CSV file content First line is header, used as session variable name
Use CSV Feeder Add Feeder to Scenario object Already created CSV Feeder object Iterate scenario forever val scn = scenario("Search products").feed(csvFeeder).forever() { exec(http("Search product").get("/products?q=${search_term}"))} Execute HTTP Requests in body HTTP GET Request Access CSV data by header with Gatling EL
HTTP POST Request Create HTTP Post Request object Request URI Gatling EL parser replaces session variables val reqSavePerson = http("Save Person").post("/person/save") .body(ElFileBody("person.json")).header("Content-Type", "application/json") person.json {"id": "${id}","firstName": "${first_name}","lastName": "${last_name}","email": "${email}"} Add body to HTTP Post request Read body file and parse with Gatling EL File name Add header field
Checks Checks can be defined on HTTP Protocol level Add check to HTTP Protocol object Response code is 200 OK val myProtocol = http.baseURL("http://localhost:81").check(status.is(200))val myRequest = http("Home").get("/home").check(regex("Hello, (*.?) (*.?)!")) Usually check are defined on HTTP Request level Add check to HTTP Request object Response body matches regular expression
Save to Session HTTP GET Request Access session data with Gatling EL val reqSearch = http("Search product").get("/products?q=${search_term}") .check(regex("Found ([\\d]{1,4}) products:").saveAs("numberOfProducts")) Check response body matches specific regex Save regular expression matched group Name of session variable to save to
Manage Session variables Read variable from Session object as String and convert to Integer Access Session objectinside exec block with lambda val reqOpenProduct = exec(session => {var prds = session("numberOfProducts").as[String].toIntvar productId = Random.nextInt(prds) + 1session.set("productId", productId)}).exec(http("Open").get("/products?id=${productId}")) Some test logic Create and return new Session object with variable saved in it Execute HTTP Get request Variable is accessible only on second exec block
Conditional execution Conditions are calculated on Scenario object If Session variable equals given value val scnLogoutOrHome = scenario("Logout Or Home") .doIfEqualsOrElse("${action}", "Logout") { exec(http("Do logout").get("/logout")) } { exec(http("Home page").get("/home")) } Execute Requests chain in case of TRUE Execute Requests chain in case of FALSE
Advanced setUp Different scenarios with different injection profiles setUp(scnSearch.inject(rampUsers(10) over 10.seconds),scnOpenProduct.inject(atOnceUsers(10))) .protocols(myProtocol) .maxDuration(10.minutes) .assertions( global.responseTime.max.lessThan(800), global.successfulRequests.percent.greaterThan(99) ) Maximum duration in case of forever() Assert each response time is bellow 800ms Assert 99% success responses for the Simulation