"""Integration tests for workspace instance endpoints.""" import asyncio import tempfile import uuid from datetime import datetime from unittest.mock import patch import pytest from fastapi.testclient import TestClient from sqlalchemy.ext.asyncio import AsyncSession from src.models import GitRepository, Project, ToolInstance, ToolType, Workspace def _get_user_id(client: TestClient) -> uuid.UUID: from src.auth.session import decode_session_cookie from src.config import Settings settings = Settings() cookie = client.cookies.get("session") data = decode_session_cookie(settings=settings, cookie_value=cookie) if not data: raise RuntimeError("No session") return uuid.UUID(data["user_id"]) @pytest.fixture def test_workspace_with_tool_type( db_session: AsyncSession, authenticated_client: TestClient ): """Create a project, repo, workspace, and tool type.""" user_id = _get_user_id(authenticated_client) async def _create(): project = Project(name="Instance Test Project", owner_id=user_id) db_session.add(project) await db_session.flush() repo = GitRepository( name="instance-test-repo", path="/tmp/instance-test-repo", remote_url="https://example.com/repo.git", project_id=project.id, owner_id=user_id, ) db_session.add(repo) await db_session.flush() tmpdir = tempfile.mkdtemp() ws = Workspace( name="dev", repo_id=repo.id, user_id=user_id, branch="main", path=tmpdir, ) db_session.add(ws) await db_session.flush() tool_type = ToolType( name="test-tool", display_name="Test Tool", default_port=8080, category="dev", ) db_session.add(tool_type) await db_session.commit() await db_session.refresh(ws) await db_session.refresh(tool_type) return ws, tool_type, project return asyncio.run(_create()) class TestListWorkspaceInstances: """Tests for GET /workspaces/{id}/instances.""" def test_list_empty( self, authenticated_client: TestClient, test_workspace_with_tool_type ): ws, _, _ = test_workspace_with_tool_type response = authenticated_client.get(f"/workspaces/{ws.id}/instances") assert response.status_code == 200 assert response.json() == [] def test_list_instances( self, authenticated_client: TestClient, db_session: AsyncSession, test_workspace_with_tool_type, ): ws, tool_type, project = test_workspace_with_tool_type async def _create_instance(): instance = ToolInstance( name="test-instance", display_name="Test Instance", tool_type_id=tool_type.id, repository_id=ws.repo_id, project_id=project.id, owner_id=ws.user_id, workspace_id=ws.id, status="running", ) db_session.add(instance) await db_session.commit() asyncio.run(_create_instance()) response = authenticated_client.get(f"/workspaces/{ws.id}/instances") assert response.status_code == 200 data = response.json() assert len(data) == 1 assert data[0]["display_name"] == "Test Instance" class TestCreateWorkspaceInstance: """Tests for POST /workspaces/{id}/instances.""" def test_create_instance( self, authenticated_client: TestClient, test_workspace_with_tool_type, ): ws, tool_type, project = test_workspace_with_tool_type mock_instance = ToolInstance( id=uuid.uuid4(), name="mock-instance", display_name="Mock Instance", tool_type_id=tool_type.id, repository_id=ws.repo_id, project_id=project.id, owner_id=ws.user_id, workspace_id=ws.id, status="pending", created_at=datetime.now(), ) with patch( "src.api.workspace.workspace_instances.create_tool_instance", return_value=mock_instance, ): response = authenticated_client.post( f"/workspaces/{ws.id}/instances", json={"tool_type_id": str(tool_type.id), "display_name": "New Instance"}, ) assert response.status_code == 201 data = response.json() assert data["display_name"] == "Mock Instance" assert data["status"] == "pending"