Repository navigation
TSI-4320: test(acceptance): 补齐恢复类验收的可执行载体 - #162
Conversation
|
Sorry @multica-tsic404[bot], you've used your own review budget of 250,000 diff characters for the last 7 days. You can request another review in 23 hours and 9 minutes by commenting |
Reviewer's Guide本 PR 仅修改 tests/acceptance,通过新增统一的真实 daemon/FUSE 测试夹具和四个恢复类验收载体,覆盖大目录索引性能、SIGTERM 关停与缓存落盘、读取日志质量,以及会话断开后的 102/104 状态和入口恢复预算;同时将用例接入验收注册表,并在不具备 FUSE 或 fusectl 能力的环境中明确跳过而不降低判据。 File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
tsic404
left a comment
There was a problem hiding this comment.
overview
规模:6 文件 +1352/-0,全部落在 tests/acceptance/,src/ 零改动。
通过的审查维度(≥3):判据强度(AC-81..84 与断言逐条对照)、脚本与进程语义(退出码、SKIP/FAIL 边界、恢复预算)、并发与资源(wave_slot、Daemon Drop 的 lazy detach、读超时线程)、安全(root 写入面、固定路径副作用、无 eval/无未引号展开、无 CI 环境变量特判)、可维护性(注册表纯追加、夹具复用)。
其他审查者反馈:本 PR 此前无 review(reviews 为空),无需折叠他人意见。
点赞:
- 注册表是纯追加(
mod3 条、LANDED3 条、SCRIPT_FORM1 条),既有 21 条载体与四道门禁未动。 read_when_ready只对ENOENT重试、其它错误立即返回——把「投递窗口」与「真实失败」分开了;这正是重试窗口最容易掩盖失败的地方,处理是对的。tc_recovery_05.sh在 root/abort前置不可得时exit 2并打印原因(C 段开头与abort写入处都如此),没有静默通过;C2 逐次匹配recovery N/3、重启计数恰为 3、第 4 次入口 104,恢复预算与终态都锁住了。Daemon::Drop在断言 panic 后 lazy-detach 挂载,一个用例失败不会污染后续用例。- 日志判据走
strip_ansi+ 行形态分类(级别 + 是否点名单个 piece),不锁死措辞。
无法锚定的发现(不在本 diff 的可锚定行上,按规则写在这里):
🟡 CI 接线缺口:ci.yml 的 acceptance-fuse-e2e 循环(P0 脚本清单)不含 tc_recovery_05.sh,entrypoint-test 的 bash -n 清单也没有它;Cargo Test 跑在 debian:sid-slim(无 --device /dev/fuse),因此三个 Rust 模块在 CI 里必然 SKIP。净结果:本批 4 条载体在 CI 中一条都不执行,唯一证据是本地 run;而 PR 自述本机非 root,所以只走了 entrypoint 的 rootless 分支——rootful 两段发布分支与整个 C 段从未执行。建议在本 PR 内把 tc_recovery_05.sh 接进 FUSE E2E job(root + /dev/fuse,需对 exit 2 放行),或单开 root job。
安全维度(显式检查):脚本无 eval、无未引号变量展开、无外部输入拼接进命令;root 写入面只有 /sys/fs/fuse/connections/<minor>/abort 与固定 /mnt-inner,前者是 C 段明示前提,后者见 cleanup 那条 inline。未发现注入或凭据类问题;也没有以环境变量特判跳过断言/放宽判据的代码(跳过全部由能力探测决定)。
结论:REQUEST CHANGES——1 项 blocking(脚本在 root 下无法通过,AC-84 至今没有能变绿的证据)、6 项 🟡、1 项 💭。
fb994ac to
9aecb1f
Compare
tsic404
left a comment
There was a problem hiding this comment.
overview
规模:9 文件 +1562/-30。行数落在 L4 区间,但改动类型是验收载体 + CI 接线,src/ 零改动(git diff --stat origin/main...HEAD -- src/ 为空),因此按判据文件分组逐条核对,不按「大 diff 直接打回」处理。
通过维度(5):判据强度(AC-81..84 与断言逐条对照)、rebase 完整性(共享追加点与同名函数解析)、CI 可执行性(用 CI 日志而不是整改自述验证)、安全(root 写入面、无 CI 环境特判)、测试判别力(假绿与假红两侧)。
未通过 2 条:1 🟡 + 1 💭,均为小改,见 inline。
上轮 8 项(7 inline + 1 💭)核对:全部收口
$WORK0700:chmod 0755 "$WORK"(tc_recovery_05.sh:37),$BIN绝对化(:215-216)。rootful 不再靠自述——CI 日志里 A/B/C1/C2 四段全部执行。- 环境判定:
mount_stage_exit ∈ {2,3,100}且行形态(common.rs:514-522),user_allow_other已移出清单,exit 1(状态库/引擎)与 101(实例锁)不再落 SKIP。方向正确;仅 100 支的 marker 不可达(inline)。 - TC-recovery-02 真实 LOOKUP:
CACHE_EXPIRY_WAIT = 1200ms(test_tc_recovery_02.rs:55)晚于 C-1.3.4 的 1s,fs::metadata(&torrent_root)(:261)在过期后发起真实请求;查找走 READDIR 未实例化的d07/f0042.bin(:321)。2s/5s/5s 预算(:49,57,59)相对 AC-81 的「秒级」是宽松方向。 - TC-recovery-04:
raw_os_error() == Some(libc::ENODATA)(:252),锁的是 errno 本身。 - 退避:区间只剩「恢复行 → 重启进程
/proc/<pid>/stat第 22 字段」(tc_recovery_05.sh:311-340),挂载与 detach 都在区间外;recovery_at_ms取在等日志之前,只会把区间估长 ~50ms(单向偏松,可接受)。CI 实测 1179 / 1194 / 1156 ms。 - harness 去重:
fuse_minor_at/wait_for_fuse上提(lib_fuse_harness.sh:28-52),TORRENTFS_FUSE_HARNESS_LIB_ONLY=1在挂载前返回(:50-52);session_recovery_e2e.sh:114用同一变量 source,两处调用改名后语义等价(30s 上限,轮询 0.2s vs 0.5s),Session Recovery E2E 绿。 - CI 接线(上轮唯一 🔴 的根因):
bash -n清单加tc_recovery_05.sh(ci.yml:109);P0 循环 7→8(:601);新步骤-- tc_recovery_0命中 3 个用例(:612-616);uid 1000 用户照session_recovery_e2e先例建(:589-596)。CI 日志实证:[TC-recovery-05] external unmount → daemon exit 102/entrypoint external unmount → exit 102, no restart/severed session → daemon exit 104/recovery 1..3/3 recoveries then exit 104/PASS,且test_tc_recovery_02|03|04 ... ok(3 passed,无 SKIP 行)。四条载体在 CI 里都真的执行了。 - 💭
/mnt-inner:危险方向(无条件 umount)已消除,但守卫条件恒假(inline 💭)。
rebase 完整性
main.rs+7/-0:测试模块 28→31、LANDED28→31、SCRIPT_FORM9→10(main.rs:48-50,153-155,180)。与origin/main的差集只有本批 4 条,别批条目零删除、零重排。common.rs+358/-0:别批的quiet_config/service_with_state/build_multi_file_torrent/rig/ingest与 service 级ingest_torrent(:235)都在;本批挂载级函数改名ingest_torrent_through_mount(:618),两个函数不同名且签名不同,别批调用点(test_tc_negative_01.rs:35,46、test_tc_negative_02.rs:149,155)仍解析到 service 级那份——不是「覆盖同名函数」的另一种写法。36deba0 → 9aecb1f的本批文件差异只有改名与一处断言措辞,内容无丢失。
安全(显式核对)
无 eval、无未引号展开;root 写入面仅 /sys/fs/fuse/connections/<minor>/abort(C 段明示前提,minor 取自 mountinfo)与 rootful entrypoint 的固定发布路径;chmod 0755 的工作目录只含测试缓存与日志,无凭据;跳过条件只看 /dev/fuse 与 fusermount 是否存在,没有「检测 CI 环境变量即跳过断言 / 放宽判据」的写法。
其他审查者
PR 上只有本审查者上一轮的 CHANGES_REQUESTED(锚在 84e691b,已悬空),无其他审查者的变更请求需要并入。
点赞
- 环境分类改成「退出码 ∧ 行形态」的合取,而不是为了让环境跑通去放宽断言。
- 退避改测进程启动时刻(
/proc/<pid>/stat+btime+CLK_TCK):AC-84 的 1s 第一次被单独见证,是这轮最扎实的一处。 - 四个载体的判据都钉在可观察量(退出码、mountinfo、
cache_metadata.txt键值、errno),不是日志措辞。
无法锚定:无。
0bf9378 to
65d4d88
Compare
tsic404
left a comment
There was a problem hiding this comment.
overview
规模:9 文件 +1581/-30(tests/acceptance/*、ci/tests/session_recovery_e2e.sh、.github/workflows/ci.yml),src/ 零改动。行数在 L4 区间,但改动类型是验收载体 + CI 接线,不含产品逻辑,按载体判据逐条审。
通过的维度(≥3):量测基准(新旧时钟逐式对照)、判据强度(AC-81..84 与断言逐条)、CI 接线实证(读 run 40242197444 的 P0 作业日志)、共享 harness 等价性、安全(root 写入面与命令构造)。
本轮时钟改动核对通过:
uptime_ms(/proc/uptime第一段,1/100s 精度,+0.5取整)与proc_started_uptime_ms(/proc/<pid>/stat第 22 字段 × 1000 /getconf CLK_TCK)两端同为零点=开机的同一时钟,不再拼btime(整秒向下取整)与精确墙钟;旧式系统性偏早 0–999ms 已消除。- 量化误差:
/proc/uptime±5ms、starttime10ms 向下取整、CLK_TCK=100(Linux glibc 固定 USER_HZ)⇒ 合计 ≤10ms 单向偏短,对 900ms 下限有 100ms 余量,不产生取整假绿,也不会假红。 - pid 消失 ⇒
cat失败 ⇒return 1⇒ 显式fail … cannot read the start time,不静默;pid 复用只在容器内极窄窗口可能,误判方向为偏晚(假红)而非假绿。 - CI 实测 1460 / 1470 / 1480 ms 全部 > 1s,
0bf9378上那条 577ms 的红已消失,BACKOFF_MIN_MS/BACKOFF_MAX_MS未动。
上轮 2 条 inline 按 65d4d88 复核,均已收口:
- exit 100 分支可达:两个 marker 表都加了
Mount failed and /dev/fuse cannot be opened(common.rs:77、tc_recovery_05.sh:126),与源码src/main.rs:960(100)、949(2)、801(3)三条独占 marker 对齐;exit 1/101 仍落 FAIL,没有退回「任何启动期失败都 SKIP」。 INTERNAL_MNT_USED已移到主 shell(tc_recovery_05.sh:265-269,328-330),cleanup的回收段真实生效(实跑后/mnt-inner不在 mountinfo、.torrentfs.lock所在目录被 rmdir),且不再是「永不回收」。
本轮另两处改动核对:
-- tc_recovery_0精确命中 3 个用例:全仓 Rust 载体里只有tc_recovery_02_large_directory_answers_within_seconds、tc_recovery_03_sigterm_exits_zero_and_persists_cache_metadata、tc_recovery_04_debug_logging_stays_lean_during_reads含该串(TC-recovery-01是脚本形态,无同名 Rust 载体);CI 日志3 passed; 81 filtered out+ 三条… ok实证执行,无 SKIP 行。uid 1000 用户的建法与session_recovery_e2e作业同款(ci.yml:541-547vs:600-607)。fuse_minor/wait_for_fuse_mount上提:fuse_minor_at的 awk 与旧实现逐字节等价,wait_for_fuse保留 30s 上限(轮询 0.5s→0.2s),TORRENTFS_FUSE_HARNESS_LIB_ONLY=1在挂载前return(lib_fuse_harness.sh:58-60),两处调用点改名后语义不变,Session Recovery E2E 绿。
其他审查者反馈:无外部 CHANGES_REQUESTED(两条 review 都出自本账号前两轮)。
无法锚定的发现:无。
发现
- 🟡
tests/acceptance/tc_recovery_05.sh:341—— 退避窗口的起点仍在恢复行之前约 460ms,900ms 下限实际只覆盖 ~440ms 的真实退避(详见该行 inline)。 - 💭
tests/acceptance/tc_recovery_05.sh:250——/mnt-inner占用守卫只在根分支执行,非 root 跑时仍可能选中别人的挂载(详见该行 inline)。
做对的,勿因整改丢失:两侧时钟统一到开机时钟并把偏早写成注释事实;recovery_at_ms 的取帧方向选「只偏长」;INTERNAL_MNT_USED 移到主 shell 后 cleanup 的守卫语义与注释一致;注册表纯追加(main.rs mod/LANDED/SCRIPT_FORM 各 3/3/1 条,既有 21 条载体未动);四道门禁未改;marker 表与源码退出码一一可达;-- tc_recovery_0 在无 /dev/fuse 的 Cargo Test 作业里只静默跳过(由 FUSE 作业负责真跑,日志实证)。
安全维度(显式核对):无 eval;$(cat …/children) 仅做 pid 分词;路径全部引号化;root 写入面仍只有 /sys/fs/fuse/connections/<minor>/abort(C 段前置写明)与 /mnt-inner(清理受 INTERNAL_MNT_USED 收口);新增 CI 步骤只建本地用户、不引入 secret;tests/acceptance/ 与 ci/tests/ 无任何按 CI 环境变量跳过或放宽判据的分支(grep 无命中)。
65d4d88 to
5c9709d
Compare
tsic404
left a comment
There was a problem hiding this comment.
overview
规模:9 文件 +1612/-30(本轮 delta 仅 tests/acceptance/tc_recovery_05.sh +54/-23),src/ 0 文件。改动类型:验收载体判据修正 + CI 接线,不含产品逻辑。
通过的维度(≥3):量测路径(取戳点与窗口构成的代码级核对)、边界与失败面(children 空/不可读、超时分支)、环境分类(ROOTFUL 定值时机与两段入口复用)、注释↔断言一致性、安全。
上轮 2 条 inline 按 5c9709d 复核,均已收口:
- 区间起点:
wait_for_daemon_exit(tc_recovery_05.sh:172-182)在「第一个没有 torrentfs 子进程」的那一轮就地取uptime_ms,调用点是exit_at_ms="$(wait_for_daemon_exit 30)"(:371)——取值发生在同一轮迭代、同一命令替换内,wait返回之后没有任何补读。窗口 = 前一 daemon 退出 → 替代进程 exec,daemon 关停(src/main.rs:503-530)与恢复行打印都在窗口开之前,重启后的 mount/republish 在starttime之后。CI 三次 1000/1000/1010ms 与该口径自洽(若 stamp 晚 40ms 就会读到 960ms)。 - 负对照按代码路径成立:窗口内只有 detach +
sleep+ exec,0.5s 的SESSION_RECOVERY_BACKOFF_SECS必然测到 ~500ms < 900ms 下限。该实验是 Dev 自建副本,我没有复跑(本角色不跑测试),此处只确认判据本身能分辨。 /mnt-inner守卫:占用检查提到根判定之外(:282-284),且daemon_mountpoint只在ROOTFUL=1且固定路径确有 FUSE 挂载时才选它(:234-240)——非 root 路径回落到$ENTRY_MNT,INTERNAL_MNT_USED保持 0,别人的挂载既不被fusermount -u也不会被 cleanup 回收。
你点名的四处边界,逐条核过(均无问题):
- 取戳点确实在「daemon 子进程消失」那一轮,不是窗口外的补读(见上)。
children在入口已wait回收时:文件存在但为空 →for空转 →return 1→ 就地取戳,这正是「daemon 已消失、入口尚未打印恢复行」的正确时刻。入口自身退出导致children不可读时同样立即取戳,随后wait_for_log30s 超时 FAIL,不静默。超时分支return 1经exit_at_ms="$(…)" || fail "…still running 30s after the abort"落到 FAIL(set -e下赋值 +||合法,不会落空)。ROOTFUL在 B 段开头定值(:272-276),C2 在同一 shell、同一 uid 起第二个入口,值不变;daemon_mountpoint另加「固定路径上真有 FUSE 挂载」这一条件,所以即使ROOTFUL=1而入口实际走了 rootless 分支(容器 root + rootless podman),也会回落到$ENTRY_MNT,不会误认别人的挂载。:348-353的注释与:366-386的断言一致:窗口含 detach + 退避 + exec,不含被 abort 的 daemon 的关停、不含重启后的挂载;上轮被点的两句(「detach 在区间外」「最多迟一个轮询」)已删除,~90ms余量与 10ms 轮询/10ms tick 的说法对得上。
其他审查者反馈:无外部 CHANGES_REQUESTED(历史两条 review 均出自本账号)。
无法锚定的发现:无。
发现
- 💭
tests/acceptance/tc_recovery_05.sh:173——local timeout="${1:-30}"声明后从未读取,deadline用的是${1:-30}(详见该行 inline)。这是本轮唯一发现,属一行改动的清理;判据本身不需要再动。
做对的,勿因整改丢失:取戳点从「abort 之后」挪到「daemon 消失」,把关停排除在窗口外并同步改写注释;wait_for_daemon_exit 超时即 FAIL;ROOTFUL 单一来源同时约束选点与守卫,rootless 与 rootful 的负向路径都保留了实跑证据;:298 的诊断行让「选了哪个点」可从日志直接判定;BACKOFF_MIN_MS/BACKOFF_MAX_MS 未动;CI 由 FUSE 作业真跑四条载体(3 passed + 三行 recovery N/3)。
安全维度(显式核对):无 eval;$(cat …/children) 仅做 pid 分词;路径全引号化;root 写入面仍只有 abort(C 段前置写明)与受 ROOTFUL/INTERNAL_MNT_USED 双重收口的 /mnt-inner;非 root 路径不再触碰别人的挂载;无按 CI 环境变量跳过或放宽判据的分支(tests/acceptance/、ci/tests/ grep 无命中)。
5c9709d to
8b7bf15
Compare
恢复批次的四个用例此前只有设计条目、没有可执行形态,大目录列出、 SIGTERM 优雅停止、debug 日志精简与会话切断恢复因此无法自动判定。 新增三个 Rust 模块与一个脚本:分别驱动真实守护进程的挂载面命名空间 操作、退出码与缓存元数据落盘、日志行形态,以及容器入口的恢复预算与 外部卸载终态。判据复用既有 harness 与注册表,不新增也不放宽。 计时只测被测对象:进入目录取过期内核缓存后的真实往返,恢复退避以 重启进程的启动时刻为准。四条载体接入带 FUSE 设备的 CI 作业,无法 挂载或缺少 root 的环境自行跳过并写明原因。
8b7bf15 to
5bc20b6
Compare
tsic404
left a comment
There was a problem hiding this comment.
overview
规模:9 文件 +1613/-30(相对 origin/main@46d6360),src/ 0 文件。改动类型:验收载体 + CI 接线 + 一次 rebase 并集解。相对上一轮 head 5c9709d,本批内容只有 wait_for_daemon_exit 的两行清理(:172-174)。
通过维度:rebase 并集正确性(证明级核对)、CI 接线(main 新 rc=$? 循环)、判据四处复核、注释↔断言一致性、安全。零发现。
rebase 并集:按 diff 判定,不按符号名
git diff origin/main..5bc20b6 -- tests/acceptance/common.rs = +359 / -0。零删除即证明 main 上那份 Rig::with_database / reopen / IngestHarness 重构的正文一字未动,本批只在其尾部追加 daemon 夹具,并补三行 import(fs、path、process;BTreeSet 是 main 原有且被 :638 使用)。逐条核过你点名的面:
Rig两条构造路径仍在:rig()→Rig::with_database(:102-106)、IngestHarness::with_file_db→Rig::with_database(:400-403)、reopen供remount用(:122-139、:409-425)。- import 全为并集且都被使用:main 的
BTreeSet(:638)、DirEntry(:514);本批Child/Command/ExitStatus/Stdio(:759,788,834,898,922)。无重复顶层定义(^(pub )?(fn|struct|enum|const|mod)去重为空)。 - marker 表两处一致:
common.rs:861-867与tc_recovery_05.sh:126为同五条(含Mount failed and /dev/fuse cannot be opened),退出码集合仍为{2,3,100}。 - 本批 359 行窗口夹具(
Daemon/MountGate/fuse_mount_blocker/mountinfo_fuse_count/ingest_torrent_through_mount/read_when_ready/wait_for_projection/wait_for_path/daemon_config)全部在位,ingest_torrent_through_mount与 main 的 service 级ingest_torrent(:265)仍是两个函数,没有互相覆盖。
CI 接线
tc_recovery_05 落在 main 的新循环里(ci.yml:618,列表尾部追加),没有回退成旧的 set -euo pipefail 直跑式:rc=$? + rc=2 → ::warning:: + rc≠0 → ::error:: 并 exit(:619-626)原样保留,tc_ingest_03/06 与其余 7 条都在;bash -n 清单加的是我们自己那行(:111);Create the daemon user 只出现在 FUSE 作业内(:604-610),与 session-recovery 作业那份(:544-549)分属不同容器,无重复建用户。
判据四处(上轮结论在本 head 上未被 rebase 改动)
5c9709d..5bc20b6 里 tc_recovery_05.sh 的 delta 只有 :173-174 两行,其余逐字节不变,四处按新行号复核:
- 取戳点
wait_for_daemon_exit(:172-183):uptime_ms在entry_daemon_pid首次失败的那一轮就地取,:372的exit_at_ms="$(wait_for_daemon_exit 30)"是同一命令替换内的值,wait返回后无补读。 children边界:空文件 →for空转 →return 1→ 就地取戳;不可读同理;超时return 1经|| fail(:373)落 FAIL。ROOTFUL在 B 段开头定值,C2 同 shell/同 uid 复用;daemon_mountpoint另要求固定路径上确有 FUSE 挂载。- 注释
:349-354与断言:367-389一致(窗口 = daemon 退出 → 替代进程 exec)。
CI 实证(head 5bc20b6,run 40250891265)
15 项 check 全 SUCCESS(Sourcery review SKIPPED),headSha = 5bc20b6。FUSE 作业日志:recovery 1/3: 990ms / 2/3: 1000ms / 3/3: 1010ms,TC-recovery-05: PASS,循环里没有 ::warning::tc_recovery_05(即真跑而非 SKIP);三个 Rust 载体 ok. 3 passed; 0 failed(91 filtered out,含别批新增用例)。990ms 这条比 1s 低 10ms,正是 10ms tick 取整的量级,与 ~90ms 余量的说法一致。
其他审查者反馈:无外部 CHANGES_REQUESTED(历史四条 review 均出自本账号)。
无法锚定的发现:无。
做对的:并集按「main 的正文不动、本批只追加」解,因此 sizeof 级核对就能否证「语义被动过」;CI 循环换成 main 的新跑法而不是把旧式加回来;一行清理按同文件三处参照式样对齐(:92-93、:103-104、:213-214)。
安全维度(显式核对):无 eval;$(cat …/children) 仅做 pid 分词;路径全引号化;root 写入面仍只有 abort(C 段前置写明)与受 ROOTFUL/INTERNAL_MNT_USED 双重收口的 /mnt-inner;CI 新增步骤只建本地用户、无 secret;tests/acceptance/、ci/tests/ 无按 CI 环境变量跳过或放宽判据的分支。
Closes TSI-4320
Issue: https://multica.tsic.top/issues/01a172d1-afe8-7857-befe-0f843da537ec
设计依据
tsic/torrentfs-design@5b622b6本批引用的 AC-81..84、C-9.2、C-9.3、C-1.2、C-2.3.7、C-1.3.4、C-10.7/10.8、C-5.2.2、C-11.6 在
5b622b6..HEAD区间只有拆行与版式变化,语义未变,故仍以5b622b6判定。本 PR 无 D1–D4 设计变更。设计实现
tests/acceptance/test_tc_recovery_02.rs·tc_recovery_02_large_directory_answers_within_seconds:4000 文件多文件种子(根 3000 + 20 目录 × 50);进入/列出/递归/查找各自计时,列表集合全等 3020 项,递归 20 目录 / 4000 文件;预算 2s / 5s / 5stest_tc_recovery_02.rs· 列表集合与递归条目数全等断言 + 单次 listing / 整树递归计时test_tc_recovery_02.rs· 计时前等过 1s 有效期(+200ms 余量),使「进入」成为真实 LOOKUP 而非 dcache 命中test_tc_recovery_02.rs·wait_for_file_table:有界等待落库后的文件表,再在稳定形态上测量tests/acceptance/test_tc_recovery_03.rs·tc_recovery_03_sigterm_exits_zero_and_persists_cache_metadatatest_tc_recovery_03.rs· 先经挂载读出一片再 SIGTERM,wait_for_exit断言status.code() == Some(0)test_tc_recovery_03.rs· 进程退出后读<cache>/cache_metadata.txt,断言<info_hash>:piece:0存在且 piece 大小 = 16384tests/acceptance/test_tc_recovery_04.rs·is_read_summary/mentions_piece_index/is_read_warning按行形态判定;32 片夹具下逐 piece 行 ≤ 3ENODATA)test_tc_recovery_04.rs· 空 swarm 读断言raw_os_error() == Some(libc::ENODATA)(EIO、重试耗尽的ENOENT不再算异常路径成立)tests/acceptance/tc_recovery_05.sh· A 段(daemon 外部卸载 → 102)、B 段(rootful 入口外部卸载 → 入口 102、无重启行)、C 段(C1 切断 → daemon 104;C2 连续四次切断 → recovery 1/3..3/3、退避、第 4 次入口 104)tc_recovery_05.sh· A 段fusermount -u后断言 102 且 mountinfo 无残留;C1 段 abort 后断言 104tc_recovery_05.sh· C2 段逐次匹配recovery N/3;退避 = 恢复行时刻 → 重启进程的/proc/<pid>/statstarttime 换算墙钟,断言 900ms..6s;第 4 次断言入口 104 且重启行恰 3 条tc_recovery_05.sh· B 段断言入口退出 102 且日志无restarting torrentfstests/acceptance/<用例编号>」tests/acceptance/main.rs· 三个mod、LANDED三条、SCRIPT_FORM一条(纯追加)src/;git diff --stat origin/main...HEAD -- src/为空tests/acceptance/common.rs的进程级夹具(Daemon、mountinfo_fuse_count、read_when_ready、ingest_torrent、wait_for_projection、wait_for_path、daemon_config)复用既有TestHarness/MiniTracker/ 做种端;tests/acceptance/lib_fuse_harness.sh上提fuse_minor_at/wait_for_fuse两个共享函数,本脚本与ci/tests/session_recovery_e2e.sh各取一份,不再各写一套 mountinfo 解析。判据强度
piece:0且 size 正确,三条逐条断言。ENODATA本身,而不是「任意 errno」。冷读前用.stats的Seeds:确认有源,把「有源」作为前置条件而不是判据。force_unmount、挂载与入口轮询),上限 6s 只约束退避加卸载;恢复计数、第 4 次 104、外部卸载 102 不重启逐项断言。MountGate::Environment只认「挂载阶段才有的退出码(2/3/100)+ 只有挂载尝试才会写出的行」;user_allow_other是 mount 之前的无条件告警,单独不再构成 SKIP。tc_recovery_05.sh的mount_unavailable采用同一张表。CI 接线
四条载体此前在 CI 中一条都不执行;现在:
entrypoint-test的bash -n清单加入tests/acceptance/tc_recovery_05.sh;acceptance-fuse-e2e(debian:sid-slim+--device /dev/fuse --cap-add SYS_ADMIN)的 P0 循环加入tc_recovery_05,并新增cargo test --locked --release --test acceptance -- tc_recovery_0步骤执行三个 Rust 载体(cargo test作业没有/dev/fuse,它们在那里自行 SKIP);session_recovery_e2e的先例创建 uid 1000 的 daemon 用户——rootful 入口会setpriv到TORRENTFS_UID,fusermount3需要该 uid 能过 NSS。验证
已 rebase 到
origin/main(670d95d)后重跑。环境:debian:sid-slim+--device /dev/fuse --cap-add SYS_ADMIN --security-opt apparmor=unconfined容器,root,容器内cargo build --locked --release(与acceptance-fuse-e2e同镜像同参数)。cargo test --locked --release --test acceptance -- registry_tests:4 passed / 0 failed(67 filtered out)。cargo test --locked --release --test acceptance -- tc_recovery_0:3 passed / 0 failed(55.32s)。bash -n:tc_recovery_05.sh、lib_fuse_harness.sh、session_recovery_e2e.sh均通过;git diff --check干净。git merge-tree --write-tree origin/main HEAD返回单树、退出码 0;GitHub 侧mergeable=MERGEABLE。环境限制
本轮没有在宿主直跑:宿主非 root、
fusermount非 setuid,rootful 两段根本起不来。上表全部在容器内以 root 实跑,rootful 分支(B 段、C2 段)与 C 段都已执行;非 root 用例另行实跑,确认它如实exit 2而不是静默通过。观察(未改产品行为)
同一份多文件种子在
data/<filename>.torrent下的形态随 C-2.5.3 的窗口变化:临时态直接列出文件表(扁平,含 3000 文件 + 20 目录),落库后切换为「以种子名命名的根目录」。载体因此有界等待落库后的稳定形态再测量,未把临时态的形状写进判据;两种形态的取舍属产品语义,不在本批范围。Summary by Sourcery
Add executable acceptance coverage for recovery behavior and wire it into FUSE-enabled CI.
New Features:
Enhancements:
CI:
Tests: