test_triage_dump.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. """Tests for the opt-in triage I/O dump (TriageDumper)."""
  2. import json
  3. import re
  4. from datetime import datetime
  5. from stt_daemon.assistant.triage_dump import TriageDumper
  6. TS = 1759073916.19
  7. def _only_file(directory):
  8. files = list(directory.rglob("*.json"))
  9. assert len(files) == 1
  10. return files[0]
  11. def test_enabled_writes_one_shaped_file(tmp_path):
  12. dumper = TriageDumper(True, directory=str(tmp_path))
  13. dumper.begin(
  14. TS,
  15. laya={"request": {"state": "s"}, "response": {"ok": True}, "error": None},
  16. llm={"request": {"url": "u", "body": {}}, "response": {"c": 1}, "error": None},
  17. )
  18. dumper.finalize(TS)
  19. path = _only_file(tmp_path)
  20. assert re.fullmatch(r"\d{6}-\d{3}\.json", path.name)
  21. expected_day = datetime.fromtimestamp(TS).strftime("%Y-%m-%d")
  22. assert path.parent.name == expected_day
  23. data = json.loads(path.read_text(encoding="utf-8"))
  24. assert data["ts"] == TS
  25. assert isinstance(data["iso"], str) and data["iso"]
  26. assert data["laya"] == {
  27. "request": {"state": "s"},
  28. "response": {"ok": True},
  29. "error": None,
  30. }
  31. assert data["llm"] == {
  32. "request": {"url": "u", "body": {}},
  33. "response": {"c": 1},
  34. "error": None,
  35. }
  36. def test_disabled_writes_nothing(tmp_path):
  37. dumper = TriageDumper(False, directory=str(tmp_path))
  38. assert dumper.enabled is False
  39. dumper.begin(TS, laya={"request": {}, "response": {}, "error": None})
  40. dumper.record(TS, llm={"request": {}, "response": {}, "error": None})
  41. dumper.finalize(TS)
  42. dumper.clear()
  43. assert list(tmp_path.rglob("*")) == []
  44. def test_record_merges_without_dropping_earlier_parts(tmp_path):
  45. dumper = TriageDumper(True, directory=str(tmp_path))
  46. dumper.begin(
  47. TS, laya={"request": {"state": "s"}, "response": None, "error": None}
  48. )
  49. dumper.record(TS, llm={"request": {"url": "u"}, "response": None, "error": None})
  50. dumper.record(TS, laya={"response": {"ok": True}, "error": None})
  51. dumper.finalize(TS)
  52. data = json.loads(_only_file(tmp_path).read_text(encoding="utf-8"))
  53. assert data["laya"]["request"] == {"state": "s"}
  54. assert data["laya"]["response"] == {"ok": True}
  55. assert data["llm"]["request"] == {"url": "u"}
  56. def test_llm_response_phase_keeps_request(tmp_path):
  57. """The response-phase record must not wipe the captured request."""
  58. dumper = TriageDumper(True, directory=str(tmp_path))
  59. dumper.begin(TS, laya={"request": {}, "response": {}, "error": None})
  60. dumper.record(
  61. TS,
  62. llm={"request": {"url": "u", "body": {"m": 1}}, "response": None, "error": None},
  63. )
  64. dumper.record(TS, llm={"request": None, "response": {"c": 1}, "error": None})
  65. dumper.finalize(TS)
  66. data = json.loads(_only_file(tmp_path).read_text(encoding="utf-8"))
  67. assert data["llm"]["request"] == {"url": "u", "body": {"m": 1}}
  68. assert data["llm"]["response"] == {"c": 1}
  69. assert data["llm"]["error"] is None
  70. def test_finalize_unknown_ts_is_noop(tmp_path):
  71. dumper = TriageDumper(True, directory=str(tmp_path))
  72. dumper.finalize(1234567890.0)
  73. assert list(tmp_path.rglob("*")) == []
  74. def test_clear_drops_pending(tmp_path):
  75. dumper = TriageDumper(True, directory=str(tmp_path))
  76. dumper.begin(TS, laya={"request": {}, "response": {}, "error": None})
  77. dumper.clear()
  78. dumper.finalize(TS)
  79. assert list(tmp_path.rglob("*")) == []
  80. def test_write_failure_is_swallowed(tmp_path):
  81. blocker = tmp_path / "blocker"
  82. blocker.write_text("not a directory")
  83. dumper = TriageDumper(True, directory=str(blocker / "sub"))
  84. # Must not raise even though no directory can be created here.
  85. dumper.begin(TS, laya={"request": {}, "response": {}, "error": None})
  86. dumper.finalize(TS)
  87. assert blocker.is_file()
  88. def test_discard_drops_pending_without_writing(tmp_path):
  89. dumper = TriageDumper(True, directory=str(tmp_path))
  90. dumper.begin(TS, laya={"request": {}, "response": {}, "error": None})
  91. dumper.discard(TS)
  92. dumper.finalize(TS)
  93. assert list(tmp_path.rglob("*")) == []
  94. def test_discard_unknown_and_disabled_is_noop(tmp_path):
  95. dumper = TriageDumper(True, directory=str(tmp_path))
  96. dumper.discard(1234567890.0)
  97. assert list(tmp_path.rglob("*")) == []
  98. disabled = TriageDumper(False, directory=str(tmp_path))
  99. disabled.discard(TS)
  100. disabled.finalize(TS)
  101. assert list(tmp_path.rglob("*")) == []