Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Mochitest

この記事内
    1. テストを実行する
      1. テストスイート全体を実行する
      2. テストを選択して実行する
    2. Gecko 2.0 およびそれ以降で特定のテストを実行する
      1. 個々のテストのデバッグ
      2. エラーを探す
      3. 結果のロギング
      4. Xの出力を迂回させる
      5. runtests.pyのその他のオプション
    3. テストを書く
      1. Mochitestを使わない事を試みる
      2. テストのテンプレート
      3. テスト関数
      4. ヘルパー関数
    4. テストをツリーに追加する
      1. 場所の選択
      2. Makefileの変更
      3. ビルドと新しいテストの実行
    5. SSLとhttpsを有効にしたテスト
      1. 動作させる方法
    6. スタックトレースの取得
    7. FAQ
      1. onloadイベントの時に実行されるようなテストが動かない時はどうすればいいですか?
      2. テストの中で設定(Preference)を変える必要がある時はどうすればいいですか?
      3. テストはChrome URLの中でも実行できますか?
      4. どうすれば「Permission denied to get property XPCComponents.classes」エラーを回避できますか?
      5. Mochitestで使われるファイルのHTTPヘッダやステータスを変えるにはどうすればよいですか?
      6. 複数のドメインに渡って実行されるテストでのみ発生する事象をテストするにはどうすればよいですか?
      7. HTTPリクエストのヘッダの値、メソッドの種類などを確認するテストはどのように書けばよいですか?
      8. 異なるサーバサイドスクリプトの間で状態を引き継ぐにはどうすればよいですか?
      9. 非同期にレスポンスを返す SJS スクリプトはどのように書けばいいですか?
      10. SJS スクリプトからサーバ上にあるファイルに XPCOM オブジェクトとしてアクセスするにはどうすればよいですか?(Gecko 1.9.3 およびそれ以降の場合)

Mochitestは、MochiKit JavaScriptライブラリに基づいて構築された自動テストフレームワークです。これはMozillaによって利用されている、後退バグの自動テストフレームワークの一つです。テストはテストハーネスに対して、JavaScriptの関数を用いて成功あるいは失敗の旨を報告します。

Mochitestのユニークな特長は、Webページの形で書かれたテストを、完全なブラウザ環境の中でChrome(に昇格した)特権付きで実行できるという点です。これは、他のフレームワークでできることよりも非常に多くの事をテストの中のJavaScriptでできるようにします。通常のスクリプトが可能な事(DOM操作など)に加えて、テストのスクリプトはXPCOMコンポーネントやサービス、そしてブラウザそれ自体にすらもアクセスする事ができます。これによって、例えば、入力が意図されたとおりの結果をもたらすかどうかを確認するために、ブラウザのユーザーインターフェースに対してユーザによる入力をシミュレートして渡すなどのことができます。

Mochitestにおける、テストの成否を通知するためのJavaScript関数の呼び出し方は、いくつかの種類のテストに対しては不向きです。(Chrome特権付きの)JavaScriptによってテストできるような内容だけが、このフレームワークを使ってテストできます。創造性を発揮する事によって、あなたが最初に考えているよりもずっとたくさんの事ができますが、しかし、例えばスクリプトではないC++のコンポーネントを直接テストするようなMocihkitテストを書く事は不可能です(それを行うにはコンパイル済みコードのテストを使ってください)。

テストを実行する

MozillaのビルドマシンはMochitestをビルドの過程の一つとして実行します。そのため、誰かがソースコードにコミットした変更が何かを壊していれば、それを極めて迅速に知る事ができます。しかし依然として、あらゆる新しい危険性のあるコードをコミットする前には、あなた自身の手でMochitestを走らせておくべきです。あなたも、避けられるなら、ツリーを壊して他のみんなの時間を無駄にさせる元凶になどなりたくないでしょう? :-)

テストスイート全体を実行する

Mochitestを実行するには、まずあなたが行った変更を含めてMozillaをビルドします。次に、以下のようにします:

  • 1.9.1およびそれ以降(bug 417516が修正されて以降)では、トップレベルのディレクトリで以下のコマンドを実行してください:
    • make -C $(OBJDIR) mochitest-plain
  • それより古いブランチでテストを行う場合は、Mochitestのruntests.pyスクリプトをオプション指定無しでコマンドラインから実行してください:
    • cd $(OBJDIR)/_tests/testing/mochitest
      python runtests.py

