rspec3系 での serverspec JUnit.xml出力対応について(CentOS 6.x + rbenv + bundler + rspec_junit_formatter)


先日のCIお試し環境に、serverspecによるテストもJenkins対応しようとしたところ、webでよく見かけるci_reporterの構築事例が単純に再現できなくなりました。時間が経って昔のノウハウが単純に生かせなくなっているようです。ひと手間加え、ひとまず一般ユーザでJUnit.xml出力できるまで進めたので、いまどきのserverspec JUnit.xml対応として控えておきます。

問題点

serverspec単体では、RHEL6系に標準のRuby1.8.7でもスムーズに使えるのですが、JUnit.xml出力のための環境整備をしようとすると、以下のような問題にぶつかりました。

  • 2014年6月よりRSpec 3がリリースされたことで、ci_reporterがうまく動かなくなった。
  • 代替となりそうなrspec_junit_formatterは、依存するBuilder gemが必要。一方で、自分の環境Cent6系にバンドルされているruby 1.8系ではgemが見つからない。

ちなみに、ruby 1.8系環境でBundlerを使ってBuilderをインストールしようとすると以下のようなエラーとなります。

Could not find gem 'Builder (>= 0) ruby' in any of the gem sources listed in your Gemfile or installed on this machine.
Run `bundle install` to install missing gems.

対応方向性

あえて古い環境を生かし続けるより、いまどきの事情に合わせて動くように整理してしまおうと思い、以下のようにしています。

  • rbenvとBundlerで管理
  • Ruby最新系(2.2.2)を適用
  • RSpec 3系で実装
  • rspec_junit_formatter でJUnit.xml出力を実現

環境

用途 台数 ホスト名 IP Address
テスト対象サーバ 1 stage01 192.168.0.101
CIサーバ 1 ci01 192.168.0.99

テスト対象サーバは予めhttpdをインストールし、スタートアップ設定とサービス起動を済ませてあります。また、hostsファイルで名前解決させています。sshログインユーザが異なるなどの場合は~/.ssh/configに定義を書いてパスワード入力なしでログインできるようにしておきます。

手順

すべてCIサーバ側の手順になります。

rbenvとruby-buildの準備

$HOME 直下に.rbenvを、また、.rbenvのpluginとしてruby-buildをそれぞれのレポジトリから持ってきます。
終わりましたら、.bash_prifuleまたは.bashrcなどにrbenvのPATHを通します。

[ci01 ~]$ sudo yum install -y gcc openssl-devel libyaml-devel libffi-devel readline-devel zlib-devel gdbm-devel ncurses-devel
[ci01 ~]$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
[ci01 ~]$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
[ci01 ~]$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
[ci01 ~]$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
[ci01 ~]$ source ~/.bash_profile

念のため、rbenvコマンドが呼び出せるか確認しておきましょう。

[ci01 ~]$ rbenv --version
rbenv 0.4.0-146-g7ad01b2

rbenvによるRuby最新系(2.2.2)のインストールと環境変数への設定

[ci01 ~]$ rbenv install --list
Available versions:
  1.8.6-p383
  1.8.6-p420
  (...中略...)
  2.2.1
  2.2.2
  2.3.0-dev
  (...中略...)
  ree-1.8.7-2012.01
  ree-1.8.7-2012.02
  topaz-dev
[ci01 ~]$ rbenv install 2.2.2
Downloading ruby-2.2.2.tar.gz...
-> http://dqw8nmjcqpjn7.cloudfront.net/5ffc0f317e429e6b29d4a98ac521c3ce65481bfd22a8cf845fa02a7b113d9b44
Installing ruby-2.2.2...
Installed ruby-2.2.2 to /home/admin01/.rbenv/versions/2.2.2

[ci01 ~]$ rbenv rehash
[ci01 ~]$ rbenv versions
  2.2.2
[ci01 ~]$ rbenv global
system
[ci01 ~]$ rbenv global 2.2.2
[ci01 ~]$ rbenv global
2.2.2
[ci01 ~]$ 

Bundlerによるgemインストール

[ci01 ~]$ rbenv exec gem install bundler
[ci01 ~]$ rbenv rehash

[ci01 ~]$ rbenv exec gem install bundler
Fetching: bundler-1.9.4.gem (100%)
Successfully installed bundler-1.9.4
Parsing documentation for bundler-1.9.4
Installing ri documentation for bundler-1.9.4
Done installing documentation for bundler after 6 seconds
1 gem installed
[ci01 ~]$ rbenv rehash
[ci01 ~]$ rbenv exec gem which bundler
/home/***/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/bundler-1.9.4/lib/bundler.rb
[ci01 ~]$ 

serverspec初期化と簡易テスト

serverspecディレクトリを作成し、その配下に環境を整備することとします。

[ci01 ~]$ mkdir serverspec
[ci01 ~]$ cd serverspec
[ci01 serverspec]$ rbenv exec bundle init
Writing new Gemfile to /home/***/serverspec/Gemfile
[ci01 serverspec]$ ls -al
合計 12
drwxr-xr-x 2 *** users 4096  4月 19 23:11 2015 .
drwx------ 8 *** users 4096  4月 19 23:06 2015 ..
-rw-r--r-- 1 *** users   64  4月 19 23:11 2015 Gemfile
[ci01 serverspec]$ cat Gemfile
# A sample Gemfile
source "https://rubygems.org"

# gem "rails"
[ci01 serverspec]$ vi Gemfile
[ci01 serverspec]$ 
[ci01 serverspec]$ cat Gemfile 
source "https://rubygems.org"

gem "serverspec"
gem "builder"
gem "rspec_junit_formatter"
[ci01 serverspec]$ rbenv exec bundle install --path vendor/bundle
Fetching gem metadata from https://rubygems.org/.......
Fetching version metadata from https://rubygems.org/..
Resolving dependencies...
Installing builder 3.2.2
Installing diff-lcs 1.2.5
Installing multi_json 1.11.0
Installing net-ssh 2.9.2
Installing net-scp 1.2.1
Installing rspec-support 3.2.2
Installing rspec-core 3.2.3
Installing rspec-expectations 3.2.1
Installing rspec-mocks 3.2.1
Installing rspec 3.2.0
Installing rspec-its 1.2.0
Installing rspec_junit_formatter 0.2.0
Installing specinfra 2.29.0
Installing serverspec 2.14.1
Using bundler 1.9.4
Bundle complete! 3 Gemfile dependencies, 15 gems now installed.
Bundled gems are installed into ./vendor/bundle.
[ci01 serverspec]$ ls -al
合計 24
drwxr-xr-x 4 *** users 4096  4月 19 23:13 2015 .
drwx------ 8 *** users 4096  4月 19 23:06 2015 ..
drwxr-xr-x 2 *** users 4096  4月 19 23:13 2015 .bundle
-rw-r--r-- 1 *** users   90  4月 19 23:12 2015 Gemfile
-rw-r--r-- 1 *** users  976  4月 19 23:13 2015 Gemfile.lock
drwxr-xr-x 3 *** users 4096  4月 19 23:13 2015 vendor
[ci01 serverspec]$ 

serverspecの初期化をします。一度実行するとわかりますが、”set :request_pty, true”をspec_helper.rbに書き込んであげる必要がある場合があります。

[ci01 serverspec]$ rbenv exec bundle exec serverspec-init
Select OS type:

  1) UN*X
  2) Windows

Select number: 1

Select a backend type:

  1) SSH
  2) Exec (local)

Select number: 1

Vagrant instance y/n: n
Input target host name: stage01
 + spec/
 + spec/stage01/
 + spec/stage01/sample_spec.rb
 + spec/spec_helper.rb
 + Rakefile
[ci01 serverspec]$
[ci01 serverspec]$ rbenv exec bundle exec rake spec
/home/***/.rbenv/versions/2.2.2/bin/ruby -I/home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.2.3/lib:/home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-support-3.2.2/lib /home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.2.3/exe/rspec --pattern spec/stage01/\*_spec.rb
Please write "set :request_pty, true" in your spec_helper.rb or other appropriate file.
/home/***/.rbenv/versions/2.2.2/bin/ruby -I/home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.2.3/lib:/home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-support-3.2.2/lib /home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.2.3/exe/rspec --pattern spec/stage01/\*_spec.rb failed
[ci01 serverspec]$ 
[ci01 serverspec]$ vi spec/spec_helper.rb
[ci01 serverspec]$ cat spec/spec_helper.rb
require 'serverspec'
require 'net/ssh'

set :backend, :ssh
set :request_pty, true

