serverspecでconfigファイルを複数行まとめてテストする
configファイルの記述の正当性をserverspecでテストするときは、ヒアドキュメントを使うといいかも、という話です。
configファイルを普通にテストする
serverspecで、configファイルの記述をテストするとき、普通はits(:content)
matcherを使います。
describe file('/etc/httpd/conf/httpd.conf') do its(:content) { should match /ServerName www.example.jp/ } end
が、configの記述が1行では意味をなさず、複数行にわたって「ブロック」として記載されていたとき、昔はits(:content)
matcherをひたすら繋げて書いていました。
describe file('/etc/td-agent/td-agent.conf') do its(:content) { should match %r{^[[:blank:]]*<source>} } its(:content) { should match %r{^[[:blank:]]*type monitor_agent} } its(:content) { should match %r{^[[:blank:]]*bind 0.0.0.0} } its(:content) { should match %r{^[[:blank:]]*port 24220} } its(:content) { should match %r{^[[:blank:]]*</source>} } end
例はtd-agent.conf
のテストです。
この記述のダメなところは、結局行単位で評価しているので、前後関係が全く意味を成さないところです。それぞれの行をconfig内のどこにどういう順番で書こうが、そのconfigが実際には無効な記述だったとしても、serverspecのテストは通ります。
素直にits(:content)
をまとめて書く
一応、最初から最後までまとめて1つのmatcherで繋げて書くことはできます。
describe file('/etc/td-agent/td-agent.conf') do its(:content) { should match %r{<source>\n type monitor_agent\n bind 0.0.0.0\n port 24220\n</source>} } end
この記述の良くないところは、仮にテストがfailedしたときに、どこが間違っているのかわかりづらいところです。
2) File "/etc/td-agent/td-agent.conf" content should match /<source>\n type monitor_agent\n bind 0.0.0.0\n port 24220\n<\/source>/ On host `localhost' Failure/Error: its(:content) { should match %r{<source>\n type monitor_agent\n bind 0.0.0.0\n port 24220\n</source>} } expected "<match debug.**>\n type stdout\n</match>\n\n<source>\n type monitor_agent\n bind 0.0.0.0\n port 24222\n</source>\n\ninclude /etc/td-agent/conf.d/*.conf\n\n" to match /<source>\n type monitor_agent\n bind 0.0.0.0\n port 24220\n<\/source>/ Diff: @@ -1,2 +1,12 @@ -/<source>\n type monitor_agent\n bind 0.0.0.0\n port 24220\n<\/source>/ +<match debug.**> + type stdout +</match> + +<source> + type monitor_agent + bind 0.0.0.0 + port 24222 +</source> + +include /etc/td-agent/conf.d/*.conf
上記はport番号を24222とわざと間違って書いているのですが、ブロック全体が誤っていると捉えられます。というか、いちいちテストコードを書くのも、わざわざ改行を¥n
で書かなければいけなかったりと面倒です。
ヒアドキュメントを使う
test-monitor_agent = <<"EOS" <source> type monitor_agent bind 0.0.0.0 port 24220 </source> EOS describe file('/etc/td-agent/td-agent.conf') do its(:content) { should match test-monitor_agent } end
もしテストがfailedしても、その部分を判別してくれます。
1) File "/etc/td-agent/td-agent.conf" content should match "<source>\n type monitor_agent\n bind 0.0.0.0\n port 24220\n</source>\n" On host `localhost' Failure/Error: its(:content) { should match test } expected "<match debug.**>\n type stdout\n</match>\n\n<source>\n type monitor_agent\n bind 0.0.0.0\n port 24222\n</source>\n\ninclude /etc/td-agent/conf.d/*.conf\n\n" to match "<source>\n type monitor_agent\n bind 0.0.0.0\n port 24220\n</source>\n" Diff: @@ -1,6 +1,12 @@ +<match debug.**> + type stdout +</match> + <source> type monitor_agent bind 0.0.0.0 - port 24220 + port 24222 </source> + +include /etc/td-agent/conf.d/*.conf
普通に書く
普通に書いても動きます。(これ昔はできなかったと思ったのですが…昔から動いてましたっけ?)
describe file('/etc/td-agent/td-agent.conf') do its(:content) { should match " <source> type monitor_agent bind 0.0.0.0 port 24220 </source>" } end
当たり前ですがテストfailed時もヒアドキュメントと同じ表示になります。
一番簡単なのはこれですが、テストコードとconfigの記載が混在するので見づらいという問題はあります。好みですが、自分ならヒアドキュメントで変数化して使うかなという印象です。
そう考えると、configファイルをどこまで厳密にチェックするかは考えものです。
そこまでやるなら、もうconfigファイルの最初から最後までまるっとspecファイルに書いてテストすればいいんじゃないかとか、そもそもそれやるならもうserverspecじゃなくて、正しいconfigとのdiff
でいいんじゃないかとか思ったりもします。configファイルのテストはある程度妥協して、あとは正しく動くのかというinfratasterの範疇になるかもしれません。