Image:Mochitest.png

注意: テストを実行している間は、ブラウザウィンドウがフォーカスされた状態を保つべきです。そうでないと、いくつかのテストが失敗する事があります(例えばバグ 330705のテストがそうです)。Linuxユーザは、ダミーのXサーバを使う事でその状態を保存する事ができます(後述のXの出力を迂回させる手順を参照してください)。

テストを選択して実行する

テストを一つだけ実行する場合(あなたが書いたばかりの新しいテストなど)や、Mochitestスイート全体のうち一部分だけを実行する場合は、runtests.pyの--test-pathオプションを使って、実行したいテストまたはサブディレクトリを指定してください。例えば、Mozillaのソースツリーのtest_CrossSiteXHR.htmlのテストだけを実行したい場合は、以下のようなコマンドを使う事になります:

TEST_PATH=content/base/test/test_CrossSiteXHR.html make -C $(OBJDIR) mochitest-plain

あるいは、mochitest-plain targetがサポーとされていないブランチでは以下のようにします:

python runtests.py --test-path=content/base/test/test_CrossSiteXHR.html

content/svg/の中にあるすべてのテストを実行する場合は、以下のコマンドを使います:

TEST_PATH=content/svg/ make -C $(OBJDIR) mochitest-plain

--test-pathによって指定されるパスは、Mozillaのソースツリー内のテストまたはディレクトリへの物である事に注意してください。パスがディレクトリの場合、そのディレクトリおよびすべてのサブディレクトリ内のテストが読み込まれます。

Gecko 2.0 およびそれ以降で特定のテストを実行する

Gecko 2.0 が必要(Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)

Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) から、mochitest-1 から mochitest-5 までを make コマンドで簡単に実行できるようになりました。例:

make mochitest-1

これによって、すべてのテストスイートを実行したり、トライサーバの buildbot のコードを調べて特定のテストだけを実行するための書き方を調べる代わりに、buildbot の挙動を真似る事ができます。

個々のテストのデバッグ

ある1つのテストについてデバッグする必要が生じた場合に、そのテストだけを実行するために、Firefox にデバッガをアタッチし、デバッガがアタッチされた状態でテストを含むページをリロードするのにも、前述の方法が利用できます。もし問題が起こる前にデバッガをアタッチする事が難しい場合には(例えば、テストが読み込まれた時にブラウザがクラッシュするような場合)、以下のようにしてテストスイート全体をまず最初に実行できます:

python $OBJDIR/_tests/testing/mochitest/runtests.py

この時、デバッガをアタッチして、新しいタブを開き、"https://mochi.test:8888/tests/PATH/TO/MY/TEST" のようにテストを手動で指定することができます。例: "https://mochi.test:8888/tests/modules...ginstream.html"

あるいは、あなたはmochitestの実行時にデバッガを指定するよう試みるかもしれません:

TEST_PATH='...' EXTRA_TEST_ARGS='--debugger=gdb' make mochitest-plain

引数の --debuggerArgs と --debuggerInteractive も参照してください。

エラーを探す

予期されない失敗を探すには、「TEST-UNEXPECTED-FAIL」という文字列を検索してください。最終的なテストの実行結果の要約を見るには「SimpleTest FINISHED」を検索してください。連結されたログではMochitestの出力は最後にあるとは限らないので、すべてのTinderboxのログをまとめて見る時に、後者は特に便利です。

結果のロギング

テストの実行による出力は、コンソールおよび(または)ファイルに送る事ができます(デフォルトでは、結果はブラウザ上にのみ表示されます)。出力の詳細さはいくつかのレベルで指定できます。DEBUG、INFO、WARNING、ERROR、FATALの各レベルがあり、DEBUGでは出力は最も詳細(すべて出力)になり、FATALでは出力は最も少なく(テストを中断させるようなイベントが発生した時だけメッセージを出力)なります。

ファイルにログを保存するには --log-file=ファイルのパス オプションを使います。デフォルトではファイルへのログ出力レベルはINFOですが、--file-level=レベル オプションを使う事でレベルを変更できます。

