Spaces:
Sleeping
Sleeping
| """Tests for POST /api/v1/sessions/{session_id}/ocr_preview (auth + owner + merge).""" | |
| from __future__ import annotations | |
| import os | |
| from unittest.mock import AsyncMock, MagicMock, patch | |
| import pytest | |
| from httpx import ASGITransport, AsyncClient | |
| os.environ.setdefault("ALLOW_TEST_BYPASS", "true") | |
| from app.main import app # noqa: E402 | |
| _VALID_SESSION_ID = "00000000-0000-0000-0000-000000000099" | |
| def auth_headers(): | |
| return {"Authorization": "Test test-user-ocr-preview"} | |
| async def test_ocr_preview_requires_auth(): | |
| async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: | |
| res = await client.post( | |
| f"/api/v1/sessions/{_VALID_SESSION_ID}/ocr_preview", | |
| files={"file": ("t.png", b"\x89PNG\r\n\x1a\n", "image/png")}, | |
| data={"user_message": "hello"}, | |
| ) | |
| assert res.status_code == 401 | |
| async def test_ocr_preview_forbidden_when_not_owner(auth_headers): | |
| with patch("app.routers.solve.session_owned_by_user", return_value=False): | |
| async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: | |
| res = await client.post( | |
| f"/api/v1/sessions/{_VALID_SESSION_ID}/ocr_preview", | |
| headers=auth_headers, | |
| files={"file": ("t.png", b"\x89PNG\r\n\x1a\n", "image/png")}, | |
| data={"user_message": "note"}, | |
| ) | |
| assert res.status_code == 403 | |
| async def test_ocr_preview_success_merges_draft(auth_headers): | |
| mock_orch = MagicMock() | |
| mock_orch.ocr_agent.process_image = AsyncMock(return_value="OCR_LINE") | |
| with ( | |
| patch("app.routers.solve.session_owned_by_user", return_value=True), | |
| patch("app.routers.solve.get_orchestrator", return_value=mock_orch), | |
| ): | |
| async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: | |
| res = await client.post( | |
| f"/api/v1/sessions/{_VALID_SESSION_ID}/ocr_preview", | |
| headers=auth_headers, | |
| files={"file": ("t.png", b"\x89PNG\r\n\x1a\n", "image/png")}, | |
| data={"user_message": " my note "}, | |
| ) | |
| assert res.status_code == 200, res.text | |
| data = res.json() | |
| assert data["ocr_text"] == "OCR_LINE" | |
| assert data["user_message"] == "my note" | |
| assert data["combined_draft"] == "my note\n\nOCR_LINE" | |
| mock_orch.ocr_agent.process_image.assert_called_once() | |
| async def test_ocr_preview_rejects_oversized_file(auth_headers): | |
| mock_orch = MagicMock() | |
| mock_orch.ocr_agent.process_image = AsyncMock(return_value="") | |
| big = b"x" * (11 * 1024 * 1024) | |
| with ( | |
| patch("app.routers.solve.session_owned_by_user", return_value=True), | |
| patch("app.routers.solve.get_orchestrator", return_value=mock_orch), | |
| ): | |
| async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: | |
| res = await client.post( | |
| f"/api/v1/sessions/{_VALID_SESSION_ID}/ocr_preview", | |
| headers=auth_headers, | |
| files={"file": ("huge.png", big, "image/png")}, | |
| ) | |
| assert res.status_code == 413 | |
| mock_orch.ocr_agent.process_image.assert_not_called() | |
| async def test_ocr_preview_rejects_empty_file(auth_headers): | |
| with patch("app.routers.solve.session_owned_by_user", return_value=True): | |
| async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: | |
| res = await client.post( | |
| f"/api/v1/sessions/{_VALID_SESSION_ID}/ocr_preview", | |
| headers=auth_headers, | |
| files={"file": ("empty.png", b"", "image/png")}, | |
| ) | |
| assert res.status_code == 400 | |