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:
@@ -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.
|
||||||
|
|
||||||
|
The call to make the request will catch a WSGIAppError from
|
||||||
|
wsgi_intercept so that the real traceback from a catastrophic
|
||||||
|
error in the intercepted app can be examined.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
response, content = self.http.request(
|
response, content = self.http.request(
|
||||||
url,
|
url,
|
||||||
method=method,
|
method=method,
|
||||||
headers=headers,
|
headers=headers,
|
||||||
body=body
|
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
|
||||||
|
@@ -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
|
||||||
|
@@ -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)))
|
||||||
|
@@ -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 && \
|
||||||
|
Reference in New Issue
Block a user