Skip to content

Commit

Permalink
test(asgi): Cover missing branches
Browse files Browse the repository at this point in the history
  • Loading branch information
kgriffs committed Dec 13, 2019
1 parent 000129f commit 95b588a
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 5 deletions.
4 changes: 2 additions & 2 deletions falcon/api_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ def prepare_middleware(middleware, independent_middleware=False, asgi=False):
)
)

process_resource = _wrap_non_coroutine_unsafe(
process_resource = (
util.get_bound_method(component, 'process_resource_async') or
_wrap_non_coroutine_unsafe(
util.get_bound_method(component, 'process_resource')
)
)

process_response = _wrap_non_coroutine_unsafe(
process_response = (
util.get_bound_method(component, 'process_response_async') or
_wrap_non_coroutine_unsafe(
util.get_bound_method(component, 'process_response')
Expand Down
6 changes: 5 additions & 1 deletion falcon/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,11 @@ def handle(req, resp, ex, params):
"""
def wrap_old_handler(old_handler):
if iscoroutinefunction(old_handler):
# NOTE(kgriffs): This branch *is* actually tested by
# test_error_handlers.test_handler_signature_shim_asgi() (as
# verified manually via pdb), but for some reason coverage
# tracking isn't picking it up.
if iscoroutinefunction(old_handler): # pragma: no cover
@wraps(old_handler)
async def handler_async(req, resp, ex, params):
await old_handler(ex, req, resp, params)
Expand Down
28 changes: 27 additions & 1 deletion tests/test_error_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import falcon
from falcon import constants, PY35, testing

from _util import create_app # NOQA
from _util import create_app, disable_asgi_non_coroutine_wrapping # NOQA


def capture_error(req, resp, ex, params):
Expand Down Expand Up @@ -208,3 +208,29 @@ def legacy_handler3(err, rq, rs, prms):
client.simulate_delete()
client.simulate_get()
client.simulate_head()

def test_handler_signature_shim_asgi(self):
def check_args(ex, req, resp):
assert isinstance(ex, BaseException)
assert isinstance(req, falcon.Request)
assert isinstance(resp, falcon.Response)

async def legacy_handler(err, rq, rs, prms):
check_args(err, rq, rs)

app = create_app(True)
app.add_route('/', ErroredClassResource())
app.add_error_handler(Exception, legacy_handler)
client = testing.TestClient(app)

client.simulate_get()

def test_handler_must_be_coroutine_for_asgi(self):
async def legacy_handler(err, rq, rs, prms):
pass

app = create_app(True)

with disable_asgi_non_coroutine_wrapping():
with pytest.raises(ValueError):
app.add_error_handler(Exception, capture_error)
26 changes: 25 additions & 1 deletion tests/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest

import falcon
import falcon.errors
import falcon.testing as testing

from _util import create_app # NOQA
Expand Down Expand Up @@ -854,9 +855,14 @@ def test_http_status_raised_from_error_handler(self, asgi):
def _http_error_handler(error, req, resp, params):
raise falcon.HTTPStatus(falcon.HTTP_201)

async def _http_error_handler_async(error, req, resp, params):
raise falcon.HTTPStatus(falcon.HTTP_201)

h = _http_error_handler_async if asgi else _http_error_handler

# NOTE(kgriffs): This will take precedence over the default
# handler for facon.HTTPError.
app.add_error_handler(falcon.HTTPError, _http_error_handler)
app.add_error_handler(falcon.HTTPError, h)

response = client.simulate_request(path='/', method='POST')
assert response.status == falcon.HTTP_201
Expand Down Expand Up @@ -949,3 +955,21 @@ def test_api_initialization_with_cors_enabled_and_middleware_param(self, mw, asg
client = testing.TestClient(app)
result = client.simulate_get()
assert result.headers['Access-Control-Allow-Origin'] == '*'


def test_async_postfix_method_must_be_coroutine():
class FaultyComponentA:
def process_request_async(self, req, resp):
pass

class FaultyComponentB:
def process_resource_async(self, req, resp, resource, params):
pass

class FaultyComponentC:
def process_response_async(self, req, resp, resource, req_succeeded):
pass

for mw in (FaultyComponentA, FaultyComponentB, FaultyComponentC):
with pytest.raises(falcon.errors.CompatibilityError):
create_app(True, middleware=[mw()])

0 comments on commit 95b588a

Please sign in to comment.