Wrap the http request to trap WSGIAppError and reraise

To create a strong boundary between the client and the server,
wsgi-intercept wraps exceptions raised in the intercepted app in a
WSGIAppError. In most situations this is a good thing. However if
gabbi is being used to do TDD against a nascent API this behavior
can obscure useful traceback information when there is a
catastrophic and untrapped exception in the server code.

To deal with this the WSGIAppError is caught and the contained
exception is reraised in all its glory to spew into STDERR for
debugging purposes.
This commit is contained in:
Chris Dent
2015-04-08 20:04:48 +01:00
parent d7871e038b
commit 5b2ac224bd
4 changed files with 31 additions and 10 deletions

View File

@@ -27,7 +27,9 @@ import os
import re import re
import sys import sys
import wsgi_intercept
import jsonpath_rw import jsonpath_rw
import six
from six.moves.urllib import parse as urlparse from six.moves.urllib import parse as urlparse
from testtools import testcase from testtools import testcase
@@ -243,14 +245,24 @@ class HTTPTestCase(testcase.TestCase):
self._json_replacer, message) self._json_replacer, message)
def _run_request(self, url, method, headers, body): def _run_request(self, url, method, headers, body):
"""Run the http request and decode output.""" """Run the http request and decode output.
response, content = self.http.request( The call to make the request will catch a WSGIAppError from
url, wsgi_intercept so that the real traceback from a catastrophic
method=method, error in the intercepted app can be examined.
headers=headers, """
body=body
) try:
response, content = self.http.request(
url,
method=method,
headers=headers,
body=body
)
except wsgi_intercept.WSGIAppError as exc:
# Extract and re-raise the wrapped exception.
six.reraise(exc.exception_type, exc.exception_value,
exc.traceback)
# Set headers and location attributes for follow on requests # Set headers and location attributes for follow on requests
self.response = response self.response = response

View File

@@ -19,11 +19,11 @@ tests:
- name: bogus method - name: bogus method
url: / url: /
method: DIE method: UNREAL
status: 405 status: 405
response_headers: response_headers:
allow: GET, PUT, POST, DELETE, PATCH allow: GET, PUT, POST, DELETE, PATCH
x-gabbi-method: DIE x-gabbi-method: UNREAL
x-gabbi-url: $SCHEME://$NETLOC/ x-gabbi-url: $SCHEME://$NETLOC/
- name: query returned - name: query returned
@@ -105,3 +105,9 @@ tests:
xfail: true xfail: true
response_test: response_test:
- 'CO"alpha": ["1"]' - 'CO"alpha": ["1"]'
- name: test exception wrapper
desc: simple wsgi will raise exception
url: /
xfail: true
method: DIE

View File

@@ -51,6 +51,9 @@ class SimpleWsgi(object):
('X-Gabbi-url', request_url), ('X-Gabbi-url', request_url),
] ]
if request_method == 'DIE':
raise Exception('because you asked me to')
if request_method not in METHODS: if request_method not in METHODS:
headers.append( headers.append(
('Allow', ', '.join(METHODS))) ('Allow', ', '.join(METHODS)))

View File

@@ -2,7 +2,7 @@
# Run the tests and confirm that the stuff we expect to skip or fail # Run the tests and confirm that the stuff we expect to skip or fail
# does. # does.
GREP_FAIL_MATCH='expected failures=3' GREP_FAIL_MATCH='expected failures=4'
GREP_SKIP_MATCH='skips=2' GREP_SKIP_MATCH='skips=2'
python setup.py testr && \ python setup.py testr && \