diff --git a/Makefile b/Makefile index da78f87..c7fc1ad 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ install: ## Sync project-local dependencies from both lockfiles cd apps/web && bun install --frozen-lockfile dev: ## Start PostgreSQL and run the native backend and web together - $(MAKE) --jobs=2 backend-dev web-dev + $(MAKE) --jobs=2 backend-dev web-dev BACKEND_PORT=$(BACKEND_PORT) db-up: ## Start local PostgreSQL and wait until ready docker compose up -d --wait postgres diff --git a/tests/conftest.py b/tests/conftest.py index 2f63992..82c98e7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,5 @@ import asyncio +import os import time from collections.abc import Callable, Iterator from typing import Any @@ -19,6 +20,15 @@ from ai_platform.infrastructure.persistence.models import AIProfile, AppCredenti from ai_platform.platform.security import digest +@pytest.fixture +def isolated_settings(monkeypatch: pytest.MonkeyPatch) -> None: + """Keep pure configuration tests independent of operator credentials and local URLs.""" + monkeypatch.setitem(Settings.model_config, "env_file", None) + for name in tuple(os.environ): + if name.startswith("AI_PLATFORM_"): + monkeypatch.delenv(name) + + @pytest.fixture def valid_run_payload(): return { diff --git a/tests/test_aihub_settings.py b/tests/test_aihub_settings.py index 3d27011..f2b7265 100644 --- a/tests/test_aihub_settings.py +++ b/tests/test_aihub_settings.py @@ -4,6 +4,7 @@ from pydantic import SecretStr, ValidationError from ai_platform.infrastructure.config.settings import Settings _TEST_DATABASE_URL = "postgresql+asyncpg://test:test@localhost/ai_platform_test" +pytestmark = pytest.mark.usefixtures("isolated_settings") @pytest.mark.parametrize( diff --git a/tests/test_dev_commands.py b/tests/test_dev_commands.py index 75d75f5..0708dab 100644 --- a/tests/test_dev_commands.py +++ b/tests/test_dev_commands.py @@ -35,7 +35,9 @@ def test_dev_uses_the_same_backend_port_for_both_servers( (tmp_path / ".env").write_text(config) # Only the port lookup executes during dry-run; bypass uv project discovery in this fixture. uv = tmp_path / "uv" - uv.write_text(f'#!/bin/sh\nshift 3\nexec {shlex.quote(sys.executable)} "$@"\n') + uv.write_text( + f'#!/bin/sh\necho port-lookup >&2\nshift 3\nexec {shlex.quote(sys.executable)} "$@"\n' + ) uv.chmod(0o700) environment = os.environ.copy() for name in ("BACKEND_PORT", "MAKEFLAGS", "MFLAGS", "MAKEOVERRIDES"): @@ -62,3 +64,5 @@ def test_dev_uses_the_same_backend_port_for_both_servers( assert "alembic" not in result.stdout assert secret not in result.stdout + result.stderr assert "AI_PLATFORM_OPENAI_API_KEY" not in result.stdout + result.stderr + expected_lookups = 0 if environment_port is not None or argument_port is not None else 1 + assert result.stderr.count("port-lookup") == expected_lookups diff --git a/tests/test_notifications.py b/tests/test_notifications.py index 4eb6c41..89c0a8a 100644 --- a/tests/test_notifications.py +++ b/tests/test_notifications.py @@ -27,6 +27,7 @@ NOW = datetime(2026, 9, 28, tzinfo=UTC) SECRET = "test-only-webhook-secret-32-characters-long" +@pytest.mark.usefixtures("isolated_settings") def test_webhook_configuration_requires_pair_and_safe_url(): with pytest.raises(ValidationError): AppWebhook.model_validate({"url": "https://omni.example.invalid/events"})