test-kitchenを使ってChefのレシピを複数環境でテストする方法
test-kitchenはopscodeが提供するChefのレシピをテストするための仕掛けで、Vagrantを使って複数のOSやOSのバージョンを立ち上げレシピをテストすることができる。(Vagrant以外も使える) テストはminitestやcucumberなどを使って記述する。 テストの流れは以下のようになる。
- 設定ファイルに記載されたOSをVagrantで起動する(既にOSが起動している場合はそのまま利用する。ひな形となるbaseboxが存在しない場合は、設定ファイルに記載された入手元からbaseboxをダウンロードする)
- Vagrant側とレシピが共用され、レシピが実行される
- レシピ実行後、テストが実行される
- テストが終了すると、OSの設定が複数あれば次のOSを使ってテストする
では早速設定を行なってみよう。まず1つのレシピをテストする場合だ。
1つのレシピをテストする場合
まずトップディレクトリに移動する。すなわち以下のような構成の場所だ。(なお今回のテストには僕が使っているanalogインストールのレシピを使った)
├── CHANGELOG.md
├── README.md
├── attributes
├── definitions
├── libraries
├── metadata.rb
├── providers
├── recipes
├── resources
└── templates
まずGemfileを作成する。内容は以下の通り。
source :rubygems
gem 'test-kitchen'
gem 'minitest'
gem 'minitest-chef-handler'
ファイルの作成が終わったら以下のコマンドを実行してモジュールを導入する。
bundle install
ついでテスト用のディレクトリを初期化する。
bundle kitchen init
これによってtestディレクトリが作られる。テストディレクトリには、kitchen/Kitchenfile というファイルが作られている。 デフォルトでは、レシピ名が書かれたブロックのみが存在している。 なお、この状態だと、テストはopscodeのCentOS5.8, CentOS6.3、Ubuntu10.04、Ubuntu12.04で行われるようになっている。
以下のKitchenfileの例では、ubuntuでのテストはせず、自前のVagrantのbaseboxを使って、CentOS 5.8 / 6.2 / 6.3をテストする設定にしている。
# vim: ft=ruby
platform :centos do
version "6.3" do
box "centos_63_x86_64_ja"
box_url "https://dl.dropbox.com/u/428597/vagrant_boxes/centos_63_x86_64_ja.box"
end
version "6.2" do
box "centos_62_x86_64_ja"
box_url "https://dl.dropbox.com/u/428597/vagrant_boxes/centos_62_x86_64_ja.box"
end
version "5.8" do
box "centos_58_x86_64_ja"
box_url "https://dl.dropbox.com/u/428597/vagrant_boxes/centos_58_x86_64_ja.box"
end
end
cookbook "analog" do
exclude :platform => 'ubuntu'
end
いまはレシピにテストが用意されていないので、テストを作成しよう。 minitestを使った場合は、レシピのトップディレクトリにfiles/default/tests/minitest ディレクトリを作成する。 その上で、以下のファイルを作る
files/default/tests/minitest/default_test.rb
内容は以下のようなものになる。この例では、analogをインストールするレシピをテストしており、テストの中では、analogがパッケージでインストールされ、実行ファイルは/usr/bin/analogに配置され、パーミッションは0755であることをテストしている(もちろんサンプルなのでもっと色々テストは書ける)。
# vim: ft=ruby
describe 'analog' do
require 'chef/mixin/shell_out'
include Chef::Mixin::ShellOut
include MiniTest::Chef::Assertions
include MiniTest::Chef::Context
include MiniTest::Chef::Resources
it 'installs analog' do
# minitest-chef-handler
package('analog').must_be_installed
file('/usr/bin/analog').must_exist
# minitest
assert File.exist?('/usr/bin/analog')
end
it 'has correct permission' do
file('/usr/bin/analog').must_have(:mode, "0755")
end
end
ここまでできたらテストを実行してみよう。テストはレシピのトップディレクトリで実行する。
bundle exec kitchen test
これを実行すればテストが走る。テストの際にはfoodcriticによるレシピの内容チェックも行われる。 冒頭で以下のように表示されるはずだ(もちろん作ったレシピによって警告の内容は異なる)。
FC007: Ensure recipe dependencies are reflected in cookbook metadata: /path/to/cookbooks/analog/recipes/default.rb:11
FC007: Ensure recipe dependencies are reflected in cookbook metadata: /path/to/cookbooks/analog/recipesdefault.rb:12
FC007: Ensure recipe dependencies are reflected in cookbook metadata: /path/to/cookbooks/analog/recipesdefault.rb:13
FC007: Ensure recipe dependencies are reflected in cookbook metadata: /path/to/cookbooks/analog/recipesdefault.rb:14
なお、指定したOS/バージョンのみテストを実行したい場合は
bundle exec kitchen test --platform cents-5.8
のようにオプションを指定する。また、テスト実行後にVagrantのインスタンスを破棄したい場合は
bundle exec kitchen test --teardown
のようにすると良い。もちろん後からインスタンスを破棄することもできる。その場合は
bundle exec kitchen destroy --platform centos-5.8
のようにする。なお、プラットフォームの指定の仕方はKitchenfileで定義しているOS名-バージョン名となる。 現在のインスタンスの起動状況を確認したい場合は
bundle exec kitchen status
とすると、インスタンスの動作状況が以下のように表示される。
Current VM states:
centos-5.8 running
centos-6.2 running
centos-6.3 running
ubuntu-10.04 not created
ubuntu-12.04 not created
This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.
また作ったVMにログインする場合は以下のようにする。
bundle exec kitchen ssh --platform centos-6.2
利用可能なOSとバージョンのリストを表示する場合は
bundle exec kitchen platform list
とすれば
The source :rubygems is deprecated because HTTP requests are insecure.
Please change your source to 'https://rubygems.org' if possible, or 'http://rubygems.org' if not.
centos-5.8
centos-6.2
centos-6.3
ubuntu-10.04
ubuntu-12.04
のように表示される。
これで1つのレシピのテストが複数のプラットフォームでおこなうことが可能になった。 次に複数のレシピを同時にテストする方法について見ていこう。
複数のレシピをテストする場合
複数のレシピをまるごとテストするオプションは用意されていないので一捻り必要だ。すなわち全部をテストするためのレシピを作成する必要がある。僕は、別のディレクトリにテスト専用のレシピを作って実現したのでその方法を紹介する。テスト専用レシピの作成
レシピ格納用のフォルダを作り、その中でknife cookbook create all_tests -o .
としてレシピを作る。また、このディレクトリの中で、冒頭のケースと同じようにGemfileを作成し、その後、
bundle exec kitchen init
としてtestディレクトリを作成する。ここでもKitchenfileが作られるので、今度は内容を以下のようにする。
# vim: ft=ruby
platform :centos do
version "6.3" do
box "centos_63_x86_64_ja"
box_url "https://dl.dropbox.com/u/428597/vagrant_boxes/centos_63_x86_64_ja.box"
end
version "6.2" do
box "centos_62_x86_64_ja"
box_url "https://dl.dropbox.com/u/428597/vagrant_boxes/centos_62_x86_64_ja.box"
end
version "5.8" do
box "centos_58_x86_64_ja"
box_url "https://dl.dropbox.com/u/428597/vagrant_boxes/centos_58_x86_64_ja.box"
end
end
cookbook "all-tests" do
exclude :platform => 'ubuntu'
# テストしたい名前を列挙する
run_list_extras ["apache_mysql_php", "trac", "analog"]
end
レシピの作成
次にテスト対象となるレシピを修正する。レシピはrecipes/default.rb だ。内容を以下のようにする。 単純にテストしたいレシピをinclude_recipeで列挙すればOKだ。include_recipe "analog"
include_recipe "apache_mysql_php"
include_recipe "trac"
依存するレシピの配置
そして最後に上記のレシピをtest/kitchen/cookbooksに配置する。 すなわちこのようになる。test/kitchen/cookbooks
├── README.md
├── analog
├── apache_mysql_php
├── (略)
└── trac
ここまでできたらテストが実行可能だ。トップディレクトリで
bundle exec kitchen test
とすれば良い。これで複数のテストもまとめて実行できる。
画面の出力はこんな感じだ。

なお、いままでの説明だと分かりにくいかもしれないが、上記を設定した内容を僕のgithubにおいておいた。 https://github.com/ryuzee/cookbooks-test https://github.com/ryuzee/cookbooks 僕の場合はcookbook-testの方で、cookbooksをsubmoduleとして登録しておくようにしている。
アジャイルコーチングやトレーニングを提供しています
株式会社アトラクタでは、アジャイル開発に取り組むチーム向けのコーチングや、認定スクラムマスター研修などの各種トレーニングを提供しています。ぜひお気軽にご相談ください。
詳細はこちら