TravisCIでAnsibleのrole単体のテストを実行する

Ansibleのrole単体についてのテストをやりたくてWeb上で記事を探していたのですが、意外と書いている人がいない…
個人的には、role単体でもテストは必要だと思っていたので結構驚きました。

とりあえず、自分で考えてTravisCIで動かせるところまでやってみました。
私が公開している[nodebrewのrole](https://github.com/djyugg/ansible-role-nodebrew)に適用してみたので、これを元に紹介してみます。

# 構成
`ansible-galaxy init xxxxxx`で生成されるテンプレートに加えてtestというディレクトリを作り、その中にテスト用のplaybookやスクリプトを入れます。


```
role/
  defaults/
  files/
  handlers/
  meta/
  tasks/
  templates/
  vars/
  test/                # テスト用ディレクトリ
    before_script.sh   # テスト事前処理実行スクリプト
    hosts              # テスト用インベントリファイル
    test.sh            # テスト実行スクリプト
    travis-ci-site.yml # テスト用Playbook
```

testディレクトリ配下のファイルについては、以下の内容で作成しています。

```:before_script.sh
#!/bin/sh

WORK_DIR="./test"
ROLE_DIR=${WORK_DIR}"/roles/djyugg.nodebrew"

# roles配置ディレクトリの初期化
if [ -d ${ROLE_DIR} ]; then
  rm -rf ${ROLE_DIR}/*
else
  mkdir -p ${ROLE_DIR}
fi

# rolesファイルのコピー
for dir in "defaults handlers meta tasks templates";
  do cp -pR ${dir} ${ROLE_DIR};
done
```

```:hosts
172.0.0.1
```

```:test.sh
#!/bin/sh

# 戻り値が0以外であれば処理終了
check_return_code(){
  if [ $? -ne 0 ]; then
    exit 1
  fi
}

# パス設定のファイル存在確認
ls -l /etc/profile.d/nodebrew.sh
check_return_code

. /etc/profile
# インストールしたnodebrewにパスが通っていることを確認
which nodebrew
check_return_code

# インストールしたnode.jsにパスが通ってることを確認
which node
check_return_code
```

```:travis-ci-site.yml
- hosts: 127.0.0.1
  connection: local
  sudo: yes
  user: travis
  roles:
    - role: djyugg.nodebrew
      nodebrew:
        nodejs_version: v0.10.25
        install_user: travis
```

また、TravisCIを利用するため`.travis.yml`が別途必要になります。

```:.travis.yml
language: python
sudo: true
python:
  - "2.7"
install:
  - pip install ansible
before_script:
  - ansible --version
  - sh ./test/before_script.sh
script:
  - ansible-playbook --syntax-check ./test/travis-ci-site.yml -i ./test/hosts
  - ansible-playbook ./test/travis-ci-site.yml -i ./test/hosts
  - sh ./test/test.sh
```

# 具体的に何をやっているか
role単体では、SyntaxCheckやroleの実行ができないので、呼び出し元になるplaybookを作成してそれを叩いて実行しています。
また、Playbookの実行先はTravisCIにて用意されているホストとなります。

1. 事前処理
  - testディレクトリ配下にrolesというディレクトリを生成し、Githubよりcloneしてきたroleをコピーして配置する。
2. あらかじめ用意していたplaybookを元にSyntaxCheckを実行。
3. playbook実行
4. playbook実行後の確認
    - 意図した通りファイルが作成されているか
    - パスが通っているか等

playbook実行後の確認は、コマンドと戻り値を確認する関数で簡単に行っています。

# 実際に試してみた感想等
## ちょっとはまったところ
role内でsudoが必要となる場合、TravisCI側でsudoが利用できるように`.travis.yml`に設定する必要があります。
`sudo: true`という設定を.travis.ymlに記載しないと、sudoが利用できないためplaybook実行時にエラーとなります。
ちなみに、TravisCIは標準でDockerを利用しているようなのですが、この設定を行うとDockerを使ったCIができなくなってしまいます。
Dockerを使用しない場合は、ビルドが実行されるまで長く待たされるようになったりします。  
※[こちらの記事](http://postd.cc/faster-builds-with-container-based-infrastructure/)に詳しく書かれています。


## いまいちなところ
###パターンの網羅が難しい
おそらく、環境構築自動化のすべてにおいて言えることだと思うのですが、パターンの網羅が難しいです。
今回やってみたものの、テストパターンが1つしか定義できていません。
Dockerとか使って環境を適宜まっさらな状態に戻すようにすれば、ある程度テストパターンを増やせそうではありますが、roleが複数OSに対応している場合は、パターンを網羅しようとするとそれだけ環境を用意する必要が出てきます。

自動テストを網羅的にやるだけでも時間がかかってしまうのに、テスト環境作るだけでもコストが膨大になってしまいますね。これがrole単体のテストが書かれていない理由かなと思いました。


## やってみてよかったこと
### バグを見つけられました...
[paizaの実行環境をVagrantで再現するやつ](https://github.com/djyugg/paiza-environment-provision)を以前作ったときに、出来たものを切り出してnodebrewのroleを作ったのですが、そのとき一緒に実行していた他のroleの処理に依存する形になっていたようで、nodebrewのrole単体では動かないようになっていました。
そのとき以来まったく触っていなかったので今更気づいたという...

コミットするたびにSyntaxCheckや動作確認をすることができれば、こういった凡ミスはなくなります。TravisCIのようなCI as a Serviceを使えば結構簡単にできてしまうので、やる価値はあるかもしれませんね。

# 編集履歴
## 2015/6/28 14:24編集
1つのスクリプトに書いていた処理を分割しました。