diff --git a/tests/integration/test_tornado.py b/tests/integration/test_tornado.py index f10c70b..7fd2574 100644 --- a/tests/integration/test_tornado.py +++ b/tests/integration/test_tornado.py @@ -284,3 +284,17 @@ def test_tornado_with_decorator_use_cassette(get_client): http.HTTPRequest('http://www.google.com/', method='GET') ) assert response.body.decode('utf-8') == "not actually google" + + +@pytest.mark.gen_test +@vcr.use_cassette(path_transformer=vcr.default_vcr.ensure_suffix('.yaml')) +def test_tornado_exception_can_be_caught(get_client): + try: + yield get(get_client(), 'http://httpbin.org/status/500') + except http.HTTPError as e: + assert e.code == 500 + + try: + yield get(get_client(), 'http://httpbin.org/status/404') + except http.HTTPError as e: + assert e.code == 404 diff --git a/tests/integration/test_tornado_exception_can_be_caught.yaml b/tests/integration/test_tornado_exception_can_be_caught.yaml new file mode 100644 index 0000000..c88f1f0 --- /dev/null +++ b/tests/integration/test_tornado_exception_can_be_caught.yaml @@ -0,0 +1,62 @@ +interactions: +- request: + body: null + headers: {} + method: GET + uri: http://httpbin.org/status/500 + response: + body: {string: !!python/unicode ''} + headers: + - !!python/tuple + - Content-Length + - ['0'] + - !!python/tuple + - Server + - [nginx] + - !!python/tuple + - Connection + - [close] + - !!python/tuple + - Access-Control-Allow-Credentials + - ['true'] + - !!python/tuple + - Date + - ['Thu, 30 Jul 2015 17:32:39 GMT'] + - !!python/tuple + - Access-Control-Allow-Origin + - ['*'] + - !!python/tuple + - Content-Type + - [text/html; charset=utf-8] + status: {code: 500, message: INTERNAL SERVER ERROR} +- request: + body: null + headers: {} + method: GET + uri: http://httpbin.org/status/404 + response: + body: {string: !!python/unicode ''} + headers: + - !!python/tuple + - Content-Length + - ['0'] + - !!python/tuple + - Server + - [nginx] + - !!python/tuple + - Connection + - [close] + - !!python/tuple + - Access-Control-Allow-Credentials + - ['true'] + - !!python/tuple + - Date + - ['Thu, 30 Jul 2015 17:32:39 GMT'] + - !!python/tuple + - Access-Control-Allow-Origin + - ['*'] + - !!python/tuple + - Content-Type + - [text/html; charset=utf-8] + status: {code: 404, message: NOT FOUND} +version: 1 diff --git a/vcr/cassette.py b/vcr/cassette.py index 1a290cd..cc1df6d 100644 --- a/vcr/cassette.py +++ b/vcr/cassette.py @@ -1,3 +1,4 @@ +import sys import inspect import logging @@ -87,16 +88,21 @@ class CassetteContextDecorator(object): return handler(function, args, kwargs) def _handle_coroutine(self, function, args, kwargs): + """Wraps a coroutine so that we're inside the cassette context for the + duration of the coroutine. + """ with self as cassette: coroutine = self.__handle_function(cassette, function, args, kwargs) - to_send = None + # We don't need to catch StopIteration. The caller (Tornado's + # gen.coroutine, for example) will handle that. + to_yield = next(coroutine) while True: try: - to_yield = coroutine.send(to_send) - except StopIteration: - break - else: to_send = yield to_yield + except Exception: + to_yield = coroutine.throw(*sys.exc_info()) + else: + to_yield = coroutine.send(to_send) def __handle_function(self, cassette, function, args, kwargs): if cassette.inject: