LoginSignup
26
23

More than 5 years have passed since last update.

cucumberのstepsでserverspecをつかう

Last updated at Posted at 2013-08-30

この記事は最終更新から1年以上経過しています。 気をつけてね。

Note: serverspecのバージョンアップにより、多分この内容そのままでは失敗しそう。

構築済みサーバの確認にはserverspecが使いやすいようです。
そして私は受け入れテストの共有にCucumber(Turnipも)を好んで使います。

さてserverspecの書式はもちろんRSpecで、英(単)語とプログラミングが嫌いなコミュニティでテストを共有しようとするのが結構気が引けたりします。cucumberのGherkinは癖がありますが、人に見てもらうのには適しています。

色々経緯もあって両方捨てがたいなーという状況だったので、cucumberからserverspec使ってみようということにしてみました。

featureの作成

ということで、手始めとしてcentosにepelリポジトリが登録されている状態をテストしてみます。

featureのシナリオをつくります。

features/epel.feature
# coding:utf-8
# language: ja

機能: epelリポジトリ

前提: 何かしらの仕組みで構築済みです

シナリオ: epelのリポジトリが登録されている
  もし "/etc/yum.repos.d/epel.repo" ファイルが存在する
  ならば "epel" の状態が "enable"

cucumberを実行するとstep定義の案内が表示されます。

steps_information
You can implement step definitions for undefined steps with these snippets:

もし(/^"(.*?)" ファイルが存在する$/) do |arg1|
  pending # express the regexp above with the code you wish you had
end

ならば(/^"(.*?)" の状態がenableだ$/) do |arg1|
  pending # express the regexp above with the code you wish you had
end

この各Stepでserverspecを使ってみます。

support/env の記述

stepでserverspecを使うために、cucumberの共通設定ファイルfeatures/support/env.rbに各種記述をしていきます。
serverspec-initの生成するspec_helperを参考にしました。

features/support/env.rb
require 'serverspec' 
include RSpec::Matchers
include Serverspec::Helper::Exec  # リモートが対象ならここはSsh
include Serverspec::Helper::DetectOS

迷ったらserverspec-initを実際に実行して、spec_helper.rbから記述をまるっと持ってきましょう。SSH経由のテストならRSpec.configure周りが必須になります。

Steps の記述

さてStepです、拡張されたMatchersはそのまま使えるわけでもなく、backendの選択が必要です。
ということでserverspecのリソースタイプをインスタンスにしてから、それに対してマッチャを使うやり方になります。

features/step_definitions/epel_steps.rb
# coding: utf-8

もし(/^"(.*?)" ファイルが存在する$/) do |filename|
  @file = Serverspec::Type::File.new(filename)
  @file.should be_file
end

ならば(/^"(.*?)" の状態がenableだ$/) do |repo|
  @file.should contain('^\s*enabled=1').from(/\[#{repo}\]/).to(/^\n/)
end

serverspecの便利なマッチャ、be_filecontain(+from_to)をこの様に使うことができました。

実行してみる

それではcucumberを実行してみましょう。

execute_cucumber
$ cucumber features/epel.feature 
# coding:utf-8
# language: ja
機能: epelリポジトリ

  前提: 何かしらの仕組みで構築済みです

  シナリオ: epelのリポジトリが登録されている                   # features/epel.feature:8
    もし"/etc/yum.repos.d/epel.repo" ファイルが存在する # features/step_definitions/epel_steps.rb:3
    ならば"epel" の状態がenableだ                    # features/step_definitions/epel_steps.rb:8

1 scenario (1 passed)
2 steps (2 passed)
0m0.111s

パスしました! serverspecのマッチャが使えるのは嬉しいですね。

もっとサンプルを、シナリオテンプレートと

とりあえずcucumberserverspecとの連携ができたので、より実践的なサンプルを作ってみました。

feature samples

デーモンの状態と、パッケージの導入状況テストです。内容は見たらだいたい分かるかと。

features/service.feature
# coding:utf-8
# language: ja

機能: サーバが適当なデーモンを上げている

前提: 何かしらの仕組みで構築済みです

シナリオテンプレート: サービスチェック
  もし サービス "<servicename>" の状態を調べる
  ならば サービスの状態は "<state>"かつ サービスの自動起動は "<on_boot>" です

  サンプル: 
    | servicename | state   | on_boot |
    | crond       | running | enable  |
    | rsyslog     | running | enable  |
    | mdmonitor   | stopped | disable |
features/package.feature
# coding:utf-8
# language: ja                 

機能: サーバが適当なパッケージを導入している

前提: 何かしらの仕組みで構築済みです

シナリオテンプレート: パッケージチェック
  もし パッケージ "<pkgname>" の状態を調べる 
  ならば パッケージの状態は "<state>" です

  サンプル:
    | pkgname   | state         |   
    | git       | installed     |   
    | syslog-ng | not_installed |   
    | tmux      | installed     |   

ちなみにテーブルのインデントを作るときはTabular.vimというvimのプラグインを使って自動で整うようにしています。

steps for features

先程のfeaturesに対するstepです。引数を工夫すればもっとメタに短く定義できると思いますがこんなもんで。

features/step_definitions/service_steps.rb
# coding: utf-8

もし(/^サービス "(.*?)" の状態を調べる$/) do |servicename|
  @service = Serverspec::Type::Service.new(servicename)
end

ならば(/^サービスの状態は "(.*?)" で$/) do |state|
  if state == 'running'
    @service.should be_running
  else
    @service.should_not be_running
  end
end

ならば(/^サービスの自動起動は "(.*?)" です$/) do |on_boot|
  if on_boot == 'enable'
    @service.should be_enabled
  else
    @service.should_not be_enabled
  end
end
features/step_definitions/package_steps.rb
# coding: utf-8

もし(/^パッケージ "(.*?)" の状態を調べる$/) do |pkgname|
  @package = Serverspec::Type::Package.new(pkgname)
end

ならば(/^パッケージの状態は "(.*?)" で$/) do |state|
  if state == 'installed'
    @package.should be_installed
  else
    @package.should_not be_installed
  end
end

stepではfailする場合に例外を出す必要があるのですが、serverspecのマッチャとshould(_not)の組み合わせでうまいこと例外になります。

results

これらを実行すると下記の結果が得られます。

execute_cucumber
$ cucumber 
# coding:utf-8
# language: ja
機能: サーバが適当なパッケージを導入している

  前提: 何かしらの仕組みで構築済みです

  シナリオテンプレート: パッケージチェック         # features/package.feature:8
    もしパッケージ "<pkgname>" の状態を調べる # features/step_definitions/package_steps.rb:4
    ならばパッケージの状態は "<state>"# features/step_definitions/package_steps.rb:8

    サンプル: 
      | pkgname   | state         |
      | git       | installed     |
      | syslog-ng | not_installed |
      | tmux      | installed     |

# coding:utf-8
# language: ja
機能: サーバが適当なデーモンを上げている

  前提: 何かしらの仕組みで構築済みです

  シナリオテンプレート: サービスチェック             # features/service.feature:8
    もしサービス "<servicename>" の状態を調べる # features/step_definitions/service_steps.rb:3
    ならばサービスの状態は "<state>"# features/step_definitions/service_steps.rb:7
    かつサービスの自動起動は "<on_boot>" です    # features/step_definitions/service_steps.rb:15

    サンプル: 
      | servicename | state   | on_boot |
      | crond       | running | enable  |
      | rsyslog     | running | enable  |
      | mdmonitor   | stopped | disable |

6 scenarios (6 passed)
15 steps (15 passed)
0m0.287s

ついでにcucumberのHTMLフォーマットで出力してみました。

Cucumber.png

見やすいので結果を共有しやすいかもしれない。

おわりに

serverspec使いたいけど、RSpecの記法が導入のネックになっていたり、人におすすめしづらいというお悩みを持っておられたら、思い切ってGherkin(cucumber)という選択もどうでしょう。

何がおすすめか、というのは場合によりますわね。


追記:

SSH経由でリモートサーバをテストする際はこのように書いてもいけました。Featuresに織り交ぜることができますね。

step_with_ssh_example
Then(/^The server has cron entry '(.*)'/) do |line|
  @cron = Serverspec::Type::Cron.new
  Net::SSH.start('test.example.com', 'root') do |ssh|
    expect(@cron.have_entry(line).with_user('www')).to be_true
  end
end
26
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
23