テスト出力のノイズを除去する複数の改善
Pumaのテスト実行時に余分な出力が混入していた問題を解消するため、ビルドの静粛化・非推奨警告のキャプチャ・テストヘルパーのリファクタリングなど、複数の改善がまとめて適用されました。
背景
テストが成功している(グリーン)にもかかわらず、標準出力やエラー出力にノイズが混入していました。このPRのタイトル「No stuff in my green dots.」が示す通り、. だけが並ぶはずのクリーンなテスト出力が、警告メッセージやビルドログによって汚染されていたことが動機です。
出力ノイズの発生源は大きく3つありました。C拡張のビルド時に make が出力するログ、非推奨メソッドが呼ばれた際に $stderr へ直接書き出される警告、そしてURLマップのテストで有効化されていた log: true オプションです。
技術的な変更
複数のファイルにまたがる変更が、それぞれ独立したノイズ源を排除しています。
Rakefileのビルド出力の抑制では、task :test => [:compile] の直接依存を compile_for_test という中間タスクに切り替えました。このタスクは ENV["MAKEFLAGS"] に -s(silent)フラグを追加してから :compile を呼び出し、ensure ブロックで元の値を確実に復元します。
task :compile_for_test do
original_makeflags = ENV["MAKEFLAGS"]
ENV["MAKEFLAGS"] = [original_makeflags, "-s"].compact.join(" ")
Rake::Task[:compile].invoke
ensure
ENV["MAKEFLAGS"] = original_makeflags
end
task :test => [:compile_for_test]
ensure により、compile が例外で失敗した場合でも MAKEFLAGS が汚染されたままにならないよう環境変数が保護されています。
test/test_config.rbの非推奨警告のキャプチャでは、on_booted・on_restart・on_stopped の3つの非推奨エイリアスに関するテストが修正されました。これらのテストはこれまで警告メッセージを $stderr へ素通りさせていましたが、capture_io ブロックで囲むことで出力をキャプチャし、警告メッセージの内容を assert_match で検証するようになりました。
# 変更前: 警告がそのまま $stderr に流れていた
conf = Puma::Configuration.new do |c|
c.on_booted { ran = true }
end
conf.clamp
conf.events.fire_after_booted!
assert ran, "on_booted callback should have run"
# 変更後: 警告をキャプチャして内容も検証する
err = capture_io do
conf = Puma::Configuration.new do |c|
c.on_booted { ran = true }
end
conf.clamp
conf.events.fire_after_booted!
end.last
assert_match(/Use 'after_booted', 'on_booted' is deprecated and will be removed in v8/, err)
assert ran, "on_booted callback should have run"
この変更は出力を抑制するだけでなく、警告の内容が正しいかどうかも検証するという点で、テストの品質も向上させています。
test/test_request_single.rbのヘルパーリファクタリングでは、create_client メソッドに peer_addr: キーワード引数が追加されました。従来、カスタムの peeraddr を設定するには create_client のブロック内で @rd.define_singleton_method を直接呼び出す必要がありましたが、新しいインターフェースではメソッド引数として渡せるようになりました。
# 変更前
create_client("GET / HTTP/1.1\r\n\r\n") { |_client|
@rd.define_singleton_method(:peeraddr, peer_addr)
}
# 変更後
create_client("GET / HTTP/1.1\r\n\r\n", peer_addr: peer_addr)
test/test_url_map.rbでは、cli_server の呼び出しから log: true オプションが単純に削除されています。
lib/puma/cluster/worker.rbでは、テスト出力とは別に、rescue IOError が rescue SystemCallError, IOError に拡張されています。IOError は一部のシステムコール起因のエラーをカバーしないため、SystemCallError(Errno::EPIPE などのスーパークラス)を追加することで、パイプ書き込み失敗などのケースでも適切に break できるようになっています。
設計判断
環境変数の汚染防止に ensure を使用した点は注目に値します。ENV["MAKEFLAGS"] = "-s" と上書きする最も単純な実装も考えられますが、既存の MAKEFLAGS が設定されている環境での動作や、ビルド失敗時の状態保全を考慮し、compact.join による既存値との結合と ensure による復元が採用されました。
非推奨警告の「抑制」ではなく「検証」への転換も重要な設計判断です。capture_io の戻り値から stderr を取り出して assert_match で検証することで、「警告が出ないこと」ではなく「正しい警告が出ること」を担保する方向に改善されています。非推奨警告のメッセージが将来変更された場合にテストが失敗するようになるため、リグレッションの検出能力が高まっています。
まとめ
このPRは、テスト出力のノイズ除去という実用的な目的のもと、ビルドの静粛化・テストアサーションの強化・ヘルパーのインターフェース改善・エラーハンドリングの堅牢化という4つの独立した改善を一度に実現しています。「グリーンなテストはクリーンに」という原則の徹底が、コード品質全体の底上げにつながっている変更です。