Commit Graph

2 Commits

Author SHA1 Message Date
agent_coder dc9a23f801 test(render): этап 0 — golden-эталоны фидов как оракул эквивалентности (#27)
Docker Image CI / build (pull_request) Has been cancelled
Первый этап эпика рефакторинга рендер-пайплайна (#34): снимает полные
snapshot'ы выходов generate_channel_rss (RSS XML) и generate_channel_html
(HTML) на записанном РЕАЛЬНОМ корпусе (4 канала: bladerunnerblues, embedoka,
meow_design, theyforcedme) и закрепляет тестом сравнения. Оракул для всех
последующих этапов: изменение байтов фида без ссылки на пункт реестра §3
спеки = регрессия. Никакой продакшн рендер-код не тронут — только тест-инфра.

- tests/golden_replay.py: реплей-загрузчик (распикливает recorded/*.cache|
  *.chatinfo, monkeypatch tg_cache.cached_get_chat_history/cached_get_chat —
  буквально прод-путь cache-hit) + генератор goldens + нормализаторы.
- tests/test_stage0_golden.py: оракул (11 тестов — RSS×4, HTML×4 + guards).
- tests/test_data/golden/: 8 замороженных snapshot'ов (~1.9 МБ).
- tests/conftest.py: пин TZ=UTC (naive-даты kurigram интерпретируются в
  локальной tz → без пина pubDate дрейфует между машинами).

Нормализации (симметрично golden+actual, минимальные, каждая с источником
недетерминизма): strip <lastBuildDate> (feedgen now()), strip <generator>
(страховка), сортировка <div class="message-flags"> (merged-флаги —
list(set(...)), hash-порядок; убирается коммитом этапа 2 по §3.8).

Детерминизм подтверждён 3 способами: двойной in-process захват, разные
PYTHONHASHSEED, регенерация в отдельном процессе — нормализованный вывод
байт-идентичен. Полный сюит 332 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 07:39:40 +03:00
vvzvlad f13d1507ad fix: escape debug title (XSS) and make test suite order-independent
Docker Image CI / build (pull_request) Has been cancelled
Issue #13: data["html"]["title"] was embedded into the debug HTML of
/post/html without escaping; title never passes through bleach, so a post
whose generated title carries markup (e.g. a poll question) was a reflected
XSS under ?debug=true. Escape it with html.escape, same as raw_message.
Add a regression test with a <script> payload in a poll question.

Issue #17: a bare 'pytest' from the repo root failed 22 tests because the
config in tests/pytest.ini was not picked up (asyncio_mode lost, .venv
collected) and every test module polluted sys.modules['config'] at import
time. Move the config to a root pytest.ini with testpaths=tests, and
centralize the sys.path bootstrap + config mock in tests/conftest.py, which
pytest imports before any test module. Drop the per-module preambles.

Closes #13, closes #17

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 17:20:01 +03:00