def test_lifespan_scope_default_version(): app = App() resource = testing.SimpleTestResourceAsync() app.add_route('/', resource) shutting_down = asyncio.Condition() req_event_emitter = testing.ASGILifespanEventEmitter(shutting_down) resp_event_collector = testing.ASGIResponseEventCollector() scope = {'type': 'lifespan'} async def t(): t = asyncio.get_event_loop().create_task( app(scope, req_event_emitter, resp_event_collector)) # NOTE(kgriffs): Yield to the lifespan task above await asyncio.sleep(0.001) async with shutting_down: shutting_down.notify() await t falcon.invoke_coroutine_sync(t) assert not resource.called
def test_lifespan_scope_version(spec_version, supported): app = App() shutting_down = asyncio.Condition() req_event_emitter = testing.ASGILifespanEventEmitter(shutting_down) resp_event_collector = testing.ASGIResponseEventCollector() scope = { 'type': 'lifespan', 'asgi': {'spec_version': spec_version, 'version': '3.0'} } if not supported: with pytest.raises(UnsupportedScopeError): falcon.async_to_sync( app.__call__, scope, req_event_emitter, resp_event_collector ) return async def t(): t = asyncio.get_event_loop().create_task( app(scope, req_event_emitter, resp_event_collector) ) # NOTE(kgriffs): Yield to the lifespan task above await asyncio.sleep(0.001) async with shutting_down: shutting_down.notify() await t falcon.async_to_sync(t)
async def test_ignore_extra_asgi_events(): collect = testing.ASGIResponseEventCollector() await collect({'type': 'http.response.start', 'status': 200}) await collect({'type': 'http.response.body', 'more_body': False}) # NOTE(kgriffs): Events after more_body is False are ignored to conform # to the ASGI spec. await collect({'type': 'http.response.body'}) assert len(collect.events) == 2
def _call_with_scope(scope): app = App() resource = testing.SimpleTestResourceAsync() app.add_route('/', resource) req_event_emitter = testing.ASGIRequestEventEmitter() resp_event_collector = testing.ASGIResponseEventCollector() falcon.invoke_coroutine_sync(app.__call__, scope, req_event_emitter, resp_event_collector) assert resource.called return resource
async def test_invalid_asgi_events(): collect = testing.ASGIResponseEventCollector() def make_event(headers=None, status=200): return { 'type': 'http.response.start', 'headers': headers or [], 'status': status } with pytest.raises(TypeError): await collect({'type': 123}) with pytest.raises(TypeError): headers = [ ('notbytes', b'bytes') ] await collect(make_event(headers)) with pytest.raises(TypeError): headers = [ (b'bytes', 'notbytes') ] await collect(make_event(headers)) with pytest.raises(ValueError): headers = [ # NOTE(kgriffs): Name must be lowercase (b'Content-Type', b'application/json') ] await collect(make_event(headers)) with pytest.raises(TypeError): await collect(make_event(status='200')) with pytest.raises(TypeError): await collect(make_event(status=200.1)) with pytest.raises(TypeError): await collect({'type': 'http.response.body', 'body': 'notbytes'}) with pytest.raises(TypeError): await collect({'type': 'http.response.body', 'more_body': ''}) with pytest.raises(ValueError): # NOTE(kgriffs): Invalid type await collect({'type': 'http.response.bod'})
def test_supported_asgi_version(version, supported): scope = { 'type': 'lifespan', 'asgi': { 'spec_version': '2.0', 'version': version }, } if version is None: del scope['asgi']['version'] app = App() resource = testing.SimpleTestResourceAsync() app.add_route('/', resource) shutting_down = asyncio.Condition() req_event_emitter = testing.ASGILifespanEventEmitter(shutting_down) resp_event_collector = testing.ASGIResponseEventCollector() async def task(): coro = asyncio.get_event_loop().create_task( app(scope, req_event_emitter, resp_event_collector)) # NOTE(vytas): Yield to the lifespan task above. await asyncio.sleep(0) assert len(resp_event_collector.events) == 1 event = resp_event_collector.events[0] if supported: assert event['type'] == 'lifespan.startup.complete' else: assert event['type'] == 'lifespan.startup.failed' assert event['message'].startswith( 'Falcon requires ASGI version 3.x') async with shutting_down: shutting_down.notify() await coro falcon.async_to_sync(task)