9e8f1bbeed
Dashboard / frontend (push) Failing after 0s
Dashboard / api (push) Failing after 0s
Lint PowerShell / powershell-lint (ubuntu-latest) (push) Failing after 1s
Python Lint / Lint Python with Ruff (push) Failing after 1s
ShellCheck / Lint shell scripts (push) Failing after 1s
Matrix Smoke / linux-smoke (push) Failing after 1s
Matrix Smoke / distro: cachyos (push) Failing after 15s
Matrix Smoke / distro: linux-mint-21.3 (push) Failing after 15s
Matrix Smoke / distro: debian-12 (push) Failing after 5m21s
Matrix Smoke / distro: fedora-41 (push) Failing after 4m56s
Matrix Smoke / distro: ubuntu-24.04 (push) Failing after 2m13s
Matrix Smoke / distro: rocky-9 (push) Failing after 10m39s
Matrix Smoke / distro: manjaro (push) Failing after 12m11s
Matrix Smoke / distro: opensuse-tw (push) Failing after 11m53s
Matrix Smoke / distro: archlinux (push) Failing after 20m3s
Matrix Smoke / distro: ubuntu-22.04 (push) Failing after 13m49s
Validate .env Schema / tier-1-env-validation (push) Successful in 52s
Validate .env Schema / tier-2-env-validation (push) Successful in 44s
Validate .env Schema / tier-3-env-validation (push) Successful in 52s
Validate .env Schema / tier-4-env-validation (push) Successful in 51s
Validate Extensions Catalog / Check catalog is up-to-date (push) Failing after 9m47s
Secret Scan / Scan for secrets (push) Failing after 21m4s
Validate Docker Compose / Validate Docker Compose files (push) Has been cancelled
Python Type Check / Type check with mypy (push) Has been cancelled
Validate .env Schema / tier-0-env-validation (push) Has been cancelled
Test Linux / integration-smoke (push) Has been cancelled
Lint PowerShell / powershell-lint (windows-latest) (push) Has been cancelled
Matrix Smoke / macos-smoke (push) Has been cancelled
128 lines
3.9 KiB
Python
128 lines
3.9 KiB
Python
"""Shared fixtures for dashboard-api unit tests."""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import types
|
|
from pathlib import Path
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
# Add dashboard-api source to path so we can import modules directly.
|
|
DASHBOARD_API_DIR = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(DASHBOARD_API_DIR))
|
|
|
|
# Set env vars BEFORE any app imports so config.py and security.py initialise
|
|
# correctly (they read env at module level).
|
|
_TEST_API_KEY = "test-key-12345"
|
|
_TEST_SHIELD_KEY = "test-shield-key-fixture"
|
|
os.environ.setdefault("DASHBOARD_API_KEY", _TEST_API_KEY)
|
|
os.environ.setdefault("SHIELD_API_KEY", _TEST_SHIELD_KEY)
|
|
os.environ.setdefault("ODS_INSTALL_DIR", "/tmp/ods-test-install")
|
|
os.environ.setdefault("ODS_DATA_DIR", "/tmp/ods-test-data")
|
|
os.environ.setdefault("ODS_EXTENSIONS_DIR", "/tmp/ods-test-extensions")
|
|
os.environ.setdefault("GPU_BACKEND", "nvidia")
|
|
|
|
if "fcntl" not in sys.modules:
|
|
try:
|
|
import fcntl # type: ignore # noqa: F401
|
|
except ModuleNotFoundError:
|
|
sys.modules["fcntl"] = types.SimpleNamespace(
|
|
LOCK_EX=0,
|
|
LOCK_UN=0,
|
|
flock=lambda *args, **kwargs: None,
|
|
)
|
|
|
|
FIXTURES_DIR = Path(__file__).resolve().parent / "fixtures"
|
|
|
|
|
|
@pytest.fixture()
|
|
def install_dir(tmp_path, monkeypatch):
|
|
"""Provide an isolated install directory with a .env file."""
|
|
d = tmp_path / "ods"
|
|
d.mkdir()
|
|
monkeypatch.setattr("helpers.INSTALL_DIR", str(d))
|
|
return d
|
|
|
|
|
|
@pytest.fixture()
|
|
def data_dir(tmp_path, monkeypatch):
|
|
"""Provide an isolated data directory for bootstrap/token files."""
|
|
d = tmp_path / "data"
|
|
d.mkdir()
|
|
monkeypatch.setattr("helpers.DATA_DIR", str(d))
|
|
monkeypatch.setattr("helpers._TOKEN_FILE", d / "token_counter.json")
|
|
monkeypatch.setattr("helpers._PERF_FILE", d / "model_performance.json")
|
|
return d
|
|
|
|
|
|
@pytest.fixture()
|
|
def setup_config_dir(tmp_path, monkeypatch):
|
|
"""Provide an isolated config directory for setup/persona files."""
|
|
d = tmp_path / "config"
|
|
d.mkdir()
|
|
import config
|
|
monkeypatch.setattr(config, "SETUP_CONFIG_DIR", d)
|
|
# Also patch the setup router which imports SETUP_CONFIG_DIR at the top
|
|
import routers.setup as setup_router
|
|
monkeypatch.setattr(setup_router, "SETUP_CONFIG_DIR", d)
|
|
return d
|
|
|
|
|
|
@pytest.fixture()
|
|
def test_client(monkeypatch):
|
|
"""Return a FastAPI TestClient pre-configured with Bearer auth."""
|
|
import security
|
|
monkeypatch.setattr(security, "DASHBOARD_API_KEY", _TEST_API_KEY)
|
|
|
|
from fastapi.testclient import TestClient
|
|
from main import app
|
|
|
|
client = TestClient(app, raise_server_exceptions=True)
|
|
client.auth_headers = {"Authorization": f"Bearer {_TEST_API_KEY}"}
|
|
return client
|
|
|
|
|
|
def load_golden_fixture(name: str):
|
|
"""Load a JSON or text fixture from tests/fixtures/.
|
|
|
|
Returns parsed JSON for .json files, raw text for anything else.
|
|
"""
|
|
path = FIXTURES_DIR / name
|
|
text = path.read_text()
|
|
if path.suffix == ".json":
|
|
return json.loads(text)
|
|
return text
|
|
|
|
|
|
@pytest.fixture()
|
|
def mock_aiohttp_session():
|
|
"""Return a factory that creates a mock aiohttp.ClientSession.
|
|
|
|
Usage::
|
|
|
|
session = mock_aiohttp_session(status=200, json_data={"ok": True})
|
|
monkeypatch.setattr("helpers._get_aio_session", AsyncMock(return_value=session))
|
|
"""
|
|
|
|
def _factory(status: int = 200, json_data=None, text_data: str = "",
|
|
raise_on_get=None):
|
|
response = AsyncMock()
|
|
response.status = status
|
|
response.json = AsyncMock(return_value=json_data or {})
|
|
response.text = AsyncMock(return_value=text_data)
|
|
|
|
ctx = AsyncMock()
|
|
ctx.__aenter__ = AsyncMock(return_value=response)
|
|
ctx.__aexit__ = AsyncMock(return_value=False)
|
|
|
|
session = MagicMock()
|
|
if raise_on_get:
|
|
session.get = MagicMock(side_effect=raise_on_get)
|
|
else:
|
|
session.get = MagicMock(return_value=ctx)
|
|
return session
|
|
|
|
return _factory
|