Files
headquarter/apps/api/tests/integration/test_workspace_files.py
Developer c26e9eacfa feat: complete workspace-first-ui cleanup and tests
- Delete dead repo-workspace code: RepoWorkspacePage, useRepoWorkspace,
  WorkspaceLayout, FileBrowser, old git components (git-toolbar, file-editor,
  commit-panel), and repo-workspace.css.
- Fix stale backend test imports for moved models/services.
- Add GitOperations unit tests.
- Add integration tests for workspace files, git, and instances endpoints.
- Add frontend tests for WorkspaceDetailPage and ProjectCard.
- Update OpenSpec workspace-first-ui tasks and mark change completed.
- Regenerate project maps.

Quality gates: npm run typecheck, npm run lint, npm test -- --run (87 passed),
python3 -m py_compile on changed backend files, pytest backend workspace tests.
2026-06-12 17:25:09 +00:00

143 lines
4.5 KiB
Python

"""Integration tests for workspace file endpoints."""
import asyncio
import os
import tempfile
import uuid
from unittest.mock import patch
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.ext.asyncio import AsyncSession
from src.models import GitRepository, Project, Workspace
from src.services.shared.workspace_manager import WorkspaceManager
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_repo_with_workspace(
db_session: AsyncSession, authenticated_client: TestClient
):
"""Create a project, repo, and workspace backed by a temp directory."""
user_id = _get_user_id(authenticated_client)
async def _create():
project = Project(name="File Test Project", owner_id=user_id)
db_session.add(project)
await db_session.flush()
repo = GitRepository(
name="file-test-repo",
path="/tmp/file-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.commit()
await db_session.refresh(ws)
return ws
return asyncio.run(_create())
class TestListWorkspaceFiles:
"""Tests for GET /workspaces/{id}/files."""
def test_list_files(
self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
):
ws = test_repo_with_workspace
os.makedirs(os.path.join(ws.path, "src"))
with open(os.path.join(ws.path, "README.md"), "w") as f:
f.write("# Test")
response = authenticated_client.get(f"/workspaces/{ws.id}/files")
assert response.status_code == 200
data = response.json()
names = {e["name"] for e in data["entries"]}
assert "src" in names
assert "README.md" in names
def test_list_files_path_escapes_workspace(
self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
):
response = authenticated_client.get(
f"/workspaces/{test_repo_with_workspace.id}/files", params={"path": "../outside"}
)
assert response.status_code == 400
class TestGetFileContent:
"""Tests for GET /workspaces/{id}/files/content."""
def test_get_content(
self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
):
with open(os.path.join(test_repo_with_workspace.path, "hello.py"), "w") as f:
f.write("print('hello')")
response = authenticated_client.get(
f"/workspaces/{test_repo_with_workspace.id}/files/content",
params={"path": "hello.py"},
)
assert response.status_code == 200
assert response.json()["content"] == "print('hello')"
def test_get_missing_file(
self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
):
response = authenticated_client.get(
f"/workspaces/{test_repo_with_workspace.id}/files/content",
params={"path": "missing.txt"},
)
assert response.status_code == 404
class TestWriteFileContent:
"""Tests for POST /workspaces/{id}/files/content."""
def test_write_file(
self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
):
response = authenticated_client.post(
f"/workspaces/{test_repo_with_workspace.id}/files/content",
json={"path": "nested/file.txt", "content": "content"},
)
assert response.status_code == 200
assert os.path.exists(
os.path.join(test_repo_with_workspace.path, "nested", "file.txt")
)
def test_write_file_missing_path(
self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
):
response = authenticated_client.post(
f"/workspaces/{test_repo_with_workspace.id}/files/content",
json={"content": "content"},
)
assert response.status_code == 400