返回 DeepSeek-Reasonix
writerlease.go
根目录 / internal / testenv / writerlease.go
1 package testenv
2
3 import (
4 "fmt"
5 "os"
6 "strings"
7
8 "reasonix/internal/filelock"
9 )
10
11 // ReportLeakedFileLocks summarizes leaked locks without failing the binary. Use
12 // it for packages whose fixtures keep state under a package-scoped scratch home
13 // that is removed wholesale, where a leak is real debt but does not break the
14 // per-test t.TempDir cleanup that VerifyNoLeakedFileLocks guards.
15 func ReportLeakedFileLocks() string {
16 held := filelock.HeldPathsForTest()
17 if len(held) == 0 {
18 return ""
19 }
20 const shown = 3
21 sample := held
22 if len(sample) > shown {
23 sample = sample[:shown]
24 }
25 return fmt.Sprintf("note: tests left %d file lock(s) held, for example:\n %s",
26 len(held), strings.Join(sample, "\n "))
27 }
28
29 // VerifyNoLeakedFileLocks reports the file locks a package's tests left held.
30 //
31 // A session.Service keeps its writer lease until CloseAll or its idle TTL, so a
32 // test that never closes its service still owns the lease when t.TempDir tries
33 // to remove the directory. POSIX unlinks open files happily, so the leak is
34 // invisible there; Windows refuses with "The process cannot access the file
35 // because it is being used by another process" and fails the test during
36 // cleanup. Calling this from TestMain after m.Run turns that into one
37 // deterministic failure on every platform, and the reported lock paths contain
38 // the leaking test's TempDir name.
39 func VerifyNoLeakedFileLocks() error {
40 held := filelock.HeldPathsForTest()
41 if len(held) == 0 {
42 return nil
43 }
44 return fmt.Errorf("tests leaked %d file lock(s); close the owning session service (Service.CloseAll) before the test ends:\n %s",
45 len(held), strings.Join(held, "\n "))
46 }
47
48 // RunWithLeaseGuard runs a package test binary and fails it when a test leaves a
49 // file lock held. Packages that also need user-state isolation compose this with
50 // IsolateUserState rather than calling RunWithIsolatedUserState.
51 func RunWithLeaseGuard(m TestingM) {
52 code := m.Run()
53 if err := VerifyNoLeakedFileLocks(); err != nil {
54 fmt.Fprintln(os.Stderr, err)
55 if code == 0 {
56 code = 1
57 }
58 }
59 os.Exit(code)
60 }
61
61 lines GO