HEARTBEATS

serverspec のリソースタイプにPHPの設定テストを加えてみました

   

斎藤です。こんにちは。

今日は、serverspecのリソースタイプにPHPの設定テストを書き加えた時の事をお話しします。「きっかけ」「ファイル構成」そして「記述時の注意点」の3点を中心に記述します。その後、テストコードがどのように書き変わるかを示します。

きっかけ

PHPは、様々なLightweight Language(以下、LL)の中でも、実行するアプリケーションに応じた設定が必要な言語の一つです。設定値の代表として "mb_string", "upload_max_filesize" そして "memory_limit" で頭を悩ませた方もいらっしゃるかと思います。そこで、serverspecで設定値を評価できる仕組みを整備し、正しく設定されているかを確認できるようにしたいと考えました。

これまで、serverspecでPHPの設定の評価を行うには、commandリソースを用いて"php -i"などの出力結果をgrepし、設定すべき値がセットされているかを確認する方法のみでした。grepを通じた評価は汎用性が高いのですが、「以上」「以下」が評価しづらい事、またコマンドが冗長になりがちです。そこで、PHPの設定をより手軽に評価できるようにしたいと考え、実装する事にしました。

ファイル構成

ファイル構成は次の通りとなりました。lib配下が実際に動くリソースのプログラム、spec配下はlib配下のプログラムをテストするためのテストコードです。0.6.25の段階では7プラットフォーム分用意します。

.
├── lib
│   └── serverspec
│       ├── helper
│       │   └── type.rb
│       └── type
│           └── php_config.rb
└── spec
    ├── darwin
    │   └── php_config_spec.rb
    ├── debian
    │   └── php_config_spec.rb
    ├── gentoo
    │   └── php_config_spec.rb
    ├── redhat
    │   └── php_config_spec.rb
    ├── solaris
    │   └── php_config_spec.rb
    ├── solaris10
    │   └── php_config_spec.rb
    └── solaris11
        └── php_config_spec.rb

追加したコードが意外に少ないな、と感じていただけたのではないでしょうか。

serverspecにて設定値の評価を行うリソースタイプは、主に"command"リソースで用いられている方法と、"linux_kernel_perameter"で用いられいてる方法があります。今回は、mizzyさんからのアドバイスもあり、後者を選択しました。

さて、後者は前者に比べて優位になるポイントが2つあります。

  1. 正規表現を適用しやすい
  2. 大小比較を適用しやすい

どちらも、正規表現・大小を評価できる仕組みが既に用意されているため、別途自分自身でそれらの評価のためのコードを書く必要がありません。そのため、評価したいものが明確であれば、リソースを手軽に追加する事ができます。

記述時の注意点

作成時に私がはまったポイントを、3つご紹介します。

評価の実装が適切ではなかった

先節で評価方法を2つ紹介していますが、当初は前者で書いていました。当初は、その実装方法を詳しく理解していなかったのが原因です。ユーザとしてserverspecを用いたテストのコードを書くだけでは、自分は深く理解できていないんだなと感じました。

また、追加したリソースのテストコードについても、mizzyさんにより手厚くしていただきました。

"lib/helper/type.rb"に追加したリソースタイプを書く

6行目にあるリソースタイプの一覧に、作成したリソースを書き加える必要があります。はじめ、"lib/type/*.rb"のみを追加すればよいと勘違いしていまして、テストが通らないと悩んでしまいました。

"lib/type/*.rb"に"to_s"メソッドを書く場合と書かない場合がある

(7/19 17:30修正ここから: mizzyさんより指摘いただきました。失礼しました。 (1) (2) )

"lib/serverspec/type/base.rb" で定義している名前とは別のものをオーバーライドしたい時のみ、"to_s"メソッドを書きます。オーバーライドが不要であれば("lib/serverspec/type/base.rb"の定義通りに名前が抽出されていればよいのであれば)、書く事になります。今回は不要なパターンであるのにも関わらず書いてしまい、後になって削除しています。

今回用いた後者の場合は、書いてはいけません。名前が正しく判定できず、テストも通らなくなります。なお、前者の方法で書く場合は、"to_s"も書く事になります。

(修正ここまで)

自己解決できないとき

コードの書き方について不安がある場合、自分が書けるところまで書いたコードをもとにPull Requestを行いつつ、タイトルに[WIP]というヘッダをつけて打診するとよいでしょう。

また、今後書かれる方は、私の書いたコードがどのように直されて行くのかをご覧頂くと、同じ問題には引っかかりにくくなるのではと思います。

テストコードがどう変わったか?

参考まで、実際にserverspecを用いたテストコードを書くときに、PHPのテストが無い時・ある時でどのように変わったのか示します。同じ評価を行っていますが、後者の方がよりすっきりしているのがおわかりいただけるかと思います。

require 'spec_helper'

describe command("php -i 2>/dev/null | grep -w 'memory_limit' | awk -F' => ' '{ print $3 }'") do
    it { should return_stdout '128M' }
end

describe command("php -i 2>/dev/null | grep -w 'default_mimetype' | awk -F' => ' '{ print $3 }'") do
    it { should return_stdout /text\/html/ }
end

describe command("VAL=$(php -i 2>/dev/null | grep -w 'default_socket_timeout' | awk -F' => ' '{ print $3 }'); test $VAL -le 60; echo $?") do
    it { should return_stdout '0' }
end
require 'spec_helper'

describe 'php config' do
  context php_config('memory_limit') do
    its(:value) { should eq '128M' }
  end 

  context php_config('default_mimetype') do
    its(:value) { should match /text\/html/ }
  end 

  context php_config('default_socket_timeout') do
    its(:value) { should <= 60 }
  end 
end

おわりに

ここまで、serverspecののリソースタイプにPHPの設定テストを書き加えた時の3つの事、「きっかけ」「ファイル構成」そして「記述時の注意点」についてお話しししました。その上で、テストコードがどのように書き変わるかを示しました。実装にあたっては少ないコード量でできますので、実装したいテストが明確であれば、プログラマが本業でない方も取り組む事ができるのではないでしょうか。

また、このPHPのテストは、ITインフラ構築の自動化にはもちろん、プログラマの方がITインフラ担当者に構築を依頼する際のチェック項目をコード化する際にも利用していただけるかと思います。

serverspecは、現代のプログラミングで積極的に用いられている「テストの自動化・反復実行」をITインフラの構築にも適用できるようにした、素晴らしいソフトウェアです。ただ、ITインフラの構築でテストしなければならないものは、serverspecでカバーしているもの以外にも非常にたくさんあります。そこで、自分で気づいたことを「言葉」ばかりではなく「コード」として提案することは、自分自身はもちろん、同じ悩みを持つ人たちに対して何か貢献する事ができるのではと考えています。言い換えれば、悩めたから行動できるのではと思います。

それでは皆様、ごきげんよう。

参考資料