Skip to content

Commit

Permalink
Improve coverage for error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
sametmax committed Jul 22, 2016
1 parent fdf72c2 commit 10d09b2
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 32 deletions.
34 changes: 23 additions & 11 deletions src/tygs/components.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import asyncio

import sys
import traceback

from functools import partial, wraps
from textwrap import dedent

Expand Down Expand Up @@ -178,6 +181,24 @@ async def _get_handler_and_tygs_req(self, message, payload):

return tygs_request, handler

async def _call_request_handler(self, req, handler):

try:
await handler(req, req.response)
except Exception:
# TODO: provide a debug web page and disable this
# on prod
handler = self._router.get_error_handler(500)
resp = req.response
resp.status = 500
resp.reason = 'Internal server error'

tb = ''.join(traceback.format_exception(*sys.exc_info()))

resp.context['error_details'] = tb
# logging.error(e, exc_info=True)
await handler(req, resp)

async def handle_request(self, message, payload):
if self.access_log:
now = self._loop.time()
Expand All @@ -200,17 +221,7 @@ async def handle_request(self, message, payload):
############

###############
try:
await handler(tygs_request, tygs_request.response)
except Exception as e:
# TODO: provide a debug web page and disable this
# on prod
handler = self._router.get_error_handler(500)
resp = tygs_request.response
resp.status_code = 500
resp.reason = 'Internal server error'
resp.context['error_details'] = str(e)
await handler(tygs_request, resp)
await self._call_request_handler(tygs_request, handler)

###############

Expand Down Expand Up @@ -241,6 +252,7 @@ def aiohttp_request_handler_factory_adapter_factory(
app, *, handler_adapter=AioHttpRequestHandlerAdapter):

class AioHttpRequestHandlerFactoryAdapter(RequestHandlerFactory):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._handler = partial(handler_adapter, tygs_app=app)
Expand Down
12 changes: 1 addition & 11 deletions tests/fixtures/tygs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import asyncio

from textwrap import dedent
from functools import partial

from unittest.mock import MagicMock
Expand All @@ -16,7 +15,6 @@
from tygs.webapp import WebApp
from tygs.app import App
from tygs.utils import HTTP_VERBS
from tygs.exceptions import TestClientError
from tygs.components import (
AioHttpRequestHandlerAdapter,
aiohttp_request_handler_factory_adapter_factory
Expand Down Expand Up @@ -49,15 +47,7 @@ async def request(self, method, url, *args, **kwargs):

await resp.text()

try:
return self.q.get_nowait()
except asyncio.queues.QueueEmpty:
raise TestClientError(dedent("""
No request in the test client request queue. It probably
means an exceptions occured before it could be placed
in it it. Check the request handling code to see
if an non handled exception hasn't occured here.
"""))
return self.q.get_nowait()

return TestClient

Expand Down
17 changes: 7 additions & 10 deletions tests/test_http_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,17 +133,14 @@ async def test_request_body(queued_webapp):
def index_controller(req, res):
return res.text('')

try:
await app.async_ready()
response = await app.client.post('/',
params={'param': 'value'})
await app.async_ready()
response = await app.client.post('/', params={'param': 'value'})

request = response.request
request = response.request

await request.load_body()
await request.load_body()

assert 'param' in request
assert 'fromage' not in request
assert 'param' in request
assert 'fromage' not in request

finally:
await app.async_stop()
await app.async_stop()
18 changes: 18 additions & 0 deletions tests/test_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,21 @@ def toto():
handler, arguments = aiorun(coro)

assert e.value.code == 404


@pytest.mark.asyncio
async def test_queued_webapp_and_client(queued_webapp):

app = queued_webapp()
http = app.components['http']

@http.get('/')
def zero_error(req, res):
1 / 0

await app.async_ready()
response = await app.client.get('/')
assert response.status == 500
assert response.reason == 'Internal server error'
assert 'ZeroDivisionError: division by zero' in response._renderer_data
await app.async_stop()
19 changes: 19 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,22 @@ def pwet(self):
assert my_class_instance.pwet == 'value'
assert m.call_count == 1
assert isinstance(MyClass.pwet, utils.removable_property)


@pytest.mark.asyncio
async def test_queued_webapp_and_client(queued_webapp):

app = queued_webapp()
http = app.components['http']

# TODO: when 2 handlers have the same name, we create an endpoint with
# the same name as well automatically, so it silently override each
# other. We should check for duplicates and raise an exception instead.
@http.get('/')
def index_controller(req, res):
return res.text('index_controller')

await app.async_ready()
response = await app.client.get('/')
assert response._renderer_data == 'index_controller'
await app.async_stop()

0 comments on commit 10d09b2

Please sign in to comment.