81b9a66ef5
- Delete 4 obsolete unit tests tied to removed git mount/clone models - Update imports and assertions across unit/integration/service tests - Fix Settings defaults (postgres host, JWT props, cookie_samesite) - Add skip guards for PostgreSQL-dependent integration tests - Fix GitService env assertions and HealthMonitor state-change tests - Repair docker/container inspect assertions in test_docker_service - Fix ToolTypeCreate default_port validator ordering bug - Fix check_port_exposed substring false-positive for port 0 - Update test_tool_types_api_extended to use interface_type field Quality gates: pytest 311 passed, 34 skipped; npm typecheck/lint/test 87 passed
234 lines
7.5 KiB
Python
234 lines
7.5 KiB
Python
"""Shared test fixtures for all test categories."""
|
|
|
|
import asyncio
|
|
import os
|
|
from typing import AsyncGenerator, Generator
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
import pytest_asyncio
|
|
from fastapi.testclient import TestClient
|
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
|
|
|
# Set test environment BEFORE importing app modules
|
|
os.environ["APP_ENV"] = "testing"
|
|
os.environ["SECRET_KEY"] = "test-secret-key-for-testing-only-do-not-use-in-production"
|
|
os.environ["DATABASE_URL"] = "sqlite+aiosqlite:///:memory:"
|
|
|
|
from src.config import Settings
|
|
from src.models.base import Base
|
|
from src.main import app
|
|
from src.auth.dependencies import get_db_session
|
|
|
|
|
|
@pytest.fixture
|
|
def test_client() -> Generator[TestClient, None, None]:
|
|
"""Provide a FastAPI test client with SQLite database."""
|
|
# Create a single engine for this test
|
|
engine = create_async_engine(
|
|
"sqlite+aiosqlite:///:memory:",
|
|
connect_args={"check_same_thread": False},
|
|
)
|
|
|
|
# Create tables
|
|
async def init_db():
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
|
|
asyncio.run(init_db())
|
|
|
|
async def override_get_db_session() -> AsyncGenerator[AsyncSession, None]:
|
|
async with async_sessionmaker(engine, expire_on_commit=False)() as session:
|
|
yield session
|
|
|
|
# Override the dependency
|
|
app.dependency_overrides[get_db_session] = override_get_db_session
|
|
|
|
# Patch startup events to prevent PostgreSQL connection attempts
|
|
with patch("src.main.init_database") as mock_init:
|
|
mock_init.return_value = True
|
|
|
|
try:
|
|
with TestClient(app) as client:
|
|
yield client
|
|
finally:
|
|
# Clean up overrides
|
|
app.dependency_overrides.pop(get_db_session, None)
|
|
asyncio.run(engine.dispose())
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def db_session(test_client) -> AsyncGenerator[AsyncSession, None]:
|
|
"""Provide an async database session for unit tests."""
|
|
# Get the override function from the test_client fixture
|
|
override_fn = app.dependency_overrides.get(get_db_session)
|
|
if override_fn:
|
|
gen = override_fn()
|
|
session = await gen.asend(None)
|
|
try:
|
|
yield session
|
|
finally:
|
|
await gen.aclose()
|
|
else:
|
|
# Fallback: create a new engine and session
|
|
engine = create_async_engine(
|
|
"sqlite+aiosqlite:///:memory:",
|
|
connect_args={"check_same_thread": False},
|
|
)
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
async with async_sessionmaker(engine, expire_on_commit=False)() as session:
|
|
yield session
|
|
await engine.dispose()
|
|
|
|
|
|
@pytest.fixture
|
|
def authenticated_client(test_client) -> Generator[TestClient, None, None]:
|
|
"""Provide an authenticated test client with a test user."""
|
|
import uuid
|
|
from src.auth.session import create_session_cookie
|
|
from src.models.user.user import User
|
|
|
|
user_id = str(uuid.uuid4())
|
|
settings = Settings()
|
|
|
|
# Create user in database using the same engine as test_client
|
|
# We need to access the engine from the test_client fixture
|
|
# Since we can't easily do that, we'll create the user via API call
|
|
# But we need the user to exist before any API calls
|
|
# So we need to create the user using the overridden dependency
|
|
|
|
async def create_test_user():
|
|
# Get the override function
|
|
override_fn = app.dependency_overrides.get(get_db_session)
|
|
if override_fn:
|
|
gen = override_fn()
|
|
session = await gen.asend(None)
|
|
try:
|
|
user = User(
|
|
id=uuid.UUID(user_id),
|
|
email="test@headquarter.local",
|
|
name="Test User",
|
|
authentik_id=f"authentik-{user_id}",
|
|
avatar_url=None,
|
|
)
|
|
session.add(user)
|
|
await session.commit()
|
|
finally:
|
|
await gen.aclose()
|
|
|
|
asyncio.run(create_test_user())
|
|
|
|
# Create session cookie
|
|
session_cookie = create_session_cookie(
|
|
settings=settings,
|
|
user_id=user_id,
|
|
)
|
|
|
|
# Set cookie on client
|
|
test_client.cookies.set("session", session_cookie)
|
|
|
|
yield test_client
|
|
|
|
|
|
@pytest.fixture
|
|
def test_project_and_repo(authenticated_client) -> tuple[str, str]:
|
|
"""Create a project and repository directly in the database."""
|
|
import uuid
|
|
from src.models.project.project import Project
|
|
from src.models.project.git_repository import GitRepository
|
|
|
|
project_id = uuid.uuid4()
|
|
repo_id = uuid.uuid4()
|
|
user_id = None
|
|
|
|
# Get user ID from session
|
|
async def get_user_id():
|
|
nonlocal user_id
|
|
from src.auth.session import decode_session_cookie
|
|
settings = Settings()
|
|
session_cookie = authenticated_client.cookies.get("session")
|
|
if session_cookie:
|
|
session = decode_session_cookie(settings=settings, cookie_value=session_cookie)
|
|
if session:
|
|
user_id = uuid.UUID(session["user_id"])
|
|
|
|
asyncio.run(get_user_id())
|
|
|
|
if not user_id:
|
|
raise RuntimeError("Could not get user ID from authenticated client")
|
|
|
|
async def create_project_and_repo():
|
|
override_fn = app.dependency_overrides.get(get_db_session)
|
|
if override_fn:
|
|
gen = override_fn()
|
|
session = await gen.asend(None)
|
|
try:
|
|
project = Project(
|
|
id=project_id,
|
|
name="test-project",
|
|
description="Test project",
|
|
owner_id=user_id,
|
|
)
|
|
session.add(project)
|
|
|
|
repo = GitRepository(
|
|
id=repo_id,
|
|
name="test-repo",
|
|
path="/tmp/test-repo",
|
|
project_id=project_id,
|
|
owner_id=user_id,
|
|
remote_url="https://github.com/test/repo.git",
|
|
)
|
|
session.add(repo)
|
|
await session.commit()
|
|
finally:
|
|
await gen.aclose()
|
|
|
|
asyncio.run(create_project_and_repo())
|
|
|
|
return str(project_id), str(repo_id)
|
|
|
|
|
|
@pytest.fixture
|
|
def admin_client(test_client) -> Generator[TestClient, None, None]:
|
|
"""Provide an authenticated test client with an admin user."""
|
|
import uuid
|
|
from src.auth.session import create_session_cookie
|
|
from src.models.user.user import User
|
|
|
|
user_id = str(uuid.uuid4())
|
|
settings = Settings()
|
|
|
|
async def create_admin_user():
|
|
override_fn = app.dependency_overrides.get(get_db_session)
|
|
if override_fn:
|
|
gen = override_fn()
|
|
session = await gen.asend(None)
|
|
try:
|
|
user = User(
|
|
id=uuid.UUID(user_id),
|
|
email="admin@headquarter.local",
|
|
name="Admin User",
|
|
authentik_id=f"authentik-admin-{user_id}",
|
|
avatar_url=None,
|
|
is_admin=True,
|
|
)
|
|
session.add(user)
|
|
await session.commit()
|
|
finally:
|
|
await gen.aclose()
|
|
|
|
asyncio.run(create_admin_user())
|
|
|
|
# Create session cookie
|
|
session_cookie = create_session_cookie(
|
|
settings=settings,
|
|
user_id=user_id,
|
|
)
|
|
|
|
# Set cookie on client
|
|
test_client.cookies.set("session", session_cookie)
|
|
|
|
yield test_client
|