From 4e66e644daa32d4df4bce77876761c826cb3732a Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Tue, 20 Oct 2026 10:24:31 +0800 Subject: [PATCH] =?UTF-8?q?test(security):=20=E4=BF=AE=20-race=20=E4=B8=8B?= =?UTF-8?q?=20TempDir=20=E6=B8=85=E7=90=86=E5=81=87=E7=BA=A2=20=E2=80=94?= =?UTF-8?q?=E2=80=94=20=E6=96=AD=E8=A8=80=E5=B7=B2=E8=BF=87=E5=8D=B4?= =?UTF-8?q?=E8=A2=AB=E6=B8=85=E7=90=86=E5=88=A4=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## CI 实证(run #86 / #87,Race detector 连续两次红) 失败信息自相矛盾: --- FAIL: TestE2E_ResponseSecretNeverReachesContext (0.00s) persist_leak_test.go:94: ✅ 回复侧明文未进 context;变量库 1 条 testing.go:1369: TempDir RemoveAll cleanup: unlinkat /tmp/TestE2E_.../001: directory not empty 断言全过、变量库也拦住了,唯一失败点是 `t.TempDir()` 的严格清理:RemoveAll 要 rmdir 那一刻,变量库还有一次落盘(saveLocked 的 tmp→rename)在途/刚落完, 于是判 "directory not empty"。本地不复现是因为机器快、时序不同;CI 在 -race 下慢一拍就撞上。 ## 修法 `newScrubStore` 改为自建 MkdirTemp + 重试清理(50×20ms),最后尽力删除且 **不让清理失败污染判据**。安全判据本身没有放宽——只修测试基础设施。 ## 验证 本地 `go test -race ./internal/agent/core/ ./cmd/waiter/ -count=1`: 两个包全绿(16.2s / 1.0s)。 --- internal/agent/core/toolresult_scrub_test.go | 27 ++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/internal/agent/core/toolresult_scrub_test.go b/internal/agent/core/toolresult_scrub_test.go index 33391e46..ef7b4f4f 100644 --- a/internal/agent/core/toolresult_scrub_test.go +++ b/internal/agent/core/toolresult_scrub_test.go @@ -17,8 +17,10 @@ package core import ( "context" + "os" "strings" "testing" + "time" agentAPI "github.com/JianFeeeee/HomeAgent/internal/agent/api" agentIO "github.com/JianFeeeee/HomeAgent/internal/agent/io" @@ -28,7 +30,17 @@ import ( func newScrubStore(t *testing.T) *security.Store { t.Helper() - dir := t.TempDir() + // 不用 t.TempDir():它的清理是**严格**的 RemoveAll,只要清理瞬间还有 + // 落盘写入(变量库 saveLocked 的 tmp→rename)就会报 "directory not empty", + // 把断言已通过的用例判成失败。CI 2026-10-20 连续两次在 -race 下踩到 + // (persist_leak_test.go: TestE2E_ResponseSecretNeverReachesContext, + // 日志先打印 ✅ 再报 TempDir cleanup 失败)。 + // + // 这里自己建目录 + 重试清理:等异步收尾,最后尽力删除,清理失败不污染判据。 + dir, err := os.MkdirTemp("", "homeagent-scrub-") + if err != nil { + t.Fatalf("建临时目录失败: %v", err) + } s, err := security.InitGlobal(security.Options{ Path: dir + "/v.json", KeyFn: func() ([]byte, error) { return []byte("0123456789abcdef0123456789abcdef"), nil }, @@ -37,7 +49,18 @@ func newScrubStore(t *testing.T) *security.Store { if err != nil { t.Fatal(err) } - t.Cleanup(func() { security.SetGlobal(nil) }) + t.Cleanup(func() { + security.SetGlobal(nil) + // 50 × 20ms:足够让在途 saveLocked 收尾;仍不行就尽力删,不让清理失败 + // 把一个已经通过的安全判据变成假红。 + for i := 0; i < 50; i++ { + if err := os.RemoveAll(dir); err == nil { + return + } + time.Sleep(20 * time.Millisecond) + } + _ = os.RemoveAll(dir) + }) return s }