async def test_host_matching() -> None: app = Quart(__name__, static_host="quart.com", host_matching=True) @app.route("/", host="quart.com") async def route() -> str: return "" test_client = app.test_client() response = await test_client.get("/", headers={"host": "quart.com"}) assert response.status_code == 200 response = await test_client.get("/", headers={"host": "localhost"}) assert response.status_code == 404
def test_bad_request_if_websocket_route() -> None: app = Quart(__name__) url_adapter = Mock() url_adapter.match.side_effect = BadRequest() app.create_url_adapter = lambda *_: url_adapter # type: ignore request = Request('GET', 'http', '/', b'', CIMultiDict(), send_push_promise=no_op_push) RequestContext(app, request) assert isinstance(request.routing_exception, BadRequest)
def test_add_url_rule_host_and_subdomain_errors( host_matching: bool, server_name: Optional[str], subdomain: Optional[str], host: Optional[str], error: Exception, ) -> None: static_host = 'quart.com' if host_matching else None app = Quart(__name__, static_host=static_host, host_matching=host_matching) app.config['SERVER_NAME'] = server_name def route() -> str: return '' with pytest.raises(error): app.add_url_rule('/', view_func=route, subdomain=subdomain, host=host)
async def test_make_response(result: ResponseReturnValue, expected: Response, raises: bool) -> None: app = Quart(__name__) app.config["RESPONSE_TIMEOUT"] = None try: response = await app.make_response(result) except TypeError: if not raises: raise else: assert set(response.headers.keys()) == set(expected.headers.keys()) assert response.status_code == expected.status_code assert (await response.get_data()) == (await expected.get_data())
async def test_secure_cookie_session_interface_open_session() -> None: session = SecureCookieSession() session['something'] = 'else' interface = SecureCookieSessionInterface() app = Quart(__name__) app.secret_key = 'secret' response = Response('') await interface.save_session(app, session, response) request = Request( 'GET', 'http', '/', b'', CIMultiDict(), "", "1.1", send_push_promise=no_op_push, ) request.headers['Cookie'] = response.headers['Set-Cookie'] new_session = await interface.open_session(app, request) assert new_session == session
async def test_host_matching() -> None: app = Quart(__name__, static_host='quart.com', host_matching=True) app.config['SERVER_NAME'] = 'quart.com' @app.route('/') def route() -> str: return '' test_client = app.test_client() response = await test_client.get('/', headers={'host': 'quart.com'}) assert response.status_code == 200 response = await test_client.get('/', headers={'host': 'localhost'}) assert response.status_code == 404
async def test_works_without_copy_current_request_context() -> None: app = Quart(__name__) @app.route("/") async def index() -> str: async def within_context() -> None: assert request.path == "/" await asyncio.ensure_future(within_context()) return "" test_client = app.test_client() response = await test_client.get("/") assert response.status_code == 200
async def test_fails_without_copy_current_request_context() -> None: app = Quart(__name__) @app.route('/') async def index() -> str: async def within_context() -> None: assert request.path == '/' await asyncio.ensure_future(within_context()) return '' test_client = app.test_client() response = await test_client.get('/') assert response.status_code == 500
def test_add_url_rule_automatic_options( methods: Set[str], arg_automatic: Optional[bool], func_automatic: Optional[bool], expected_methods: Set[str], expected_automatic: bool, ) -> None: app = Quart(__name__) def route() -> str: return '' route.provide_automatic_options = func_automatic # type: ignore app.add_url_rule('/', 'end', route, methods, provide_automatic_options=arg_automatic) assert app.url_map.endpoints['end'][0].methods == expected_methods assert app.url_map.endpoints['end'][0].provide_automatic_options == expected_automatic
def test_bad_request_if_websocket_missmatch( request_factory: object, context_class: object, is_websocket: bool, ) -> None: app = Quart(__name__) url_adapter = Mock() url_adapter.match.return_value = Rule('/', ['GET'], 'index', is_websocket=is_websocket), {} app.create_url_adapter = lambda *_: url_adapter # type: ignore request_websocket = request_factory('GET', '/', CIMultiDict()) # type: ignore context_class(app, request_websocket) # type: ignore assert isinstance(request_websocket.routing_exception, BadRequest)
def test_request_context_match() -> None: app = Quart(__name__) url_adapter = Mock() rule = Rule('/', {'GET'}, 'index') url_adapter.match.return_value = (rule, {'arg': 'value'}) app.create_url_adapter = lambda *_: url_adapter # type: ignore request = Request('GET', 'http', '/', b'', CIMultiDict(), send_push_promise=no_op_push) RequestContext(app, request) assert request.url_rule == rule assert request.view_args == {'arg': 'value'}
async def test_copy_current_websocket_context() -> None: app = Quart(__name__) @app.websocket('/') async def index() -> None: @copy_current_websocket_context async def within_context() -> None: return websocket.path data = await asyncio.ensure_future(within_context()) await websocket.send(data.encode()) test_client = app.test_client() with test_client.websocket('/') as test_websocket: data = await test_websocket.receive() assert data == b'/'
async def test_overlapping_request_ctx() -> None: app = Quart(__name__) request = Request('GET', 'http', '/', b'', CIMultiDict(), send_push_promise=no_op_push) ctx1 = app.request_context(request) await ctx1.__aenter__() ctx2 = app.request_context(request) await ctx2.__aenter__() await ctx1.__aexit__(None, None, None) assert has_app_context() # Ensure the app context still exists for ctx2 await ctx2.__aexit__(None, None, None)
def test_request_context_matching_error( exception_type: Exception, exception_instance: Exception, ) -> None: app = Quart(__name__) url_adapter = Mock() url_adapter.match.side_effect = exception_instance app.create_url_adapter = lambda *_: url_adapter # type: ignore request = Request('GET', 'http', '/', b'', CIMultiDict(), send_push_promise=no_op_push) RequestContext(app, request) assert isinstance(request.routing_exception, exception_type) # type: ignore
def test_add_url_rule_automatic_options( methods: Set[str], arg_automatic: Optional[bool], func_automatic: Optional[bool], expected_methods: Set[str], expected_automatic: bool, ) -> None: app = Quart(__name__) def route() -> str: return "" route.provide_automatic_options = func_automatic # type: ignore app.add_url_rule("/", "end", route, methods, provide_automatic_options=arg_automatic) assert app.url_map._rules_by_endpoint["end"][0].methods == expected_methods # type: ignore assert app.url_map._rules_by_endpoint["end"][0].provide_automatic_options == expected_automatic # type: ignore # noqa: E501
def test_env_and_debug_environments(quart_env: Optional[str], quart_debug: Optional[bool], expected_env: bool, expected_debug: bool) -> None: if quart_env is None: os.environ.pop("QUART_ENV", None) else: os.environ["QUART_ENV"] = quart_env if quart_debug is None: os.environ.pop("QUART_DEBUG", None) else: os.environ["QUART_DEBUG"] = str(quart_debug) app = Quart(__name__) assert app.env == expected_env assert app.debug is expected_debug
async def test_copy_current_app_context() -> None: app = Quart(__name__) @app.route("/") async def index() -> str: g.foo = "bar" @copy_current_app_context async def within_context() -> None: assert g.foo == "bar" await asyncio.ensure_future(within_context()) return "" test_client = app.test_client() response = await test_client.get("/") assert response.status_code == 200
async def test_copy_current_app_context() -> None: app = Quart(__name__) @app.route('/') async def index() -> str: g.foo = 'bar' # type: ignore @copy_current_app_context async def within_context() -> None: assert g.foo == 'bar' await asyncio.ensure_future(within_context()) return '' test_client = app.test_client() response = await test_client.get('/') assert response.status_code == 200
async def test_app_handle_request_asyncio_cancelled_error() -> None: app = Quart(__name__) @app.route("/") async def index() -> NoReturn: raise asyncio.CancelledError() request = app.request_class("GET", "http", "/", b"", CIMultiDict(), "", "1.1", send_push_promise=no_op_push) with pytest.raises(asyncio.CancelledError): await app.handle_request(request)
def test_secure_cookie_session_interface_save_session() -> None: session = SecureCookieSession() session['something'] = 'else' interface = SecureCookieSessionInterface() app = Quart(__name__) app.secret_key = 'secret' response = Response('') interface.save_session(app, session, response) cookies = SimpleCookie() cookies.load(response.headers['Set-Cookie']) cookie = cookies[app.session_cookie_name] assert cookie['path'] == interface.get_cookie_path(app) assert cookie['httponly'] == '' if not interface.get_cookie_httponly(app) else True assert cookie['secure'] == '' if not interface.get_cookie_secure(app) else True assert cookie['domain'] == (interface.get_cookie_domain(app) or '') assert cookie['expires'] == (interface.get_expiration_time(app, session) or '') assert response.headers['Vary'] == 'Cookie'
def test_bad_request_if_websocket_route() -> None: app = Quart(__name__) url_adapter = Mock() url_adapter.match.side_effect = WBadRequest() app.create_url_adapter = lambda *_: url_adapter # type: ignore request = Request( "GET", "http", "/", b"", Headers([("host", "quart.com")]), "", "1.1", send_push_promise=no_op_push, ) RequestContext(app, request) assert isinstance(request.routing_exception, BadRequest)
async def test_propagation(debug: bool, testing: bool, raises: bool) -> None: app = Quart(__name__) @app.route("/") async def exception() -> ResponseReturnValue: raise SimpleException() app.debug = debug app.testing = testing test_client = app.test_client() if raises: with pytest.raises(SimpleException): await test_client.get("/") else: response = await test_client.get("/") assert response.status_code == 500
def test_request_context_matching_error( exception_type: Exception, exception_instance: Exception ) -> None: app = Quart(__name__) url_adapter = Mock() url_adapter.match.side_effect = exception_instance app.create_url_adapter = lambda *_: url_adapter # type: ignore request = Request( "GET", "http", "/", b"", Headers([("host", "quart.com")]), "", "1.1", send_push_promise=no_op_push, ) RequestContext(app, request) assert isinstance(request.routing_exception, exception_type) # type: ignore
def test_request_context_match() -> None: app = Quart(__name__) url_adapter = Mock() rule = QuartRule("/", methods={"GET"}, endpoint="index") url_adapter.match.return_value = (rule, {"arg": "value"}) app.create_url_adapter = lambda *_: url_adapter # type: ignore request = Request( "GET", "http", "/", b"", Headers([("host", "quart.com")]), "", "1.1", send_push_promise=no_op_push, ) RequestContext(app, request) assert request.url_rule == rule assert request.view_args == {"arg": "value"}
async def test_app_handle_websocket_asyncio_cancelled_error() -> None: app = Quart(__name__) @app.websocket("/") async def index() -> NoReturn: raise asyncio.CancelledError() websocket = app.websocket_class( "/", b"", "wss", CIMultiDict(), None, None, None, None, ) with pytest.raises(asyncio.CancelledError): await app.handle_websocket(websocket)
async def test_secure_cookie_session_interface_open_session() -> None: session = SecureCookieSession() session["something"] = "else" interface = SecureCookieSessionInterface() app = Quart(__name__) app.secret_key = "secret" response = Response("") await interface.save_session(app, session, response) request = Request("GET", "http", "/", b"", Headers(), "", "1.1", {}, send_push_promise=no_op_push) request.headers["Cookie"] = response.headers["Set-Cookie"] new_session = await interface.open_session(app, request) assert new_session == session
def test_env_and_debug_environments( quart_env: Optional[str], quart_debug: Optional[bool], expected_env: bool, expected_debug: bool, monkeypatch: MonkeyPatch, ) -> None: if quart_env is None: monkeypatch.delenv("QUART_ENV", raising=False) else: monkeypatch.setenv("QUART_ENV", quart_env) if quart_debug is None: monkeypatch.delenv("QUART_DEBUG", raising=False) else: monkeypatch.setenv("QUART_DEBUG", str(quart_debug)) app = Quart(__name__) assert app.env == expected_env assert app.debug is expected_debug
def test_endpoint_overwrite() -> None: app = Quart(__name__) def route() -> str: return "" def route2() -> str: return "" async def route3() -> str: return "" app.add_url_rule("/a", "index", route, ["GET"]) app.add_url_rule("/a/a", "index", route, ["GET"]) # Should not assert, as same view func with pytest.raises(AssertionError): app.add_url_rule("/a/b", "index", route2, ["GET"]) app.add_url_rule("/b", "async", route3, ["GET"]) app.add_url_rule("/b/a", "async", route3, ["GET"]) # Should not assert, as same view func with pytest.raises(AssertionError): app.add_url_rule("/b/b", "async", route2, ["GET"])
async def test_overlapping_request_ctx() -> None: app = Quart(__name__) request = Request( "GET", "http", "/", b"", Headers([("host", "quart.com")]), "", "1.1", send_push_promise=no_op_push, ) ctx1 = app.request_context(request) await ctx1.__aenter__() ctx2 = app.request_context(request) await ctx2.__aenter__() await ctx1.__aexit__(None, None, None) assert has_app_context() # Ensure the app context still exists for ctx2 await ctx2.__aexit__(None, None, None)
async def test_app_handle_request_asyncio_cancelled_error(http_scope: HTTPScope) -> None: app = Quart(__name__) @app.route("/") async def index() -> NoReturn: raise asyncio.CancelledError() request = app.request_class( "GET", "http", "/", b"", Headers([("host", "quart.com")]), "", "1.1", http_scope, send_push_promise=no_op_push, ) with pytest.raises(asyncio.CancelledError): await app.handle_request(request)