This repository has been archived on 2026-05-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
GallerySubscriber/backend/tests/services/test_gallery_dl_run_stats.py
T
bvandeusen 86bf43c80a feat(downloader): tier-limited classification, config defaults, yt-dlp support
- Classify Patreon "Not allowed to view post" warnings as TIER_LIMITED so
  subscription-gated runs are distinguished from genuine failures, and persist
  error_type/message on completed runs so the distinction survives to the UI.
- Fold PLATFORM_DEFAULTS into _get_default_config so gallery-dl.conf is a
  complete, editable document; _build_config_for_source now preserves the
  user's conf and only re-seeds missing platform sections.
- Add Reset-to-Defaults action in Settings (vs. Revert Changes which just
  reloads disk); show info banner when no gallery-dl.conf exists yet.
- Fix Discord embeds option: must be "all" string, not bool (gallery-dl
  iterates the value).
- Install yt-dlp + ffmpeg in Docker images so Patreon/Mux HLS video posts
  download instead of logging "Cannot import yt-dlp" and skipping.
- Recognize yt-dlp import failures as per-item errors so they don't mask
  TIER_LIMITED/NO_NEW_CONTENT classification.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 19:32:44 -04:00

98 lines
3.4 KiB
Python

"""Unit tests for GalleryDLService._compute_run_stats.
Covers the structured counts the Downloads modal surfaces in its header row:
exit code, downloaded count, skipped count, per-item failures, warning count.
"""
from unittest.mock import patch
from app.services.gallery_dl import GalleryDLService
def _make_service():
with patch.object(GalleryDLService, "_load_base_config", return_value={}):
return GalleryDLService(rate_limit=1.0)
def test_run_stats_all_zeros_on_empty_output():
service = _make_service()
stats = service._compute_run_stats(0, "", "")
assert stats == {
"exit_code": 0,
"downloaded_count": 0,
"skipped_count": 0,
"per_item_failures": 0,
"warning_count": 0,
"tier_gated_count": 0,
}
def test_run_stats_counts_downloads_from_stdout_paths():
service = _make_service()
stdout = (
"/data/downloads/Foo/bar/1.jpg\n"
"/data/downloads/Foo/bar/2.jpg\n"
"[some log line that should not count]\n"
)
stats = service._compute_run_stats(0, stdout, "")
assert stats["downloaded_count"] == 2
def test_run_stats_skips_from_both_streams():
"""stdout '#' lines AND stderr 'skipping ' lines both count."""
service = _make_service()
stdout = (
"# /data/downloads/Foo/already_archived_1.jpg\n"
"# /data/downloads/Foo/already_archived_2.jpg\n"
)
stderr = (
"[patreon][debug] skipping https://example.com/a.jpg (abc image_large)\n"
"[patreon][debug] skipping https://example.com/b.jpg (def image_large)\n"
"[patreon][debug] skipping https://example.com/c.jpg (ghi image_large)\n"
)
stats = service._compute_run_stats(0, stdout, stderr)
assert stats["skipped_count"] == 5
def test_run_stats_per_item_failures_counted():
service = _make_service()
stderr = (
"[download][error] Failed to download 02_46004845.part\n"
"[download][error] Failed to download 03_46004845.part\n"
"[patreon][debug] something unrelated\n"
)
stats = service._compute_run_stats(1, "", stderr)
assert stats["per_item_failures"] == 2
def test_run_stats_warnings_counted():
service = _make_service()
stderr = (
"[downloader.http][warning] '404 OK' for 'https://example.com/x'\n"
"[patreon][warning] something else\n"
"[patreon][error] not a warning\n"
)
stats = service._compute_run_stats(1, "", stderr)
assert stats["warning_count"] == 2
def test_run_stats_exit_code_passed_through():
service = _make_service()
assert service._compute_run_stats(0, "", "")["exit_code"] == 0
assert service._compute_run_stats(4, "", "")["exit_code"] == 4
assert service._compute_run_stats(-9, "", "")["exit_code"] == -9
def test_run_stats_tier_gated_count_from_patreon_warnings():
"""'Not allowed to view post N' warnings tallied separately from generic warnings."""
service = _make_service()
stderr = (
"[patreon][warning] Not allowed to view post 100\n"
"[patreon][warning] Not allowed to view post 101\n"
"[patreon][warning] Not allowed to view post 102\n"
"[downloader.http][warning] '404 OK' for 'https://example.com/x'\n"
)
stats = service._compute_run_stats(4, "", stderr)
assert stats["tier_gated_count"] == 3
# Still tallied in warning_count — tier_gated is a subset, not separate
assert stats["warning_count"] == 4