serverspecの評価結果をjson形式で出力する(複数ホストにも対応)

serverspecの結果を他の仕組みと連携させたい場合など、json形式で出力する方法です。

標準

specに標準でjsonフォーマッターが付いているので、 --format オプション指定するとjson形式の結果が得られます。

bundle exec rake spec SPEC_OPTS="--format json"

カスタマイズ

ただ、もう少し形式や項目カスタマイズしたいとかの場合、自分でカスタムのフォーマッターを作ることができます。

複数ホストへのテスト結果を指定のディレクトリにはき出すように作ってみました。

require 'rspec/core/formatters/documentation_formatter'
require 'specinfra'
require 'serverspec/version'
require 'serverspec/type/base'
require 'serverspec/type/command'
require 'json'

class ServerspecJsonDumper < RSpec::Core::Formatters::DocumentationFormatter
  RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished,
                                        :example_passed, :example_pending, :example_failed

  def initialize(output)
    super
  end

  def example_passed(notification)
    super
    dump_evidence_as_json(notification.example)
  end

  def example_pending(notification)
    super
    dump_evidence_as_json(notification.example)
  end

  def example_failed(notification)
    super
    dump_evidence_as_json(notification.example, notification.exception)
  end

  def dump_evidence_as_json(example, exception=nil)
    if !(json_file_prefix = ENV['JSON_PREFIX']) then
      json_file_prefix = 'serverspec_result_'
    end

    if json_dir = ENV['JSON_DIR'] then
      if Dir.exists?(json_dir) then
        data = example.metadata
        described_class = data[:described_class].to_s.gsub(' ','_').gsub('"','').gsub(File::SEPARATOR,'_')
        description = data[:description].to_s.gsub(' ','_').gsub('"','').gsub(File::SEPARATOR,'_')
        json_file = "#{ENV['JSON_DIR']}/#{json_file_prefix}#{ENV['TARGET_HOST']}-#{described_class}-#{description}.json"

        export_data = {
          :target_host => ENV['TARGET_HOST'],
          :timestamp => Time.now.to_i,
          :described_class => data[:described_class],
          :line_number => data[:line_number],
          :full_description => data[:full_description],
          :started_at => data[:execution_result].started_at,
          :finished_at => data[:execution_result].finished_at,
          :run_time => data[:execution_result].run_time,
          :status => data[:execution_result].status,
          :absolute_file_path => data[:example_group][:absolute_file_path],
          :command => data[:command],
          :stdout => data[:stdout]
        }
        export_data[:exception] =  {
                  :class => exception.class.name,
                  :message => exception.message,
                  :backtrace => exception.backtrace,
        } if exception
        File.open(json_file,'w') do |file|
          str = JSON.dump(export_data,file)
        end
      else
        output.puts RSpec::Core::Formatters::ConsoleCodes.wrap(
          "JSON output directory [#{json_dir}] does not exists.",:pending)
      end
    end
  end
end

実行例

./lib/serverspec_json_dumper.rb として上記のスクリプトを保存しました。

JSONの出力先に JSON_DIR を指定しながら実行します。

bundle exec rake spec SPEC_OPTS="--format ServerspecJsonDumper --require ./lib/serverspec_json_dumper.rb" JSON_DIR="./data"

ファイル名はここで指定してるので適当に変更して使ってください。 TARGET_HOST をキーにしていると複数ホストに実行した場合もファイル名が被ることありません。

described_class = data[:described_class].to_s.gsub(' ','_').gsub('"','').gsub(File::SEPARATOR,'_')
description = data[:description].to_s.gsub(' ','_').gsub('"','').gsub(File::SEPARATOR,'_')
json_file = "#{ENV['JSON_DIR']}/#{json_file_prefix}#{ENV['TARGET_HOST']}-#{described_class}-#{description}.json"