diff options
| -rw-r--r-- | conftest.py | 100 |
1 files changed, 94 insertions, 6 deletions
diff --git a/conftest.py b/conftest.py index c4a51dc..250f72d 100644 --- a/conftest.py +++ b/conftest.py @@ -7,14 +7,20 @@ Base URLs default to the CD environment. Override via environment variables: GN3_BASE_URL e.g. https://genenetwork.org/api3 (default: CD) GN_AUTH_BASE_URL e.g. https://auth.genenetwork.org (default: CD) -For auth-flow tests also set: +For auth-flow tests set either: - GN_TEST_EMAIL registered test-user e-mail address - GN_TEST_PASSWORD password for GN_TEST_EMAIL + File-based (CI — populated by create-test-users / create-test-oauth2-client): + GN_TEST_USERS_FILE path to the users credentials JSON file + GN_TEST_CLIENT_FILE path to the OAuth2 client credentials JSON file + + Individual env vars (manual runs, admin user only): + GN_TEST_EMAIL registered admin test-user e-mail address + GN_TEST_PASSWORD password for GN_TEST_EMAIL GN_OAUTH2_CLIENT_ID OAuth2 client UUID GN_OAUTH2_CLIENT_SECRET OAuth2 client secret """ +import json import os import time import pytest @@ -48,6 +54,18 @@ def _wait_for(url: str, timeout: int = 120, interval: int = 2) -> None: ) from last_exc +def _read_json_file(path: str) -> dict: + with open(path, encoding="utf8") as f: + return json.load(f) + + +def _user_by_role(users_data: dict, role: str): + return next( + (u for u in users_data.get("users", []) if u["role"] == role), + None, + ) + + @pytest.fixture(scope="session") def gn2_url() -> str: url = os.environ.get("GN2_BASE_URL", _GN2_DEFAULT).rstrip("/") @@ -83,20 +101,68 @@ def http() -> requests.Session: @pytest.fixture(scope="session") def oauth2_credentials(): - """Returns (email, password, client_id, client_secret) or skips the test.""" + """Return (email, password, client_id, client_secret) for the admin test user. + + Reads from GN_TEST_USERS_FILE + GN_TEST_CLIENT_FILE when set (CI), or + falls back to GN_TEST_EMAIL / GN_TEST_PASSWORD / GN_OAUTH2_CLIENT_ID / + GN_OAUTH2_CLIENT_SECRET for manual runs. Skips if neither is available. + """ + users_file = os.environ.get("GN_TEST_USERS_FILE") + client_file = os.environ.get("GN_TEST_CLIENT_FILE") + if users_file and client_file: + users_data = _read_json_file(users_file) + client_data = _read_json_file(client_file) + admin = _user_by_role(users_data, "system-admin") + if admin is None: + pytest.fail(f"No system-admin user found in {users_file}") + return ( + admin["email"], + admin["password"], + client_data["client"]["client_id"], + client_data["client"]["client_secret"], + ) email = os.environ.get("GN_TEST_EMAIL") password = os.environ.get("GN_TEST_PASSWORD") client_id = os.environ.get("GN_OAUTH2_CLIENT_ID") client_secret = os.environ.get("GN_OAUTH2_CLIENT_SECRET") if not all([email, password, client_id, client_secret]): pytest.skip( - "Set GN_TEST_EMAIL, GN_TEST_PASSWORD, GN_OAUTH2_CLIENT_ID, and " - "GN_OAUTH2_CLIENT_SECRET to run auth-flow tests." + "Set GN_TEST_USERS_FILE + GN_TEST_CLIENT_FILE (CI), or " + "GN_TEST_EMAIL, GN_TEST_PASSWORD, GN_OAUTH2_CLIENT_ID, and " + "GN_OAUTH2_CLIENT_SECRET (manual) to run auth-flow tests." ) return email, password, client_id, client_secret @pytest.fixture(scope="session") +def basic_oauth2_credentials(): + """Return (email, password, client_id, client_secret) for the unprivileged test user. + + Requires GN_TEST_USERS_FILE + GN_TEST_CLIENT_FILE (set by the CI + auth-flow job). Skips if not available — basic-user tests only run + in CI where the full test-session setup has been performed. + """ + users_file = os.environ.get("GN_TEST_USERS_FILE") + client_file = os.environ.get("GN_TEST_CLIENT_FILE") + if not (users_file and client_file): + pytest.skip( + "Set GN_TEST_USERS_FILE and GN_TEST_CLIENT_FILE to run " + "auth-flow tests that require an unprivileged user." + ) + users_data = _read_json_file(users_file) + client_data = _read_json_file(client_file) + basic = _user_by_role(users_data, "none") + if basic is None: + pytest.fail(f"No user with role='none' found in {users_file}") + return ( + basic["email"], + basic["password"], + client_data["client"]["client_id"], + client_data["client"]["client_secret"], + ) + + +@pytest.fixture(scope="session") def access_token(gn_auth_url, oauth2_credentials, http): """Obtains a Bearer token via the password grant and caches it for the session.""" email, password, client_id, client_secret = oauth2_credentials @@ -116,3 +182,25 @@ def access_token(gn_auth_url, oauth2_credentials, http): data = resp.json() assert "access_token" in data return data["access_token"] + + +@pytest.fixture(scope="session") +def basic_access_token(gn_auth_url, basic_oauth2_credentials, http): + """Bearer token for the unprivileged test user.""" + email, password, client_id, client_secret = basic_oauth2_credentials + resp = http.post( + f"{gn_auth_url}/auth/token", + json={ + "grant_type": "password", + "username": email, + "password": password, + "scope": "profile group resource", + "client_id": client_id, + "client_secret": client_secret, + }, + timeout=30, + ) + assert resp.status_code == 200, f"Basic user token request failed: {resp.text}" + data = resp.json() + assert "access_token" in data + return data["access_token"] |