コンソールへのログ出力を有効にするには、--console-level=レベル オプションを使います。

例えば、テスト実行時の出力を ~/mochitest.log というファイルにDEBUGレベルの詳細さで保存したい場合は以下のようになります:

python runtests.py --log-file=~/mochitest.log --file-level=DEBUG

Xの出力を迂回させる

テスト実行中のコンピュータでユーザが行うあらゆる他の操作による影響を防ぐために、テストは必ずフォーカスされたウィンドウの中で実行されなくてはなりません。Linuxユーザはスイートに指示を与える事で、不可視の仮想デスクトップを使うようにすることができます。もしXvfbがインストールされている、またはインストールできる場合は、以下のコマンドは現在のセッションをブロックすることなくテストを実行します。:

nice xvfb-run python _tests/testing/mochitest/runtests.py --log-file=./mochitest-plain.log --file-level=DEBUG --autorun --close-when-done --console-level=DEBUG

他に可能な設定については、バグ 434365で議論されています。

runtests.pyのその他のオプション

runtests.pyスクリプトは他にもいくつかのオプションを解釈します。それらの一覧を見るには --help オプションを使ってください。ちなみに、--chrome--browser-chrome--a11yの各オプションについては個別のドキュメントがあります。

テストを書く

Mochitest用のテストファイルは、いくつかの条件についてテストを行うJavaScriptを含んだシンプルなHTML、XHTML、またはXULのファイルです。

Mozillaをビルドせずに大部分のテストを実行するために、Mochitest makerを利用できます。

Mochitestを使わない事を試みる

はい、これは冗談ではなく本当にです。様々な理由のために、Mochitestは過剰な物となっています。一般的な用途では、より軽量なテストフレームワーク使うように常に試みる事をお勧めします。例えば、ある一つのXPCOMコンポーネントをテストしたいだけであれば、xpcshellを使うべきです。また、Mochitestにもできない事や、それをするようには設計されていないという事がいくつかあります。こちらの例は視覚的な出力についてのテストで、その場合はreftestフレームワークを使うのがお勧めです。他の異なる種類の自動テストフレームワークについての情報は、Mozillaの自動テストを参照してください。

テストのテンプレート

定型的な内容を毎回入力する手間を省くために、gen_template.pl Perlスクリプトがテストのテンプレートの生成に利用できます。このスクリプトは2つの省略可能な引数を取ります:

  1. -b : バグの番号。
  2. -type : 連符レートの種類。html、xhtml、xul のいずれかを選択する。デフォルトはhtml。

利用例:

cd mozilla/testing/mochitest/
perl gen_template.pl -b=123456 > path/to/test_bug123456.html
perl gen_template.pl -b=123456 --type=xul > path/to/test_bug123456.xul

Mochitest ではすべてのテストのファイル名は「test_」で始まっている必要がある事に注意してください。テストをツリーのどの位置に置けばよいのかを決める手助けとしては、後述の内容を参照してください。

Mochitest の定型的なコードに加えて、このスクリプトは 'content' という id を持った要素と 'display' という id を持った要素も生成するでしょう。あなたが書くテストでは、これらを他のあなたが追加する要素と同様に操作して構いません。

テスト関数

個々のテストは、Mochitestに対してテストが成功したのか失敗したのかを通知するために実行されるいくつかのJavaScriptを含んでいる必要があります。 SimpleTest.js は、テストにおいてMochitestにテストの成否を知らせるための様々な関数を含んでいます。これらには以下の物が含まれます:

  • ok(trueになるべき文, "エラーメッセージ") -- 値が真である事をテストする。
  • is(実際の値, 期待される値, "エラーメッセージ") -- 二つの値を比較する(===ではなく==を使用)。
  • isnot(実際の値, 期待されない値, "エラーメッセージ") -- is()の逆。

これらの関数の使い方の例は、 README を参照してください。

もし、現在のところは失敗するというテストを含めたい場合、単にその部分をコメントアウトしないでください! その代わりに、 相当する「todo」を使ってください。これによってTinderboxは、不意にテストが成功するようになった時に、(いつの時点でテストが成功するようになったのかを)知らせる事ができます。:

  • todo(今はfalseになるが本当はtrueになるべき文, "エラーメッセージ")
  • todo_is(実際の値, 期待される値, "エラーメッセージ")
  • todo_isnot(実際の値, 期待されない値, "エラーメッセージ")

ヘルパー関数

現時点では、すべてのMochikitの機能が利用できます(これはバグ 367393によって変わるでしょう)。バグ 367569で、ヘルパー関数としてsendCharsendKeysendStringが追加されました。これらはtesting/mochitest/tests/SimpleTest/EventUtils.jsにおいて利用できます。

テストをツリーに追加する

新しいテストを書いたら、すぐにそれをMozillaのソースツリーに追加して、ビルドシステムにその事を通知する必要があります。これによって、Mozilla tinderboxはそれを自動的に実行するようになります。

場所の選択

新しいMochitestのテストはテストされるコードの近くのどこか、できれば同じモジュールに置かれるべきで、これにより、テストケースが何のための物なのかが明確になります。例えば、あるHTMLの機能のテストを作成した場合、おそらく、テストをcontent/html/content/testまたはcontent/html/document/testに置きたいと思うでしょう。もしも、テストしようとしているコードの近くにテスト用のディレクトリがなければ、バグ 368531のパッチで実際にそうしているように、新しいテスト用のディレクトリを作成する事ができます。

Makefileの変更

あなたが書いた新しいテストの事をビルドシステムに通知するために、あなたが書いたテストファイルの名前をそのテストディレクトリのMakefile.inの中の_TEST_FILESに追加する必要があります。

もしもあなたが書いたテストが複数のファイルに渡っているなら、その場合はメインのファイルの名前を「test_...」としてください。これは実行するテストのリストに登場する名前となります。他のファイルはそれ以外の名前になっているべきですが、Makefile.in_TEST_FILESに追加されなければならないという点は変わりません。

Chromeのテストを追加する場合、テストを _tests/testing/mochitest/tests ではなく _tests/testing/mochitest/chrome にインストールするようMakefileを変更する事を忘れないでください。

ビルドと新しいテストの実行

新しいテストをコミットする前に、Makefile.inの変更内容が正しく、また、あなたが書いたテストが期待通りに成功する事を確認してください。あなたが書いたテストを確認するには、まず、以下のコマンドでそのテストをMochitestのディレクトリ(ソースツリーのテストファイルの位置と同じ場所)に取り出してください:

make

次に、Mochitestを前述の通りに開きますが、この時、「Run Tests」リンクをクリックする代わりに、あなたが書いたテストを一覧から探してそれをクリックしてください。

SSLとhttpsを有効にしたテスト

Mochitestのテストは、正常な動作のために https://localhost:8888 で実行されなくてはなりません。しかし、テストの中にはオリジンが異なる場合のための機能のテストとして、他のプロトコル、ホスト、ポートを使う必要があるものもあるでしょう。Mochitestのテストハーネスは、元のサーバのすべてのコンテンツをproxy autoconfigとSSLトンネリングを用いて他の様々なサーバに同期(ミラー)することで、この問題を解決します。テストを実行したいすべてのスキーム、ホスト、ポートのリスト(それらはすべて https://localhost:8888 と完全に同じコンテンツを返す必要があります)はbuild/pgo/server-locations.txtで指定します。ただし、そこに記述されたオリジンのすべてが完全に同じである必要はありません。テスト用として特定のSSL証明書を指定された物や、そのサーバ上のページで特権の昇格の要求を許可する物も設定できます。完全な詳細説明については、ファイルの内容を参照してください。

動作させる方法


Mochitestのハーネスは、要求されたURLをサーバにマッチさせるためにブラウザにproxy autoconfig を使わせる設定を含んでいます。network.proxy.autoconfig_url の設定は、要求されたURLがマップされているホストを認識するためのFindProxyForURLという JavaScript 関数をエンコードしたdata: URLがセットされます。SSLのサイトがミラーされる場合、その関数はリクエストを、RFC 2817で定められたCONNECTメソッドによる説明に応じて、トラフィックを実際のサーバへ透過的に転送するSSLトンネルにマップします。このようにして、https://127.0.0.1:8888に立てられた単一のサーバは異なる場所を示す何十ものサーバをエミュレートします。

