def https_server(cert_pem_file, cert_private_key_file): config = Config(app=app, lifespan="off", ssl_certfile=cert_pem_file, ssl_keyfile=cert_private_key_file, host="localhost", port=8001, loop="asyncio") server = TestServer(config=config) yield from serve_in_thread(server)
def test_log_config_default( mocked_logging_config_module: MagicMock, use_colors: typing.Optional[bool], expected: typing.Optional[bool], ) -> None: """ Test that one can specify the use_colors option when using the default logging config. """ config = Config(app=asgi_app, use_colors=use_colors) config.load() mocked_logging_config_module.dictConfig.assert_called_once_with( LOGGING_CONFIG) (provided_dict_config, ), _ = mocked_logging_config_module.dictConfig.call_args assert provided_dict_config["formatters"]["default"][ "use_colors"] == expected
def test_log_config_yaml( mocked_logging_config_module: MagicMock, logging_config: dict, yaml_logging_config: str, mocker: MockerFixture, config_filename: str, ) -> None: """ Test that one can load a yaml config from disk. """ mocked_open = mocker.patch("uvicorn.config.open", mocker.mock_open(read_data=yaml_logging_config)) config = Config(app=asgi_app, log_config=config_filename) config.load() mocked_open.assert_called_once_with(config_filename) mocked_logging_config_module.dictConfig.assert_called_once_with( logging_config)
async def server(): config = Config(app=app, lifespan="off") server = Server(config=config) task = asyncio.ensure_future(server.serve()) try: while not server.started: await asyncio.sleep(0.0001) yield server finally: task.cancel()
def test_log_config_yaml( mocked_logging_config_module, logging_config, yaml_logging_config, mocker, config_filename, ): """ Test that one can load a yaml config from disk. """ mocked_open = mocker.patch("uvicorn.config.open", mocker.mock_open(read_data=yaml_logging_config)) config = Config(app=asgi_app, log_config=config_filename) config.load() mocked_open.assert_called_once_with(config_filename) mocked_logging_config_module.dictConfig.assert_called_once_with( logging_config)
def test_should_reload_when_python_file_in_subdir_is_changed(self) -> None: file = self.reload_path / "app" / "sub" / "sub.py" with as_cwd(self.reload_path): config = Config(app="tests.test_config:asgi_app", reload=True) reloader = self._setup_reloader(config) assert self._reload_tester(reloader, file) reloader.shutdown()
def test_reloader_should_initialize(self): """ A basic sanity check. Simply run the reloader against a no-op server, and signal for it to quit immediately. """ config = Config(app=None, reload=True) reloader = self._setup_reloader(config) reloader.shutdown()
def run(app: typing.Union[ASGIApplication, str], **kwargs: typing.Any) -> None: config = Config(app, **kwargs) server = Server(config=config) if (config.reload or config.workers > 1) and not isinstance(app, str): logger = logging.getLogger("uvicorn.error") logger.warning( "You must pass the application as an import string to enable 'reload' or " "'workers'.") sys.exit(1) if config.should_reload: sock = config.bind_socket() ChangeReload(config, target=server.run, sockets=[sock]).run() elif config.workers > 1: sock = config.bind_socket() Multiprocess(config, target=server.run, sockets=[sock]).run() else: server.run()
def test_should_not_reload_when_dot_file_is_changed(self) -> None: file = self.reload_path / ".dotted" with as_cwd(self.reload_path): config = Config(app="tests.test_config:asgi_app", reload=True) reloader = self._setup_reloader(config) assert not self._reload_tester(reloader, file) reloader.shutdown()
def run(app, **kwargs): config = Config(app, **kwargs) server = Server(config=config) if config.reload and not isinstance(app, str): config.logger_instance.warn( "auto-reload only works when app is passed as an import string." ) if isinstance(app, str) and (config.debug or config.reload): socket = config.bind_socket() supervisor = StatReload(config) supervisor.run(server.run, sockets=[socket]) elif config.workers > 1: socket = config.bind_socket() supervisor = Multiprocess(config) supervisor.run(server.run, sockets=[socket]) else: server.run()
def get_connected_protocol(app, protocol_cls, **kwargs): loop = MockLoop() transport = MockTransport() config = Config(app=app, **kwargs) server_state = ServerState() protocol = protocol_cls(config=config, server_state=server_state, _loop=loop) protocol.connection_made(transport) return protocol
async def test(): config = Config(app=app, lifespan=mode) lifespan = LifespanOn(config) await lifespan.startup() assert not lifespan.startup_failed await lifespan.shutdown() assert lifespan.shutdown_failed assert lifespan.error_occured is raise_exception assert lifespan.should_exit
def __init__( self, config: Config, server_state: ServerState, _loop: Optional[asyncio.AbstractEventLoop] = None, ) -> None: if not config.loaded: config.load() self.config = config self.app = config.loaded_app self.loop = _loop or asyncio.get_event_loop() self.logger = logging.getLogger("uvicorn.error") self.access_logger = logging.getLogger("uvicorn.access") self.access_log = self.access_logger.hasHandlers() self.conn = h11.Connection(h11.SERVER) self.ws_protocol_class = config.ws_protocol_class self.root_path = config.root_path self.limit_concurrency = config.limit_concurrency # Timeouts self.timeout_keep_alive_task: Optional[asyncio.TimerHandle] = None self.timeout_keep_alive = config.timeout_keep_alive # Shared server state self.server_state = server_state self.connections = server_state.connections self.tasks = server_state.tasks self.default_headers = server_state.default_headers # Per-connection state self.transport: asyncio.Transport = None # type: ignore[assignment] self.flow: FlowControl = None # type: ignore[assignment] self.server: Optional[Tuple[str, int]] = None self.client: Optional[Tuple[str, int]] = None self.scheme: Optional[Literal["http", "https"]] = None # Per-request state self.scope: HTTPScope = None # type: ignore[assignment] self.headers: List[Tuple[bytes, bytes]] = None # type: ignore[assignment] self.cycle: RequestResponseCycle = None # type: ignore[assignment]
def __init__(self, *args, **kwargs): super(UvicornWorker, self).__init__(*args, **kwargs) logger = logging.getLogger("uvicorn.error") logger.handlers = self.log.error_log.handlers logger.setLevel(self.log.error_log.level) logger.propagate = False logger = logging.getLogger("uvicorn.access") logger.handlers = self.log.access_log.handlers logger.setLevel(self.log.access_log.level) logger.propagate = False config_kwargs = { "app": None, "log_config": None, "timeout_keep_alive": self.cfg.keepalive, "timeout_notify": self.timeout, "callback_notify": self.callback_notify, "limit_max_requests": self.max_requests, "forwarded_allow_ips": self.cfg.forwarded_allow_ips, "gunicorn_log": self.log, } if self.cfg.is_ssl: ssl_kwargs = { "ssl_keyfile": self.cfg.ssl_options.get("keyfile"), "ssl_certfile": self.cfg.ssl_options.get("certfile"), "ssl_keyfile_password": self.cfg.ssl_options.get("password"), "ssl_version": self.cfg.ssl_options.get("ssl_version"), "ssl_cert_reqs": self.cfg.ssl_options.get("cert_reqs"), "ssl_ca_certs": self.cfg.ssl_options.get("ca_certs"), "ssl_ciphers": self.cfg.ssl_options.get("ciphers"), } config_kwargs.update(ssl_kwargs) if self.cfg.settings["backlog"].value: config_kwargs["backlog"] = self.cfg.settings["backlog"].value config_kwargs.update(self.CONFIG_KWARGS) self.config = Config(**config_kwargs)
def test_statreload(certfile_and_keyfile): certfile, keyfile = certfile_and_keyfile config = Config(app=None, ssl_certfile=certfile.name, ssl_keyfile=keyfile.name) server = Server(config) type(server).run = lambda self: None reloader = StatReload(config) reloader.run(server.run)
def test_statreload(): """ A basic sanity check. Simply run the reloader against a no-op server, and signal for it to quit immediately. """ config = Config(app=None, reload=True) reloader = StatReload(config, target=run, sockets=[]) reloader.signal_handler(sig=signal.SIGINT, frame=None) reloader.run()
async def test_run_chain(tls_ca_ssl_context, tls_certificate_pem_path): config = Config( app=app, loop="asyncio", limit_max_requests=1, ssl_certfile=tls_certificate_pem_path, ) async with run_server(config): async with httpx.AsyncClient(verify=tls_ca_ssl_context) as client: response = await client.get("https://127.0.0.1:8000") assert response.status_code == 204
def test_reloader_should_initialize(self) -> None: """ A basic sanity check. Simply run the reloader against a no-op server, and signal for it to quit immediately. """ with as_cwd(self.reload_path): config = Config(app="tests.test_config:asgi_app", reload=True) reloader = self._setup_reloader(config) reloader.shutdown()
def run(app, **kwargs): config = Config(app, **kwargs) server = Server(config=config) if (config.reload or config.workers > 1) and not isinstance(app, str): logger = logging.getLogger("uvicorn.error") logger.warn( "You must pass the application as an import string to enable 'reload' or 'workers'." ) sys.exit(1) if config.should_reload: sock = config.bind_socket() supervisor = StatReload(config, target=server.run, sockets=[sock]) supervisor.run() elif config.workers > 1: sock = config.bind_socket() supervisor = Multiprocess(config, target=server.run, sockets=[sock]) supervisor.run() else: server.run()
def test_should_reload_when_python_file_is_changed(self): file = "example.py" update_file = self.tmp_path.joinpath(file) update_file.touch() with self.tmpdir.as_cwd(): config = Config(app=None, reload=True) reloader = self._setup_reloader(config) assert self._reload_tester(reloader, update_file) reloader.shutdown()
async def test(): config = Config(app=app, lifespan="auto") lifespan = LifespanOn(config) assert not startup_complete assert not shutdown_complete await lifespan.startup() assert startup_complete assert not shutdown_complete await lifespan.shutdown() assert startup_complete assert shutdown_complete
async def test_return_close_header(): config = Config(app=app, host="localhost", loop="asyncio", limit_max_requests=1) async with run_server(config): async with httpx.AsyncClient() as client: response = await client.get( "http://127.0.0.1:8000", headers={"connection": "close"} ) assert response.status_code == 204 assert ( "connection" in response.headers and response.headers["connection"] == "close" )
async def test(): config = Config(app=app, loop=asyncio.get_event_loop()) lifespan = LifespanOn(config) assert not startup_complete assert not shutdown_complete await lifespan.startup() assert startup_complete assert not shutdown_complete await lifespan.shutdown() assert startup_complete assert shutdown_complete
def test_env_file( web_concurrency: int, forwarded_allow_ips: str, caplog: pytest.LogCaptureFixture, tmp_path: Path, ) -> None: """ Test that one can load environment variables using an env file. """ fp = tmp_path / ".env" content = (f"WEB_CONCURRENCY={web_concurrency}\n" f"FORWARDED_ALLOW_IPS={forwarded_allow_ips}\n") fp.write_text(content) with caplog.at_level(logging.INFO): config = Config(app=asgi_app, env_file=fp) config.load() assert config.workers == int(str(os.getenv("WEB_CONCURRENCY"))) assert config.forwarded_allow_ips == os.getenv("FORWARDED_ALLOW_IPS") assert len(caplog.records) == 1 assert f"Loading environment from '{fp}'" in caplog.records[0].message
def test_non_existant_reload_dir_is_not_set( reload_directory_structure: Path, caplog: pytest.LogCaptureFixture) -> None: with as_cwd(reload_directory_structure), caplog.at_level(logging.WARNING): config = Config(app="tests.test_config:asgi_app", reload=True, reload_dirs=["reload"]) assert config.reload_dirs == [reload_directory_structure] assert ( caplog.records[-1].message == "Provided reload directories ['reload'] did not contain valid " + "directories, watching current working directory.")
def test_reload_when_pattern_matched_file_is_changed(self, result: bool) -> None: file = self.reload_path / "app" / "js" / "main.js" with as_cwd(self.reload_path): config = Config( app="tests.test_config:asgi_app", reload=True, reload_includes=["*.js"] ) reloader = self._setup_reloader(config) assert self._reload_tester(reloader, file) == result reloader.shutdown()
def main(): model = Model() async def homepage(request): return JSONResponse({'counter': model.counter}) app = Starlette(debug=True, routes=[ Route('/', homepage), ]) config = Config(app) sv = Server(config, model) sv.run()
async def test_accept_connection(protocol_cls): class App(WebSocketResponse): async def websocket_connect(self, message): await self.send({"type": "websocket.accept"}) async def open_connection(url): async with websockets.connect(url) as websocket: return websocket.open config = Config(app=App, ws=protocol_cls, lifespan="off") async with run_server(config): is_open = await open_connection("ws://127.0.0.1:8000") assert is_open
async def test_send_before_handshake(protocol_cls): async def app(scope, receive, send): await send({"type": "websocket.send", "text": "123"}) async def connect(url): await websockets.connect(url) config = Config(app=app, ws=protocol_cls, lifespan="off") async with run_server(config): with pytest.raises( websockets.exceptions.InvalidStatusCode) as exc_info: await connect("ws://127.0.0.1:8000") assert exc_info.value.status_code == 500
async def test_missing_handshake(protocol_cls): async def app(app, receive, send): pass async def connect(url): await websockets.connect(url) config = Config(app=app, ws=protocol_cls, lifespan="off") async with run_server(config): with pytest.raises( websockets.exceptions.InvalidStatusCode) as exc_info: await connect("ws://127.0.0.1:8000") assert exc_info.value.status_code == 500