Test-Kitchenを手っ取り早くはじめるには、シェルスクリプトを使うのがいい
シェルで構築シェルでテストする例を作ってみた。
- Test-Kitchen公式: Welcome to Test Kitchen - KitchenCI
- Github: test-kitchen/test-kitchen
- この記事のコード: higanworks/shell-test-kitchen
Test-Kitchen環境の準備
手元に必要なものはこの通り。
- Ruby
- Gem: Bundler
- Vagrant
Gemfile
には2つのGemを書こう。
source "https://rubygems.org"
gem 'test-kitchen'
gem 'kitchen-vagrant'
bundleでは(とりあえず)--binstubs
で./bin
に各種コマンドが入るようにしておくとこのチュートリアルでは楽。
$ bundle install --binstubs --path=vendor/bundle
Fetching gem metadata from https://rubygems.org/..........
Fetching version metadata from https://rubygems.org/..
Resolving dependencies...
Installing safe_yaml 1.0.4
Installing net-ssh 2.9.2
Using bundler 1.9.2
Installing mixlib-shellout 2.0.1
Installing net-scp 1.2.1
Installing thor 0.19.1
Installing test-kitchen 1.3.1
Installing kitchen-vagrant 0.16.0
Bundle complete! 2 Gemfile dependencies, 8 gems now installed.
Bundled gems are installed into ./vendor/bundle.
※ direnvでlayout ruby
をしていればコマンドはbundle
だけでもOK。このへんは各自のスタイルで。
./bin/kitchen
としてコマンドが叩けるようになっているはず。
$ ./bin/kitchen -v
Test Kitchen version 1.3.1
次はkitchen init
でひな形を作成しよう。
$ ./bin/kitchen init
create .kitchen.yml
create test/integration/default
.kitchen.ymlとdiagnose
とりあえず試したいならこの項は無視して、
VMにShellを流してみよう
まで飛んでOK。
初期の.kitchen.yml
はこうなっている、Shell用に書き換えよう。
---
driver:
name: vagrant
provisioner:
name: chef_solo
platforms:
- name: ubuntu-12.04
- name: centos-6.4
suites:
- name: default
run_list:
attributes:
書き換え対象は2箇所、次の通り。
---
driver:
name: vagrant
provisioner:
name: shell ## Shellに変更
platforms:
- name: ubuntu-14.04 ## ubuntu-14.04のみに変更
suites:
- name: default
run_list:
attributes:
kitchen list
ではテストに使うVMの一覧が表示される。次のように出力されないならもう一度.kitchen.yml
を見直そう。
$ ./bin/kitchen list
Instance Driver Provisioner Last Action
default-ubuntu-1404 Vagrant Shell <Not Created>
Diagnose
Test-Kitchenは設定の記述場所によって色々な要素が上書きされたりマージされたりする(まるでChefのAttributesだ! )。
幸い各種設定がどのように反映されているか確認するためのkitchen diagnose
コマンドが用意されているので、設定の重なり具合をいつでも確認できる。
さっきの.kitchen.yml
でdiagnoseを表示してみよう。
$ ./bin/kitchen diagnose default-ubuntu-1404
---
timestamp: 2015-04-03 04:06:20 UTC
kitchen_version: 1.3.1
instances:
default-ubuntu-1404:
state_file: {}
driver:
box: opscode-ubuntu-14.04
box_check_update:
box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_ubuntu-14.04_chef-provisionerless.box
box_version:
customize: {}
gui:
kitchen_root: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen"
log_level: :info
name: vagrant
network: []
port: 22
pre_create_command:
provider: virtualbox
provision: false
ssh: {}
sudo: true
synced_folders: []
test_base_path: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen/test/integration"
vagrantfile_erb: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen/vendor/bundle/ruby/2.2.0/gems/kitchen-vagrant-0.16.0/templates/Vagrantfile.erb"
vagrantfiles: []
vm_hostname: default-ubuntu-1404
provisioner:
data_path:
kitchen_root: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen"
log_level: :info
name: shell
root_path: "/tmp/kitchen"
script:
sudo: true
test_base_path: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen/test/integration"
busser:
busser_bin: "/tmp/busser/bin/busser"
kitchen_root: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen"
root_path: "/tmp/busser"
ruby_bindir: "/opt/chef/embedded/bin"
sudo: true
suite_name: default
test_base_path: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen/test/integration"
version: busser
とりあえず今はprovisioner:
に注目してみよう。
Test-Kitchenのコマンドや対象は正規表現で解釈されるので、kitchen diagnose default-ubuntu-1404
はkitchen diag ubu
なりと省略できる。
$ ./bin/kitchen diag ubu | grep 'provisioner:' -A 8
provisioner:
data_path:
kitchen_root: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen"
log_level: :info
name: shell
root_path: "/tmp/kitchen"
script:
sudo: true
test_base_path: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen/test/integration"
script:
が実行対象っぽさを醸し出しているね。
ここにはbootstrap.sh
(プラットフォームによってはbootstrap.ps1
)というファイルがあれば自動でそれが使われるようになっている。
もちろん.kitchen.yml
で指定してもいい。
VMにShellを流してみよう - kitchen converge
.kitchen.yml
を次のように編集してある状態から。前項を飛ばした人は編集してね。
---
driver:
name: vagrant
provisioner:
name: shell
platforms:
- name: ubuntu-14.04
suites:
- name: default
run_list:
attributes:
bootstrap.sh
という名前でファイルを作成すると、VM内で実行する対象として勝手に選択される。
$ touch bootstrap.sh
$ ./bin/kitchen diag ubu | grep 'provisioner:' -A 8
provisioner:
data_path:
kitchen_root: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen"
log_level: :info
name: shell
root_path: "/tmp/kitchen"
>>> 検出された。
script: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen/bootstrap.sh"
<<<
sudo: true
test_base_path: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen/test/integration"
bootstrap.sh
に書いた内容は実行時にちょっとラップされる、次のように。
sh -c '
bootstrap.shに書いた内容がここに入る
'
'
(シングルクォート)でくくられているけど、数さえ合っていればスクリプト内で'
を使う分には問題ない。
bootstrap.shに処理を書いて実行する
とりあえずNginxでもいれとくか。
sudo apt-get update
sudo apt-get -y install nginx
準備ができたらkitchen converge ubu
で。
$ ./bin/kitchen converge ubu
-----> Starting Kitchen (v1.3.1)
-----> Creating <default-ubuntu-1404>...
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'opscode-ubuntu-14.04'...
(略) apt-get updateが始まる
-----> Converging <default-ubuntu-1404>...
Preparing files for transfer
Preparing script
Transferring files to <default-ubuntu-1404>
Ign http://us.archive.ubuntu.com trusty InRelease
Ign http://security.ubuntu.com trusty-security InRelease
Ign http://us.archive.ubuntu.com trusty-updates InRelease
Get:1 http://security.ubuntu.com trusty-security Release.gpg [933 B]
Ign http://us.archive.ubuntu.com trusty-backports InRelease
Get:2 http://us.archive.ubuntu.com trusty Release.gpg [933 B]
Get:3 http://security.ubuntu.com trusty-security Release [63.5 kB]
Get:4 http://us.archive.ubuntu.com trusty-updates Release.gpg [933 B]
Get:5 http://us.archive.ubuntu.com trusty-backports Release.gpg [933 B]
Get:6 http://us.archive.ubuntu.com trusty Release [58.5 kB]
Get:7 http://security.ubuntu.com trusty-security/main Sources [76.1 kB]
(略)
Processing triggers for ureadahead (0.100.0-16) ...
Setting up nginx-core (1.4.6-1ubuntu3.2) ...
Setting up nginx (1.4.6-1ubuntu3.2) ...
Processing triggers for libc-bin (2.19-0ubuntu6) ...
Finished converging <default-ubuntu-1404> (1m19.28s).
-----> Kitchen is finished. (1m19.50s)
Nginx入ったね。
batsでVMをテストしてみよう - kitchen verify
テスト用の環境はTest-Kitchen関連プロダクトのbusser
を使って用意される。
kitchen diag
で軽くbusser
周りを確認してみよう。
$ ./bin/kitchen diag ubu | grep busser: -A 8
busser:
busser_bin: "/tmp/busser/bin/busser"
kitchen_root: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen"
root_path: "/tmp/busser"
ruby_bindir: "/opt/chef/embedded/bin"
sudo: true
suite_name: default
test_base_path: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen/test/integration"
version: busser
ruby_bindir
があることから分かる通り、Test-Kitchenではテストの実行にはVMの中にRubyが必要なんだ。
RubyとBusser
Ruby入れたくない? そうだよね。
でもテスト用のVMにくらい入れたっていいじゃない。初期構築のbootstrap.sh
にちょっと分岐を作らせてよ。
sudo apt-get update
sudo apt-get -y install nginx
## For busser
if [ "vagrant" = "$SUDO_USER" ];then
sudo apt-get -y install ruby2.0
fi
bootstrap.sh
を更新したら、もう一度kitchen conv ubu
して、Rubyのインストールを済ませておきましょう。
Rubyのインストールに問題がなければ、.kitchen.yml
にBusserのruby_bindir
を上書きするよう仕向けます。
---
driver:
name: vagrant
provisioner:
name: shell
platforms:
- name: ubuntu-14.04
busser:
ruby_bindir: /usr/bin ## さっきのRubyへのパス
suites:
- name: default
run_list:
attributes:
kitchen diag ubu
でもかくにん。
$ ./bin/kitchen diag ubu | grep busser: -A 8
busser:
busser_bin: "/tmp/busser/bin/busser"
kitchen_root: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen"
root_path: "/tmp/busser"
ruby_bindir: "/usr/bin" ## .kitchen.ymlに書いた値で上書き
sudo: true
suite_name: default
test_base_path: "/Users/sawanoboriyu/github/higanworks/shell-test-kitchen/test/integration"
version: busser
これでテスト実施の環境は整いました。
Batsのテストを書く
- Bats: Bash Automated Testing System
今日テストで使うBatsは別にRubyが必要ってわけではなく、Shellで書かれたShellの実行結果をテストするためのライブラリだ。
bats
ディレクトリを作成しよう。
$ mkdir test/integration/default/bats
ではBatsによるコマンド実行&出力チェックのテストをtest/integration/default/bats/nginx.bats
に書いていこう。
@test
の直後に何をテストするかの注釈、そしてブレスでテストを囲めばいい。
@test "it should exists nginx bin with supports TLS SNI" {
run nginx -V
[ "$status" -eq 0 ] ## ExitStatusが0か
[ "${lines[2]}" = "TLS SNI support enabled" ] ## 出力の2行目をチェック
}
@test "it should exists nginx process" {
run pgrep nginx
[ "$status" -eq 0 ]
}
ファイルを保存したらkitchen verify ubu
でBatsのテストが実行される。
$ ./bin/kitchen verify ubu
-----> Starting Kitchen (v1.3.1)
-----> Setting up <default-ubuntu-1404>...
Fetching: thor-0.19.0.gem (100%)
Fetching: busser-0.7.0.gem (100%)
Successfully installed thor-0.19.0
Successfully installed busser-0.7.0
2 gems installed
-----> Setting up Busser
Creating BUSSER_ROOT in /tmp/busser
Creating busser binstub
Plugin bats installed (version 0.3.0)
-----> Running postinstall for bats plugin
Installed Bats to /tmp/busser/vendor/bats/bin/bats
Finished setting up <default-ubuntu-1404> (1m1.08s).
-----> Verifying <default-ubuntu-1404>...
Suite path directory /tmp/busser/suites does not exist, skipping.
Uploading /tmp/busser/suites/bats/nginx.bats (mode=0644)
>>> ここからテスト
-----> Running bats test suite
✓ it should exists nginx bin with supports TLS SNI
✓ it should exists nginx process
2 tests, 0 failures
Finished verifying <default-ubuntu-1404> (0m1.09s).
された!
おわりに
ここまで出来たらkitchen test
を実行して、眺めるかコーヒーでも汲みに行こう
$ ./bin/kitchen test
-----> Starting Kitchen (v1.3.1)
-----> Cleaning up any prior instances of <default-ubuntu-1404>
-----> Destroying <default-ubuntu-1404>...
==> default: Forcing shutdown of VM...
==> default: Destroying VM and associated drives...
Vagrant instance <default-ubuntu-1404> destroyed.
Finished destroying <default-ubuntu-1404> (0m4.06s).
-----> Testing <default-ubuntu-1404>
-----> Creating <default-ubuntu-1404>...
...