Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
    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()
Ejemplo n.º 7
0
    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()
Ejemplo n.º 8
0
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()
Ejemplo n.º 9
0
    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()
Ejemplo n.º 10
0
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()
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
    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
Ejemplo n.º 13
0
    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]
Ejemplo n.º 14
0
    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)
Ejemplo n.º 15
0
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)
Ejemplo n.º 16
0
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()
Ejemplo n.º 17
0
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
Ejemplo n.º 18
0
    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()
Ejemplo n.º 19
0
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()
Ejemplo n.º 20
0
    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()
Ejemplo n.º 21
0
    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
Ejemplo n.º 22
0
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"
    )
Ejemplo n.º 23
0
    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
Ejemplo n.º 24
0
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
Ejemplo n.º 25
0
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.")
Ejemplo n.º 26
0
    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()
Ejemplo n.º 27
0
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()
Ejemplo n.º 28
0
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
Ejemplo n.º 29
0
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
Ejemplo n.º 30
0
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