BFT名古屋 TECH BLOG

日々の業務で得た知識を所属するエンジニアたちがアウトプットしていきます。

【Serverspec】【Ruby】文字列マッチのエスケープ処理

はじめまして!
餃子とビールがだいすきな BFT名古屋支店の猫です!

入社してから約1年、たくさんのことを学びました。
これからはインプットと合わせてアウトプットの練習も頑張っていきたい! というか書かないと忘れる!
ということで、備忘録的な感じで書いていきたいと思います。

題して、『新卒インフラ女子の備忘録 part1』!
今回はインフラ業界でも流行りの "自動化"技術 の一つである、Serverspecについてです。

はじめに

Serverspecでファイルの中身や標準出力などをテストする際、文字列マッチを行います。マッチさせる文字列が特殊文字を含む場合、エスケープ処理をする必要があります。
エスケープ処理をすべて手で行おうとすると、以下のようなデメリットが発生します。

  • 人的ミスの発生
  • コードの可読性の低下
  • コードのメンテナンス性の低下

これは望ましいやり方とは言えないですよね。

そこで、今回は "簡単に" エスケープ処理を行う方法をご紹介したいと思います。

エスケープ処理が必要になる場合

まず、エスケープ処理が必要な場合とはどんな場合でしょうか。
例えば <Attribute Name=“LogicalProc”>Enabled</Attribute> という文字列を、マッチさせる文字列としてコードにする場合

its(:content) { should match /<Attribute Name=“LogicalProc”>Enabled</Attribute>/ }
と書きたいところです。

しかし、この書き方では、rubyの構文で意味を持つ "/ が邪魔をして、狙った通りのテストができません。
そのため、以下のようにエスケープ処理をする(\を追加する)必要があります。
its(:content) { should match /<Attribute Name=\“LogicalProc\”>Enabled<\/Attribute>/ }

この処理を、漏れなく、速く、大量の箇所に行うのは大変な作業です。

解決策

解決策としては、「コードに組み込む」ことです。 具体的には以下の3ステップを行います。

  1. マッチさせる文字列を変数に格納
  2. エスケープ処理
  3. 文字列マッチ

順番にご説明します。

1. マッチさせる文字列を変数に格納

マッチさせる文字列が一行の場合
Rubyの%記法を使用します。
どちらを使っても意味は同じです。文字列の中身と囲い文字([],!!)が重複しない方を使用します。

target=%Q[<マッチさせる文字列>]

target=%q!<マッチさせる文字列>!

マッチさせる文字列が複数行の場合
Rubyのヒアドキュメントを使用します。
一行だけど囲い文字どっちも入ってる…という場合にも使用できます。
target=<<'EOF'
<マッチさせる文字列>
EOF

%記法、ヒアドキュメントについては以下のサイトをご参照ください。

docs.ruby-lang.org

2.関数でエスケープ処理

テスト対象がLinuxサーバの場合
Regexp.escapeに先ほど文字列を格納した変数を渡します。
返り値を格納する変数は別のもの(target_escape等)を用意してもいいのですが、めんどくさかったので 今回は同じtargetに格納しています。

target=Regexp.escape(target)

テスト対象がWindowsサーバの場合
Linux同様、Regexp.escapeを用います。
改行コードがLinuxと異なるため、gsubで置換する処理を追加で行います。
target=Regexp.escape(target)
target=target.gsub(/\\n/,"\\\\r\\\\n")

Regexp.escape、gsubについては以下のサイトをご参照ください。

docs.ruby-lang.org

docs.ruby-lang.org

3.文字列マッチ

変数を代入して文字列をマッチさせます。

describe file('<ファイルパス>') do
    its(:content) { should match /#{target}/ }
end

コード例

2つ紹介します。
マッチさせる文字列が一行&テスト対象がLinuxサーバの場合

target=%Q[<Attribute Name=“LogicalProc”>Enabled</Attribute>]

target=Regexp.escape(target)

describe file('/etc/hogehoge/hugahuga') do its(:content) { should match /#{target}/ } end


マッチさせる文字列が複数行&テスト対象がWindowsサーバの場合
target=<<'EOF'
cd c:\scripts\wanwan\nyannyan
copy *.* c:\scripts\wanwan\back
EOF

target=Regexp.escape(target) target=target.gsub(/\\n/,"\\\\r\\\\n")

describe command('Get-Content C:\scripts\backup.bat') do its(:stdout) { should match /#{target}/ } end



使用しているリソースについては、以下をご参照ください。

serverspec.org

終わりに

自動化ツールはすでに便利なものですが、工夫して使用することで、構築やテストのさらなる効率化を目指すことができます。

今回は、『文字列マッチのエスケープ処理を簡単に行う』ことについてご紹介しました。
文字列マッチに悩んでいる方の一助となれば幸いです。

以上、新卒インフラ女子の備忘録 part1でした!