Rubyで書いたmilterをテストするには

先日リリースしたmilter manager 2.0.4でmilterのテストを自動化するのに便利な機能を追加したので紹介します。

ここではテスティングフレームワークとしてtest-unitを使います。 なおmilter managerはインストール済みであるとします。1

milter-test-sample にサンプルコードを置いておきます。

件名に「EMERGENCY」と入っていたら、定められた宛先にもメールを送信するという動作をするmilterを作成します。 件名で判断して宛先を追加するのはPostfixではheader_checksのフィルタアクションを使えばできなくはないですが、少々手間がかかります。

milterのコードはこんな感じです。2 3

require "milter/client"

class MilterTransfer < Milter::ClientSession

  EMERGENCY_ADDRESSES = [
    "emergency@example.com",
    "root@example.com",
  ]


  def initialize(context, options)
    super(context)
  end

  def header(name, value)
    if /\ASubject\z/i =~ name
      @need_transfer = true if /EMERGENCY/ =~ value
    end
  end

  def end_of_message
    if @need_transfer
      EMERGENCY_ADDRESSES.each do |address|
        add_recipient(address)
      end
    end
  end

  def reset
    @need_transfer = false
  end
end

テストは以下のように書くことができます。一部を抜粋します。全体はリポジトリを見てください。

class TestMilterTransfer < Test::Unit::TestCase

  SPEC = "inet:20025"

  def setup
    @server = ::Milter::TestServer.new
    @milter_runner = ::Milter::Client::Test::MilterRunner.new(milter_path("milter-transfer"))
    @milter_runner.run
  end

  def teardown
    @milter_runner.stop
  end

  def test_no_emergency_mail
    result = @server.run(["--connection-spec", SPEC],
                         ["--mail-file", fixture_path("no-emergency.eml")],
                         ["--envelope-from", "from@example.com"],
                         ["--envelope-recipient", "to@example.com"])
    assert_equal("pass", result.status)
    assert_recipients(["to@example.com"], result.envelope_recipients)
  end

  def test_emergency_mail
    result = @server.run(["--connection-spec", SPEC],
                         ["--mail-file", fixture_path("emergency.eml")],
                         ["--envelope-from", "from@example.com"],
                         ["--envelope-recipient", "to@example.com"])
    assert_equal("pass", result.status)
    assert_recipients(["to@example.com"] + MilterTransfer::EMERGENCY_ADDRESSES,
                      result.envelope_recipients)
  end
end

milterを起動してmilter-test-server4で叩いて結果をチェックしています。 milterプロトコルを使ってテストしているので、このテストが全部パスしていればMTAに組み込んだ場合でも正常に動作することが期待できます。

また MTA に組み込んだあとに、発生した不具合を修正したときに書くリグレッションテストにも使うことができます。

まとめ

Rubyで書いたmilterのテストを書く方法を紹介しました。

  1. インストール方法についてはmilter managerリファレンスマニュアルを参照してください。 

  2. Rubyでのmilter開発についてはRubyでmilter開発を参照してください。 

  3. NKFを使えばMIMEエンコードされたヘッダも簡単に処理することができます。 

  4. milter managerに同梱されているmilterプロトコルを話すプログラム