| # Writing Complex Tests # | 
 |  | 
 | For many tests, writing one or more static HTML files is | 
 | sufficient. However there are a large class of tests for which this | 
 | approach is insufficient, including: | 
 |  | 
 | * Tests that require cross-domain access | 
 |  | 
 | * Tests that depend on setting specific headers or status codes | 
 |  | 
 | * Tests that need to inspect the browser sent request | 
 |  | 
 | * Tests that require state to be stored on the server | 
 |  | 
 | * Tests that require precise timing of the response. | 
 |  | 
 | To make writing such tests possible, we are using a number of | 
 | server-side components designed to make it easy to manipulate the | 
 | precise details of the response: | 
 |  | 
 | * *wptserve*, a custom python HTTP server. | 
 |  | 
 | * *pywebsocket*, an existing websockets server | 
 |  | 
 | This document will concentrate on the features of wptserve available | 
 | to test authors. | 
 |  | 
 | ## Introduction to wptserve ## | 
 |  | 
 | wptserve is a python-based web server. By default it serves static | 
 | files in the testsuite. For more sophisticated requirements, several | 
 | mechanisms are available to take control of the response. These are | 
 | outlined below. | 
 |  | 
 | ## Pipes ## | 
 |  | 
 | Suitable for: | 
 |  | 
 |  * Cross domain requests | 
 |  * Adding headers or status codes to static files | 
 |  * Controlling the sending of static file bodies | 
 |  | 
 | Pipes are designed to allow simple manipulation of the way that | 
 | static files are sent without requiring any custom code. They are also | 
 | useful for cross-origin tests because they can be used to activate a | 
 | substitution mechanism which can fill in details of ports and server | 
 | names in the setup on which the tests are being run. | 
 |  | 
 | Pipes are indicated by adding a query string to a request for a static | 
 | resource, with the parameter name `pipe`. The value of the query | 
 | should be a `|` serperated list of pipe functions. For example to | 
 | return a `.html` file with the status code 410 and a Content-Type of | 
 | text/plain, one might use: | 
 |  | 
 |     /resources/example.html?pipe=status(410)|header(Content-Type,text/plain) | 
 |  | 
 | There are a selection of pipe functions provided with wptserve and | 
 | more may be added if there are good use cases. | 
 |  | 
 | ### sub ### | 
 |  | 
 | Used to subsitute variables from the server environment, or from the | 
 | request into the response. A typical use case is for testing | 
 | cross-domain since the exact domain name and ports of the servers are | 
 | generally unknown. | 
 |  | 
 | Substitutions are marked in a file using a block delimited by `{{` | 
 | and `}}`. Inside the block the following variables are avalible: | 
 |  | 
 | * `{{host}}` - the host name of the server exclusing any subdomain part. | 
 | * `{{domains[]}}` - the domain name of a particular subdomain | 
 |     e.g. `{{domains[www]}}` for the `www` subdomain. | 
 | * `{{ports[][]}}` - The port number of servers, by protocol | 
 |     e.g. `{{ports[http][1]}}` for the second (i.e. non-default) http | 
 |   server. | 
 | * `{{headers[]}}` - The HTTP headers in the request | 
 |     e.g. `{{headers[X-Test]}}` for a hypothetical `X-Test` header. | 
 | * `{{GET[]}}` - The query parameters for the request | 
 |     e.g. `{{GET[id]}}` for an id parameter sent with the request. | 
 |  | 
 | So, for example, to write a javascript file called `xhr.js` that does a | 
 | cross domain XHR test to a different subdomain and port, one would | 
 | write in the file: | 
 |  | 
 |     var server_url = "http://{{domains[www]}}:{{ports[http][1]}}/path/to/resource"; | 
 |     //Create the actual XHR and so on | 
 |  | 
 | The file would then be included as: | 
 |  | 
 |     <script src="xhr.js?pipe=sub"></script> | 
 |  | 
 | ### status ### | 
 |  | 
 | Used to set the HTTP status of the response, for example: | 
 |  | 
 |     example.js?pipe=status(410) | 
 |  | 
 | ### headers ### | 
 |  | 
 | Used to add or replace http headers in the response. Takes two or | 
 | three arguments; the header name, the header value and whether to | 
 | append the header rather than replace an existing header (default: | 
 | False). So, for example, a request for: | 
 |  | 
 |     example.html?pipe=header(Content-Type,text/plain) | 
 |  | 
 | causes example.html to be returned with a text/plain content type | 
 | whereas: | 
 |  | 
 |     example.html?pipe=header(Content-Type,text/plain,True) | 
 |  | 
 | Will cause example.html to be returned with both text/html and | 
 | text/plain content-type headers. | 
 |  | 
 | ### slice ### | 
 |  | 
 | Used to send only part of a response body. Takes the start and, | 
 | optionally, end bytes as arguments, although either can be null to | 
 | indicate the start or end of the file, respectively. So for example: | 
 |  | 
 |     example.txt?pipe=slice(10,20) | 
 |  | 
 | Would result in a response with a body containing 10 bytes of | 
 | example.txt including byte 10 but excluding byte 20. | 
 |  | 
 |     example.txt?pipe=slice(10) | 
 |  | 
 | Would cause all bytes from byte 10 of example.txt to be sent, but: | 
 |  | 
 |     example.txt?pipe=slice(null,20) | 
 |  | 
 | Would send the first 20 bytes of example.txt. | 
 |  | 
 | ### trickle ### | 
 |  | 
 | Used to send the body of a response in chunks with delays. Takes a | 
 | single argument that is a microsyntax consisting of colon-separated | 
 | commands. There are three types of commands: | 
 |  | 
 | * Bare numbers represent a number of bytes to send | 
 |  | 
 | * Numbers prefixed `d` indicate a delay in seconds | 
 |  | 
 | * Numbers prefixed `r` must only appear at the end of the command, and | 
 |     indicate that the preceding N items must be repeated until there is | 
 |   no more content to send. | 
 |  | 
 | In the absence of a repetition command, the entire remainder of the content is | 
 | sent at once when the command list is exhausted. So for example: | 
 |  | 
 |     example.txt?pipe=trickle(d1) | 
 |  | 
 | causes a 1s delay before sending the entirety of example.txt. | 
 |  | 
 |     example.txt?pipe=trickle(100:d1) | 
 |  | 
 | causes 100 bytes of example.txt to be sent, followed by a 1s delay, | 
 | and then the remainder of the file to be sent. On the other hand: | 
 |  | 
 |     example.txt?pipe=trickle(100:d1:r2) | 
 |  | 
 | Will cause the file to be sent in 100 byte chunks separated by a 1s | 
 | delay until the whole content has been sent. | 
 |  | 
 | ## asis files ## | 
 |  | 
 | Suitable for: | 
 |  | 
 |  * Static, HTTP-non-compliant responses | 
 |  | 
 | asis files are simply files with the extension `.asis`. They are sent | 
 | byte for byte to the server without adding a HTTP status line, | 
 | headers, or anything else. This makes them suitable for testing | 
 | situations where the precise bytes on the wire are static, and control | 
 | over the timing is unnecessary, but the response does not conform to | 
 | HTTP requirements. | 
 |  | 
 | ## py files ## | 
 |  | 
 | Suitable for: | 
 |  | 
 |  * All tests requiring dynamic responses | 
 |  * Tests that need to store server side state. | 
 |  | 
 | The most flexible mechanism for writing tests is to use `.py` | 
 | files. These are interpreted as code and are suitable for the same | 
 | kinds of tasks that one might achieve using cgi, PHP or a similar | 
 | technology. Unlike cgi or PHP, the file is not executed directly and | 
 | does not produce output by writing to `stdout`. Instead files must | 
 | contain (at least) a function named `main`, with the signature: | 
 |  | 
 |     def main(request, response): | 
 |         pass | 
 |  | 
 | Here `request` is a `Request` object that contains details of the | 
 | request, and `response` is a `Response` object that can be used to set | 
 | properties of the response. Full details of these objects is | 
 | provided in the [wptserve documentation](http://wptserve.readthedocs.org/en/latest/). | 
 |  | 
 | In many cases tests will not need to work with the `response` object | 
 | directly. Instead they can set the status, headers and body simply by | 
 | returning values from the `main` function. If any value is returned, | 
 | it is interpreted as the response body. If two values are returned | 
 | they are interpreted as headers and body, and three values are | 
 | interpreted as status, headers, body. So, for example: | 
 |  | 
 |     def main(request, response): | 
 |         return "TEST" | 
 |  | 
 | creates a response with no non-default headers and the body | 
 | `TEST`. Headers can be added as follows: | 
 |  | 
 |     def main(request, response): | 
 |         return ([("Content-Type", "text/plain"), ("X-Test", "test")], | 
 |                 "TEST") | 
 |  | 
 | And a status code as: | 
 |  | 
 |     def main(request, response): | 
 |         return (410, | 
 |                 [("Content-Type", "text/plain"), ("X-Test", "test")], | 
 |               "TEST") | 
 |  | 
 | A custom status string may be returned by using a tuple `code, string` | 
 | in place of the code alone. | 
 |  | 
 | At the other end of the scale, some tests require precision over the | 
 | exact bytes sent over the wire and their timing. This can be achieved | 
 | using the `writer` property of the response, which exposes a | 
 | `ResponseWriter` object that allows wither writing specific parts of | 
 | the request or direct access to the underlying socket. | 
 |  | 
 | For full documentation on the facilities available in `.py` files, see | 
 | the [wptserve documentation](http://wptserve.readthedocs.org/en/latest/). |