返回 DeepSeek-Reasonix
session_temp_rebuild_test.go
根目录 / internal / boot / session_temp_rebuild_test.go
1 package boot
2
3 import (
4 "context"
5 "os"
6 "path/filepath"
7 "testing"
8
9 "reasonix/internal/control"
10 "reasonix/internal/event"
11 "reasonix/internal/sessiontemp"
12 )
13
14 func TestRebuildReusesSessionTempManager(t *testing.T) {
15 // Isolate config/home so boot.Build does not touch the developer home.
16 home := t.TempDir()
17 t.Setenv("HOME", home)
18 t.Setenv("REASONIX_HOME", filepath.Join(home, ".reasonix"))
19 t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, "config"))
20 t.Setenv("XDG_DATA_HOME", filepath.Join(home, "data"))
21
22 workspace := t.TempDir()
23 m := sessiontemp.New()
24 old := control.New(control.Options{
25 SessionTemp: m,
26 Sink: event.Discard,
27 Label: "test",
28 })
29 lease, err := old.SessionTemp().Acquire()
30 if err != nil {
31 t.Fatal(err)
32 }
33 dir := lease.Dir()
34 if err := os.WriteFile(filepath.Join(dir, "keep.txt"), []byte("ok"), 0o600); err != nil {
35 t.Fatal(err)
36 }
37 lease.Release()
38
39 res, err := Rebuild(context.Background(), old, Options{
40 WorkspaceRoot: workspace,
41 Sink: event.Discard,
42 RequireKey: false,
43 Stderr: os.Stderr,
44 })
45 if err != nil {
46 // Fail-atomic: old manager still works and is not sealed.
47 again, aerr := old.SessionTemp().Acquire()
48 if aerr != nil {
49 t.Fatalf("old session temp broken after failed rebuild: %v", aerr)
50 }
51 if again.Dir() != dir {
52 t.Fatalf("failed rebuild rotated old temp: got %q want %q", again.Dir(), dir)
53 }
54 body, rerr := os.ReadFile(filepath.Join(dir, "keep.txt"))
55 if rerr != nil || string(body) != "ok" {
56 t.Fatalf("temp file lost after failed rebuild: %q %v", body, rerr)
57 }
58 again.Release()
59 old.Close()
60 return
61 }
62
63 // Successful rebuild: replacement shares the Manager and the generation.
64 if res == nil || res.Controller == nil {
65 t.Fatal("Rebuild returned nil result without error")
66 }
67 newCtrl := res.Controller
68 if newCtrl.SessionTemp() != m {
69 t.Fatal("replacement controller must share the old SessionTemp Manager")
70 }
71 if old.SessionTemp() != m {
72 t.Fatal("old controller lost SessionTemp identity during rebuild")
73 }
74 again, err := newCtrl.SessionTemp().Acquire()
75 if err != nil {
76 t.Fatal(err)
77 }
78 if again.Dir() != dir {
79 t.Fatalf("rebuild changed generation: got %q want %q", again.Dir(), dir)
80 }
81 body, err := os.ReadFile(filepath.Join(dir, "keep.txt"))
82 if err != nil || string(body) != "ok" {
83 t.Fatalf("temp file lost across rebuild: %q %v", body, err)
84 }
85 again.Release()
86
87 // Publish-order: release old after replacement is live.
88 old.ReleaseResources()
89 if m.Sealed() {
90 t.Fatal("shared manager must not seal while replacement still owns it")
91 }
92 still, err := newCtrl.SessionTemp().Acquire()
93 if err != nil {
94 t.Fatalf("replacement lost temp after old close: %v", err)
95 }
96 still.Release()
97 newCtrl.Close()
98 }
99
99 lines GO