513b191e47
Backend foundation for the upcoming Downloads modal refresh. Adds three
helpers on GalleryDLService:
_compute_run_stats exit_code + downloaded/skipped/per-item-failure/
warning counts, derived from stdout+stderr
_extract_errors_warnings filters stderr to just [error]/[warning] lines
so the modal can show a concise errors-only view
_truncate_log caps a log string (default 500KB) with head+tail+
elision marker, preventing verbose multi-hour runs
from bloating the download_sessions JSONB
Wires all three into download.metadata_ in the download task. No schema
change — everything nests into the existing metadata JSONB column.
Follow-up PR will consume these fields in the Downloads.vue modal.
58 lines
2.1 KiB
Python
58 lines
2.1 KiB
Python
"""Unit tests for GalleryDLService._extract_errors_warnings and _truncate_log.
|
|
|
|
These are the save-time log transforms that feed the Downloads modal's
|
|
errors-only panel and prevent multi-MB stderr blobs from landing in JSONB.
|
|
"""
|
|
from app.services.gallery_dl import GalleryDLService
|
|
|
|
|
|
def test_extract_errors_warnings_filters_debug_and_info():
|
|
stderr = (
|
|
"[gallery-dl][debug] Version 1.31.10\n"
|
|
"[patreon][info] campaign_id: 548223\n"
|
|
"[urllib3.connectionpool][debug] https://example.com 'HEAD /' 200 0\n"
|
|
"[download][error] Failed to download 01.part\n"
|
|
"[downloader.http][warning] '404 OK' for 'https://example.com'\n"
|
|
"[patreon][debug] skipping https://example.com/x\n"
|
|
)
|
|
result = GalleryDLService._extract_errors_warnings(stderr)
|
|
lines = result.splitlines()
|
|
assert len(lines) == 2
|
|
assert "[download][error]" in lines[0]
|
|
assert "[downloader.http][warning]" in lines[1]
|
|
|
|
|
|
def test_extract_errors_warnings_empty_when_clean_run():
|
|
stderr = (
|
|
"[gallery-dl][debug] Version 1.31.10\n"
|
|
"[patreon][debug] skipping https://example.com/x\n"
|
|
)
|
|
assert GalleryDLService._extract_errors_warnings(stderr) == ""
|
|
|
|
|
|
def test_extract_errors_warnings_handles_empty_input():
|
|
assert GalleryDLService._extract_errors_warnings("") == ""
|
|
assert GalleryDLService._extract_errors_warnings(None) == ""
|
|
|
|
|
|
def test_truncate_log_passthrough_when_under_limit():
|
|
small = "line\n" * 100
|
|
assert GalleryDLService._truncate_log(small, max_bytes=10_000) == small
|
|
|
|
|
|
def test_truncate_log_elides_middle_when_oversized():
|
|
large = ("x" * 100 + "\n") * 2000 # ~200KB
|
|
truncated = GalleryDLService._truncate_log(large, max_bytes=10_000)
|
|
|
|
assert len(truncated.encode("utf-8")) < len(large.encode("utf-8"))
|
|
assert "lines elided" in truncated
|
|
assert "bytes" in truncated
|
|
# Head and tail preserved
|
|
assert truncated.startswith("x")
|
|
assert truncated.rstrip().endswith("x")
|
|
|
|
|
|
def test_truncate_log_handles_empty_and_none():
|
|
assert GalleryDLService._truncate_log("") == ""
|
|
assert GalleryDLService._truncate_log(None) is None
|