Posted at

ChefSpecのcookbook_pathを一括指定する

More than 5 years have passed since last update.

ChefSpecを使うときに地味に面倒なのが、複数のcookbook_pathがあるときのその指定。ChefRunner.newするときに指定できますが、これだとspecファイル毎に指定なのでとっても面倒。

実際に実行するのはrakeからという方も多いと思うので、rakeから実行するspecファイル全部にcookbook_path指定をする方法。


はじめに

ここではcookbookssite-cookbooksの2つのディレクトリにcookbookが分かれて保存されており、rake rspecで実行できる状態になっているものとします。テスト対象はsite-cookbooksのみ。


Rakefile_org

require "rspec/core/rake_task"

TOPDIR=File.expand_path(File.dirname(__FILE__))

desc "execute all chefspec test"
task :rspec do
RSpec::Core::RakeTask.new(:rspec) do |t|
t.pattern = 'site-cookbooks/*/spec/*_spec.rb'
t.rspec_opts = ['-c']
end
end



spec_helperの作成

Rubyの場合、オープンクラスという機能を使って、gemで配られているライブラリのコードを書き換える事ができます。ChefSpec::ChefRunnerではvendor/cookbooks,test/cookbooks, spec/cookbooksの3つは存在すれば追加してくれるようですが、今回のケースみたいに特定のサイトで使うChef全部のリポジトリを想定したものではないので当てはまりません。

なので、この3つのパスを追加している部分をオープンクラスで書き換えてしまいます。


spec_helper.rb

require 'chefspec/chef_runner'

TOPDIR=File.expand_path(File.dirname(__FILE__))

module ChefSpec
class ChefRunner
remove_method :cookbook_paths
def cookbook_paths
["#{TOPDIR}/cookbooks", "#{TOPDIR}/site-cookbooks"]
end
end
end


ここでは元あったcookbook_pathsの定義を削除して、都合のいいcookbook_pathsに差し替えています。


Rakefileの修正

先ほどのspec_helperを有効にするには、ChefSpec実行前にこのコードが読み込まれている必要があります。なので、ChefSpec(RSpec)実行時にこのファイルを必ず読み込むように、以下のようにRakefileを修正します。


Rakefile_new

require "rspec/core/rake_task"

TOPDIR=File.expand_path(File.dirname(__FILE__))

desc "execute all chefspec test"
task :rspec do
RSpec::Core::RakeTask.new(:rspec) do |t|
t.pattern = 'site-cookbooks/*/spec/*_spec.rb'
t.rspec_opts = ['-c']
t.ruby_opts = ["-r", "#{TOPDIR}/spec_helper.rb"]
end
end


追加したのはt.ruby_opts = ["-r", "#{TOPDIR}/spec_helper.rb"]です。これによってChefSpecを実行する際は必ずspec_helper.rbを読んでから実行するようになります。


補足

上記を組み込んだ場合は「cookbook_pathのデフォルト値がspec_helperで指定したものになる」だけなので、ChefRunner.new(:cookbook_path => paths)として渡した場合はそちらが優先されます。また、これはcookbook_path以外にも応用可能なので、それでコードの重複を減らすこともできます。