dgossを使ってDockerコンテナを自動テストする方法

## 本稿で学べること

* dgossを使ったDockerコンテナの自動テストのはじめかた。
* dgossのテストコードの生成方法。

## 前提条件

* docker runが分かる
* macOS + Docker for Mac

## gossとは

* Go製のサーバ設定の検証ツール。
    * "Quick and Easy server testing/validation"
* ServerSpec(Ruby製)みたいなやつ。
* YAMLで検証内容を記述する。
* https://goss.rocks

## dgossとは

* Dockerのテストを書くためのgoss付録ツール。
* テストコード(YAML)を生成できる。
* テストを実行できる。

## dgossを使ってテストコードを生成する

dgossをインストールする。(下記はmacOSでの手順)

```bash
# dgossをインストールする
curl -L https://raw.githubusercontent.com/aelsabbahy/goss/master/extras/dgoss/dgoss -o /usr/local/bin/dgoss
chmod +rx /usr/local/bin/dgoss

# gossをダウンロードする
curl -L https://github.com/aelsabbahy/goss/releases/download/v0.3.6/goss-linux-amd64 -o ~/Downloads/goss-linux-amd64

# gossのパスをセットする
export GOSS_PATH=~/Downloads/goss-linux-amd64
```

gossのテストは`docker run`と同じ形式のオプションを与える。例えば、nginxを`docker run`で起動するとき、次のようなオプションを与えることを想定してみよう。

```bash
docker run -p 8080:80 nginx:1.11.10
# テストを生成するために、このコマンドは実行しなくてよい
```

この場合、`dgoss`でテスト生成を開始するには、`docker run`部分を`dgoss edit`に書き換えて、次のようなコマンドを実行する。

```bash
dgoss edit -p 8080:80 nginx:1.11.10
```

このコマンドはテスト作成のために、Dockerコンテナを作成&起動し(内部的に`docker run`している)、インタラクティブシェルを開いてくれる。

インタラクティブシェルにて、下記コマンドを実行していく。

```
goss add file /var/log/nginx/access.log /var/log/nginx/error.log
goss add process nginx
goss add port 80
goss add package nginx
goss add http http://localhost
exit
```

上を終えると、`goss.yml`が作られている。

```goss.yml
file:
  /var/log/nginx/access.log:
    exists: true
    mode: "0777"
    size: 11
    owner: root
    group: root
    linked-to: /dev/stdout
    filetype: symlink
    contains: []
  /var/log/nginx/error.log:
    exists: true
    mode: "0777"
    size: 11
    owner: root
    group: root
    linked-to: /dev/stderr
    filetype: symlink
    contains: []
package:
  nginx:
    installed: true
    versions:
    - 1.11.10-1~jessie
port:
  tcp:80:
    listening: true
    ip:
    - 0.0.0.0
process:
  nginx:
    running: true
http:
  http://localhost:
    status: 200
    allow-insecure: false
    no-follow-redirects: false
    timeout: 5000
    body: []
```

テストの作成は以上で完了。

## テストを実行する

`dgoss run`コマンドを使ってテストを実行してみる。

```
dgoss run nginx:1.11.10
```

テスト結果:

```
INFO: Running Tests
File: /var/log/nginx/error.log: exists: matches expectation: [true]
File: /var/log/nginx/error.log: mode: matches expectation: ["0777"]
File: /var/log/nginx/error.log: owner: matches expectation: ["root"]
File: /var/log/nginx/error.log: group: matches expectation: ["root"]
File: /var/log/nginx/error.log: linkedto: matches expectation: ["/dev/stderr"]
File: /var/log/nginx/error.log: filetype: matches expectation: ["symlink"]
File: /var/log/nginx/error.log: size: matches expectation: [11]
File: /var/log/nginx/access.log: exists: matches expectation: [true]
File: /var/log/nginx/access.log: mode: matches expectation: ["0777"]
File: /var/log/nginx/access.log: owner: matches expectation: ["root"]
File: /var/log/nginx/access.log: group: matches expectation: ["root"]
File: /var/log/nginx/access.log: linkedto: matches expectation: ["/dev/stdout"]
File: /var/log/nginx/access.log: filetype: matches expectation: ["symlink"]
File: /var/log/nginx/access.log: size: matches expectation: [11]
Port: tcp:80: listening: matches expectation: [true]
Port: tcp:80: ip: matches expectation: [["0.0.0.0"]]
Package: nginx: installed: matches expectation: [true]
Package: nginx: version: matches expectation: [["1.11.10-1~jessie"]]
Process: nginx: running: matches expectation: [true]
HTTP: http://localhost: status: matches expectation: [200]


Total Duration: 0.027s
Count: 20, Failed: 0, Skipped: 0
```

試しに、nginxのマイナーバージョンを1下げてテストしてみる。

```
dgoss run nginx:1.11.9
```

nginxのバージョンが`1.11.10`じゃないので、テスト結果はFAILになる。

```
Failures/Skipped:

Package: nginx: version:
Expected
    <[]string | len:1, cap:1>: ["1.11.9-1~jessie"]
to contain element matching
    <string>: 1.11.10-1~jessie

Total Duration: 0.031s
Count: 20, Failed: 1, Skipped: 0
```

## 参考

* [Tutorial: How to test your docker image in half a second](https://medium.com/@aelsabbahy/tutorial-how-to-test-your-docker-image-in-half-a-second-bbd13e06a4a9)
* [dgoss-examples](https://github.com/aelsabbahy/dgoss-examples) - dgossの書き方のサンプル
* [gossのマニュアル](https://github.com/aelsabbahy/goss/blob/master/docs/manual.md)