Merge pull request #89 from cdent/method-shortcut

added optional shortcut for specifying HTTP method and URL
This commit is contained in:
Chris Dent 2015-09-23 09:16:41 +01:00
commit 84a89c4962
4 changed files with 119 additions and 3 deletions
docs/source
gabbi

@ -3,13 +3,20 @@ Test Format
Gabbi tests are expressed in YAML containing an HTTP request and an
expected response. Each YAML file is an ordered sequence of requests.
The bare minimum YAML file for a single request is::
A minimal YAML file for a single request is::
tests:
- name: the name of a test
GET: /
This is :ref:`short <method-shortcut>` for::
tests:
- name: the name of a test
method: GET
url: /
This will make a request to ``/`` on whatever the configured
This will make a ``GET`` request to ``/`` on whatever the configured
:doc:`host` is. The test will pass if the status of the HTTP response
is ``200``.
@ -90,6 +97,21 @@ Many of these items allow substitutions (explained below).
This makes it possible to poll for a resource created via an
asynchronous request. Use with caution.
.. _method-shortcut:
Note that it's possible to combine ``method`` and ``url`` into a single
statement by exchanging the ``url`` key for the actual method::
method: PATCH
url: /
corresponds to::
PATCH: /
Any uppercase key is considered an HTTP method, there is no pre-defined
list of approved methods.
The ``response_*`` items are examples of Response Handlers. Additional
handlers may be created by test authors for specific use cases. See
:doc:`handlers` for more information.

@ -153,7 +153,7 @@ def test_suite_from_yaml(loader, test_base_name, test_yaml, test_directory,
# Set defaults from BASE_TESTS then update those defaults
# with any defaults set in the YAML file.
base_test_data = copy.deepcopy(case.HTTPTestCase.base_test)
defaults = test_yaml.get('defaults', {})
defaults = _validate_defaults(test_yaml.get('defaults', {}))
test_update(base_test_data, defaults)
# Establish any fixture classes.
@ -184,6 +184,21 @@ def test_suite_from_yaml(loader, test_base_name, test_yaml, test_directory,
test_name = '%s_%s' % (test_base_name,
test['name'].lower().replace(' ', '_'))
# use uppercase keys as HTTP method
method_key = None
for key, val in six.iteritems(test):
if _is_method_shortcut(key):
if method_key:
raise GabbiFormatError(
'duplicate method/URL directive in "%s"' %
test_name)
test['method'] = key
test['url'] = val
method_key = key
if method_key:
del test[method_key]
if not test['url']:
raise GabbiFormatError('Test url missing in test %s.'
% test_name)
@ -216,3 +231,18 @@ def test_suite_from_yaml(loader, test_base_name, test_yaml, test_directory,
prior_test = this_test
return file_suite
def _validate_defaults(defaults):
"""Ensure default test settings are acceptable
Raises GabbiFormatError for invalid settings.
"""
if any(_is_method_shortcut(key) for key in defaults):
raise GabbiFormatError(
'"METHOD: url" pairs not allowed in defaults')
return defaults
def _is_method_shortcut(key):
return key.isupper()

@ -0,0 +1,42 @@
tests:
- name: simple POST
POST: /somewhere
data:
cow: barn
request_headers:
content-type: application/json
response_json_paths:
$.cow: barn
- name: POST with query
POST: /somewhere?chicken=coop
data:
cow: barn
request_headers:
content-type: application/json
response_json_paths:
$.cow: barn
$.chicken[0]: coop
- name: simple GET
GET: /
ssl: True
response_headers:
x-gabbi-url: https://$NETLOC/
- name: arbitrary method
IMAGINARY: /
status: 405
response_headers:
allow: GET, PUT, POST, DELETE, PATCH
x-gabbi-method: IMAGINARY
x-gabbi-url: $SCHEME://$NETLOC/
# Can't do this because format validation is during test generation not
# test running. xfail only works during test running :(
# See gabbi/tests/test_driver for a test of this.
# - name: duplicate shortcut
# GET: /
# POST: /
# xfail: true

@ -111,3 +111,25 @@ class DriverTest(unittest.TestCase):
'localhost', 80, None, None)
self.assertIn("Invalid test keys used in test foo_simple:",
str(failure.exception))
def test_method_url_pair_format_error(self):
test_yaml = {'defaults': {'GET': '/foo'}, 'tests': []}
with self.assertRaises(driver.GabbiFormatError) as failure:
driver.test_suite_from_yaml(self.loader, 'foo', test_yaml, '.',
'localhost', 80, None, None)
self.assertIn('"METHOD: url" pairs not allowed in defaults',
str(failure.exception))
def test_method_url_pair_duplication_format_error(self):
test_yaml = {'tests': [{
'GET': '/',
'POST': '/',
'name': 'duplicate methods',
}]}
with self.assertRaises(driver.GabbiFormatError) as failure:
driver.test_suite_from_yaml(self.loader, 'foo', test_yaml, '.',
'localhost', 80, None, None)
self.assertIn(
'duplicate method/URL directive in "foo_duplicate_methods"',
str(failure.exception)
)