Skip to content

TSI-4314: test(acceptance): 覆盖缓存淘汰、删除清理与停顿诊断 - #156

Merged
tsic404 merged 1 commit into
mainfrom
multica/TSI-4314
Oct 25, 2026
Merged

tsic404 merged 1 commit into
mainfrom
multica/TSI-4314

Conversation

@multica-tsic404

@multica-tsic404 multica-tsic404 Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Closes TSI-4314

设计依据: tsic/torrentfs-design@5b622b6

设计实现

设计要求 代码落点
docs/03-acceptance.md §D AC-32;docs/02-contracts.md §C-5.1.5、§C-6.2.5、§C-6.3.1 tests/acceptance/test_tc_cache_03.rs tc_cache_03_evicted_piece_is_cached_again_on_reread
docs/03-acceptance.md §D AC-33;docs/02-contracts.md §C-5.2.3、§C-5.2.4、§C-5.4.4 tests/acceptance/test_tc_cache_04.rs tc_cache_04_removing_a_torrent_purges_cache_and_metadata;见证的读取辅助由 tc_cache_04_missing_metadata_reads_as_empty 与 tc_cache_04_unreadable_metadata_is_not_swallowed 钉住
docs/03-acceptance.md §D AC-34;docs/02-contracts.md §C-4.4.2、§C-4.4.6、§C-4.4.7 tests/acceptance/test_tc_cache_05.rs tc_cache_05_cache_stall_diagnosis_and_enodata
docs/03-acceptance.md 编号与可执行形态注册 tests/acceptance/main.rs(mod + LANDED)

验证

  • cargo test --test acceptance -- tc_cache_0:10 passed, 0 failed(cache-01/03/04/05)。
  • cargo test --test acceptance -- registry_tests:4 passed, 0 failed。
  • 反证:把 read_metadata 回退为 read_to_string(path).unwrap_or_default() 后 tc_cache_04_unreadable_metadata_is_not_swallowed FAILED(exit 101),其余三条 TC-cache-04 仍绿 ⇒ 该分支判别力有实测证据。
  • 运行环境缺少 rustfmt / clippy 组件,格式化与 lint 静态门禁未执行;编译无新增警告。
  • 前端/UI 无变更。

Summary by Sourcery

Expand acceptance coverage for cache lifecycle behavior and stalled-read diagnostics.

New Features:

  • Add acceptance coverage for cache eviction and re-fetch behavior, torrent removal cleanup, and cache-stall diagnostics with ENODATA handling.

Enhancements:

  • Register the new cache acceptance cases and their identifiers in the acceptance test suite.

Tests:

  • Add end-to-end tests validating cache eviction, metadata and piece cleanup after torrent removal, and diagnostic output for stalled reads.

@sourcery-ai

sourcery-ai Bot commented Oct 25, 2026

Copy link
Copy Markdown

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 21 hours and 6 minutes by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Oct 25, 2026

Copy link
Copy Markdown

Reviewer's Guide

Expands acceptance coverage for cache eviction and re-downloads, torrent-removal cleanup, and stalled-cache diagnostics with ENODATA mapping, using live torrent infrastructure and production service paths; the cases are registered in the acceptance suite.

File-Level Changes

Change Details Files
Adds an acceptance test for cache eviction and re-download behavior.
  • Builds a multi-piece torrent with a cache smaller than the file and reads it through DownloadService.
  • Selects an actually evicted piece, re-reads it, and verifies its data and leaf .stats cached marker.
  • Verifies the root .stats eviction counter is rendered and nonzero.
tests/acceptance/test_tc_cache_03.rs
Adds an acceptance test for complete cache and metadata cleanup when removing a torrent.
  • Warms all torrent pieces through TorrentService and confirms cache files and metadata exist.
  • Removes the torrent through the production removal path and verifies the info-hash directory and in-memory records are purged.
  • Polls for metadata convergence, with shutdown flush as the fallback authoritative check.
tests/acceptance/test_tc_cache_04.rs
Adds an acceptance test for cache-stall diagnosis and ENODATA propagation.
  • Exercises both oversized-read and missing-piece cache-stall scenarios in an isolated child process.
  • Captures stderr and validates exactly one diagnostic per stall with the expected evidence and cache/read context.
  • Checks the resulting error maps through FsError to libc::ENODATA rather than EIO.
tests/acceptance/test_tc_cache_05.rs
Registers the three new acceptance cases in the executable test suite.
  • Adds module declarations for the new test files.
  • Adds their TC identifiers to LANDED for registry and coverage validation.
tests/acceptance/main.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@tsic404 tsic404 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

规模 L2 · 795 行新增 / 4 文件,类型:验收载体(无产品代码改动)。

覆盖维度:代码质量 ✓ | 安全 ✓ | 架构一致性 ✓ | 并发与资源 ✓ | 编码规范 ✓ | 测试判别力 ✓ | 设计符合性 ✓

点赞

  • 三条载体断言的都是真实渲染器与真实错误出口,没有自造第二套格式:generate_torrent_stats / generate_global_stats(src/fuse/stats.rs:255,454)、TorrentError → FsError → errno(src/fuse/errno.rs:46)。片标记的 is_cached 取自 cache.has_piece(src/infrastructure/download/engine.rs:3237),所以「重读后被重新缓存」不是自证 —— 用内部 has_piece 选片、再用 .stats 断言,这一步做得对。
  • TC-cache-05 覆盖两种 stall 形态与两个 evidence 枚举值,evidence_span ^ evidence_gone 与 stalls.len() == 2 互相约束,判据没有被放宽。
  • TC-cache-04 按 C-5.2.4 用 10s 轮询 + 关停后读取兜底,没有对存活 daemon 做单次即时断言;只调 TorrentService::remove_torrent(src/fuse/fs_service.rs:1148 的同一条 unlink 路径),不是测试自造的清理。
  • 子进程捕获 fd 2 沿用 test_tc_read_05 / test_tc_config_07 的既有形态;TORRENTFS_TC_CACHE_05_CHILD 是重入标记而非 CI 跳过(env 存在时仍执行两条 stall 场景,父进程再断言 stderr),不构成 CI 造假。

其他审查者:gh pr view --json reviews 为空,无既有 CHANGES_REQUESTED 需并入。

安全:无密钥 / 外部网络 / 路径穿越;Command::new(current_exe()) 固定参数、无 shell;只写本机临时目录与 127.0.0.1 tracker。通过。

提交信息:test(acceptance): 覆盖缓存淘汰、删除清理与停顿诊断 —— 无 TSI / C-x / AC-x / TC-x 编号、未照抄 issue 标题、正文写了为什么与可观察变化、无署名 trailer,合规。

发现 3 条(1 条 🟡 + 2 条 💭),均已行内提交,改动只在测试内。

Comment thread tests/acceptance/test_tc_cache_03.rs Resolved
Comment thread tests/acceptance/test_tc_cache_04.rs Resolved
Comment thread tests/acceptance/test_tc_cache_04.rs Resolved
@multica-tsic404
multica-tsic404 Bot force-pushed the multica/TSI-4314 branch 2 times, most recently from 8664397 to d76c549 Compare October 25, 2026 19:56
tsic404
tsic404 previously approved these changes Oct 25, 2026

@tsic404 tsic404 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

概述:本次修订(d76c549,相对上一轮 9b4edb2 仅 +123/−30,全部落在 tests/acceptance/test_tc_cache_0{3,4}.rs)逐条闭合了上一轮的 1 🟡 + 2 💭,无新增发现。规模 L2(888 行新增 / 4 文件,src/ 零改动)。通过维度:判据正确性与可失败性、设计合规(01-scope / 02-contracts @ 5b622b6)、安全、提交信息。其它审查者:无 CHANGES_REQUESTED。CI:Acceptance FUSE E2E 及 Cargo Test amd64/arm64 全绿。

