test(security): 修 -race 下 TempDir 清理假红 —— 断言已过却被清理判失败

## 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)。
This commit is contained in:
JianFeeeee
2026-10-20 10:24:31 +08:00
parent 8a2503796e
commit 4e66e644da

View File

@ -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
}