- 更新日: 2014年8月5日
- RSpec
Serverspec で rbenv と Ruby のインストールをテスト
Chef で rbenv で ruby をインストールするための Cookbook を以前作成したのですが、それに対する Serverspec テストを書きました。以下の Chef Cookbook に対応するテスト。
Chefでrbenvとruby-buildをインストール | EasyRamble
※ 2014/08/06 serverspec で sudo なしでコマンドを実行する方法について追記しました。全てのリソースで “let(:disable_sudo) { true }” や “:sudo => false” のオプションを付けるなどの方法で、sudo なしでコマンドを実行できるそうです。
rbenv, ruby が正しくインストールされているか確認する serverspec コード
以下をチェックしています。
1. /usr/local/rbenv/bin/rbenv に rbenv がインストールされていること
2. /etc/profile.d/rbenv.sh が正しく作成されていること
3. rbenv のプラグインとして ruby-build がインストールされていること
4. 目的のバージョンの Ruby が正しくインストールされていること
5. Ruby 2.1.2 が global として設定されていること
spec/centos.vagrant/app_rbenv_spec.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
require 'spec_helper' # rbenv group describe group('rbenv') do it { should exist } end describe user('vagrant') do it { should exist } it { should belong_to_group 'rbenv' } end # install rbenv describe command('source /etc/profile.d/rbenv.sh; which rbenv') do let(:disable_sudo) { true } it { should return_stdout('/usr/local/rbenv/bin/rbenv') } end # rbenv.sh describe file('/etc/profile.d/rbenv.sh') do it { should be_file } it { should be_owned_by 'root' } it { should be_grouped_into 'root' } it { should be_mode 644 } its(:content) { should match(/^export RBENV_ROOT="\/usr\/local\/rbenv"$/) } its(:content) { should match(/^export PATH="\$RBENV_ROOT\/bin:\$PATH"$/) } its(:content) { should match(/^eval "\$\(rbenv init -\)"$/) } end # ruby-build describe file('/usr/local/rbenv/plugins') do it { should be_directory } it { should be_owned_by 'root' } it { should be_grouped_into 'rbenv' } it { should be_mode 755 } end describe file('/usr/local/rbenv/plugins/ruby-build/.git/') do it { should be_directory } it { should be_owned_by 'root' } it { should be_grouped_into 'rbenv' } it { should be_mode 755 } end # install ruby ['2.1.2', '2.0.0-p247'].each do |ruby_version| describe command("source /etc/profile.d/rbenv.sh; rbenv versions | grep #{ruby_version}") do let(:disable_sudo) { true } its(:stdout) { should match(/#{Regexp.escape(ruby_version)}/) } end end describe command('source /etc/profile.d/rbenv.sh; rbenv global') do let(:disable_sudo) { true } it { should return_stdout('2.1.2') } end |
/etc/profiled.d/rbenv.sh の中身は以下。
/etc/profiled.d/rbenv.sh
1 2 3 4 5 |
export RBENV_ROOT="/usr/local/rbenv" export PATH="$RBENV_ROOT/bin:$PATH" eval "$(rbenv init -)" |
テスト実行。
1 2 3 4 5 6 7 |
$ bundle exec rspec spec/centos.vagrant/app_rbenv_spec.rb ..................... Finished in 5.41 seconds 21 examples, 0 failures |
ちゃんとテストは全て通過。
rbenv コマンドを使う箇所ではまった
実は最初、rbenv コマンドを使う処理の部分で、以下のように書いていてはまりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# install rbenv describe command('which rbenv') do it { should return_stdout('/usr/local/rbenv/bin/rbenv') } end # install ruby ['2.1.2', '2.0.0-p247'].each do |ruby_version| describe command("rbenv versions | grep #{ruby_version}") do its(:stdout) { should match(/#{Regexp.escape(ruby_version)}/) } end end describe command('rbenv global') do it { should return_stdout('2.1.2') } end |
この書き方だと何回テストを繰り返してもテストは失敗し続けました。vagrant に ssh で入って確認すると、ちゃんと設定通り rbenv, ruby がインストールされていたのですが。
1 2 3 4 5 6 7 8 9 |
$ vagrant ssh [vagrant@localhost ~]$ which ruby /usr/local/rbenv/shims/ruby [vagrant@localhost ~]$ rbenv versions | grep 2.1.2 * 2.1.2 (set by /usr/local/rbenv/version) [vagrant@localhost ~]$ rbenv global 2.1.2 |
原因は sudo rbenv global で rbenv コマンドの PATH が追加されないため
しばらく serverspec のテスト結果を見ていて気付いたのですが、serverspec の場合、デフォルトでは sudo でコマンドが実行されますので、この書き方のテストで実際に実行されるコマンドは各々以下のようになります。
1 2 3 4 5 |
$ sudo which rbenv $ sudo rbenv versions | grep #{ruby_version} $ sudo rbenv global |
serverspec のテスト終了後のログ。
1 2 3 4 5 6 7 8 9 10 |
Failures: 1) Command "which rbenv" should return stdout "/usr/local/rbenv/bin/rbenv" On host `centos.vagrant` Failure/Error: it { should return_stdout('/usr/local/rbenv/bin/rbenv') } sudo which rbenv # ←ココ expected Command "which rbenv" to return stdout "/usr/local/rbenv/bin/rbenv" ... |
これら sudo が付いたコマンドを実際に vagrant にログイン後に実行すると、やはりエラーになることに気付きました。
1 2 3 4 5 6 7 8 9 |
$ vagrant ssh [vagrant@localhost ~]$ sudo which rbenv which: no rbenv in (/sbin:/bin:/usr/sbin:/usr/bin) [vagrant@localhost ~]$ sudo rbenv versions sudo: rbenv: コマンドが見つかりません [vagrant@localhost ~]$ sudo rbenv global sudo: rbenv: コマンドが見つかりません |
どうやら sudo 経由だと、/etc/profiled.d/rbenv.sh で追加するはずの PATH(/usr/local/rbenv/bin)が引き継がれず、エラーになる模様です。
【追記 2014/08/06】
ということで、command リソースで sudo なしで rbenv コマンドを実行させるようにします。
コメントで教えて頂きましたが、”let(:disable_sudo) { true }” や “:sudo => false” のオプションを使うと、一時的に sudo なしでコマンドを実行できるそうです。mizzy さんありがとうございました!command リソースを含め全てのリソースで利用できるそうです。
Serverspec – Advanced Tips の下の方の見出し、How to control sudo に書いてあります。一時的ではなく、デフォルトで sudo なしにする方法なども掲載されています。
修正前、当初の command リソースを使うテストコード。rbenv コマンドを実行する command リソースで、env コマンドで PATH を追加していました。これも一応動くのですが、見た目がちょっとよろしくない感じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# install rbenv describe command('env PATH="/usr/local/rbenv/bin:$PATH">/dev/null 2>&1; which rbenv') do it { should return_stdout('/usr/local/rbenv/bin/rbenv') } end # install ruby ['2.1.2', '2.0.0-p247'].each do |ruby_version| describe command("env PATH=\"/usr/local/rbenv/bin:$PATH\">/dev/null 2>&1; rbenv versions | grep #{ruby_version}") do its(:stdout) { should match(/#{Regexp.escape(ruby_version)}/) } end end describe command('env PATH="/usr/local/rbenv/bin:$PATH">/dev/null 2>&1; rbenv global') do it { should return_stdout('2.1.2') } end |
修正後のコード。command リソースに let(:disable_sudo) { true } を追加して、sudo なしで rbenv コマンドを使うように修正。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# install rbenv describe command('source /etc/profile.d/rbenv.sh; which rbenv') do let(:disable_sudo) { true } it { should return_stdout('/usr/local/rbenv/bin/rbenv') } end # install ruby ['2.1.2', '2.0.0-p247'].each do |ruby_version| describe command("source /etc/profile.d/rbenv.sh; rbenv versions | grep #{ruby_version}") do let(:disable_sudo) { true } its(:stdout) { should match(/#{Regexp.escape(ruby_version)}/) } end end describe command('source /etc/profile.d/rbenv.sh; rbenv global') do let(:disable_sudo) { true } it { should return_stdout('2.1.2') } end |
この場合も、明示的に source コマンドで /etc/profile.d/rbenv.sh を読み込む必要があるみたいです。これで無事に sudo なしでコマンドを実行できテストもパスしました。テストコードもすっきりして良い感じです。
ちなみに sudo source は、source コマンドが bash のコマンドなのでエラーになる。なので、sudo なしで command リソースが実行されるように let(:disable_sudo) { true } を追加する必要があります。
bash – sudo: source: command not found – Ask Ubuntu
【追記ここまで】
※ 以降は追記する前の文ですので、読まなくて構いません。
一般ユーザーで sudo なしで Serverspec の command リソースを実行する方法も模索したのですが、結局やり方が分かりませんでした。なので、以下のように env コマンドで PATH を追加した後に、rbenv コマンドを使うように対応しました。
1 2 3 |
describe command('env PATH="/usr/local/rbenv/bin:$PATH">/dev/null 2>&1; rbenv global') do it { should return_stdout('2.1.2') } end |
>/dev/null 2>&1 してるのは、env コマンドを出力させないため。だいぶださい感じになっちゃってますけど、とりあえずこれでテストは全てOKとなった。
Serverspec を書き進めるにつれて、色々と自分で書いた Cookbook Recipe のボロが出てきています… 良いことです!
- RSpec の関連記事
- FactoryGirlをSpringと共に使う時の注意
- 複数モデルのpost :createをテストするRSpecコード(Controller Spec)
- RSpec3でTime.nowをスタブ化(stub)
- RSpecでJSONによるPOSTリクエストをテスト
- RSpec & Capybara の雑感
- RSpec+Capybaraで同名の複数要素の並び順をテストする
- RSpec3ではrails_helper.rbがrequireされる
- Capybara + Launchy で RSpec テストをブラウザで確認
- CapybaraのwithinをRSpecで使う
- Serverspec(RSpec)のテスト出力に色を付けて見やすくフォーマット
- 4件のコメント
sudoしないやり方はこのページの下の方にありますよ。
http://serverspec.org/advanced_tips.html
大変助かりました。ありがとうございます!修正を追記しました。
commandリソースだけじゃなく、全部のリソースにあてはまります。
ありがとうございます。再度修正しました。