Files
pipu-music/docs/testing.md
T
mrleo1nidandClaude Opus 5.5 86c3e4e477 test(load): k6 smoke for 100 wave listeners and 20 rps suggest (M7)
Three minutes of wave sessions with stream starts, play events and next batches
alongside a steady suggest load; thresholds follow the documented p95 targets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 23:01:10 +03:00

7.8 KiB
Raw Permalink Blame History

Тестирование

Пирамида

Уровень Где Инструменты Что покрываем
Unit Go testing, testify, табличные тесты Политики прав (вся матрица из auth-and-roles.md), парсинг шаблонов путей и слияние с тегами, нормализация имён, подпись ссылок, расчёт implicit_score, рендер write_template и очистка имён, обратимость шаблон ↔ регэксп, учёт квоты при конкурентных резервах, переходы статусов загрузки
Unit Python pytest, hypothesis Формулы скоринга, context_fit, MMR, бандит, обновление сессионного вектора, правила переранжирования
Unit TS vitest packages/core: очередь, события (подсчёт played_ms, засчитанное прослушивание), single-flight refresh, офлайн-очередь
Компоненты Web vitest + Testing Library Поиск (клавиатура, Enter / выбор), плеер, MoodPicker, формы админки
Компоненты Mobile jest + RNTL Экраны входа, коллекции, диалог обновления
Интеграция Go testcontainers-go (Postgres + pgvector, Redis, Meilisearch) Репозитории, миграции, сканер на тестовой библиотеке, API-хендлеры через httptest
Интеграция Python testcontainers Чтение событий из Redis Stream, kNN в pgvector, ночной пайплайн на синтетических данных
Контракт — schemathesis против запущенного api Ответы соответствуют openapi.yaml, нет 500 на фаззинге
E2E Web Playwright (Chromium + Firefox) Сценарии ниже, на deploy/compose.test.yaml
E2E Mobile Maestro (эмулятор) Вход, волна, фоновое воспроизведение, скачивание, офлайн — ночной прогон, не на каждый PR
Качество рекомендаций Python офлайн-оценка NDCG / Recall на синтетическом датасете с известными «вкусами»; регрессия качества ломает тест

Тестовая музыка

Реальную музыку в репозиторий не кладём. tests/fixtures/music/generate.sh генерирует через ffmpeg ~200 коротких (5–20 с) файлов разных форматов (FLAC, MP3, Opus, M4A) с синусами / шумом разного темпа и громкости, с полными, частичными и отсутствующими тегами, в нескольких структурах папок — для проверки шаблонов, дублей, переименований, кириллицы в путях. Генерация детерминирована (фиксированные параметры), результат кэшируется в CI.

Для аудиоанализа — отдельный набор из нескольких клипов с известным BPM (метроном 90 / 128 / 170).

E2E-сценарии (обязательные)

  1. Первый запуск: вход bootstrap-админа → принудительная смена логина / пароля → главная.
  2. Админ создаёт модератора; модератор создаёт пользователя; модератор не может создать модератора (UI и API).
  3. Админ добавляет local-источник, задаёт два шаблона, предпросмотр, скан → треки появились в поиске.
  4. Поиск: выпадающий список → переход к исполнителю; Enter → страница поиска.
  5. Воспроизведение: запуск трека, перемотка, перезагрузка страницы → трек и позиция восстановлены.
  6. Моя волна: запуск с занятием «Бегаю» → в выдаче треки с BPM из профиля; дизлайк → следующий трек, трек в «Дизлайках».
  7. Коллекция: лайк → в «Лайках»; история содержит прослушанное.
  8. Смена пароля пользователем → старые сессии разлогинены.
  9. Переключение языка ru ↔ en.
  10. Сброс пароля пользователю → обязательная смена при входе.
  11. Очередь на добавление: модератор загружает папку из 5 файлов, где 1 — точная копия трека из библиотеки, 1 — тот же трек в другом формате → первый отброшен на предпроверке, второй — по отпечатку; оба не учтены в квоте; оставшиеся 3 — pending_review. Админ правит альбом, одобряет → файлы появились в хранилище по write_template, трек найден поиском; квота освобождена.
  12. Квота: лимит 50 МБ, загрузка 80 МБ → часть файлов отклонена uploads.queue_full; модератор не может одобрить собственную загрузку, а обычный пользователь — открыть загрузку вообще (UI и API).

Правила

  • Покрытие: Go и Python ≥ 70% по строкам для internal/*/service и pipu_rec/*; для auth/policy — 100% веток.
  • Тест на каждый исправленный баг.
  • Flaky-тесты помечаются и чинятся в течение недели, а не перезапускаются бесконечно.
  • Нагрузочный smoke (k6, вручную перед релизом) — см. ниже.

Нагрузочный smoke

tests/load/smoke.js (k6 ≥ 0.50), 3 минуты: 100 одновременных слушателей волны (старт волны, начало потока каждого трека — первые 64 КБ, события прослушивания, следующая пачка с отзывами) и 20 запросов подсказок поиска в секунду. Пороги — цели из api.md и recommendations.md:

Запрос p95
GET /search/suggest < 50 мс
POST /wave/sessions/{id}/next < 150 мс
POST /wave/sessions < 300 мс
начало потока (Range: bytes=0-65535) < 300 мс
POST /events < 100 мс

Ошибок < 1%. k6 завершается с ненулевым кодом, если порог не выполнен.

k6 run -e BASE_URL=https://music.example.com -e PIPU_USER=loadtest -e PIPU_PASSWORD=… tests/load/smoke.js

Пользователь — отдельный обычный (role=user): тест наполняет его историю и лайки. Нагрузку можно менять: -e LISTENERS=20 -e SUGGEST_RPS=5 -e DURATION=1m. Запускать с машины в той же сети, что и сервер, — иначе в цифрах будет задержка канала.