Spaces:
Running
Running
| """Coverage tests for animetix.views.api. | |
| ``get_task_status`` is a module-level function view that is not wired into the | |
| URL conf via this module (the routed streaming endpoints live in | |
| ``animetix.api.streams``). It is driven directly with a ``RequestFactory`` | |
| request, with the ``get_session_service`` collaborator patched at the module | |
| level so no real DI / cache is exercised. | |
| """ | |
| import json | |
| from unittest.mock import MagicMock, patch | |
| import pytest | |
| from animetix.views import api as api_mod | |
| from django.core.cache import cache | |
| from django.test import RequestFactory | |
| def rf(): | |
| return RequestFactory() | |
| def _sse_events(response): | |
| """Decode a StreamingHttpResponse into a list of parsed SSE payloads.""" | |
| events = [] | |
| for chunk in response.streaming_content: | |
| text = chunk.decode("utf-8") if isinstance(chunk, bytes) else chunk | |
| for line in text.splitlines(): | |
| line = line.strip() | |
| if line.startswith("data: "): | |
| events.append(json.loads(line[len("data: ") :])) | |
| return events | |
| # --------------------------------------------------------------------------- # | |
| # get_task_status | |
| # --------------------------------------------------------------------------- # | |
| def test_get_task_status_not_ready_returns_204(rf): | |
| cache.clear() | |
| request = rf.get("/x") | |
| with patch.object(api_mod, "get_session_service", return_value=MagicMock()): | |
| resp = api_mod.get_task_status(request, "task-1") | |
| assert resp.status_code == 204 | |
| def test_get_task_status_ready_json_result(rf): | |
| cache.set("task_result:task-2", {"ready": True, "result": {"answer": 42}}) | |
| request = rf.get("/x") | |
| with patch.object(api_mod, "get_session_service", return_value=MagicMock()): | |
| resp = api_mod.get_task_status(request, "task-2") | |
| assert resp.status_code == 200 | |
| assert json.loads(resp.content)["result"] == {"answer": 42} | |
| def test_get_task_status_ready_scenario_renders_fragment(rf): | |
| cache.set( | |
| "task_result:task-3", | |
| { | |
| "ready": True, | |
| "result": { | |
| "scenario": "The Forge", | |
| "reasoning": "because", | |
| "fusion_image": "img.png", | |
| }, | |
| }, | |
| ) | |
| session = MagicMock() | |
| session.get.side_effect = lambda k: {"temp_item_A": "A", "temp_item_B": "B"}.get(k) | |
| request = rf.get("/x") | |
| # render() is the dict-with-"scenario" branch; patch it so we don't depend on the | |
| # archetypist template being collected. Assert the view returned its result. | |
| sentinel = MagicMock(status_code=200) | |
| with ( | |
| patch.object(api_mod, "get_session_service", return_value=session), | |
| patch.object(api_mod, "render", return_value=sentinel) as render_mock, | |
| ): | |
| resp = api_mod.get_task_status(request, "task-3") | |
| render_mock.assert_called_once() | |
| # the fragment context wires the scenario through to the template | |
| assert render_mock.call_args.args[2]["scenario"] == "The Forge" | |
| assert resp is sentinel | |
| def test_get_task_status_cache_error_returns_204(rf): | |
| request = rf.get("/x") | |
| with ( | |
| patch.object(api_mod, "get_session_service", return_value=MagicMock()), | |
| patch.object(api_mod.cache, "get", side_effect=RuntimeError("boom")), | |
| ): | |
| resp = api_mod.get_task_status(request, "task-err") | |
| assert resp.status_code == 204 | |