import io.gatling.commons.validation._
import io.gatling.core.check.Validator
import io.gatling.core.Predef._
import io.gatling.http.Predef.{http, _}
import scala.concurrent.duration._
class DemoSimulation extends Simulation {
// 支持多种格式的csv
val csvFeeder = csv("foo.csv") // use a comma separator
val tsvFeeder = tsv("foo.tsv") // use a tabulation separator
val ssvFeeder = ssv("foo.ssv") // use a semicolon separator
val customSeparatorFeeder = separatedValues("foo.txt", '#') // use your own separator
// 一次加载所有数据
val csvFeeder1 = csv("foo.csv").eager.random
// 批量加载数据,默认2000
val csvFeeder2 = csv("foo.csv").batch.random
// 修改默认buffer
val csvFeeder3 = csv("foo.csv").batch(200).random
val feeder = csv("search.csv").random
// 可进行全局配置
val httpProtocol = http
// .enableHttp2 // 支持http2
.warmUp("http://www.baidu.com") // 热机,启动客户端的http(默认访问的是https://gatling.io,但是这个地址往往不通)
.baseUrl("http://www.baidu.com", "http://www.baidu.com", "http://www.baidu.com") // 支持多个地址,绕过负载均衡,直接向服务器施加压力
.header("key", "value")
.connectionHeader("close")
.disableCaching
// 创建场景
val scn_1 = scenario("scn_1").during(1 minutes) {
exec(
feed(feeder).exec(
http("http_1")
.get("/")
.queryParam("key", "value")
/** http协议常用的检查点设置 **/
.check(
/** Targets the HTTP response status code. **/
status.is(200),
status.in(200, 304),
status.not(404),
// 以下所有关于正则的查找,都支持:find、find(occurrence)、findAll、findRandom、findRandom(num: Int)、findRandom(num: Int, failIfLess = true)、count
/** Targets the current page absolute URL. Useful when following redirects in order to check if the landing page is indeed the expected one. **/
currentLocation.validate(new StringValidator[String](CheckType.equals, "http://www.baidu.com/")), // 可以检查有没有出现重定向。
currentLocationRegex("www").validate(new StringValidator[String](CheckType.equals, "www")), // 支持正则匹配,取出关键字。
// currentLocationRegex("http://(www).(baidu).(com)").ofType[(String, String, String)].validate(todo), // 支持多个匹配,这个时候Option[T]是Option[(String, String, String)],StringValidator需要重新适配。
/** Targets the HTTP response header of the given name. **/
header("connection").validate(new StringValidator[String](CheckType.equals, "close")),
headerRegex("Set-Cookie", "delPer=(.+?);").validate(new StringValidator[String](CheckType.equals, "0")),
// headerRegex("FOO", "foo(.*)bar(.*)baz").ofType[(String, String)].validate(todo), // 同样支持多个匹配
/** Returns the response time of this request in milliseconds = the time between starting to send the request and finishing to receive the response. **/
responseTimeInMillis.lte(1000),
/** Return the full response body String. Note that this can be matched against content from the the filesystem using RawFileBody or ElFileBody. **/
bodyString.validate(new StringValidator[String](CheckType.contains, "百度")),
/** bodyBytes 和 bodyStream 应该用不到吧 **/
/** Scans for the indices of a given substring inside the body string. **/
substring("baidu"), // same as substring("baidu").find.exists
substring("baidu").findAll.saveAs("indices"), // 可以保存到session中(保存为一个Seq序列)
substring("baidu").count.gte(10), // 可以检查某正则条件出现的次数
// 官网描述,substring 似乎比 regex 更节省CPU资源,推荐使用 substring
/** 正则匹配 **/
regex("""<link rel="dns-prefetch" href="//(.+?)"/>""").find.validate(new StringValidator[String](CheckType.contains, "com")), // 默认查询第一个
regex("""<link rel="dns-prefetch" href="//(.+?)"/>""").find(0).validate(new StringValidator[String](CheckType.contains, "com")), // 可以指定查询第几个
regex("""<link rel="dns-prefetch" href="//(.+?)"/>""").findRandom.validate(new StringValidator[String](CheckType.contains, "com")), // 随机匹配一个
// regex("""<link rel="dns-prefetch" href="//(.+?)"/>""").findAll.validate(new StringValidator[String](CheckType.contains, "www")), // 这个返回是一个Seq[String],需要单独写Validator
regex("""<link rel="dns-prefetch" href="//(.+?)"/>""").count.gte(5),
/** XPath匹配 **/
// xpath("//input[@id='text1']/@value"),
/** JSON匹配 **/
// jsonPath("$..foo.bar[2].baz").ofType[Int] // 支持 ofType[Int] 进行类型转换
)
))
}
val scn_2 = scenario("scn_2").forever() {
exec(
/** form **/
http("http_1")
.post("/")
.formParam("myKey", "myValue")
.formParamSeq(Seq(("myKey", "myValue"), ("anotherKey", "anotherValue"))) // 批量
.formParamMap(Map("myKey" -> "myValue", "anotherKey" -> "anotherValue")) // 这样也可以
.multivaluedFormParam("multi1", "${foo}") // 一个key对应多个value。where foo is the name of a Seq Session attribute
.multivaluedFormParam("multi2", session => List("foo", "bar")), // 这样也可以
/** from 上传文件 **/
http("http_upload")
.post("my.form-action.uri")
.formParam("myKey", "myValue")
.formUpload("myKey2", "myAttachment.txt"),
/** row格式 **/
http("http_row")
.body(RawFileBody("myFileBody.json")).asJson // { "myContent": "myHardCodedValue" }
.body(ElFileBody("myFileBody.json")).asJson // { "myContent": "${myDynamicValue}" },将会解析myDynamicValue的具体值
.body(StringBody("""{ "myContent": "${myDynamicValue}" }""")).asJson // 将会解析myDynamicValue的具体值
.body(StringBody(session => """{ "myContent": """" + someGenerator(session) + """" }""")).asJson // TODO
// .body(ByteArrayBody(bytes: Expression[Array[Byte]]))
// .body(InputStreamBody(stream: Expression[InputStream]))
.body(PebbleStringBody("""{ "myContent": "{% if myCondition %}{{myDynamicValue}}{% endif %}" }""")).asJson // 支持一些复杂的逻辑
.body(PebbleFileBody("myFileBody.json")).asJson, // 可以使用文件中的内容
/** 支持模拟浏览器的并行获取资源 **/
http("http_resources")
.get("https://www.github.com/gatling/gatling/issues")
.resources(
http("api.js").get("https://collector-cdn.github.com/assets/api.js"),
http("ga.js").get("https://ssl.google-analytics.com/ga.js")
)
)
}
// 开始执行
setUp(
scn_1.inject(atOnceUsers(1)),
scn_2.inject(atOnceUsers(1))
).protocols(httpProtocol)
}
/**
* 自定义的字符串检查方法
*
* @param checkType
* @param param
* @tparam A
*/
class StringValidator[A](checkType: String, param: String) extends Validator[A] {
val name = "StringValidator"
def apply(actual: Option[A], displayActualValue: Boolean): Validation[Option[A]] = {
actual match {
case Some(value) => {
checkType match {
case CheckType.contains => {
if (s"${value}".contains(param)) {
actual.success
} else {
s"${value}中未发现${param}".failure
}
}
case CheckType.equals => {
if (s"${value}".equals(param)) {
actual.success
} else {
s"${value}与${param}不相等".failure
}
}
case CheckType.startswith => {
if (s"${value}".startsWith(param)) {
actual.success
} else {
s"${value}不是以${param}开始".failure
}
}
case CheckType.endswith => {
if (s"${value}".endsWith(param)) {
actual.success
} else {
s"${value}不是以${param}结尾".failure
}
}
case _ => {
"CheckType Error!".failure
}
}
}
case None => {
"found nothing!".failure
}
}
}
}
object CheckType {
val contains: String = "contains"
val equals: String = "equal"
val startswith: String = "startwith"
val endswith: String = "endwith"
}