Files
hkuds--deeptutor/tests/services/session/test_turn_runtime_subscribe.py
wehub-resource-sync e4dcfc49aa
Tests / Import Check (Python 3.13) (push) Has been cancelled
Tests / Import Check (Python 3.14) (push) Has been cancelled
Tests / Python Tests (Python 3.11) (push) Has been cancelled
Tests / Python Tests (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.14) (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Tests / Lint and Format (push) Has been cancelled
Tests / Web Node Tests (push) Has been cancelled
Tests / Import Check (Python 3.11) (push) Has been cancelled
Tests / Import Check (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.13) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:00:43 +08:00

104 lines
3.3 KiB
Python

from __future__ import annotations
import asyncio
import pytest
from deeptutor.services.session.sqlite_store import SQLiteSessionStore
from deeptutor.services.session.turn_runtime import TurnRuntimeManager, _TurnExecution
@pytest.mark.asyncio
async def test_subscribe_turn_does_not_synthesize_done_for_running_turn(tmp_path) -> None:
"""A paused/replaced subscription must not make the UI think the turn ended."""
store = SQLiteSessionStore(tmp_path / "chat_history.db")
runtime = TurnRuntimeManager(store)
session = await store.ensure_session(None)
turn = await store.create_turn(session["id"], capability="chat")
execution = _TurnExecution(
turn_id=turn["id"],
session_id=session["id"],
capability="chat",
payload={},
)
runtime._executions[turn["id"]] = execution
events: list[dict] = []
async def _collect() -> None:
async for event in runtime.subscribe_turn(turn["id"], after_seq=0):
events.append(event)
task = asyncio.create_task(_collect())
for _ in range(200):
if execution.subscribers:
break
await asyncio.sleep(0.01)
assert execution.subscribers
await execution.subscribers[0].queue.put(None)
await asyncio.wait_for(task, timeout=1)
assert events == []
persisted = await store.get_turn(turn["id"])
assert persisted is not None
assert persisted["status"] == "running"
@pytest.mark.asyncio
async def test_subscribe_turn_marks_orphan_running_turn_failed(tmp_path) -> None:
"""A DB-running turn with no in-process execution is stale after restart."""
store = SQLiteSessionStore(tmp_path / "chat_history.db")
runtime = TurnRuntimeManager(store)
session = await store.ensure_session(None)
turn = await store.create_turn(session["id"], capability="chat")
events: list[dict] = []
async for event in runtime.subscribe_turn(turn["id"], after_seq=0):
events.append(event)
persisted = await store.get_turn(turn["id"])
assert persisted is not None
assert persisted["status"] == "failed"
assert "restart" in persisted["error"].lower()
assert [event["type"] for event in events] == ["error", "done"]
assert events[-1]["metadata"]["status"] == "failed"
@pytest.mark.asyncio
async def test_start_turn_clears_orphan_running_turn_before_create(
monkeypatch: pytest.MonkeyPatch, tmp_path
) -> None:
"""A stale active turn should not block the next user message after restart."""
store = SQLiteSessionStore(tmp_path / "chat_history.db")
runtime = TurnRuntimeManager(store)
session = await store.ensure_session(None)
stale = await store.create_turn(session["id"], capability="chat")
async def _noop_run_turn(_execution):
return None
monkeypatch.setattr(runtime, "_run_turn", _noop_run_turn)
_, new_turn = await runtime.start_turn(
{
"type": "start_turn",
"session_id": session["id"],
"capability": "chat",
"content": "hello",
"tools": [],
"knowledge_bases": [],
"attachments": [],
"language": "en",
"config": {},
}
)
assert new_turn["id"] != stale["id"]
persisted = await store.get_turn(stale["id"])
assert persisted is not None
assert persisted["status"] == "failed"