Shiki’s Weblog

ESウェブブラウザ通信 - テストハーネスの使い方

2012/08/19 #ESウェブブラウザ通信

今回はESウェブブラウザでのCSS 2.1 Conformance Test Suiteのヘッドレステスト方法について紹介します。
CSS 2.1 Conformance Test Suiteは、CSS 2.1の実装が仕様通りになされているかどうか判断するためのテスト ページを集めたものです。テストスイートには仕様書の編集者が作成したものだけなく、Internet Explorere, Firefox, WebKitなどブラウザ ベンダーから提供したされたものも含まれています。そのテストページ数はhtml4だけでも9,365ページに及びます。
escortウェブ ブラウザでは、このテストスイートを使ってレンダリング エンジンを開発してきました。その内容については21回にわけてこのブログで報告してきました。仕様書の文面だけでは解釈が分かれそうな箇所についても、テストスイートで確認することによって解釈違いを修正できた場面なども少なくありません。以前も紹介したように、IEBlogでJason Uptonさんが、

The only way to know if a browser has correctly implemented a specification is to develop a comprehensive set of tests for the specification.

と述べられている通り、テストスイートなしに仕様書だけを見て各ベンダー間で互換性のあるウェブブラウザを実装することは現実的には不可能かもしれません。

テスト ハーネス

CSSレンダリング エンジンには高速化や新機能の実装といった形で日々修正が加えられています。そういったときに修正に何か問題があると、それまでパスしていたテストページのテストに失敗して表示が崩れたりすることがあります(リグレッションと呼ばれています)。ですので、原則としては何か修正を行ったらテストスイートのすべてのテストページを再確認しておくべき、ということになります。
一方、CSS 2.1 Conformance Test Suiteの個々のテスト ページは基本的には実際にブラウザで表示して目で見て成否を確認するように作られています。しかし何か修正を加えるたびに9,370ページものページをひとつひとつ目視で確認していたのでは実装ペースを上げることができません。そこでいちいち目視せずに自動でテストを行うためのソフトウェア、テストハーネス、を利用することが重要になってきます。
ESウェブブラウザでは、レンダーツリーのテキスト形式のダンプにpass, failといったタグをつけて記録したログファイルと、実際の実行結果を比較して判定するharnessというプログラムを用意しています。以下ではこのharnessの使ったテスト方法について説明していきます。

テスト環境の構築

1)Apache HTTPサーバーのセットアップ

CSS 2.1 Conformance Test SuiteではApache HTTPサーバー用の.htaccessファイルを利用して、特定のキャラクターエンコードでHTTPファイルを送信するといった指定がされている箇所があります。そのためテスト用のHTTPサーバーとしてはApacheを利用するのが簡単です。
harnessは、いまのところテスト用PC上でローカルに起動されているHTTPサーバーにアクセスするようになっています。Fedoraであれば、

$ sudo yum install httpd

でApacheをインストールして、/etc/httpd/conf/httpd.confを開いて、ServerNameを、

ServerName localhost:80

に、<Directory "/var/www/html">の部分のAllowOverrideを、

AllowOverride All

と変更して、.htaccessを利用できるようにします。あとは、

# systemctl start httpd.service
# systemctl enable httpd.service

のようにすれば、Apacheをいつも起動した状態に設定できます。

2)テストスイートの展開

W3CのサイトからCSS 2.1 Conformance Test Suiteを取得してきます(現在の最新版は20110323.zipです)。これを、/var/www/html/suites/css2.1に展開します。

# cd /var/www/html/suites/css2.1
# wget http://test.csswg.org/suites/css2.1/20110323.zip
# unzip 20110323.zip

3)テスト フォントの展開

CSS 2.1 Conformance Test Suiteを利用すために必要なフォントが、やはりW3Cのサイトから提供されています。これを、/var/www/html/Style/CSS/Test/Fontsに展開します。

# cd /var/www/html/Style/CSS/Test/Fonts
# wget http://www.w3.org/Style/CSS/Test/Fonts/css-testsuite-fonts-v2.zip
# unzip css-testsuite-fonts-v2.zip

今のところ、harnessでテスト中は、ユーザースタイルシート等のサポートファイルに関しては、http経由ではなくて、上記のディレクトリに直接アクセスしています。
これでテストスイートの準備ができました。試しに、http://localhost/suites/css2.1/20110323/ にアクセスしてみてください。下のような画面が表示されれば、正しくセットアップできています。

CSS 2.1 Conformance Test SuiteCSS 2.1 Conformance Test Suite

テストハーネスを使ったテスト方法

テスト結果のレポート形式

CSS 2.1 Conformance Test Suiteのテスト結果のレポート形式については、W3CのCSSWG(CSS ワーキンググループ)で決められていて、下記のサイトにまとめられています:
http://wiki.csswg.org/test/implementation-report
escortウェブ ブラウザでは、今のところhtml4のテストのみ行なっています。そのテスト結果は以下のページから確認することができます:
http://code.google.com/p/es-operating-system/source/browse/trunk/escort/testlog/css2.1/20110323/implement-report-Escort-Fedora.data
r2923の段階ではFedora 17上でescortは約90.8%のテストにパスしていることがわかります。

自動テスト用のログファイルの準備

自動テストを行うためには、まず各テストのタグ付きのログファイルを用意します。はじめてテストするときは目視でひとつひとつテストをチェックしていかないといけません。一方、テスト済みのテストに関しては、implement-report-Escort-Fedora.dataの結果を元にログファイルを自動で生成する機能がharnessにあります。
ログを生成するには、implement-report-Escort-Fedora.dataに対応するリビジョンのビルド ディレクトリで以下のようにコマンドを実行します:

$ mkdir html4
$ ./harness -j16 -g ~/es/trunk/escort/testlog/css2.1/20110323/implement-report-Escort-Fedora.data ./Script.test ~/es/trunk/escort/testdata/default.css --v=2 -geometry +0+0

-g オプションがログファイルの生成を指示しています。-j16 はテストを16プロセスで並行して実行するように指示しています(プロセス数はお使いのCPUに合わせて調整してください)。
./Script.test以降が各テストプロセスで実行するコマンドになります。--vはログレベルの指定です(harnessでは 2 を指定します)。-geometry以降はglutInitが処理する引数になります。
2012/8/24 補足 :r2948以降、ログレベル1だとharnessに対応しなくなっています。2を指定してくださいい。
harnessの実行が終わると(Core i7 3770のPCでは5分前後かかります)、ログファイルがディレクトリhtml4の下に生成されています。

$ ls html4
absolute-non-replaced-height-001.log
absolute-non-replaced-height-002.log
absolute-non-replaced-height-003.log
・・・snip・・・

ちなみにログファイルの中身はこのような感じになっています:
$ cat html4/absolute-non-replaced-height-001.log

$ cat html4/absolute-non-replaced-height-001.log
# html4/absolute-non-replaced-height-001.htm    pass
## render tree
* block-level box [html] (0, 0) w:816 h:17.6783 (0, 0) m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 transparent
  * block-level box [body] (0, 0) w:816 h:17.6783 (0, 0) m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 transparent
    * block-level box [p] (0, 0) w:816 h:17.6783 (0, 0) m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 transparent
      * line box (0, 0) w:581.614 h:17.6783 (0, 0) m:0:0:0:0
        * inline-level box (0, 0) w:581.614 h:17.6783 m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 "Test passes the a filled blue square touches the upper-left corner of the black box." #000000
    * block-level box [anonymous] (0, 17.6783) w:816 h:0 (0, 0) t:0 m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 transparent
      * line box (0, 17.6783) w:0 h:0 (0, 0) m:0:0:0:0
        * block-level box [div] (0, 96) w:288 h:192 (0, 0) m:0:0:0:0 p:0:0:0:0 b:3:3:3:3 transparent
          * line box (3, 99) w:0 h:0 (0, 0) m:0:0:0:0
            * block-level box [div] (3, 99) w:96 h:96 (0, 0) m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 #0000ff

1 行目に実装レポートの形式で結果が記述されていて、2行目以降にScript.testから出力されたレンダー ツリーのダンプが書き込まれています。
なおharnessが保存したり比較したりするレンダー ツリーはloadイベントを処理した直後のツリーになっています。ですので、ページのロードが完了した後でさらにマウスで何か操作したりしないといけないようなテストについてはharnessで完全にテストできているわけではない、という点は注意が必要です。

自動テストの実行と確認

ログファイルの準備ができたので、実際にテストしてみます:

