def test_wsgi_app(): config = Config(app=wsgi_app, interface="wsgi", proxy_headers=False) config.load() assert isinstance(config.loaded_app, WSGIMiddleware) assert config.interface == "wsgi" assert config.asgi_version == "3.0"
def test_config_log_level(log_level): config = Config(app=asgi_app, log_level=log_level) config.load() assert logging.getLogger("uvicorn.error").level == log_level assert logging.getLogger("uvicorn.access").level == log_level assert logging.getLogger("uvicorn.asgi").level == log_level assert config.log_level == log_level
def test_ssl_config_combined(tls_certificate_key_and_chain_path: str) -> None: config = Config( app=asgi_app, ssl_certfile=tls_certificate_key_and_chain_path, ) config.load() assert config.is_ssl is True
def test_ssl_config_combined(tls_certificate_pem_path): config = Config( app=asgi_app, ssl_certfile=tls_certificate_pem_path, ) config.load() assert config.is_ssl is True
def test_log_config_file(mocked_logging_config_module): """ Test that one can load a configparser config from disk. """ config = Config(app=asgi_app, log_config="log_config") config.load() mocked_logging_config_module.fileConfig.assert_called_once_with( "log_config", disable_existing_loggers=False)
def test_ssl_config(tls_ca_certificate_pem_path, tls_ca_certificate_private_key_path): config = Config( app=asgi_app, ssl_certfile=tls_ca_certificate_pem_path, ssl_keyfile=tls_ca_certificate_private_key_path, ) config.load() assert config.is_ssl is True
def test_get_subprocess() -> None: # pragma: py-win32 fdsock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) fd = fdsock.fileno() config = Config(app=app, fd=fd) config.load() process = get_subprocess(config, server_run, [fdsock]) assert isinstance(process, SpawnProcess) fdsock.close()
def test_bind_fd_works_with_reload_or_workers(reload, workers): fdsock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) fd = fdsock.fileno() config = Config(app=asgi_app, fd=fd, reload=reload, workers=workers) config.load() sock = config.bind_socket() assert isinstance(sock, socket.socket) assert sock.family == socket.AF_UNIX assert sock.getsockname() == "" sock.close() fdsock.close()
def test_bind_unix_socket_works_with_reload_or_workers(tmp_path, reload, workers): uds_file = tmp_path / "uvicorn.sock" config = Config( app=asgi_app, uds=uds_file.as_posix(), reload=reload, workers=workers ) config.load() sock = config.bind_socket() assert isinstance(sock, socket.socket) assert sock.family == socket.AF_UNIX assert sock.getsockname() == uds_file.as_posix() sock.close()
def test_app_unimportable_other(caplog): config = Config(app="tests.test_config:app") with pytest.raises(SystemExit): config.load() error_messages = [ record.message for record in caplog.records if record.name == "uvicorn.error" and record.levelname == "ERROR" ] assert ( 'Error loading ASGI app. Attribute "app" not found in module "tests.test_config".' # noqa: E501 == error_messages.pop(0))
def test_bind_unix_socket_works_with_reload_or_workers( tmp_path, reload, workers, short_socket_name): # pragma: py-win32 config = Config(app=asgi_app, uds=short_socket_name, reload=reload, workers=workers) config.load() sock = config.bind_socket() assert isinstance(sock, socket.socket) assert sock.family == socket.AF_UNIX assert sock.getsockname() == short_socket_name sock.close()
def test_log_config_default(mocked_logging_config_module, use_colors, expected): """ 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_subprocess_started() -> None: # pragma: py-win32 fdsock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) fd = fdsock.fileno() config = Config(app=app, fd=fd) config.load() with patch("tests.test_subprocess.server_run") as mock_run: with patch.object(config, "configure_logging") as mock_config_logging: subprocess_started(config, server_run, [fdsock], None) mock_run.assert_called_once() mock_config_logging.assert_called_once() fdsock.close()
def test_log_config_json(mocked_logging_config_module, logging_config, json_logging_config, mocker): """ Test that one can load a json config from disk. """ mocked_open = mocker.patch("uvicorn.config.open", mocker.mock_open(read_data=json_logging_config)) config = Config(app=asgi_app, log_config="log_config.json") config.load() mocked_open.assert_called_once_with("log_config.json") mocked_logging_config_module.dictConfig.assert_called_once_with( logging_config)
def test_env_file(web_concurrency: int, forwarded_allow_ips: str, caplog, tmp_path): """ 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(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_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_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)
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.parser = httptools.HttpRequestParser(self) 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[TimerHandle] = None self.timeout_keep_alive = config.timeout_keep_alive # Global 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 self.pipeline: Deque[Tuple[RequestResponseCycle, ASGI3Application]] = deque() # Per-request state self.scope: HTTPScope = None # type: ignore[assignment] self.headers: List[Tuple[bytes, bytes]] = None # type: ignore[assignment] self.expect_100_continue = False self.cycle: RequestResponseCycle = None # type: ignore[assignment]
def test_log_config_default( mocked_logging_config_module: MagicMock, use_colors: typing.Optional[bool], expected: typing.Optional[bool], logging_config, ) -> 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, log_config=logging_config) 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_app_factory(): def create_app(): return asgi_app config = Config(app=create_app, factory=True, proxy_headers=False) config.load() assert config.loaded_app is asgi_app # Flag missing. config = Config(app=create_app) with pytest.raises(SystemExit): config.load() # App not a no-arguments callable. config = Config(app=asgi_app, factory=True) with pytest.raises(SystemExit): config.load()
def test_app_factory(caplog): def create_app(): return asgi_app config = Config(app=create_app, factory=True, proxy_headers=False) config.load() assert config.loaded_app is asgi_app # Flag not passed. In this case, successfully load the app, but issue a warning # to indicate that an explicit flag is preferred. caplog.clear() config = Config(app=create_app, proxy_headers=False) with caplog.at_level(logging.WARNING): config.load() assert config.loaded_app is asgi_app assert len(caplog.records) == 1 assert "--factory" in caplog.records[0].message # App not a no-arguments callable. config = Config(app=asgi_app, factory=True) with pytest.raises(SystemExit): config.load()
def test_proxy_headers(): config = Config(app=asgi_app) config.load() assert config.proxy_headers is True assert isinstance(config.loaded_app, ProxyHeadersMiddleware)
def test_debug_app(): config = Config(app=asgi_app, debug=True, proxy_headers=False) config.load() assert config.debug is True assert isinstance(config.loaded_app, DebugMiddleware)
def test_socket_bind(): config = Config(app=asgi_app) config.load() assert isinstance(config.bind_socket(), socket.socket)
def test_config_access_log(access_log: bool, handlers: int): config = Config(app=asgi_app, access_log=access_log) config.load() assert len(logging.getLogger("uvicorn.access").handlers) == handlers assert config.access_log == access_log
def test_app_unimportable(): config = Config(app="no.such:app") with pytest.raises(ImportError): config.load()
def test_concrete_http_class(): config = Config(app=asgi_app, http=protocols.http.h11_impl.H11Protocol) config.load() assert config.http_protocol_class is protocols.http.h11_impl.H11Protocol
def test_ws_max_size() -> None: config = Config(app=asgi_app, ws_max_size=1000) config.load() assert config.ws_max_size == 1000
def test_concrete_http_class(): config = Config(app=asgi_app, http=H11Protocol) config.load() assert config.http_protocol_class is H11Protocol
def test_asgi_version(app, expected_interface): config = Config(app=app) config.load() assert config.asgi_version == expected_interface