async def client( request: pytest.FixtureRequest, ) -> AsyncGenerator[httpx.AsyncClient, None]: marker = request.node.get_closest_marker("fastapi") if marker is None: raise ValueError("client fixture: the marker fastapi must be provided") try: app = marker.kwargs["app"] except KeyError: raise ValueError( "client fixture: keyword argument app must be provided in the marker" ) if not isinstance(app, FastAPI): raise ValueError("client fixture: app must be a FastAPI instance") dependency_overrides = marker.kwargs.get("dependency_overrides") if dependency_overrides: if not isinstance(dependency_overrides, dict): raise ValueError( "client fixture: dependency_overrides must be a dictionary" ) app.dependency_overrides = dependency_overrides run_lifespan_events = marker.kwargs.get("run_lifespan_events", True) if not isinstance(run_lifespan_events, bool): raise ValueError("client fixture: run_lifespan_events must be a bool") test_client_generator = httpx.AsyncClient(app=app, base_url="http://app.io") if run_lifespan_events: async with LifespanManager(app): async with test_client_generator as test_client: yield test_client else: async with test_client_generator as test_client: yield test_client
async def client(app: FastAPI) -> AsyncClient: async with LifespanManager(app): async with AsyncClient(app=app, base_url='http://testserver', headers={'Content-type': 'application/json'}) as client: yield client
async def app(): async def startup(): print("Starting up") async def shutdown(): print("Shutting down") async def home(request): return PlainTextResponse("Hello, world!") async def endless(req: Request): async def event_publisher(): i = 0 try: while True: # i <= 20: # yield dict(id=..., event=..., data=...) i += 1 yield dict(data=i) await asyncio.sleep(0.3) except asyncio.CancelledError as e: _log.info(f"Disconnected from client (via refresh/close) {req.client}") # Do any other cleanup, if any raise e return EventSourceResponse(event_publisher()) app = Starlette( routes=[Route("/", home), Route("/endless", endpoint=endless)], on_startup=[startup], on_shutdown=[shutdown], ) async with LifespanManager(app): print("We're in!") yield app
async def director_v2_client( minimal_configuration: None, loop: asyncio.BaseEventLoop, mock_env: None, network_name: str, monkeypatch, ) -> httpx.AsyncClient: monkeypatch.setenv("SC_BOOT_MODE", "production") monkeypatch.setenv("DYNAMIC_SIDECAR_EXPOSE_PORT", "true") monkeypatch.setenv("SIMCORE_SERVICES_NETWORK_NAME", network_name) monkeypatch.delenv("DYNAMIC_SIDECAR_MOUNT_PATH_DEV", raising=False) monkeypatch.setenv("DIRECTOR_V2_DYNAMIC_SCHEDULER_ENABLED", "true") monkeypatch.setenv("DIRECTOR_V2_CELERY_SCHEDULER_ENABLED", "false") monkeypatch.setenv("DIRECTOR_V2_DASK_CLIENT_ENABLED", "false") monkeypatch.setenv("DIRECTOR_V2_DASK_SCHEDULER_ENABLED", "false") monkeypatch.setenv("POSTGRES_HOST", "mocked_host") monkeypatch.setenv("POSTGRES_USER", "mocked_user") monkeypatch.setenv("POSTGRES_PASSWORD", "mocked_password") monkeypatch.setenv("POSTGRES_DB", "mocked_db") monkeypatch.setenv("DIRECTOR_V2_POSTGRES_ENABLED", "false") settings = AppSettings.create_from_envs() app = init_app(settings) async with LifespanManager(app): async with httpx.AsyncClient( app=app, base_url="http://testserver/v2") as client: yield client
async def client(app: FastAPI) -> AsyncClient: async with LifespanManager(app): async with AsyncClient(app=app, base_url="http://testserver", headers={"Content-Type": "application/json"}) as client: yield client
async def test_client_some_sensitive(app_generator, some_sensitive_csrfmiddleware): app = app_generator(some_sensitive_csrfmiddleware) async with LifespanManager(app): async with httpx.AsyncClient(app=app, base_url="http://app.io") as test_client: yield test_client
async def app(): from demo import app from fastapi_slack import with_valid_signature async with LifespanManager(app): app.dependency_overrides[with_valid_signature] = lambda: "signature" yield app
async def client(app): async with LifespanManager(app): transport = httpx.ASGITransport(app=app, raise_app_exceptions=False) async with httpx.AsyncClient( transport=transport, base_url="http://example.local") as client: yield client
async def client(): # httpx client does not trigger lifespan events on it's own # https://github.com/encode/httpx/issues/350 async with LifespanManager(app): async with AsyncClient(app=app, base_url="http://testserver") as test_client: test_client.app = app yield test_client
async def app() -> AsyncIterator[FastAPI]: """Return a configured test application. Wraps the application in a lifespan manager so that startup and shutdown events are sent during test execution. """ async with LifespanManager(main.app): yield main.app
async def test_01_general(mock_env): fake_args = mock.MagicMock() fake_args.daemonize = True fake_args.bucket = 'test_bucket' assert not APP run_main(TestBackup, args=fake_args) assert BS assert not BS.monitoring async with LifespanManager(APP): assert BS.monitoring
async def client() -> Generator: """Async client with db connection.""" nest_asyncio.apply() initializer(modules=APP_MODELS) app = create_application() async with AsyncClient( app=app, base_url="https://testserver") as test_client, LifespanManager( app): yield test_client finalizer()
async def async_client(override_get_db: Callable) -> AsyncGenerator: """Create test client to be used to test api endpoints""" from app.db.session import get_db from app.main import app app.dependency_overrides[get_db] = override_get_db async with LifespanManager(app): async with AsyncClient(app=app, base_url="http://testserver") as client: yield client
async def initialized_app(monkeypatch: MonkeyPatch) -> Iterator[FastAPI]: monkeypatch.setenv("DYNAMIC_SIDECAR_IMAGE", "itisfoundation/dynamic-sidecar:MOCK") monkeypatch.setenv("SIMCORE_SERVICES_NETWORK_NAME", "test_network_name") monkeypatch.setenv("TRAEFIK_SIMCORE_ZONE", "test_traefik_zone") monkeypatch.setenv("SWARM_STACK_NAME", "test_swarm_name") monkeypatch.setenv("DIRECTOR_V2_DYNAMIC_SCHEDULER_ENABLED", "false") monkeypatch.setenv("SC_BOOT_MODE", "production") settings = AppSettings.create_from_envs() app = init_app(settings) async with LifespanManager(app): yield app
async def client(app: FastAPI) -> Client: async with LifespanManager(app): app.state.pool = await FakePool.create_pool(app.state.pool) connection: Connection async with app.state.pool.acquire() as connection: transaction: Transaction = connection.transaction() await transaction.start() async with Client( app=app, base_url="http://testserver", headers={"Content-Type": "application/json"}, ) as client: yield client await transaction.rollback() await app.state.pool.close()
async def app( mock_kubernetes: MockKubernetesApi, podinfo: Path ) -> AsyncIterator[FastAPI]: """Return a configured test application. Wraps the application in a lifespan manager so that startup and shutdown events are sent during test execution. """ assets_path = Path(__file__).parent / "_assets" config.m_config_path = str(assets_path / "m.yaml") config.quips = str(assets_path / "quips.txt") config.moneypenny_timeout = 5 async with LifespanManager(main.app): await moneypenny_dependency.clear_state() yield main.app
async def director_v2_client( minimal_configuration: None, network_name: str, monkeypatch, ) -> AsyncIterable[httpx.AsyncClient]: # Works as below line in docker.compose.yml # ${DOCKER_REGISTRY:-itisfoundation}/dynamic-sidecar:${DOCKER_IMAGE_TAG:-latest} registry = os.environ.get("DOCKER_REGISTRY", "local") image_tag = os.environ.get("DOCKER_IMAGE_TAG", "production") image_name = f"{registry}/dynamic-sidecar:{image_tag}" logger.warning("Patching to: DYNAMIC_SIDECAR_IMAGE=%s", image_name) monkeypatch.setenv("DYNAMIC_SIDECAR_IMAGE", image_name) monkeypatch.setenv("TRAEFIK_SIMCORE_ZONE", "test_traefik_zone") monkeypatch.setenv("SWARM_STACK_NAME", "test_swarm_name") monkeypatch.setenv("SC_BOOT_MODE", "production") monkeypatch.setenv("DYNAMIC_SIDECAR_EXPOSE_PORT", "true") monkeypatch.setenv("PROXY_EXPOSE_PORT", "true") monkeypatch.setenv("SIMCORE_SERVICES_NETWORK_NAME", network_name) monkeypatch.delenv("DYNAMIC_SIDECAR_MOUNT_PATH_DEV", raising=False) monkeypatch.setenv("DIRECTOR_V2_DYNAMIC_SCHEDULER_ENABLED", "true") monkeypatch.setenv("DIRECTOR_V2_DASK_CLIENT_ENABLED", "false") monkeypatch.setenv("DIRECTOR_V2_DASK_SCHEDULER_ENABLED", "false") monkeypatch.setenv("POSTGRES_HOST", "mocked_host") monkeypatch.setenv("POSTGRES_USER", "mocked_user") monkeypatch.setenv("POSTGRES_PASSWORD", "mocked_password") monkeypatch.setenv("POSTGRES_DB", "mocked_db") monkeypatch.setenv("DIRECTOR_V2_POSTGRES_ENABLED", "false") monkeypatch.setenv("R_CLONE_S3_PROVIDER", "MINIO") # patch host for dynamic-sidecar, not reachable via localhost # the dynamic-sidecar (running inside a container) will use # this address to reach the rabbit service monkeypatch.setenv("RABBIT_HOST", f"{get_ip()}") settings = AppSettings.create_from_envs() app = init_app(settings) async with LifespanManager(app): async with httpx.AsyncClient( app=app, base_url="http://testserver/v2" ) as client: yield client
async def create(cls, tmp_path: Path, httpx_mock: HTTPXMock) -> AsyncIterator[SetupTest]: """Create a new `SetupTest` instance. This is the only supported way to set up the test environment and should be called instead of calling the constructor directly. It initializes and starts the application and configures an `httpx.AsyncClient` to talk to it. Whether to use a real PostgreSQL and Redis server or to use SQLite and mock Redis is determined by the environment variables set by ``tox``. Parameters ---------- tmp_path : `pathlib.Path` The path for temporary files. httpx_mock : `pytest_httpx.HTTPXMock` The mock for simulating `httpx.AsyncClient` calls. """ config = initialize(tmp_path) redis = await redis_dependency(config) # Create the database session that will be used by SetupTest and by # the factory it contains. The application will use a separate # session handled by its middleware. connect_args = {} if urlparse(config.database_url).scheme == "sqlite": connect_args = {"check_same_thread": False} engine = create_engine(config.database_url, connect_args=connect_args) session = Session(bind=engine) # Build the SetupTest object inside all of the contexts required by # its components and handle clean shutdown. try: async with LifespanManager(app): base_url = f"https://{TEST_HOSTNAME}" async with AsyncClient(app=app, base_url=base_url) as client: yield cls( tmp_path=tmp_path, httpx_mock=httpx_mock, config=config, redis=redis, session=session, client=client, ) finally: await redis_dependency.close() session.close()
async def app_for_httpx(): app = Starlette( debug=settings.DEBUG, routes=routes, middleware=middleware, exception_handlers=exception_handlers, ) register_tortoise( app, db_url=settings.DB_URL, modules={"models": ["models"]}, generate_schemas=settings.GENERATE_SCHEMAS, ) async with LifespanManager(app): yield app
async def _app(): """Returns our ASGI app, that uses a temporary DB""" @app.on_event('startup') async def startup(): db.conn.client = AsyncIOMotorClient(MONGO_URL) @app.on_event('shutdown') async def shutdown(): db.conn.client.close() async def _get_test_db(): return db.conn.client.test_db app.dependency_overrides[db.get_db] = _get_test_db async with LifespanManager(app): yield app
async def test_setup_client_instance(): @dataclass class TheClientApi(BaseServiceClientApi): x: int = 33 # setup app app = FastAPI() assert not TheClientApi.get_instance(app) setup_client_instance( app, api_cls=TheClientApi, api_baseurl="http://the_service", service_name="the_service", health_check_path="/health", x=42, ) assert not TheClientApi.get_instance(app) # test startup/shutdown async with LifespanManager(app): # check startup assert TheClientApi.get_instance(app) api_obj = TheClientApi.get_instance(app) # test responsivity assert await api_obj.is_responsive() == False # now start the server with respx.mock( base_url="http://the_service", assert_all_mocked=True, ) as respx_mock: respx_mock.get("/health", name="health_check").respond(200, content="healthy") # test responsitivity assert await api_obj.is_responsive() assert respx_mock["health_check"].called assert respx_mock["health_check"].call_count == 1 # check shutdown assert not TheClientApi.get_instance(app), "Expected automatically cleaned"
async def client( request: pytest.FixtureRequest, ) -> AsyncGenerator[httpx.AsyncClient, None]: marker = request.node.get_closest_marker("fastapi") if marker is None: raise ValueError("client fixture: the marker fastapi must be provided") try: app = marker.kwargs["app"] except KeyError: raise ValueError( "client fixture: keyword argument app must be provided in the marker" ) if not isinstance(app, FastAPI): raise ValueError("client fixture: app must be a FastAPI instance") async with LifespanManager(app): async with httpx.AsyncClient(app=app, base_url="http://app.io") as test_client: yield test_client
async def test_fastapi_integration(): from fastapi_sqla import _Session, setup app = FastAPI() setup(app) @app.get("/one") def now(): session = _Session() result = session.execute(text("SELECT 1")).scalar() session.close() return result async with LifespanManager(app): async with httpx.AsyncClient( app=app, base_url="http://example.local" ) as client: res = await client.get("/one") assert res.json() == 1
async def test_http_client(respx_mock: respx.Router) -> None: app = FastAPI() respx_mock.get("https://www.google.com").respond(200) @app.get("/") async def handler( http_client: AsyncClient = Depends(http_client_dependency), ) -> Dict[str, str]: assert isinstance(http_client, AsyncClient) await http_client.get("https://www.google.com") return {} @app.on_event("shutdown") async def shutdown_event() -> None: await http_client_dependency.aclose() async with LifespanManager(app): async with AsyncClient(app=app, base_url="http://example.com") as c: r = await c.get("/") assert r.status_code == 200
async def main( get_raw: bool = False, get_nice: bool = False, get_basic: bool = False, test: str | None = None, ) -> None: print("Saving test data ...") if not any([get_raw, get_nice, get_basic]): get_raw = get_nice = get_basic = True async with LifespanManager(app), AsyncClient(app=app, base_url="http://test") as ac: for to_download, query_data, endpoint, folder in ( (get_raw, test_raw_data, "raw", "test_data_raw"), (get_nice, test_nice_data, "nice", "test_data_nice"), (get_basic, test_basic_data, "basic", "test_data_basic"), ): if to_download: if test and test in query_data: query, file_name = query_data[test] await save_test_data(ac, endpoint, query, folder, file_name) else: for query, file_name in query_data.values(): await save_test_data(ac, endpoint, query, folder, file_name)
async def initialized_app(minimal_app: FastAPI) -> Iterator[FastAPI]: async with LifespanManager(minimal_app): yield minimal_app
async def client() -> AsyncGenerator[AsyncClient, None]: async with LifespanManager(app): async with AsyncClient(app=app, base_url="http://test") as ac: yield ac
async def app() -> typing.Generator[FastAPI, None, None]: app = FastAPI() async with LifespanManager(app): yield app
async def _get_test_client(app: ASGIApp) -> AsyncGenerator[httpx.AsyncClient, None]: async with LifespanManager(app): async with httpx.AsyncClient( app=app, base_url="http://app.io" ) as test_client: yield test_client
async def admin_graphql_client(): async with LifespanManager(app): async with AsyncClient(app=app, base_url="http://testserver") as client: yield GraphQLClient(client, admin_endpoint=True)