GatlingのTips

Gatlingとは負荷試験ツールです。
Scalaで負荷試験のシナリオを作成でき、結果をブラウザで確認できます。
[https://gatling.io/docs/2.3/]

## 基本的な使い方

* gatlingは`Simulation`をextendsして使います
* `setUp`では負荷試験のシナリオ(`scenario`)を設定します。
    * シナリオに対して`inject`を使い、ユーザ数と実行時間(`rampUsers(1) over(10)`)を設定します。
* また`setUp`の`protocols`には負荷試験の対象となるURI(`baseURL`)とヘッダ情報(`acceptHeader`)などを設定します。

すでにScalaを使ったプロジェクトが存在する場合は、以下のようにpackageを使用してgatlingを追加できます。

※ sbtの設定については [https://gatling.io/docs/2.3/extensions/sbt_plugin/] をご確認ください。

```Scala
// サンプル
package gatling
import io.gatling.core.Predef._
import io.gatling.http.Predef._

class Sample extends Simulation {
  val httpConf = http
    .baseURL("http://localhost:8080")
    .acceptHeader("application/json")

  val scn = scenario("sample scenario")
    .exec(http("get ok").get("/ok"))

  setUp(scn.inject(rampUsers(1) over(10)).protocols(httpConf))
}
```

## 複数URIを負荷試験の対象にする場合

以下のように`exec`を増やします。

```Scala
  val scn = scenario("sample scenario")
    .exec(http("GET ok").get("/ok"))
    .exec(http("POST login").post("/login"))
    .exec(http("GET me").get("/me"))
```

## レスポンスの確認と保存

execはそれぞれ分けて定義することもできます。
また、`check`を使えばレスポンスの確認(`.check(status is 200)`)や、
保存(`.check(bodyString.saveAs("getOk"))`)も可能です。

```Scala
    val scn = scenario("sample scenario")
      .exec(getOk)

    val getOk = exec(
      http("GET ok")
        .get("/ok")
        .check(status is 200)
        .check(bodyString.saveAs("getOk"))
    )
```

例えば、ログイン処理が事前に必要な場合、以下のように`check`を使いTokenを保存しておき、
以降のexecの処理で使うことができます。

httpのヘッダやFormの設定方法は下記URLをご確認ください。

* [https://gatling.io/docs/2.3/http/http_request/]

```Scala
    val scn = scenario("sample scenario")
      .exec(postLogin)
      .exec(getMe)

    val postLogin = exec(
      http("POST login")
        .post("/login")
        .formParam("password", "pass")
        .formParam("email", "sample@email.jp")
        .check(status is 200)
        // レスポンスが {Token: XXX} の場合、下記の方法で値を保存可能
        .check(jsonPath("$.Token").saveAs(s"token"))
        .check(bodyString.saveAs("postLogin"))
    )

    val getMe = exec(
      http("GET me")
        .get("/me")
        // postLoginで保存したtokenは ${token} で取得可能
        .headers(Map("Auth" -> s"${token}"))
        .check(status is 200)
        .check(bodyString.saveAs("getMe"))
    )
```

負荷試験中にAPIからレスポンスを詳細に確認したい場合は、下記のようにラムダ式を使用します。

```Scala
    val scn = scenario("sample scenario")
      .exec(getOk)
      .exec { session =>
        println(session)
        session
      }
```

## 負荷試験の前後で別処理を実行する

たとえば、認証処理などを事前に済ませておいて、そのあとで負荷試験する場合、
下記のように`before`と`after`を使用できます。
注意が必要なのは、Simulation内ではsetUpを一つしか定義できません。
仮に認証の処理を`before`に置きたい場合、setUpをつかうことはできません。
そのため、httpリクエストが必要な場合、WSやScalajなどを使う必要があります。

```Scala
class Sample extends Simulation {
  val httpConf = http
    .baseURL("http://localhost:8080")
    .acceptHeader("application/json")

  val scn = scenario("sample scenario")
    .exec(http("get ok").get("/ok"))

  before {
    // 負荷試験前に処理
  }

  setUp(scn.inject(rampUsers(1) over(10)).protocols(httpConf))

  after {
    // 負荷試験後に処理
  }
}
```

## API別に負荷試験する

sbtを使った、gatlingでの負荷試験は下記のようになります。
下記の例では全てのSimulationに対して負荷試験が行われます。

* 参考URL:[https://gatling.io/docs/2.3/extensions/sbt_plugin/]

```bash
sbt "gatling:test"
```

API別に負荷試験したい場合、gatlingのディレクトリ下に複数のscalaのpackageを作ります。
一例ですが、application.confにbaseUrlを書いておいて、実行時に切り替えるということもできます。

```bash
gatling/src/
└── test
    ├── resources
    │   ├── dev
    │   │   └── application.conf
    │   └── local
    │       └── application.conf
    └── scala
        ├── Api1
        │   └── Sample.scala
        └── Api2
            └── Sample.scala
```

```Scala
// gatling/src/test/resources/local/application.conf
gatling {
    baseUrl{
        Api1 = "http://localhost:8080",
        Api2 = "http://localhost:3000"
    }
}
```

```Scala
// gatling/src/test/scala/Api1/Sample.scala
package gatling.Api1
import com.typesafe.config.ConfigFactory
import io.gatling.core.Predef._
import io.gatling.http.Predef._

class Sample extends Simulation {
  val private val conf = ConfigFactory.load()

  val httpConf = http
    // application.confからbaseUrlを取得
    .baseURL(conf.getString("gatling.baseUrl.Api1"))
    .acceptHeader("application/json")

  val scn = scenario("sample scenario")
    .exec(http("get ok").get("/ok"))

  setUp(scn.inject(rampUsers(1) over(10)).protocols(httpConf))
}
```

例えば、Api1のSample.scalaをlocal(`http://localhost:8080`)で実行したい場合は以下のようになります。
testディレクトリにapplication.confがあるので、PlayFramworkを使っている場合は`-Dconfig.file=`で指定する必要があります。

* 参考URL:[https://www.playframework.com/documentation/ja/2.3.x/ProductionConfiguration]

```Scala
export JAVA_OPTS="-Dconfig.file=src/test/resources/local/application.conf"
// testOnlyをつかうとClassを指定して負荷試験ができます。
sbt "gatling:testOnly Api1.Sample"
```