Created
February 6, 2017 13:32
-
-
Save maiksprenger/3e4fd1a5aefe4e53fa48868f222e07f5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from urllib.parse import urlencode | |
from hypothesis import strategies | |
HTTP_METHODS = ['OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT'] | |
letters = strategies.characters(whitelist_categories=('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl')) | |
def http_method(): | |
return strategies.sampled_from(HTTP_METHODS) | |
def http_path(): | |
""" | |
Returns a URL path. It only ensures that it starts with a slash. | |
It's too broad because it may return any sequence of unicode characters, but it | |
suffices for our needs. | |
""" | |
return strategies.text(min_size=0, max_size=255, alphabet=letters).map(lambda s: '/' + s) | |
def reject_bidi_violations(host): | |
try: | |
host.encode('idna') | |
except UnicodeError: | |
return False | |
else: | |
return True | |
def _domain(): | |
return strategies.text(alphabet=letters, min_size=1, average_size=6, max_size=63).filter(reject_bidi_violations) | |
def http_host(): | |
""" | |
Returns an string of a domain name, IDNA-encoded. | |
""" | |
return strategies.lists(_domain(), min_size=2, average_size=2).map(lambda s: ('.'.join(s)).encode('idna')) | |
def query_param(): | |
return strategies.text(alphabet=letters, min_size=1, average_size=10, max_size=255) | |
def query_params(): | |
""" | |
Returns a list of two-tuples, ready for encoding with urlencode. | |
It ensures that the total urlencoded query string is not longer than 1500 characters. We're aiming | |
for a total length of the URL below 2083 characters. | |
""" | |
return strategies.lists( | |
strategies.tuples(query_param(), query_param()), min_size=0, average_size=20).\ | |
filter(lambda x: len(urlencode(x)) < 1500) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@given( | |
request_method=http_strategies.http_method(), | |
request_host=http_strategies.http_host(), | |
request_path=http_strategies.http_path(), | |
request_params=http_strategies.query_params()) | |
def test_basic_request(self, request_method, request_host, request_path, request_params): | |
request = self.build_request(request_method, request_path, host=request_host, params=request_params) | |
message = self.message_for_request(request) | |
assert message | |
assert 'reply_channel' in message | |
reply_channel = message['reply_channel'] | |
assert isinstance(reply_channel, six.text_type) | |
assert reply_channel.startswith('http.response!') | |
assert 'http_version' in message | |
http_version = message['http_version'] | |
assert isinstance(http_version, six.text_type) | |
assert http_version in ['1.0', '1.1', '1.2'] | |
assert 'method' in message | |
method = message['method'] | |
assert isinstance(method, six.text_type) | |
assert method.isupper() | |
assert message['method'] == request_method | |
# Optional | |
scheme = message.get('scheme') | |
if scheme: | |
assert isinstance(scheme, six.text_type) | |
assert scheme in ['http', 'https'] | |
assert 'path' in message | |
path = message['path'] | |
assert isinstance(path, six.text_type) | |
assert path == request_path | |
# Test that the URL path is already decoded. That is easily tested if the original | |
# path does not contain percent signs, but I can't think of a way to test it when they're | |
# present. | |
if '%' not in request_path: | |
self.assertEqual(path, unquote(path)) | |
assert 'query_string' in message | |
query_string = message['query_string'] | |
# Assert that query_string is a byte string and still url encoded | |
assert isinstance(query_string, six.binary_type) | |
assert query_string == urlencode(request_params).encode('ascii') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment