Spaces:
Running
Running
Download tests/test_lumen_devtrace.py from SilverElixir/Lumen: direct link, hf CLI and curl.
- Browser
- Download file 4.45 kB
-
https://huggingface.co/spaces/SilverElixir/Lumen/resolve/main/tests/test_lumen_devtrace.py
- Command line
-
hf download hf://spaces/SilverElixir/Lumen/tests/test_lumen_devtrace.py
-
curl -L -o test_lumen_devtrace.py https://huggingface.co/spaces/SilverElixir/Lumen/resolve/main/tests/test_lumen_devtrace.py
4.45 kB
| """test_lumen_devtrace.py — JSONL-след запросов и ответов для разбора багов.""" | |
| import asyncio | |
| from types import SimpleNamespace | |
| import bot | |
| import lumen_devtrace | |
| from tests.bot_test_helpers import _FakeAdminRequest | |
| def _enable_trace(monkeypatch, tmp_path): | |
| monkeypatch.setenv("DEV_TRACE", "1") | |
| monkeypatch.setenv("DEV_TRACE_PATH", str(tmp_path / "trace.jsonl")) | |
| def test_devtrace_disabled_by_default_writes_nothing(monkeypatch, tmp_path): | |
| # Сторож: без DEV_TRACE=1 файл не создаётся даже при прямом вызове. | |
| monkeypatch.delenv("DEV_TRACE", raising=False) | |
| monkeypatch.setenv("DEV_TRACE_PATH", str(tmp_path / "trace.jsonl")) | |
| assert lumen_devtrace.record_answer(1, user_text="hi", reply="hello") is False | |
| assert not (tmp_path / "trace.jsonl").exists() | |
| def test_devtrace_answer_clips_and_redacts_secret(monkeypatch, tmp_path): | |
| # Защищает разбор глупостей модели (полный маршрут и ответ в файле) и | |
| # отсутствие секретов в нём: регрессия — сырой токен в trace-файле. | |
| _enable_trace(monkeypatch, tmp_path) | |
| monkeypatch.setattr(bot, "BOT_TOKEN", "devtrace-secret-abc") | |
| ok = lumen_devtrace.record_answer( | |
| 5, user_text="devtrace-secret-abc " + "x" * 2500, route=[("groq", "m1")], | |
| provider="groq", model="m1", latency_ms=12, reply="y" * 5000, | |
| ) | |
| assert ok is True | |
| raw = (tmp_path / "trace.jsonl").read_text(encoding="utf-8") | |
| assert "devtrace-secret-abc" not in raw | |
| assert "<REDACTED>" in raw | |
| entries = lumen_devtrace.read_tail(10) | |
| assert len(entries) == 1 and entries[0]["kind"] == "answer" | |
| assert len(entries[0]["user"]) == 2000 | |
| assert len(entries[0]["reply"]) == 4000 | |
| assert entries[0]["route"] == ["groq:m1"] | |
| def test_devtrace_read_tail_returns_last_n_and_skips_broken(monkeypatch, tmp_path): | |
| # Хвост для /devtrace: последние N и пропуск битых строк вместо 500. | |
| _enable_trace(monkeypatch, tmp_path) | |
| for i in range(5): | |
| assert lumen_devtrace.record_passive(7, f"msg {i}") is True | |
| with open(tmp_path / "trace.jsonl", "a", encoding="utf-8") as f: | |
| f.write("{broken\n") | |
| last = lumen_devtrace.read_tail(2) | |
| assert [e["text"] for e in last] == ["msg 3", "msg 4"] | |
| def test_devtrace_endpoint_rejects_missing_or_wrong_key(monkeypatch): | |
| original = bot.ADMIN_PANEL_KEY | |
| bot.ADMIN_PANEL_KEY = "real-admin-key" | |
| try: | |
| result = asyncio.run(bot.devtrace(_FakeAdminRequest(headers={"Authorization": "Bearer wrong"}))) | |
| assert result.status_code == 401 | |
| finally: | |
| bot.ADMIN_PANEL_KEY = original | |
| def test_devtrace_endpoint_returns_entries(monkeypatch, tmp_path): | |
| # Сторож: валидный ключ отдаёт записанный след, а не пустой список. | |
| _enable_trace(monkeypatch, tmp_path) | |
| original = bot.ADMIN_PANEL_KEY | |
| bot.ADMIN_PANEL_KEY = "real-admin-key" | |
| try: | |
| assert lumen_devtrace.record_failure(9, user_text="q", error="boom") is True | |
| result = asyncio.run(bot.devtrace(_FakeAdminRequest(headers={"Authorization": "Bearer real-admin-key"}))) | |
| assert result["count"] == 1 | |
| assert result["entries"][0]["kind"] == "failure" | |
| assert result["enabled"] is True | |
| finally: | |
| bot.ADMIN_PANEL_KEY = original | |
| def test_devtrace_passive_hook_writes_background(monkeypatch, tmp_path): | |
| # Фон группы попадает в след: иначе разбирать влияние контекста не по чему. | |
| from aiogram.enums import ChatType | |
| _enable_trace(monkeypatch, tmp_path) | |
| monkeypatch.setattr(bot, "_should_only_record_passively", lambda *a, **k: True) | |
| monkeypatch.setattr(bot, "is_guest_message", lambda m: False) | |
| monkeypatch.setattr(bot, "message_mentions_bot", lambda m: False) | |
| msg = SimpleNamespace( | |
| text="фоновый текст", caption=None, | |
| chat=SimpleNamespace(id=777002, type=ChatType.GROUP), | |
| from_user=SimpleNamespace(id=456), reply_to_message=None, | |
| ) | |
| asyncio.run(bot._handle_message_core(msg)) | |
| entries = lumen_devtrace.read_tail(10) | |
| assert entries and entries[-1]["kind"] == "passive" | |
| assert "фоновый" in entries[-1]["text"] | |
| bot.chat_state.pop(777002, None) | |