HTTP server for unit tests

  • Revision slug: Httpd.js/HTTP_server_for_unit_tests
  • Revision title: HTTP server for unit tests
  • Revision id: 85538
  • Created:
  • Creator: Waldo
  • Is current revision? No
  • Comment /* Use within xpcshell unit tests */ update for bug 351968 changes

Revision Content

This page describes the JavaScript implementation of a HTTP server located in {{template.Source("netwerk/test/httpserver/")}}.

Functionality

Here are some of the things you can do with the server:

  • map a directory of files onto an HTTP path on the server, for an arbitrary number of such directories (including nested directories)
  • define custom error handlers for HTTP error codes
  • serve a given file for requests for a specific path
  • define custom "CGI" handlers for specific paths using a JavaScript-based API to create the response (headers and actual content)
  • run multiple servers at once on different ports (8080, 8081, 8082, etc.)

This functionality should be more than enough for you to use it with any test which requires storage on an HTTP server but doesn't require a particular host.

Where you can use it

The server is written primarily for use from xpcshell-based tests, but there's no fundamental reason it can't be used from other tests as well. The server is also written so that it can be used as an XPCOM component (after you compile the server's IDL file to xpt and put the files in the right places). Also, there is a partial patch in {{template.Bug(364043)}} to make the mochitests use the server for serving the tests.

Ways you might use it

  • application update testing
  • cross-"server" (but, alas, not cross-subdomain) security tests
  • tests where the behavior is dependent on the values of HTTP headers (e.g., Content-Type)
  • anything which requires use of files not stored locally
  •  ???

Use within xpcshell unit tests

To use the server in xpcshell-based tests, include the following line at the top of your test file:

do_import_script("netwerk/test/httpserver/httpd.js");

Once you've done that, you can create a new server as follows:

var server = new nsHttpServer();

server.registerDirectory("/", nsILocalFileForBasePath);

const SERVER_PORT = 8080; // or some suitably large number
server.start(SERVER_PORT);

// and when the tests are done, most likely from a callback...
server.stop();

Note that because the server only runs when the xpcshell event loop is spun, you'll have to use do_test_pending(); and doing your testing via callbacks, making sure to call do_test_finished(); when the tests finish. Doing so is a little hairy, but since such a test is unlikely to be synchronous anyway it shouldn't be too hard to handle server asynchronicity.

Examples and docs

Shorter examples (for tests which only do one test):

  • {{template.Source("netwerk/test/unit/test_bug331825.js")}}
  • {{template.Source("netwerk/test/unit/test_httpcancel.js")}}
  • {{template.Source("netwerk/test/unit/test_cookie_header.js")}}

Longer tests (where you'd need to do multiple async server requests):

  • {{template.Source("netwerk/test/httpserver/test/test_setstatusline.js")}}
  • {{template.Source("netwerk/test/unit/test_content_sniffer.js")}}
  • {{template.Source("netwerk/test/unit/test_authentication.js")}}
  • {{template.Source("netwerk/test/unit/test_event_sink.js")}}
  • {{template.Source("netwerk/test/httpserver/test/")}}

The best and first place you should look for documentation is {{template.Source("netwerk/test/httpserver/nsIHttpServer.idl")}}. It's extremely comprehensive and detailed, and it should be enough to figure out how to make the server do what you want. I also suggest taking a look at the less-comprehensive server {{wiki.template('Named-source', [ "netwerk/test/httpserver/README", "README" ])}}, although the IDL should usually be sufficient.

Future directions

The server, while very functional, is not yet complete. There are a number of things to fix and features to add, among them support for something like mod_cern_meta (define the HTTP headers sent with a file within another file), support for sending requests as their data is generated (instead of batching it and sending all at once when the response is fully created), and better conformance to the MUSTs and SHOULDs of HTTP/1.1. If you have suggestions for functionality or find bugs, file them in {{wiki.template('Enter-bug', [ "Core", "Testing" ])}} and CC jwalden+bmo.

Revision Source

<p>This page describes the JavaScript implementation of a HTTP server located in {{template.Source("netwerk/test/httpserver/")}}.
</p>
<h3 name="Functionality"> Functionality </h3>
<p>Here are some of the things you can do with the server:
</p>
<ul><li> map a directory of files onto an HTTP path on the server, for an arbitrary number of such directories (including nested directories)
</li><li> define custom error handlers for HTTP error codes
</li><li> serve a given file for requests for a specific path
</li><li> define custom "CGI" handlers for specific paths using a JavaScript-based API to create the response (headers and actual content)
</li><li> run multiple servers at once on different ports (8080, 8081, 8082, etc.)
</li></ul>
<p>This functionality should be more than enough for you to use it with any test which requires storage on an HTTP server but doesn't require a particular host.
</p>
<h3 name="Where_you_can_use_it"> Where you can use it </h3>
<p>The server is written primarily for use from <a href="en/Writing_xpcshell-based_unit_tests">xpcshell-based tests</a>, but there's no fundamental reason it can't be used from other tests as well.  The server is also written so that it can be used as an XPCOM component (after you compile the server's IDL file to xpt and put the files in the right places). Also, there is a partial patch in {{template.Bug(364043)}} to make the <a href="en/Mochitest_FAQ">mochitests</a> use the server for serving the tests.
</p>
<h3 name="Ways_you_might_use_it"> Ways you might use it </h3>
<ul><li> application update testing
</li><li> cross-"server" (but, alas, not cross-subdomain) security tests
</li><li> tests where the behavior is dependent on the values of HTTP headers (e.g., Content-Type)
</li><li> anything which requires use of files not stored locally
</li><li> ???
</li></ul>
<h3 name="Use_within_xpcshell_unit_tests"> Use within xpcshell unit tests </h3>
<p>To use the server in <a href="en/Writing_xpcshell-based_unit_tests">xpcshell-based tests</a>, include the following line at the top of your test file:
</p>
<pre class="eval">do_import_script("netwerk/test/httpserver/httpd.js");
</pre>
<p>Once you've done that, you can create a new server as follows:
</p>
<pre class="eval">var server = new nsHttpServer();

server.registerDirectory("/", nsILocalFileForBasePath);

const SERVER_PORT = 8080; // or some suitably large number
server.start(SERVER_PORT);

// and when the tests are done, most likely from a callback...
server.stop();
</pre>
<p>Note that because the server only runs when the xpcshell event loop is spun, you'll have to use <code>do_test_pending();</code> and doing your testing via callbacks, making sure to call <code>do_test_finished();</code> when the tests finish.  Doing so is a little hairy, but since such a test is unlikely to be synchronous anyway it shouldn't be too hard to handle server asynchronicity.
</p>
<h3 name="Examples_and_docs"> Examples and docs </h3>
<p>Shorter examples (for tests which only do one test):
</p>
<ul><li> {{template.Source("netwerk/test/unit/test_bug331825.js")}}
</li><li> {{template.Source("netwerk/test/unit/test_httpcancel.js")}}
</li><li> {{template.Source("netwerk/test/unit/test_cookie_header.js")}}
</li></ul>
<p>Longer tests (where you'd need to do multiple async server requests):
</p>
<ul><li> {{template.Source("netwerk/test/httpserver/test/test_setstatusline.js")}}
</li><li> {{template.Source("netwerk/test/unit/test_content_sniffer.js")}}
</li><li> {{template.Source("netwerk/test/unit/test_authentication.js")}}
</li><li> {{template.Source("netwerk/test/unit/test_event_sink.js")}}
</li><li> {{template.Source("netwerk/test/httpserver/test/")}}
</li></ul>
<p>The best and first place you should look for documentation is {{template.Source("netwerk/test/httpserver/nsIHttpServer.idl")}}.  It's extremely comprehensive and detailed, and it should be enough to figure out how to make the server do what you want.  I also suggest taking a look at the less-comprehensive server {{wiki.template('Named-source', [ "netwerk/test/httpserver/README", "README" ])}}, although the IDL should usually be sufficient.
</p>
<h3 name="Future_directions"> Future directions </h3>
<p>The server, while very functional, is not yet complete.  There are a number of things to fix and features to add, among them support for something like mod_cern_meta (define the HTTP headers sent with a file within another file), support for sending requests as their data is generated (instead of batching it and sending all at once when the response is fully created), and better conformance to the MUSTs and SHOULDs of HTTP/1.1.  If you have suggestions for functionality or find bugs, file them in {{wiki.template('Enter-bug', [ "Core", "Testing" ])}} and CC jwalden+bmo.
</p>
Revert to this revision