点赞:修复没有换形,而是把三条「假证据」换成了「可失败证据」——root_evictions 从 Option 变 Result 并把「解析失败」的 panic 文案与「计数未增长」的预算超时文案彻底分开(test_tc_cache_03.rs:260-311);orphaned_paths 改成真正的全树遍历且 ? 传播 I/O 错误(test_tc_cache_04.rs:178-200);read_metadata 用一个入口同时服务轮询见证与 shutdown 见证(test_tc_cache_04.rs:136,146)。此外每一条修复都配了会被修复前的实现打回的回归用例。

逐项复核:

  1. test_tc_cache_03.rs:260 root_evictions 去千分位后 parse ✅ 闭合。渲染源是 src/fuse/stats.rs:254-260,驱逐次数经 format_num(src/fuse/stats.rs:36-47),只插逗号、不做 K/M 缩写,所以 replace(',', "") 是完整解。两类失败不可混淆::289-295 解析失败直接 panic!("{reason}\n{text}")(文案 cannot parse the eviction count …),:302-306 预算超时断言文案是 root .stats reported no eviction growth within …,且后者回显已解析值。两条回归用例都直接调用被测函数(:314、:321),不是代理断言。「Evictions: 1,024 → 1024」正是渲染器的真实行形态(同 stats.rs:255 的字段顺序与双空格),「Evictions: — → Err」覆盖旧的 None 被当成「从未驱逐」的路径。

  2. test_tc_cache_04.rs:178 orphaned_paths ✅ 闭合。pieces/ 全树 DFS,两处布局都会被命中:pieces/<info_hash>(名字相等,任意深度)与 pieces/<info_hash>/<info_hash>:piece:N(前缀,任意深度),后者与产品布局一致(src/infrastructure/cache/mod.rs:657-661 的 piece_path、:791 的 pieces_dir_for)。I/O 错误不再被吞:read_dir(&dir)?、entry?、file_type()? 三处都用 ?,用例侧 :110-111 以 expect 把错误变成失败。断言已非恒真::107 的 wait_until 只保证 <info_hash> 顶层目录消失,:110-115 的遍历额外覆盖「片文件被平铺到 pieces/ 或写进别的目录」这类残留,回归用例 :202 用嵌套残留 + 不可读树证明了它既能检出也能报错。

  3. test_tc_cache_04.rs:160 read_metadata ✅ 闭合。NotFound → 空串(缓存清空后文件消失属合法收敛),其它错误 panic!;:136 轮询见证与 :146 shutdown 见证共用该入口,没有第二份吞错读取。覆盖边界记录:NotFound 分支有回归用例(:170,该用例在修复前的 unwrap_or_default() 下同样通过),panic 分支目前由代码阅读核对、无独立 should_panic 断言;该分支是单行 match 臂,且同一「错误不得读成空集」原则在 orphaned_paths 侧有断言(:214-218),不构成发现。

  4. test_tc_cache_03.rs:54 read_timeout_secs 15s → 60s:判定为「仅消除环境抖动」,不构成判据放宽。理由三条:(a) AC-32 的可观察判据只有「叶子 .stats 出现标记 + 驱逐计数增长」(docs/03-acceptance.md:49),无任何时延判据;(b) 决定成败的三个预算都是与被改项无关的字面量且本修订未动——标记 20s(:131-137)、驱逐计数 10s(:146)、整段读 READ_BUDGET=120s(:33);(c) read_timeout_secs 只决定单次读在等片/发现上最多阻塞多久(src/infrastructure/config/timeouts.rs:50-52),它把发现窗口压到 min(read_timeout_secs, peer_discovery_wait_secs)(timeouts.rs:59-61,后者默认 30s,timeouts.rs:23),所以 15s 是把窗口从 30s 掐到 15s、60s 是回到产品默认(timeouts.rs:72)。判据仍会失败:不重新下载的实现拿不到 [x]/[X n],也会在 :302 的 10s 预算里被驱逐计数打回,无论单次读等多久。

  5. cache-01 单次既有断言失败:判定为新增用例未引入共享资源/时序干扰,不构成驳回理由。证据:每个用例独立 tempfile::TempDir;tracker 每次 TcpListener::bind("127.0.0.1:0") 由内核分配端口(tests/common/mod.rs:74);tests/acceptance 全目录无 std::env::set_var,TORRENTFS_TC_CACHE_05_CHILD 只挂在被 spawn 的 Command 上(test_tc_cache_05.rs:56-60),不污染父进程;种子名逐用例唯一且 03/04/05 都关 LSD(main.rs 注释同源,test_tc_cache_05.rs:226-231);并发上限仍是 MAX_CONCURRENT_TESTS = 4(tests/acceptance/common.rs:30),本修订没有抬高它。cache-01 首个用例只取 wave slot、不取 session lock(test_tc_cache_01.rs:24),因此它会与持锁的新用例共跑,多出来的是 CPU 秒数而非共享状态;而 cache-01 最容易在负载下失效的恰是它自己的墙钟判据(test_tc_cache_01.rs:89-107:4096 次单字节读 < 5s),该判据未在本 PR 中改动。附记一条残余事实(非本 PR 引入、不针对 cache-01):cache-05 的子进程以 current_exe() 重入,ACTIVE_TESTS 是进程内静态量(common.rs:32),子进程不吃父进程的配额,最多使整机同时存在的 session 数为 5;这与既有 test_tc_read_05 同形,且与 cache-01 无共享状态。同一 CI 运行的 Acceptance 作业(8m6s)全绿,与「单次负载抖动」一致。

安全维度:通过。仅新增测试载体:无密钥/凭据、无外部网络(tracker 与对端均 127.0.0.1)、无路径穿越(orphaned_paths 只做只读遍历,pieces_dir_for 另有 leaf-name 防护 src/infrastructure/cache/mod.rs:781-796)、Command::new(std::env::current_exe()) 固定参数无 shell、stderr 重定向到临时文件。

提交信息(commit-message-standard):test(acceptance): 覆盖缓存淘汰、删除清理与停顿诊断,正文非空,无设计/验收编号、未照抄 issue 标题、无 Co-authored-by/Signed-off-by 等 trailer —— 合规。

设计锚点:tsic/torrentfs-design@5b622b6(= issue 冻结 design_anchor);设计仓 HEAD 已到 ed05aa1,按锚点评审。## 设计变更 声明「无」属实:src/ 零改动,无外部可观察行为变化,无需 D1–D4 设计 PR。

零发现,故无行内评论。

缓存上限、种子删除与缓存停顿诊断此前没有可执行的验收载体,QA 只能按文档逐条手工核对。新增三条用例分别驱动小容量缓存下的淘汰与重读、metadata 删除后的缓存目录与元数据收敛、缓存无法服务的读返回 ENODATA 并落冻结诊断前缀;断言走产品现有的引擎、服务与 .stats 渲染路径。载体读取缓存元数据时只把文件缺失读作空串,其它 I/O 错误必须显形,该分支由单测钉住,回退为吞错即失败。

@tsic404 tsic404 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

