feat: --smart-resume 智能断点续传 (校验最新N个文件, 损坏即重传)

This commit is contained in:
AskaEth committed 2026-08-22 14:51:09 +08:00
1 parent 15ed4330ae
commit 0f9866a031
3 files changed
+142 -2

No files matched your search

+58
View File
@@ -370,3 +370,61 @@ def test_count_files_only_files(tmp_path):
def test_parse_args_retry_infinite():
args = transfer.parse_args(["--retry", "-1", "s", "d"])
assert args.retry == -1 # 无限重试
# ---------- 智能断点续传 (校验最新N个文件) ----------
def test_verify_recent_all_ok(tmp_path):
src = tmp_path / "s"; dst = tmp_path / "d"
src.mkdir(); dst.mkdir()
(src / "a.bin").write_bytes(b"x" * 1000)
(dst / "a.bin").write_bytes(b"x" * 1000)
assert transfer.verify_recent_files(str(src), str(dst)) == []
def test_verify_recent_detects_corrupt_and_deletes(tmp_path):
src = tmp_path / "s"; dst = tmp_path / "d"
src.mkdir(); dst.mkdir()
(src / "a.bin").write_bytes(b"hello world")
(dst / "a.bin").write_bytes(b"hello worlX") # 内容损坏
bad = transfer.verify_recent_files(str(src), str(dst))
assert bad == ["a.bin"]
assert not (dst / "a.bin").exists() # 坏副本已删除
def test_verify_recent_empty_dst_no_check(tmp_path):
"""目标无已传文件时无可校验 (缺失文件由 rsync 正常补传)"""
src = tmp_path / "s"; dst = tmp_path / "d"
src.mkdir(); dst.mkdir()
(src / "a.bin").write_bytes(b"data")
assert transfer.verify_recent_files(str(src), str(dst)) == []
def test_verify_recent_large_file_checks_size_only(tmp_path):
""">100MB 只查大小, 不做内容 hash"""
src = tmp_path / "s"; dst = tmp_path / "d"
src.mkdir(); dst.mkdir()
big = b"a" * (101 * 1024 * 1024) # 101MB
(src / "big.bin").write_bytes(big)
(dst / "big.bin").write_bytes(b"b" * len(big)) # 同大小不同内容
assert transfer.verify_recent_files(str(src), str(dst)) == [] # 只查大小, 不报
def test_verify_recent_count_limit(tmp_path):
"""只校验最新 N 个, 更早的损坏不报"""
src = tmp_path / "s"; dst = tmp_path / "d"
src.mkdir(); dst.mkdir()
for i in range(3):
(src / f"f{i}.txt").write_text("ok" * 100)
(dst / f"f{i}.txt").write_text("ok" * 100)
import time
# 让 f0 是最早的
old = time.time() - 100
os.utime(str(dst / "f0.txt"), (old, old))
os.utime(str(src / "f0.txt"), (old, old))
# 损坏最早的文件 (不在最新2个内)
(src / "f0.txt").write_text("changed")
(dst / "f0.txt").write_text("changed-too")
bad = transfer.verify_recent_files(str(src), str(dst), check_count=2)
assert "f0.txt" not in bad # 只查最新2个
def test_parse_smart_resume():
assert transfer.parse_args(["s", "d"]).smart_resume is False
assert transfer.parse_args(["--smart-resume", "s", "d"]).smart_resume is True
assert transfer.parse_args(["--smart-check", "3", "s", "d"]).smart_check == 3
assert transfer.parse_args(["s", "d"]).smart_check == 5