返回 DeepSeek-Reasonix
session_removal_test.go
根目录 / internal / agent / session_removal_test.go
1 package agent
2
3 import (
4 "errors"
5 "os"
6 "path/filepath"
7 "testing"
8
9 "reasonix/internal/provider"
10 "reasonix/internal/store"
11 )
12
13 func TestSessionRemovalGuardBlocksWhileLeaseHeld(t *testing.T) {
14 dir := t.TempDir()
15 path := filepath.Join(dir, "session.jsonl")
16 s := NewSession("sys")
17 s.Add(provider.Message{Role: provider.RoleUser, Content: "work"})
18 if err := s.SaveSnapshot(path); err != nil {
19 t.Fatalf("SaveSnapshot: %v", err)
20 }
21
22 lease, err := TryAcquireSessionLease(path)
23 if err != nil {
24 t.Fatalf("TryAcquireSessionLease: %v", err)
25 }
26 defer lease.Release()
27
28 if _, err := TryAcquireSessionRemovalGuard(path); !errors.Is(err, ErrSessionLeaseHeld) {
29 t.Fatalf("guard under live lease err = %v, want ErrSessionLeaseHeld", err)
30 }
31 if _, err := os.Stat(store.SessionLeaseLock(path)); err != nil {
32 t.Fatalf("lease lock disturbed by failed guard: %v", err)
33 }
34
35 lease.Release()
36 guard, err := TryAcquireSessionRemovalGuard(path)
37 if err != nil {
38 t.Fatalf("guard after release: %v", err)
39 }
40 // While the guard holds both locks, no new lease can be acquired: this is
41 // the window that used to allow probe-then-delete races.
42 if _, err := TryAcquireSessionLease(path); !errors.Is(err, ErrSessionLeaseHeld) {
43 guard.Release()
44 t.Fatalf("lease acquired while removal guard held, err = %v", err)
45 }
46 if err := guard.RemoveSidecarsAndRelease(); err != nil {
47 t.Fatalf("RemoveSidecarsAndRelease: %v", err)
48 }
49 for _, p := range []string{
50 store.SessionLockFile(path),
51 store.SessionLeaseLock(path),
52 store.SessionLeaseInfo(path),
53 } {
54 if _, err := os.Stat(p); !os.IsNotExist(err) {
55 t.Errorf("sidecar survived removal: %s (err=%v)", p, err)
56 }
57 }
58 // The path is free again for a normal acquire afterwards.
59 after, err := TryAcquireSessionLease(path)
60 if err != nil {
61 t.Fatalf("lease after removal: %v", err)
62 }
63 after.Release()
64 }
65
66 func TestSessionRemovalGuardReleaseKeepsSidecars(t *testing.T) {
67 dir := t.TempDir()
68 path := filepath.Join(dir, "session.jsonl")
69 guard, err := TryAcquireSessionRemovalGuard(path)
70 if err != nil {
71 t.Fatalf("guard: %v", err)
72 }
73 guard.Release()
74 // Abort path: locks released, files left in place for the next owner.
75 if _, err := os.Stat(store.SessionLeaseLock(path)); err != nil {
76 t.Fatalf("lease lock missing after abort: %v", err)
77 }
78 lease, err := TryAcquireSessionLease(path)
79 if err != nil {
80 t.Fatalf("lease after abort: %v", err)
81 }
82 lease.Release()
83 }
84
84 lines GO