返回 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 fenceBootTestHistoryCatalog(t)
24 m := sessiontemp.New()
25 old := control.New(control.Options{
26 SessionTemp: m,
27 Sink: event.Discard,
28 Label: "test",
29 })
30 lease, err := old.SessionTemp().Acquire()
31 if err != nil {
32 t.Fatal(err)
33 }
34 dir := lease.Dir()
35 if err := os.WriteFile(filepath.Join(dir, "keep.txt"), []byte("ok"), 0o600); err != nil {
36 t.Fatal(err)
37 }
38 lease.Release()
39
40 res, err := Rebuild(context.Background(), old, Options{
41 WorkspaceRoot: workspace,
42 Sink: event.Discard,
43 RequireKey: false,
44 Stderr: os.Stderr,
45 })
46 if err != nil {
47 // Fail-atomic: old manager still works and is not sealed.
48 again, aerr := old.SessionTemp().Acquire()
49 if aerr != nil {
50 t.Fatalf("old session temp broken after failed rebuild: %v", aerr)
51 }
52 if again.Dir() != dir {
53 t.Fatalf("failed rebuild rotated old temp: got %q want %q", again.Dir(), dir)
54 }
55 body, rerr := os.ReadFile(filepath.Join(dir, "keep.txt"))
56 if rerr != nil || string(body) != "ok" {
57 t.Fatalf("temp file lost after failed rebuild: %q %v", body, rerr)
58 }
59 again.Release()
60 old.Close()
61 return
62 }
63
64 // Successful rebuild: replacement shares the Manager and the generation.
65 if res == nil || res.Controller == nil {
66 t.Fatal("Rebuild returned nil result without error")
67 }
68 newCtrl := res.Controller
69 if newCtrl.SessionTemp() != m {
70 t.Fatal("replacement controller must share the old SessionTemp Manager")
71 }
72 if old.SessionTemp() != m {
73 t.Fatal("old controller lost SessionTemp identity during rebuild")
74 }
75 again, err := newCtrl.SessionTemp().Acquire()
76 if err != nil {
77 t.Fatal(err)
78 }
79 if again.Dir() != dir {
80 t.Fatalf("rebuild changed generation: got %q want %q", again.Dir(), dir)
81 }
82 body, err := os.ReadFile(filepath.Join(dir, "keep.txt"))
83 if err != nil || string(body) != "ok" {
84 t.Fatalf("temp file lost across rebuild: %q %v", body, err)
85 }
86 again.Release()
87
88 // Publish-order: release old after replacement is live.
89 old.ReleaseResources()
90 if m.Sealed() {
91 t.Fatal("shared manager must not seal while replacement still owns it")
92 }
93 still, err := newCtrl.SessionTemp().Acquire()
94 if err != nil {
95 t.Fatalf("replacement lost temp after old close: %v", err)
96 }
97 still.Release()
98 newCtrl.Close()
99 }
100
100 lines GO