MochitestのSSL関連の機能や、署名を変更する方法、新しいhttpsのサーバを追加する手順などのさらに詳細な説明については、MochitestのSSLの動作の変更を参照してください。

スタックトレースの取得

Mochitest がクラッシュした時のスタックトレースを取得する方法は以下の通りです:

  1. https://hg.mozilla.org/build/tools/fi...e49a/breakpad/ からあなたのプラットフォーム用の minidump_stackwalk のバイナリを取得します。
  2. 環境変数 MINIDUMP_STACKWALK にそのバイナリのパスを指定します。

もし結果のスタックトレースが行番号を含んでいない場合には、必須のシンボルファイルを生成するために make buildsymbols を実行して下さい。詳しくは Firefox をデバッグ用のシンボル付きでビルドするを参照して下さい。

FAQ

onloadイベントの時に実行されるようなテストが動かない時はどうすればいいですか?

onloadイベントが発行される前に SimpleTest.waitForExplicitFinish() を呼んでください。その場合は、テストを完了したら SimpleTest.finish() を呼んでください。

テストの中で設定(Preference)を変える必要がある時はどうすればいいですか?

netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
                            .getService(Components.interfaces.nsIPrefService);
var domBranch = prefService.getBranch("dom.");
var oldVal = domBranch.getIntPref("max_script_run_time");
domBranch.setIntPref("max_script_run_time", 0);

// 必要な処理(テストの内容)

domBranch.setIntPref("max_script_run_time", oldVal);

あるテストを実行している間だけ設定を変更する必要がある場合には、make target mochitest-plain を実行する時に環境変数 EXTRA_TEST_ARGS を設定して下さい。

EXTRA_TEST_ARGS='--setpref=javascript.options.jit.chrome=false'

文字列型の設定を変更する必要がある場合は、バックスラッシュでエスケープしたダブルクォートで文字列を括ります:

EXTRA_TEST_ARGS='--setpref=webgl.osmesa=\"libOSMesa.so.6\"'

テストはChrome URLの中でも実行できますか?

はい。 python runtests.py --chrome を使ってください。ただしXPCOMをテストするための最初の選択肢としてはxpcshellテストハーネスを使うべきであることを心に留めておいてください。Mochitestが必要になるのは、イベントやブラウザの機能、ネットワーク関係の機能がテストに必要な場合だけです。

どうすれば「Permission denied to get property XPCComponents.classes」エラーを回避できますか?

以下の行をあなたの書いたテストファイル(およびそれぞれのイベントハンドラ)に書き加えてください。すべてのXPCOMが利用できるようになるでしょう。

netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');

この方法は明らかに不便です。これこそが、テスト実行用にテストをChromeのディレクトリにコピーするのに必要なハックを行おうと私たちが作業している理由です。

Mochitestで使われるファイルのHTTPヘッダやステータスを変えるにはどうすればよいですか?

テキストファイルを作成して、ヘッダを変えたいと思っているファイルの隣に置いてください。テキストファイルの名前はヘッダを変えようとしているファイルの名前の末尾に ^headers^ を付けた物にします。例えば foo.jpg というファイルがある場合は、テキストファイルの名前は foo.jpg^headers^ となります。(ヘッダ指定用のファイルはテストの中で他の目的では使わないでください。HTTPサーバの不可視ファイル機能は、「^」で名前が終わっているすべてのファイルを見えなくするからです。)そして、あなたが設定したいヘッダおよび(もしくは)ステータスをそのファイルの内容として記述してください。例:

HTTP 404 Not Found
Content-Type: text/html
Random-Header-of-Doom: 17

最初の行はそのファイルに関連付けられたHTTPステータスと(任意で)説明文を設定しています。この行は省略可能で、通常のレスポンスステータスと説明文で問題ない場合は記述する必要はありません。他の行は、レスポンスヘッダ中で追加または上書きしたい(後者の最も典型的な例はContent-Typeヘッダでしょう)、そのファイルについて説明する追加のヘッダです。様式はHTTPの仕様でのものと同じですが、HTTPの行末を示す必要は無く、一つのヘッダを複数書く事はできません(同じヘッダを複数回多場合は最後の物だけが有効となります)。 ファイルはUnixのテキストファイルの様式に沿って一つの空行で終わる場合がありますが、それは厳密に必要というわけではありません。

複数のドメインに渡って実行されるテストでのみ発生する事象をテストするにはどうすればよいですか?

Mochitestのハーネスはテストを行うために一つのWebサーバだけを起動しますが、proxy autoconfigの働きにより、すべてのテストファイルは異なるドメイン、異なるポートで実行できます。これらのサーバ(権限昇格のための機能に関する2つの例外を除く)で動作しているあらゆるテストは自動的に、UniversalXPConnectなどの特権の取得を要求する事ができるようになります。テストの実行が可能で、https://localhost:8888と全く同じコンテンツを提供するドメインとポートの完全なリストは、build/pgo/server-locations.txtで指定されます。

HTTPリクエストのヘッダの値、メソッドの種類などを確認するテストはどのように書けばよいですか?

その種のテストを書くには、それ用のSJS(server-side JavaScript)を書くだけでよいです。SJSは sjs という拡張子を持つ単純なJavaScriptファイルで、サンドボックス内に読み込まれます。スクリプト内でグローバルな名前空間において handleRequest という名前で定義された関数は、リクエストとレスポンスのオブジェクトを伴って実行され、そのスクリプトはリクエストの情報に基づいてレスポンスを生成します。

以下は単純なSJSの例です:

function handleRequest(request, response)
{
  // avoid confusing cache behaviors
  response.setHeader("Cache-Control", "no-cache", false);

  response.setHeader("Content-Type", "text/plain", false);
  response.write("Hello world!");
}

引数として渡されるリクエストとレスポンスのオブジェクトが持つ正確なプロパティは、nsIHttpServer.idlnsIHttpRequestMetadatansIHttpResponse インターフェースとして定義されています。ブラウザはあなたが書いたスクリプトによって生成されたレスポンスを自由にキャッシュする事に気をつけてください。もしSJSが同じURLへの複数のリクエストに対して異なるデータを返したい場合は、   Mochitestの同じセッションで手動で複数回実行された際にテストが意図せず失敗してしまう事を防ぐために、レスポンスに Cache-Control: no-cache ヘッダを加えるとよいでしょう。

reftestにおけるSJSの簡単な利用例としては、check-header.sjsがあります。

異なるサーバサイドスクリプトの間で状態を引き継ぐにはどうすればよいですか?

Mochitest のサーバサイドスクリプトは、それぞれの読み込みごとに新たに生成されるサンドボックスの中で実行されます。そのため、ハンドラの中で定義されたいかなる変数も、それぞれの読み込みごとの実行コンテキストを超えて状態を保持し続ける事はありません。状態を保存する手助けとしては、グローバルオブジェクトにおいて定義されている getState(k) および setState(k, v) メソッドを利用します。これらのメソッドはキーと値(どちらも文字列を使用)によるストレージの仕組みをサーバに提供します。(オブジェクトやその他の構造化されたデータを保存するにはJSONを使用してください。)Mochitest における無数のサーバが、プロキシとトンネリングによってそう見せられているだけで実際には単一のサーバであるために、保存された状態はすべてのサーバで常に同じとなることに注意してください。

getState および setState メソッドは、サーバサイドスクリプトが読み込まれた時点のパスでスコープが決まります。/foo/bar/baz, /foo/bar/baz?quux, /foo/bar/baz#fnord のような絶対 URL はすべて同じ状態を共有します(この場合 /foo/bar の状態はそれらとは別に保持されます)。テスト同士の依存性とバグの発生を避けるためにも、可能な限り常に、状態はパスごとに使用するべきです。しかしながら、2つのスクリプトが関連して協調動作することが必要であるなどのレアケースで、そのスクリプトから分岐に応じた挙動を要求するための専用のクエリ文字列を利用できないような場合もあります。このような用途についてのみ、あなたはグローバルオブジェクトで定義されている getSharedState(k, v) および setSharedState(k, v) メソッドを使う事ができます。このサーバ全体で共有される状態へのアクセスについては何も制限はかけられておらず、どのスクリプトからも新しい状態を設定でき、どのスクリプトからもそれを削除できます。衝突を避けるために、あなたは名前空間(意図しない衝突を避けるため、これもテスト用の物を作って下さい)をキーに含める事が望ましいです。例えば、ある HTML5 ビデオのテストで状態を共有する必要がある場合なら、dom.media.video:sharedState のようなキーを使う事になります。