$ ./harness -j16 ~/es/trunk/escort/testlog/css2.1/20110323/implement-report-Escort-Fedora.data ./Script.test ~/es/trunk/escort/testdata/default.css --v=2 -geometry +0+0

harnessをテスト プロセス数を指定する-j16以外のオプションなしで実行すると、比較テストを行います。harnessの戻り値は、何も変化がなければ0に、変化があれば1になります。

$ ./harness -j16 ~/es/trunk/escort/testlog/css2.1/20110323/implement-report-Escort-Fedora.data ./Script.test ~/es/trunk/escort/testdata/default.css --v=2 -geometry +0+0

またテスト結果は、report.dataというファイルに記録されています。何か変化があったテストでは結果が"uncertain"に、実行中にクラッシュしたりタイムアウトしたりしたテストでは結果が"fatal"と記されています。
"uncertain"となったテストを確認したい場合は、まず

$ grep '#\|uncertain' report.data > uncertain.data

のようにして、 表示に変化のあったテストだけを抜き出します。
補足 : grepで#も含めているのは、harnessは#からはじまる行をディレクテブ(命令)として処理していて、指定されたユーザースタイル シートを読み込んだり、テスト用のフォントの有効・無効を切り替えたりしているためです。
続いて以下のように、

$ ./harness -i uncertain.data ./Script.test ~/es/trunk/escort/testdata/default.css --v=2 -geometry +0+0

harnessを -i オプションをつけて実行すると、テストがひとつひとつ表示されて、コマンド プロンプトから結果を再度入力していくことができます。

[html4/absolute-non-replaced-height-001.htm] pass?

このとき単に[Enter]を押せば、ログファイル中に記録されてい判定(この例ではpass)のままログのレンダーツリーだけが更新されます。それ以外の判定を入力する場合は、判定内容を直接タイプするか、以下のような短縮形が使えます:

p   pass    成功
f   fail    失敗
i   invalid テスト自体が無効
n   na      テストしている機能が未実装
q   quit    harnessを終了
z   undo    ひとつ前のテストに戻ってテストをやり直す

また未実装の機能を利用しているためにテストが失敗しているのであれば、短縮形ではなく、

[html4/replaced-intrinsic-001.htm] ? na (svg)

といった具合に入力しておくとあとで調査しやすくなります。

ブラウザの修正中は、このようにいくつかのテストをピックアップして、それらを集中的にテストして進めていくことが多いのですが、それによって思わぬ他のテストが崩れていたりする場合もあるので要注意です。もっと大規模なプロジェクトの場合は、テスト結果が(悪い方向に)変わるようなパッチをコミットできないようにしたりすることもあると思いますが、ESプロジェクトではいまのところそこまで厳格なことはしていなくて、リグレッションはリグレッションで別パッチで後でまとめて修正したりしているのはこれまで報告してきた通りです。

付録: harnessのコマンドライン オプション

harnessコマンドには、-g, -i オプションといったオプション以外にも、次のようなオプションがあります。

-g   レポートファイルの判定を元にログファイルを生成します。
-i   テストをひとつひとつ実行して、結果を入力していきます。
-r   ログファイルからreport.dataを再生成します。
-u   ログファイル中のレンダーツリーのダンプを指定したScript.testからの出力に置換します。

-u は、レンダーツリーのダンプ内容自体を変更したりした場合に利用します。

まとめ

今回はescortウェブ ブラウザのテストを自動化するテスト ハーネスについて紹介しました。harnessプログラム自体もプロジェクトの進展とともに進化している部分もあるので、また何か新しいことがあればこのブログからもお知らせしていきます(データセンターがあればテストに16プロセスなんてケチなことは言わずに、1,024プロセスでテスト時間5秒みたいな感じになりますよね)。
それから一般的にはいわゆる標準規格のテスト スイートは、時間と労力をかけて独自に開発したり、あるいはお金を払ってテスト スイートごと購入したりしなければならないことが少なくありません(数百万円〜/年、数千万円〜/年のようなイメージです)。CSS 2.1 Conformance Test Suiteのような規模なものが無償で手に入るというのは実はすごいことです。もし仮に一律1ページ5,000円だったとしたら、・・・やめときませう f^_^;;
次回は計画中のCSSレンダリング エンジンの改良などについて報告していく予定です。