Пример #1
0
class TestSendCloseAccept(testcases.ASGIWebSocketTestCase):
    """
    Tests that, essentially, try to translate the send/close/accept section of the spec into code.
    """
    def test_empty_accept(self):
        response = WebSocketConnection().send({'accept': True})
        self.assert_websocket_upgrade(response)

    @given(text=http_strategies.http_body())
    def test_accept_and_text(self, text):
        response = WebSocketConnection().send({'accept': True, 'text': text})
        self.assert_websocket_upgrade(response, text.encode('ascii'))

    @given(data=http_strategies.binary_payload())
    def test_accept_and_bytes(self, data):
        response = WebSocketConnection().send({'accept': True, 'bytes': data})
        self.assert_websocket_upgrade(response, data)

    def test_accept_false(self):
        response = WebSocketConnection().send({'accept': False})
        self.assert_websocket_denied(response)

    def test_accept_false_with_text(self):
        """
        Tests that even if text is given, the connection is denied.

        We can't easily use Hypothesis to generate data for this test because it's
        hard to detect absence of the body if e.g. Hypothesis would generate a 'GET'
        """
        text = 'foobar'
        response = WebSocketConnection().send({'accept': False, 'text': text})
        self.assert_websocket_denied(response)
        self.assertNotIn(text.encode('ascii'), response)

    def test_accept_false_with_bytes(self):
        """
        Tests that even if data is given, the connection is denied.

        We can't easily use Hypothesis to generate data for this test because it's
        hard to detect absence of the body if e.g. Hypothesis would generate a 'GET'
        """
        data = b'foobar'
        response = WebSocketConnection().send({'accept': False, 'bytes': data})
        self.assert_websocket_denied(response)
        self.assertNotIn(data, response)

    @given(text=http_strategies.http_body())
    def test_just_text(self, text):
        assume(len(text) > 0)
        # If content is sent, accept=True is implied.
        response = WebSocketConnection().send({'text': text})
        self.assert_websocket_upgrade(response, text.encode('ascii'))

    @given(data=http_strategies.binary_payload())
    def test_just_bytes(self, data):
        assume(len(data) > 0)
        # If content is sent, accept=True is implied.
        response = WebSocketConnection().send({'bytes': data})
        self.assert_websocket_upgrade(response, data)

    def test_close_boolean(self):
        response = WebSocketConnection().send({'close': True})
        self.assert_websocket_denied(response)

    @given(number=strategies.integers(min_value=1))
    def test_close_integer(self, number):
        response = WebSocketConnection().send({'close': number})
        self.assert_websocket_denied(response)

    @given(text=http_strategies.http_body())
    def test_close_with_text(self, text):
        assume(len(text) > 0)
        response = WebSocketConnection().send({'close': True, 'text': text})
        self.assert_websocket_upgrade(response,
                                      text.encode('ascii'),
                                      expect_close=True)

    @given(data=http_strategies.binary_payload())
    def test_close_with_data(self, data):
        assume(len(data) > 0)
        response = WebSocketConnection().send({'close': True, 'bytes': data})
        self.assert_websocket_upgrade(response, data, expect_close=True)
Пример #2
0
class TestHTTPRequestSpec(testcases.ASGIHTTPTestCase):
    """
    Tests which try to pour the HTTP request section of the ASGI spec into code.
    The heavy lifting is done by the assert_valid_http_request_message function,
    the tests mostly serve to wire up hypothesis so that it exercise it's power to find
    edge cases.
    """
    def test_minimal_request(self):
        """
        Smallest viable example. Mostly verifies that our request building works.
        """
        request_method, request_path = 'GET', '/'
        message = message_for_request(request_method, request_path)

        self.assert_valid_http_request_message(message, request_method,
                                               request_path)

    @given(request_path=http_strategies.http_path(),
           request_params=http_strategies.query_params())
    def test_get_request(self, request_path, request_params):
        """
        Tests a typical HTTP GET request, with a path and query parameters
        """
        request_method = 'GET'
        message = message_for_request(request_method, request_path,
                                      request_params)

        self.assert_valid_http_request_message(message,
                                               request_method,
                                               request_path,
                                               request_params=request_params)

    @given(request_path=http_strategies.http_path(),
           request_body=http_strategies.http_body())
    def test_post_request(self, request_path, request_body):
        """
        Tests a typical POST request, submitting some data in a body.
        """
        request_method = 'POST'
        headers = [content_length_header(request_body)]
        message = message_for_request(request_method,
                                      request_path,
                                      headers=headers,
                                      body=request_body)

        self.assert_valid_http_request_message(message,
                                               request_method,
                                               request_path,
                                               request_headers=headers,
                                               request_body=request_body)

    @given(request_headers=http_strategies.headers())
    def test_headers(self, request_headers):
        """
        Tests that HTTP header fields are handled as specified
        """
        request_method, request_path = 'OPTIONS', '/te st-à/'
        message = message_for_request(request_method,
                                      request_path,
                                      headers=request_headers)

        self.assert_valid_http_request_message(message,
                                               request_method,
                                               request_path,
                                               request_headers=request_headers)

    @given(request_headers=http_strategies.headers())
    def test_duplicate_headers(self, request_headers):
        """
        Tests that duplicate header values are preserved
        """
        assume(len(request_headers) >= 2)
        # Set all header field names to the same value
        header_name = request_headers[0][0]
        duplicated_headers = [(header_name, header[1])
                              for header in request_headers]

        request_method, request_path = 'OPTIONS', '/te st-à/'
        message = message_for_request(request_method,
                                      request_path,
                                      headers=duplicated_headers)

        self.assert_valid_http_request_message(
            message,
            request_method,
            request_path,
            request_headers=duplicated_headers)

    @given(
        request_method=http_strategies.http_method(),
        request_path=http_strategies.http_path(),
        request_params=http_strategies.query_params(),
        request_headers=http_strategies.headers(),
        request_body=http_strategies.http_body(),
    )
    # This test is slow enough that on Travis, hypothesis sometimes complains.
    def test_kitchen_sink(self, request_method, request_path, request_params,
                          request_headers, request_body):
        """
        Throw everything at channels that we dare. The idea is that if a combination
        of method/path/headers/body would break the spec, hypothesis will eventually find it.
        """
        request_headers.append(content_length_header(request_body))
        message = message_for_request(request_method, request_path,
                                      request_params, request_headers,
                                      request_body)

        self.assert_valid_http_request_message(message, request_method,
                                               request_path, request_params,
                                               request_headers, request_body)

    def test_headers_are_lowercased_and_stripped(self):
        request_method, request_path = 'GET', '/'
        headers = [('MYCUSTOMHEADER', '   foobar    ')]
        message = message_for_request(request_method,
                                      request_path,
                                      headers=headers)

        self.assert_valid_http_request_message(message,
                                               request_method,
                                               request_path,
                                               request_headers=headers)
        # Note that Daphne returns a list of tuples here, which is fine, because the spec
        # asks to treat them interchangeably.
        assert message['headers'] == [(b'mycustomheader', b'foobar')]

    @given(daphne_path=http_strategies.http_path())
    def test_root_path_header(self, daphne_path):
        """
        Tests root_path handling.
        """
        request_method, request_path = 'GET', '/'
        # Daphne-Root-Path must be URL encoded when submitting as HTTP header field
        headers = [('Daphne-Root-Path',
                    parse.quote(daphne_path.encode('utf8')))]
        message = message_for_request(request_method,
                                      request_path,
                                      headers=headers)

        # Daphne-Root-Path is not included in the returned 'headers' section. So we expect
        # empty headers.
        expected_headers = []
        self.assert_valid_http_request_message(
            message,
            request_method,
            request_path,
            request_headers=expected_headers)
        # And what we're looking for, root_path being set.
        assert message['root_path'] == daphne_path