返回 DeepSeek-Reasonix
runtime_owner_test.go
根目录 / internal / boot / runtime_owner_test.go
1 package boot
2
3 import (
4 "context"
5 "testing"
6
7 "reasonix/internal/control"
8 "reasonix/internal/extension"
9 )
10
11 func TestIndependentBuildRuntimeOwnersRemainActive(t *testing.T) {
12 isolateConfigHome(t)
13 first, err := BuildRuntime(context.Background(), Options{})
14 if err != nil {
15 t.Fatal(err)
16 }
17 second, err := BuildRuntime(context.Background(), Options{})
18 if err != nil {
19 first.Controller.Close()
20 t.Fatal(err)
21 }
22 t.Cleanup(func() {
23 first.Controller.Close()
24 second.Controller.Close()
25 })
26
27 if first.Owner == nil || second.Owner == nil || first.Owner == second.Owner {
28 t.Fatal("independent builds must own independent runtime lifecycle state")
29 }
30 if first.Controller.RuntimePhase() != control.RuntimePhaseActive {
31 t.Fatalf("first phase = %s", first.Controller.RuntimePhase())
32 }
33 if second.Controller.RuntimePhase() != control.RuntimePhaseActive {
34 t.Fatalf("second phase = %s", second.Controller.RuntimePhase())
35 }
36 if first.Owner.Gate.Published() != first.Snapshot.Generation() {
37 t.Fatal("first owner lost its published generation after sibling build")
38 }
39 if second.Owner.Gate.Published() != second.Snapshot.Generation() {
40 t.Fatal("second owner did not publish its own generation")
41 }
42 }
43
44 func TestRebuildDrainsOnlySameRuntimeOwner(t *testing.T) {
45 isolateConfigHome(t)
46 lineage, err := BuildRuntime(context.Background(), Options{})
47 if err != nil {
48 t.Fatal(err)
49 }
50 sibling, err := BuildRuntime(context.Background(), Options{})
51 if err != nil {
52 lineage.Controller.Close()
53 t.Fatal(err)
54 }
55 oldGen := lineage.Snapshot.Generation()
56 siblingGen := sibling.Snapshot.Generation()
57 rebuilt, err := RebuildFrom(context.Background(), lineage, Options{})
58 if err != nil {
59 lineage.Controller.Close()
60 sibling.Controller.Close()
61 t.Fatal(err)
62 }
63 t.Cleanup(func() {
64 rebuilt.Controller.Close()
65 sibling.Controller.Close()
66 })
67
68 if rebuilt.Owner != lineage.Owner {
69 t.Fatal("same-session rebuild must reuse the previous runtime owner")
70 }
71 if rebuilt.Snapshot.Generation() != oldGen {
72 if !rebuilt.Owner.Gate.IsDraining(oldGen) || rebuilt.Owner.Gate.AdmitNewWork(oldGen) {
73 t.Fatal("rebuild must drain only its previous generation")
74 }
75 }
76 if sibling.Owner.Gate.Published() != siblingGen || sibling.Controller.RuntimePhase() != control.RuntimePhaseActive {
77 t.Fatal("rebuilding one lineage must not drain an independent session")
78 }
79 }
80
81 func TestDeferredBuildPublishesOnlyAfterCommit(t *testing.T) {
82 isolateConfigHome(t)
83 owner := extension.NewRuntimeOwner()
84 res, err := BuildRuntime(context.Background(), Options{
85 RuntimeReload: RuntimeReload{Owner: owner},
86 deferPublish: true,
87 })
88 if err != nil {
89 t.Fatal(err)
90 }
91 t.Cleanup(res.Controller.Close)
92
93 if got := owner.Gate.Published(); got != 0 {
94 t.Fatalf("replacement published before migration/commit: %d", got)
95 }
96 if phase := res.Controller.RuntimePhase(); phase != control.RuntimePhaseUnknown {
97 t.Fatalf("unpublished replacement phase = %s", phase)
98 }
99 publishBuildResult(res)
100 if got := owner.Gate.Published(); got != res.Snapshot.Generation() {
101 t.Fatalf("published = %d, want %d", got, res.Snapshot.Generation())
102 }
103 }
104
104 lines GO