Stress Testing Sitecore Websites
Stress testing a website gives the ability to have confidence that when a new website is released that the website will be responsive and handle the expected peak traffic load. In the past, stress testing would usually be implemented by using a simple batch application (wget or tinyget). This would work with the simple request that had a minimal session state, a modern website has complex session state and requires a new approach.
Gatling is performance tool that allows us to stress test a website that has complex session requirements. Gatling allows us to make request, parse the data, then include the session data in a future request. In addition, Gatling allows the ability to customize the load test from duration of the load and how many simulated users. After the load has finished a HTML report will be generated to show the results.
Gatling requires Java JDK. After Java has been installed download the Gatling software at http://gatling.io/#/resources/download. In the below example I downloaded the zip file and unziped the file at C:\inetpub\wwwroot\gatling. To create the load test script you have two options. The first option is to create a Scala class. This will define what the load test will request and how the data is handled with verification The second option is to use the Gatling Recorder. This option will allow you to browse the website in a modern web browser. The recorder will remember the data requested and create a scala load test class. For this example we are going to focus on option 1, manually create the scala load test class. If you want to find more information about option 2, using the Gatling record go to http://gatling.io/docs/2.0.0-RC2/http/recorder.html.
To create the Gatling load test class create a folder at C:\inetpub\wwwroot\gatling\user-files\simulations\SitecoreStressTest. Under the SitecoreStressTest folder create a file named LoginStressTest.scala.
The load test class will be created using the scala programming language. Below is how the a template of the scala class.
package SitecoreStressTest
import scala.concurrent.duration._
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
class LoginStressTest extends Simulation {
}
The first step in the script is to specify the location of the website url. This will allow us to have a single spot in the code to specify the location of the website. In the below example the website is located at https://sc.localhost
class LoginStressTest extends Simulation {
val httpProtocol = http
.baseURL("https://sc.localhost")
.inferHtmlResources()
}
The second step is to create a scenario. A scenario is a multiple testing step that will be executed. The scenario will include a list of resources to request. The scenario will specify how the data is parsed and verified. When making the request to the Identity Server to generate a security token for the user, the request should contain authorization token, username and password for the user. The authorization token will be passed in the header request due to the Identity Server specification. The username and password will be passed as the form param. Gatling allows the ability to customize how the data is sent to the web services to minimic multiple users in a modern website.
val identityConnectTokenHeader = Map(
"accept" -> "application/json, text/plain, */*",
"accept-encoding" -> "gzip, deflate, br",
"accept-language" -> "en-US,en;q=0.8",
"authorization" -> "Basic aFHILKabdjnnaunKLMNafasfkOIJNLKNNLasfasfafklnmQRWZPLFVifjaf==",
"user-agent" -> "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36")
val scn = scenario("HomepageLogin")
.exec(http("Identity Connect Token")
.post("/identity/connect/token")
.headers(identityConnectTokenHeader)
.formParam("grant_type", "password")
.formParam("username", "TestUser")
.formParam("password", "TestPasssword")
.formParam("scope", "iscapi")
Next we are going to parse the data response using regex to get the access_token. The access token is saved as a variable using the Gatling SaveAs function.
.check(
regex("access_token\":\"(.*?)\"")
.saveAs("access_token")))
After the access token has been saved we will make a request to get the users cart. The request will contain the access token remembered from the previous request. This will allow the website to treat the request as an authenticated user for a modern website.
.exec(http("/api/v1/cart")
.post("/api/v1/cart")
.header("authorization", "Bearer ${access_token}")
The last step in the scenario is to verify the webservice result return a 201 code. The check function allow us to verify the web service result.
.check(status.is(201)))
To wrap up the load test simulation we need to specify how the load test is run. In our example scenario the test will simulate 20 concurrent users logging into the website.
setUp(scn.inject(atOnceUsers(20))).protocols(httpProtocol)
Below is the completed load test script using Gatling.
File C:\inetpub\wwwroot\gatling-charts-highcharts-bundle-2.2.3-SNAPSHOT\user-files\simulations\SitecoreStressTest\LoginStressTest.scala
package SitecoreStressTest
import scala.concurrent.duration._
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
class LoginStressTest extends Simulation {
val httpProtocol = http
.baseURL("https://sc.localhost")
.inferHtmlResources()
val identityConnectTokenHeader = Map(
"accept" -> "application/json, text/plain, */*",
"accept-encoding" -> "gzip, deflate, br",
"accept-language" -> "en-US,en;q=0.8",
"authorization" -> "Basic aFHILKabdjnnaunKLMNafasfkOIJNLKNNLasfasfafklnmQRWZPLFVifjaf==",
"user-agent" -> "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36")
val scn = scenario("HomepageLogin")
.exec(http("Identity Connect Token")
.post("/identity/connect/token")
.headers(identityConnectTokenHeader)
.formParam("grant_type", "password")
.formParam("username", "TestUser")
.formParam("password", "TestPasssword")
.formParam("scope", "iscapi")
.check(
regex("access_token\":\"(.*?)\"")
.saveAs("access_token")))
.exec(http("/api/v1/cart")
.post("/api/v1/cart")
.header("authorization", "Bearer ${access_token}")
.check(status.is(201)))
setUp(scn.inject(atOnceUsers(20))).protocols(httpProtocol)
}
Finally, to run the stress test script open the command prompt and go to the folder located at C:\inetpub\wwwroot\gatling\bin.
Below is the command to execute the load test from the C:\inetpub\wwwroot\gatling\bin folder.
Stress testing a website gives the ability to have confidence that when a new website is released that the website will be responsive and handle the expected peak traffic load. In the past, stress testing would usually be implemented by using a simple batch application (wget or tinyget). This would work with the simple request that had a minimal session state, a modern website has complex session state and requires a new approach.
Gatling is performance tool that allows us to stress test a website that has complex session requirements. Gatling allows us to make request, parse the data, then include the session data in a future request. In addition, Gatling allows the ability to customize the load test from duration of the load and how many simulated users. After the load has finished a HTML report will be generated to show the results.
Gatling requires Java JDK. After Java has been installed download the Gatling software at http://gatling.io/#/resources/download. In the below example I downloaded the zip file and unziped the file at C:\inetpub\wwwroot\gatling. To create the load test script you have two options. The first option is to create a Scala class. This will define what the load test will request and how the data is handled with verification The second option is to use the Gatling Recorder. This option will allow you to browse the website in a modern web browser. The recorder will remember the data requested and create a scala load test class. For this example we are going to focus on option 1, manually create the scala load test class. If you want to find more information about option 2, using the Gatling record go to http://gatling.io/docs/2.0.0-RC2/http/recorder.html.
To create the Gatling load test class create a folder at C:\inetpub\wwwroot\gatling\user-files\simulations\SitecoreStressTest. Under the SitecoreStressTest folder create a file named LoginStressTest.scala.
The load test class will be created using the scala programming language. Below is how the a template of the scala class.
package SitecoreStressTest
import scala.concurrent.duration._
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
class LoginStressTest extends Simulation {
}
The first step in the script is to specify the location of the website url. This will allow us to have a single spot in the code to specify the location of the website. In the below example the website is located at https://sc.localhost
class LoginStressTest extends Simulation {
val httpProtocol = http
.baseURL("https://sc.localhost")
.inferHtmlResources()
}
The second step is to create a scenario. A scenario is a multiple testing step that will be executed. The scenario will include a list of resources to request. The scenario will specify how the data is parsed and verified. When making the request to the Identity Server to generate a security token for the user, the request should contain authorization token, username and password for the user. The authorization token will be passed in the header request due to the Identity Server specification. The username and password will be passed as the form param. Gatling allows the ability to customize how the data is sent to the web services to minimic multiple users in a modern website.
val identityConnectTokenHeader = Map(
"accept" -> "application/json, text/plain, */*",
"accept-encoding" -> "gzip, deflate, br",
"accept-language" -> "en-US,en;q=0.8",
"authorization" -> "Basic aFHILKabdjnnaunKLMNafasfkOIJNLKNNLasfasfafklnmQRWZPLFVifjaf==",
"user-agent" -> "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36")
val scn = scenario("HomepageLogin")
.exec(http("Identity Connect Token")
.post("/identity/connect/token")
.headers(identityConnectTokenHeader)
.formParam("grant_type", "password")
.formParam("username", "TestUser")
.formParam("password", "TestPasssword")
.formParam("scope", "iscapi")
Next we are going to parse the data response using regex to get the access_token. The access token is saved as a variable using the Gatling SaveAs function.
.check(
regex("access_token\":\"(.*?)\"")
.saveAs("access_token")))
After the access token has been saved we will make a request to get the users cart. The request will contain the access token remembered from the previous request. This will allow the website to treat the request as an authenticated user for a modern website.
.exec(http("/api/v1/cart")
.post("/api/v1/cart")
.header("authorization", "Bearer ${access_token}")
The last step in the scenario is to verify the webservice result return a 201 code. The check function allow us to verify the web service result.
.check(status.is(201)))
To wrap up the load test simulation we need to specify how the load test is run. In our example scenario the test will simulate 20 concurrent users logging into the website.
setUp(scn.inject(atOnceUsers(20))).protocols(httpProtocol)
Below is the completed load test script using Gatling.
File C:\inetpub\wwwroot\gatling-charts-highcharts-bundle-2.2.3-SNAPSHOT\user-files\simulations\SitecoreStressTest\LoginStressTest.scala
package SitecoreStressTest
import scala.concurrent.duration._
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
class LoginStressTest extends Simulation {
val httpProtocol = http
.baseURL("https://sc.localhost")
.inferHtmlResources()
val identityConnectTokenHeader = Map(
"accept" -> "application/json, text/plain, */*",
"accept-encoding" -> "gzip, deflate, br",
"accept-language" -> "en-US,en;q=0.8",
"authorization" -> "Basic aFHILKabdjnnaunKLMNafasfkOIJNLKNNLasfasfafklnmQRWZPLFVifjaf==",
"user-agent" -> "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36")
val scn = scenario("HomepageLogin")
.exec(http("Identity Connect Token")
.post("/identity/connect/token")
.headers(identityConnectTokenHeader)
.formParam("grant_type", "password")
.formParam("username", "TestUser")
.formParam("password", "TestPasssword")
.formParam("scope", "iscapi")
.check(
regex("access_token\":\"(.*?)\"")
.saveAs("access_token")))
.exec(http("/api/v1/cart")
.post("/api/v1/cart")
.header("authorization", "Bearer ${access_token}")
.check(status.is(201)))
setUp(scn.inject(atOnceUsers(20))).protocols(httpProtocol)
}
Finally, to run the stress test script open the command prompt and go to the folder located at C:\inetpub\wwwroot\gatling\bin.
Below is the command to execute the load test from the C:\inetpub\wwwroot\gatling\bin folder.
gatling -s SitecoreStressTest.LoginStressTest
The above steps show how to create a stress test script. This allows you to provide confidence the website will perform as expected and work reliably. The Gatling load testing tool provides this confidence.