"""api.utils.resources coverage.""" from __future__ import annotations import uuid from http import HTTPStatus from typing import TYPE_CHECKING, cast from uuid import uuid4 import pytest from fastapi import HTTPException from roboco.api.utils.resources import ( get_by_field_or_404, get_or_404, require_membership, require_ownership, require_recipient, ) from roboco.db.tables import AgentTable from roboco.models import AgentRole, AgentStatus, Team if TYPE_CHECKING: from sqlalchemy.ext.asyncio import AsyncSession @pytest.mark.asyncio async def test_get_or_404_finds_existing(db_session: AsyncSession) -> None: agent = AgentTable( id=uuid4(), name="Dev", slug=f"d-{uuid4().hex[:8]}", role=AgentRole.DEVELOPER, team=Team.BACKEND, status=AgentStatus.ACTIVE, model_config={}, system_prompt="x", capabilities=[], permissions={}, metrics={}, ) db_session.add(agent) await db_session.flush() fetched = await get_or_404(db_session, AgentTable, cast("uuid.UUID", agent.id)) assert fetched.id == agent.id @pytest.mark.asyncio async def test_get_or_404_raises_when_missing(db_session: AsyncSession) -> None: with pytest.raises(HTTPException) as exc: await get_or_404(db_session, AgentTable, uuid4(), "Agent") assert exc.value.status_code == HTTPStatus.NOT_FOUND @pytest.mark.asyncio async def test_get_by_field_or_404_finds(db_session: AsyncSession) -> None: agent = AgentTable( id=uuid4(), name="Dev2", slug=f"d2-{uuid4().hex[:8]}", role=AgentRole.DEVELOPER, team=Team.BACKEND, status=AgentStatus.ACTIVE, model_config={}, system_prompt="x", capabilities=[], permissions={}, metrics={}, ) db_session.add(agent) await db_session.flush() fetched = await get_by_field_or_404( db_session, AgentTable, "slug", agent.slug, "Agent" ) assert fetched.id == agent.id @pytest.mark.asyncio async def test_get_by_field_or_404_raises(db_session: AsyncSession) -> None: with pytest.raises(HTTPException) as exc: await get_by_field_or_404(db_session, AgentTable, "slug", "ghost-slug", "Agent") assert exc.value.status_code == HTTPStatus.NOT_FOUND # --------------------------------------------------------------------------- # Ownership / Recipients / Membership # --------------------------------------------------------------------------- def test_require_ownership_passes_for_owner() -> None: aid = uuid4() resource = type("R", (), {"owner": aid})() require_ownership(resource, "owner", aid, "edit") def test_require_ownership_raises_for_other_agent() -> None: resource = type("R", (), {"owner": uuid4()})() with pytest.raises(HTTPException) as exc: require_ownership(resource, "owner", uuid4(), "edit") assert exc.value.status_code == HTTPStatus.FORBIDDEN def test_require_ownership_no_owner_passes() -> None: resource = type("R", (), {"owner": None})() # Should not raise — no owner means open access. require_ownership(resource, "owner", uuid4(), "edit") def test_require_recipient_passes() -> None: aid = uuid4() require_recipient([uuid4(), aid, uuid4()], aid) def test_require_recipient_raises() -> None: with pytest.raises(HTTPException) as exc: require_recipient([uuid4(), uuid4()], uuid4()) assert exc.value.status_code == HTTPStatus.FORBIDDEN def test_require_membership_passes() -> None: aid = uuid4() require_membership([uuid4(), aid], aid, "channel") def test_require_membership_raises() -> None: with pytest.raises(HTTPException) as exc: require_membership([uuid4()], uuid4(), "channel") assert exc.value.status_code == HTTPStatus.FORBIDDEN