if ENV['ASK_SUDO_PASSWORD']
  begin
    require 'highline/import'
  rescue LoadError
    fail "highline is not available. Try installing it."
  end
  set :sudo_password, ask("Enter sudo password: ") { |q| q.echo = false }
else
  set :sudo_password, ENV['SUDO_PASSWORD']
end

host = ENV['TARGET_HOST']

options = Net::SSH::Config.for(host)

options[:user] ||= Etc.getlogin

set :host,        options[:host_name] || host
set :ssh_options, options

# Disable sudo
# set :disable_sudo, true


# Set environment variables
# set :env, :LANG => 'C', :LC_MESSAGES => 'C' 

# Set PATH
# set :path, '/sbin:/usr/local/sbin:$PATH'
[ci01 serverspec]$ rbenv exec bundle exec rake spec
/home/***/.rbenv/versions/2.2.2/bin/ruby -I/home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.2.3/lib:/home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-support-3.2.2/lib /home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.2.3/exe/rspec --pattern spec/stage01/\*_spec.rb

Package "httpd"
  should be installed

Service "httpd"
  should be enabled
  should be running

Port "80"
  should be listening

Finished in 0.12344 seconds (files took 0.51911 seconds to load)
4 examples, 0 failures

[ci01 serverspec]$ 

応用編

html出力
[ci01 serverspec]$ rbenv exec bundle exec rake spec SPEC_OPTS="--format html"
/home/***/.rbenv/versions/2.2.2/bin/ruby -I/home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.2.3/lib:/home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-support-3.2.2/lib /home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.2.3/exe/rspec --pattern spec/stage01/\*_spec.rb
  (...出力略...)
[ci01 serverspec]$ 

こんなのができます。

serverspec_example_result

JUnit.xml出力
[ci01 serverspec]$ rbenv exec bundle exec rake spec SPEC_OPTS="--format RspecJunitFormatter --out spec/reports/rspec.xml"
/home/***/.rbenv/versions/2.2.2/bin/ruby -I/home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.2.3/lib:/home/***/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-support-3.2.2/lib /home/***
/serverspec/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.2.3/exe/rspec --pattern spec/stage01/\*_spec.rb
[ci01 serverspec]$ cat spec/reports/rspec.xml
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="rspec" tests="4" failures="0" errors="0" time="0.115013" timestamp="2015-04-20T00:05:50+09:00">
  <properties/>
  <testcase classname="spec.stage01.sample_spec" name="Package &quot;httpd&quot; should be installed" time="0.036652"/>
  <testcase classname="spec.stage01.sample_spec" name="Service &quot;httpd&quot; should be enabled" time="0.020671"/>
  <testcase classname="spec.stage01.sample_spec" name="Service &quot;httpd&quot; should be running" time="0.035370"/>
  <testcase classname="spec.stage01.sample_spec" name="Port &quot;80&quot; should be listening" time="0.021414"/>
</testsuite>
[ci01 serverspec]$ 

動きました。

今日はここまで

Jenkinsでrbenv環境呼び出すためのセットアップ方法の細かい差異とか、実際にはserverspecをロールなどで繰り返しテストさせるためのテストコードのベストプラクティスとか、この先も多少気になることはありますが、ひとまず今日はここまでとします。もっといいやり方あるよとか、これだとまずいよとかあればフィードバックいただければ嬉しいです。

参照

今回は以下のサイトを参考にさせていただきました。ありがとうございます。

GitHub:ruby-build | Suggested build environment
https://github.com/sstephenson/ruby-build/wiki#suggested-build-environment

ncstudy | ncstudy#05 ハンズオン資料 2013/07/14 #ncstudy
http://tily.github.io/ncstudy05/

Developers.IO | rbenv を利用した Ruby 環境の構築
http://dev.classmethod.jp/server-side/language/build-ruby-environment-by-rbenv/

Developers.IO | Jenkinsの使い勝手をよくするための見直し6点
http://dev.classmethod.jp/tool/jenkins/jenkins-refactoring-jobs/

Qoosky | rbenvおよびbundlerの基本的な使用方法 @qoosky_dev
https://www.qoosky.net/references/128/

@znz blog | ci_reporter から rspec_junit_formatter に移行した
http://blog.n-z.jp/blog/2014-06-13-ci-reporter-to-rspec-junit-formatter.html

Into my web | [ruby]最初に知っておけば良かったbundlerの使い方 rails編
http://kozo002.blogspot.jp/2012/01/rubybundler.html

コメントを残す