より強力な状態保存のための機能として、あらゆる nsISupports 形式のオブジェクトを保持することができる getObjectState(k) および setObjectState(k, v) メソッドもあります。これらのメソッドは nsIHttpServer インターフェースにこの形式で存在していますが、SJS レスポンス処理用のサーバで使われるサンドボックスオブジェクトの制限のため、前者のメソッドは SJS リクエストハンドラのグローバル環境においては、getObjectState(k, callback) という形式(callback は、第1引数で示されたキーに対応するオブジェクトを引数として getObjectState の内部で呼ばれるコールバック関数)で存在します。この、値のマッピングのために、値が XPCOM オブジェクトである必要がある必要があることに注意して下さい。QueryInterface メソッドを持たない任意の JavaScript オブジェクトは利用できません。JavaScript のオブジェクトを保持させたい場合には、QueryInterface の実装を持ち、XPConnect でラップされたオブジェクトから実際の JavaScript オブジェクトを取得するための wrappedJSObject プロパティも持つオブジェクトを使って下さい。

httpd.js によって提供される状態保存の仕組みの詳細については、netwerk/test/httpserver/nsIHttpServer.idl および nsIHttpServer.get(Shared|Object)?State メソッドを参照して下さい。

非同期にレスポンスを返す SJS スクリプトはどのように書けばいいですか?

例えば一定の時間待つという風に、リクエストに対するレスポンスを非同期に返したいという場合があるでしょう。これは handleRequest() 関数に渡される response オブジェクトの processAsync() および finish() 関数によって実現できます。

processAsync() は必ず、handleRequest() からリターンする前に呼ばれなくてはなりません。この関数を実行すると、さらに追加のレスポンスを送信するために、request オブジェクトのメソッドを好きな時点で呼ぶ事ができるようになります。必要なレスポンスを送信し終えたら、finish() 関数を呼んでください。例えば、上で説明した setState()/getState() 関数を、request を保存して、後でその内容を参照し、さらに終了するために利用できます。しかしながら、ブラウザはリクエストを異なる順番で行う事があり、そのためあなたが書くコードは時々起こる失敗を避けるよう耐性を高くしなければならないということに気をつけてください。

var timer = null;

function handleRequest(request, response)
{
  response.processAsync();
  response.setHeader("Content-Type", "text/plain", false);
  response.write("hello...");

  timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
  timer.initWithCallback(function()
  {
    response.write("world!");
    response.finish();
  }, 5 * 1000 /* ミリ秒 */, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
}

より詳しい情報については、netwerk/test/httpserver/nsIHttpServer.idl にある processAsync() 関数の説明を参照してください。

SJS スクリプトからサーバ上にあるファイルに XPCOM オブジェクトとしてアクセスするにはどうすればよいですか?(Gecko 1.9.3 およびそれ以降の場合)

ファイルにアクセスする必要がある場合(例えば、画像データはファイルとして保存しておく方が、SJS スクリプトの中に直接画像を埋め込むよりも扱いが簡単です)、Mochitest で実行されている SJS スクリプトで最初から定義済みの SERVER_ROOT オブジェクトステートを利用して下さい:

function handleRequest(req, res)
{
  var file;
  getObjectState("SERVER_ROOT", function(serverRoot)
  {
    file = serverRoot.getFile("tests/content/media/test/320x240.ogv");
  });

  // この時点で file は指定されたファイルを参照する XPCOM オブジェクトになっています。
  res.write("file: " + file);
}

指定するパスは、httpd.js が取り扱うルートディレクトリからの相対パスとして扱われ、その位置に対応するnsIFile のオブジェクトが返されます。この時は、パスの書き間違いに注意してください。ファイルのオブジェクトはパス文字列を保持しているだけなので、指定したファイルは実際に存在している必要がありません。

ドキュメントのタグと貢献者

 このページの貢献者: ethertank, Piro, Shimono, Mgjbot
 最終更新者: ethertank,