概述:在 新 head eae6d4d 上重新出判决。相对上一轮批准的 d76c549 只多 tests/acceptance/test_tc_cache_04.rs 的 +20 行(一个 #[should_panic] 用例),src/ 零改动,整仓 diff 仍 4 文件。规模 L2。通过维度:判据钉定与判别力、设计合规(01-scope / 02-contracts @ 5b622b6)、安全、提交信息。其它审查者:无 CHANGES_REQUESTED(此前的批准因新推送被平台置为 DISMISSED,故本判决重新 pin 到 eae6d4d)。CI:run 40238090523 的 headSha = eae6d4d15f3…,14 项 SUCCESS + 1 项 SKIPPED(Sourcery),无失败。

点赞:这 +20 行补的正是上一轮我记录的覆盖边界——read_metadata 的「其它 I/O 错误 → panic」一支。注入手段选得对:chmod 000 在 CI 的 root 容器里不生效,而「把元数据路径做成目录」在 root 与非 root 下都稳定报错;用例还先用 expect_err + assert_ne!(kind, NotFound) 自证夹具形态,避免夹具退化后静默变成恒真。

逐项复核:

  1. 钉的是 panic 支而非被 NotFound 短接 ✅ test_tc_cache_04.rs:186 对同一路径同一操作取 expect_err,:187-191 断言 error.kind() != NotFound;因此 read_metadata(:160)里 Err(e) if e.kind() == NotFound(:163)的守卫对这条路径必为假,只能落到 :164 的 panic!。注入面是目录,read_to_string 在 Linux 上返回 EISDIR,root 下同样成立,不存在权限位失灵的空过路径。

  2. expected 与实现消息对得上,且不可被别的 panic 冒充 ✅ 属性写作 #[should_panic(expected = "read cache metadata")](:179),实现消息是 "read cache metadata {path}: {error}"(:164)——expected 是其子串,should_panic 的子串语义成立。测试体内其余五个可能 panic 的点(:183 temp dir、:185 create_dir、:186 expect_err、:187-191 断言消息、:192 之前的 join)文案都不含 read cache metadata,所以只有被测 arm 能满足期望。

  3. 判别力 ✅(静态证明;按审查职责只读,未做 scratch 执行)。把 read_metadata 函数体回退为 std::fs::read_to_string(path).unwrap_or_default() 时:目录读取返回 Err(EISDIR) 被吞成 "",unwrap_or_default 不 panic,:192 的调用不可能 panic,而 #[should_panic] 在没有 panic 时必然判失败 ⇒ 该用例必 FAIL,且同文件其余三条不受影响(它们不依赖该 arm)。这与 Verity 探针 3(修复前三条全绿、判别力缺失)和作者自述(修复后 :176 处 test did not panic as expected、exit 101)方向一致;此处结构上只有一条可达 panic 路径,静态结论比一次探针采样更强。

  4. 影响面 ✅ 新用例无 session、无 wave slot、无 session lock、无全局 env,只用独立 TempDir,因此不可能对并发时序产生干扰。CI 实测:test_tc_cache_04 四条全 ok(含 tc_cache_04_unreadable_metadata_is_not_swallowed - should panic ... ok),test_tc_cache_03 三条与 test_tc_cache_05 一条全 ok,registry_tests 四条门禁全 ok,acceptance 二进制 80 passed; 0 failed(156.35s)。registry_tests 的四条门禁只枚举模块声明、TC_ID 常量、未登记模块与脚本存在性,不枚举模块内的 #[test] 数量,故新增同模块用例不影响门禁。

安全维度:通过。仅新增测试代码:无密钥/凭据、无外部网络、无路径穿越(临时目录内自建目录);目录注入不触碰权限位,也不写任何产品路径。

提交信息(commit-message-standard):单 commit amend,subject test(acceptance): 覆盖缓存淘汰、删除清理与停顿诊断 无设计/验收编号、未照抄 issue 标题,正文非空并说明了该分支的钉定,无 Co-authored-by/Signed-off-by 等 trailer —— 合规。

设计锚点:tsic/torrentfs-design@5b622b6(= issue 冻结 design_anchor),与 Dev 声明一致;设计仓 HEAD 同为 5b622b6,docs/03-acceptance.md/docs/02-contracts.md 无漂移。src/ 零改动 ⇒ 无外部可观察行为变化,## 设计变更 声明「无」属实,不需要 D1–D4 设计 PR。

零发现,故无行内评论。

@tsic404
tsic404 merged commit 071711a into main Oct 25, 2026
15 checks passed
@tsic404
tsic404 deleted the multica/TSI-4314 branch October 25, 2026 22:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant