Add query_parameters field

This adds a query_parameters field which can be used to add query
parameters to the url of the test in which it is used. It is a dict in
a form suitable for being passed to the urlencode() method.

This change is cumbersome because urlencoded in python2 and 3 have
different behaviors: In python2 a utf-8 encoded string is required.
In 3 it will figure out the right thing. So we here we just encode.

We also need to deal with the fact that a numeral in YAML will be
provided to Python as a numeric value and we need to stringify that in
a version independent fashion.
This commit is contained in:
Chris Dent
2015-08-02 21:55:09 +01:00
parent 25e86671af
commit 063f00a7a6
4 changed files with 100 additions and 6 deletions

View File

@@ -39,6 +39,9 @@ Many of these items allow substitutions (explained below).
fully qualified URL (with host and scheme). If not qualified the
test builder will be responsible for determining host and scheme.
**Required**
* ``query_parameters``: An optional dictionary of query parameters
that will be added to the ``url``. If there is an existing set of
query parameters they wil be extended.
* ``method``: The request method to use. Defaults to ``GET``.
* ``status``: The expected response status code. The default is
``200``. If necessary you may indicate multiple response codes
@@ -110,6 +113,7 @@ character must be used at both ends.
All of these variables may be used in all of the following fields:
* ``url``
* ``query_parameters``
* ``data``
* ``request_headers``
* ``response_strings``

View File

@@ -59,6 +59,7 @@ BASE_TEST = {
'url': '',
'status': '200',
'request_headers': {},
'query_parameters': {},
'data': '',
'xfail': False,
'skip': '',
@@ -170,6 +171,14 @@ class HTTPTestCase(unittest.TestCase):
for handler in self.response_handlers:
handler(self)
def _clean_query_value(self, value):
"""Clean up a single query from query_parameters."""
value = self.replace_template(value)
# stringify ints in Python version independent fashion
value = '%s' % value
value = value.encode('UTF-8')
return value
def _environ_replace(self, message):
"""Replace an indicator in a message with the environment value."""
value = re.sub(self._replacer_regex('ENVIRON'),
@@ -249,27 +258,49 @@ class HTTPTestCase(unittest.TestCase):
Scheme and netloc are saved for later use in comparisons.
"""
parsed_url = urlparse.urlsplit(url)
url_scheme = parsed_url[0]
scheme = 'http'
netloc = self.host
query_params = self.test_data['query_parameters']
if not url_scheme:
if not parsed_url.scheme:
if (self.port
and not (int(self.port) == 443 and ssl)
and not (int(self.port) == 80 and not ssl)):
netloc = '%s:%s' % (self.host, self.port)
if ssl:
scheme = 'https'
path = parsed_url[2]
if self.prefix:
path = '%s%s' % (self.prefix, path)
if query_params:
encoded_query_params = {}
for param, value in query_params.items():
# isinstance used because we can iter a string
if isinstance(value, list):
encoded_query_params[param] = [
self._clean_query_value(subvalue)
for subvalue in value]
else:
encoded_query_params[param] = (
self._clean_query_value(value))
query_string = urlparse.urlencode(
encoded_query_params, doseq=True)
if parsed_url.query:
query_string = '&'.join([parsed_url.query, query_string])
else:
query_string = parsed_url.query
full_url = urlparse.urlunsplit((scheme, netloc, path,
parsed_url[3], ''))
query_string, ''))
self.scheme = scheme
self.netloc = netloc
else:
full_url = url
self.scheme = url_scheme
self.scheme = parsed_url.scheme
self.netloc = parsed_url[1]
return full_url

View File

@@ -0,0 +1,57 @@
#
# As a convenience a URL can be augmented with structured declaration
# of query parameters.
#
tests:
- name: simple param
url: /foo
query_parameters:
bar: 1
response_headers:
x-gabbi-url: $SCHEME://$NETLOC/foo?bar=1
- name: joined params
url: /foo?cow=moo
query_parameters:
bar: 1
response_headers:
x-gabbi-url: $SCHEME://$NETLOC/foo?cow=moo&bar=1
- name: multi params
url: /foo
request_headers:
accept: application/json
query_parameters:
bar:
- 1
- 2
response_headers:
x-gabbi-url: $SCHEME://$NETLOC/foo?bar=1&bar=2
content-type: application/json
response_json_paths:
$.bar[0]: "1"
$.bar[1]: "2"
- name: replacers in params
url: /foo
query_parameters:
fromjson: $RESPONSE['$.bar[0]']
response_headers:
x-gabbi-url: $SCHEME://$NETLOC/foo?fromjson=1
- name: unicode
url: /foo
query_parameters:
snowman:
response_headers:
x-gabbi-url: $SCHEME://$NETLOC/foo?snowman=%E2%98%83
- name: url in param
url: /foo
query_parameters:
redirect: http://example.com/treehouse?secret=true&password=hello
response_headers:
x-gabbi-url: $SCHEME://$NETLOC/foo?redirect=http%3A%2F%2Fexample.com%2Ftreehouse%3Fsecret%3Dtrue%26password%3Dhello

View File

@@ -26,9 +26,11 @@ class UrlParseTest(unittest.TestCase):
@staticmethod
def make_test_case(host, port=8000, prefix=''):
# attributes used are port, prefix and host and they must
# be set manually here, due to metaclass magics elsewhere
# Attributes used are port, prefix and host and they must
# be set manually here, due to metaclass magics elsewhere.
# test_data must have a base value.
http_case = case.HTTPTestCase('test_request')
http_case.test_data = case.BASE_TEST
http_case.host = host
http_case.port = port
http_case.prefix = prefix