| # Writing H2 Tests | 
 |  | 
 | These instructions assume you are already familiar with the testing | 
 | infrastructure and know how to write a standard HTTP/1.1 test. | 
 |  | 
 | On top of the standard `main` handler that the H1 server offers, the | 
 | H2 server also offers support for specific frame handlers in the Python | 
 | scripts. Currently there is support for for `handle_headers` and `handle_data`. | 
 | Unlike the `main` handler, these  are run whenever the server receives a | 
 | HEADERS frame (RequestReceived event) or a DATA frame (DataReceived event). | 
 | `main` can still be used, but it will be run after the server has received | 
 | the request in its entirety. | 
 |  | 
 | Here is what a Python script for a test might look like: | 
 | ```python | 
 | def handle_headers(frame, request, response): | 
 |     if request.headers["test"] == "pass": | 
 |         response.status = 200 | 
 |         response.headers.update([('test', 'passed')]) | 
 |         response.write_status_headers() | 
 |     else: | 
 |         response.status = 403 | 
 |         response.headers.update([('test', 'failed')]) | 
 |         response.write_status_headers() | 
 |         response.writer.end_stream() | 
 |  | 
 | def handle_data(frame, request, response): | 
 |     response.writer.write_data(frame.data[::-1]) | 
 |  | 
 | def main(request, response): | 
 |     response.writer.write_data('\nEnd of File', last=True) | 
 | ``` | 
 |  | 
 | The above script is fairly simple: | 
 | 1. Upon receiving the HEADERS frame, `handle_headers` is run. | 
 |     - This checks for a header called 'test' and checks if it is set to 'pass'. | 
 |     If true, it will immediately send a response header, otherwise it responds | 
 |     with a 403 and ends the stream. | 
 | 2. Any DATA frames received will then be handled by `handle_data`. This will | 
 | simply reverse the data and send it back. | 
 | 3. Once the request has been fully received, `main` is run which will send | 
 | one last DATA frame and signal its the end of the stream. | 
 |  | 
 | ## Response Writer API ## | 
 |  | 
 | The H2Response API is pretty much the same as the H1 variant, the main API | 
 | difference lies in the H2ResponseWriter which is accessed through `response.writer` | 
 |  | 
 | --- | 
 |  | 
 | #### `write_headers(self, headers, status_code, status_message=None, stream_id=None, last=False):` | 
 | Write a HEADER frame using the H2 Connection object, will only work if the | 
 | stream is in a state to send HEADER frames. This will automatically format | 
 | the headers so that pseudo headers are at the start of the list and correctly | 
 | prefixed with ':'. Since this using the H2 Connection object, it requires that | 
 | the stream is in the correct state to be sending this frame. | 
 |  | 
 | > <b>Note</b>: Will raise ProtocolErrors if pseudo headers are missing. | 
 |  | 
 | - <b>Parameters</b> | 
 |  | 
 |     - <b>headers</b>: List of (header, value) tuples | 
 |     - <b>status_code</b>: The HTTP status code of the response | 
 |     - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None | 
 |     - <b>last</b>: Flag to signal if this is the last frame in stream. | 
 |  | 
 | --- | 
 |  | 
 | #### `write_data(self, item, last=False, stream_id=None):` | 
 | Write a DATA frame using the H2 Connection object, will only work if the | 
 | stream is in a state to send DATA frames. Uses flow control to split data | 
 | into multiple data frames if it exceeds the size that can be in a single frame. | 
 | Since this using the H2 Connection object, it requires that the stream is in | 
 | the correct state to be sending this frame. | 
 |  | 
 | - <b>Parameters</b> | 
 |  | 
 |     - <b>item</b>: The content of the DATA frame | 
 |     - <b>last</b>: Flag to signal if this is the last frame in stream. | 
 |     - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None | 
 |  | 
 | --- | 
 |  | 
 | #### `write_push(self, promise_headers, push_stream_id=None, status=None, response_headers=None, response_data=None):` | 
 | This will write a push promise to the request stream. If you do not provide | 
 | headers and data for the response, then no response will be pushed, and you | 
 | should send them yourself using the ID returned from this function. | 
 |  | 
 | - <b>Parameters</b> | 
 |     - <b>promise_headers</b>: A list of header tuples that matches what the client would use to | 
 |                         request the pushed response | 
 |     - <b>push_stream_id</b>: The ID of the stream the response should be pushed to. If none given, will | 
 |                        use the next available id. | 
 |     - <b>status</b>: The status code of the response, REQUIRED if response_headers given | 
 |     - <b>response_headers</b>: The headers of the response | 
 |     - <b>response_data</b>: The response data. | 
 |  | 
 | - <b>Returns</b>: The ID of the push stream | 
 |  | 
 | --- | 
 |  | 
 | #### `write_raw_header_frame(self, headers, stream_id=None, end_stream=False, end_headers=False, frame_cls=HeadersFrame):` | 
 | Unlike `write_headers`, this does not check to see if a stream is in the | 
 | correct state to have HEADER frames sent through to it. It also won't force | 
 | the order of the headers or make sure pseudo headers are prefixed with ':'. | 
 | It will build a HEADER frame and send it without using the H2 Connection | 
 | object other than to HPACK encode the headers. | 
 |  | 
 | > <b>Note</b>: The `frame_cls` parameter is so that this class can be reused | 
 | by `write_raw_continuation_frame`, as their construction is identical. | 
 |  | 
 | - <b>Parameters</b> | 
 |     - <b>headers</b>: List of (header, value) tuples | 
 |     - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None | 
 |     - <b>end_stream</b>: Set to `True` to add END_STREAM flag to frame | 
 |     - <b>end_headers</b>: Set to `True` to add END_HEADERS flag to frame | 
 |  | 
 | --- | 
 |  | 
 | #### `write_raw_data_frame(self, data, stream_id=None, end_stream=False):` | 
 | Unlike `write_data`, this does not check to see if a stream is in the correct | 
 | state to have DATA frames sent through to it. It will build a DATA frame and | 
 | send it without using the H2 Connection object. It will not perform any flow control checks. | 
 |  | 
 | - <b>Parameters</b> | 
 |     - <b>data</b>: The data to be sent in the frame | 
 |     - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None | 
 |     - <b>end_stream</b>: Set to True to add END_STREAM flag to frame | 
 |  | 
 | --- | 
 |  | 
 | #### `write_raw_continuation_frame(self, headers, stream_id=None, end_headers=False):` | 
 | This provides the ability to create and write a CONTINUATION frame to the | 
 | stream, which is not exposed by `write_headers` as the h2 library handles | 
 | the split between HEADER and CONTINUATION internally. Will perform HPACK | 
 | encoding on the headers. It also ignores the state of the stream. | 
 |  | 
 | This calls `write_raw_data_frame` with `frame_cls=ContinuationFrame` since | 
 | the HEADER and CONTINUATION frames are constructed in the same way. | 
 |  | 
 | - <b>Parameters</b>: | 
 |     - <b>headers</b>: List of (header, value) tuples | 
 |     - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None | 
 |     - <b>end_headers</b>: Set to True to add END_HEADERS flag to frame | 
 |  | 
 | --- | 
 |  | 
 | #### `end_stream(self, stream_id=None):` | 
 | Ends the stream with the given ID, or the one that request was made on if no ID given. | 
 |  | 
 | - <b>Parameters</b> | 
 |     - <b>stream_id</b>: Id of stream to send frame on. Will use the request stream ID if None |