Backfill same-day snapshots for newly added or restored videos, preserve successful fan snapshots on resume, persist incomplete state before forced re-runs, and split collection completion from backup completion so failed backups can retry without API calls. Reject missing data payloads instead of treating them as empty folders, guard against mass-unfav on suspicious empty remote folders, rebuild Bilibili clients when credentials change, recompute primary folder ownership from active relations with per-folder fav_time, preserve original titles for dropped invalid videos, poll config every 60 seconds, and fix favsort verify interval and mixed resource types.
101 lines
2.9 KiB
Python
101 lines
2.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""favsort run 参数校验与资源类型测试(不联网): uv run python tests/test_favsort_run.py"""
|
|
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
sys.stdout.reconfigure(encoding="utf-8")
|
|
|
|
import favsort # noqa: E402
|
|
|
|
|
|
class Args:
|
|
media_id = 1
|
|
verify_every = 1
|
|
|
|
|
|
def config():
|
|
return {
|
|
"mid": 1,
|
|
"csrf": "csrf",
|
|
"cookie": "cookie",
|
|
"overrides": {},
|
|
"sleep": {
|
|
"min": 0, "max": 0,
|
|
"long_every_min": 1000, "long_every_max": 1000,
|
|
"long_min": 0, "long_max": 0,
|
|
"retry_wait": 0,
|
|
},
|
|
}
|
|
|
|
|
|
def test_zero_verify_every_rejected_before_writes():
|
|
calls = []
|
|
originals = (favsort.load_plan, favsort.fetch_ids, favsort.post_form)
|
|
favsort.load_plan = lambda media_id: {"target_order": [], "titles": {}}
|
|
favsort.fetch_ids = lambda cfg, media_id: calls.append("fetch") or []
|
|
favsort.post_form = lambda *args, **kwargs: calls.append("post") or {}
|
|
args = Args()
|
|
args.verify_every = 0
|
|
try:
|
|
code = favsort.cmd_run(config(), args)
|
|
finally:
|
|
favsort.load_plan, favsort.fetch_ids, favsort.post_form = originals
|
|
assert code == 2
|
|
assert calls == []
|
|
|
|
|
|
def test_sort_preserves_resource_types():
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
plan = {
|
|
"media_id": 1,
|
|
"target_order": [1, 2],
|
|
"titles": {"1": {"title": "音频"}, "2": {"title": "视频"}},
|
|
"types": {1: 2, 2: 12},
|
|
}
|
|
bodies = []
|
|
orders = [[2, 1]]
|
|
originals = (
|
|
favsort.load_plan,
|
|
favsort.fetch_ids,
|
|
favsort.post_form,
|
|
favsort.plan_path,
|
|
favsort.journal_path,
|
|
)
|
|
favsort.load_plan = lambda media_id: plan
|
|
favsort.plan_path = lambda media_id: str(Path(tmp) / "plan.json")
|
|
favsort.journal_path = lambda media_id: str(Path(tmp) / "journal.jsonl")
|
|
|
|
def fetch_ids(cfg, media_id):
|
|
order = orders.pop(0) if orders else [1, 2]
|
|
return [{"id": aid} for aid in order]
|
|
|
|
favsort.fetch_ids = fetch_ids
|
|
favsort.post_form = lambda cfg, url, body: bodies.append(body) or {"code": 0}
|
|
args = Args()
|
|
try:
|
|
code = favsort.cmd_run(config(), args)
|
|
finally:
|
|
(
|
|
favsort.load_plan,
|
|
favsort.fetch_ids,
|
|
favsort.post_form,
|
|
favsort.plan_path,
|
|
favsort.journal_path,
|
|
) = originals
|
|
assert code == 0
|
|
assert [body["sort"] for body in bodies] == ["1:2:2:12"]
|
|
|
|
|
|
def main():
|
|
test_zero_verify_every_rejected_before_writes()
|
|
test_sort_preserves_resource_types()
|
|
print("OK: favsort run 参数校验与资源类型测试全部通过")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|