""" Pytest configuration for backend tests. This file is loaded BEFORE any test modules are imported, which allows us to set environment variables that are checked at import time. CI Environment Variables: - CI=true: Running in CI environment (auto-detected) - SKIP_INTEGRATION_TESTS=true: Skip tests that require external services - SKIP_INTEGRATION_TESTS=false: Run integration tests with Docker Compose services - SKIP_DB_TESTS=true: Skip tests that require PostgreSQL - SKIP_WEASYPRINT_TESTS=true: Skip tests that require WeasyPrint Integration Test Environment: When SKIP_INTEGRATION_TESTS=false, the tests will use the Docker Compose test environment: - PostgreSQL: postgres-test:5432 (inside Docker network) - Valkey/Redis: valkey-test:6379 - Consent Service: consent-service-test:8081 - Backend: backend-test:8000 """ import os import sys from pathlib import Path import pytest # Add backend directory to Python path so that modules like classroom_engine # can be imported correctly during test collection backend_dir = Path(__file__).parent.parent if str(backend_dir) not in sys.path: sys.path.insert(0, str(backend_dir)) # Detect CI environment IS_CI = os.environ.get("CI", "").lower() in ("true", "1", "woodpecker") # ============================================================================= # Integration Test Environment Detection # ============================================================================= # Check if we should run integration tests (SKIP_INTEGRATION_TESTS=false means run them) IS_INTEGRATION_ENV = os.environ.get("SKIP_INTEGRATION_TESTS", "").lower() == "false" if IS_INTEGRATION_ENV: # Use Docker Compose test container URLs when in integration mode # These URLs work inside the Docker network (container names as hostnames) os.environ.setdefault("DATABASE_URL", "postgresql://breakpilot:breakpilot_test@postgres-test:5432/breakpilot_test") os.environ.setdefault("CONSENT_SERVICE_URL", "http://consent-service-test:8081") os.environ.setdefault("VALKEY_URL", "redis://valkey-test:6379") os.environ.setdefault("REDIS_URL", "redis://valkey-test:6379") os.environ.setdefault("SMTP_HOST", "mailpit-test") os.environ.setdefault("SMTP_PORT", "1025") print("[conftest.py] Integration test environment detected - using Docker Compose services") else: # Set DATABASE_URL before any modules are imported # This prevents RuntimeError from rbac_api.py during test collection if "DATABASE_URL" not in os.environ: os.environ["DATABASE_URL"] = "postgresql://test:test@localhost:5432/test_db" # ============================================================================= # Standard Test Configuration # ============================================================================= # Set other required environment variables for testing os.environ.setdefault("ENVIRONMENT", "testing") os.environ.setdefault("JWT_SECRET", "test-secret-key-for-testing-only") # Teacher Dashboard API - disable auth for testing os.environ.setdefault("TEACHER_REQUIRE_AUTH", "false") # Disable database for unit tests (use in-memory fallbacks) os.environ.setdefault("GAME_USE_DATABASE", "false") # In CI, auto-enable skips for tests that require external services # UNLESS we're explicitly running integration tests if IS_CI and not IS_INTEGRATION_ENV: os.environ.setdefault("SKIP_INTEGRATION_TESTS", "true") os.environ.setdefault("SKIP_DB_TESTS", "true") os.environ.setdefault("SKIP_WEASYPRINT_TESTS", "true") def pytest_configure(config): """Register custom markers and configure pytest.""" config.addinivalue_line( "markers", "integration: marks tests as integration tests (require external services)" ) config.addinivalue_line( "markers", "requires_postgres: marks tests that require PostgreSQL database" ) config.addinivalue_line( "markers", "requires_weasyprint: marks tests that require WeasyPrint system libraries" ) def pytest_collection_modifyitems(config, items): """ Automatically skip tests based on markers and environment. This runs after test collection and can skip tests based on: - Environment variables (SKIP_INTEGRATION_TESTS, SKIP_DB_TESTS, etc.) - Marker presence (integration, requires_postgres, requires_weasyprint) """ skip_integration = os.environ.get("SKIP_INTEGRATION_TESTS", "").lower() in ("true", "1") skip_db = os.environ.get("SKIP_DB_TESTS", "").lower() in ("true", "1") skip_weasyprint = os.environ.get("SKIP_WEASYPRINT_TESTS", "").lower() in ("true", "1") skip_integration_marker = pytest.mark.skip(reason="Skipped: SKIP_INTEGRATION_TESTS=true") skip_db_marker = pytest.mark.skip(reason="Skipped: SKIP_DB_TESTS=true (no PostgreSQL in CI)") skip_weasyprint_marker = pytest.mark.skip(reason="Skipped: SKIP_WEASYPRINT_TESTS=true (no libgobject in CI)") for item in items: # Skip integration tests if skip_integration and "integration" in item.keywords: item.add_marker(skip_integration_marker) # Skip tests requiring PostgreSQL if skip_db and "requires_postgres" in item.keywords: item.add_marker(skip_db_marker) # Skip tests requiring WeasyPrint if skip_weasyprint and "requires_weasyprint" in item.keywords: item.add_marker(skip_weasyprint_marker) # Auto-detect test_integration folder and skip if skip_integration and "test_integration" in str(item.fspath): item.add_marker(skip_integration_marker)