返回 DeepSeek-Reasonix
metadata_scan_test.go
根目录 / internal / sessioncatalog / metadata_scan_test.go
1 package sessioncatalog
2
3 import (
4 "context"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9
10 "reasonix/internal/agent"
11 )
12
13 func TestMetadataDiscoveryNeverRepairsOrClassifiesContent(t *testing.T) {
14 dir := t.TempDir()
15 path := filepath.Join(dir, "recovery.jsonl")
16 body := []byte("deliberately invalid authoritative content\n")
17 if err := os.WriteFile(path, body, 0600); err != nil {
18 t.Fatal(err)
19 }
20 if err := agent.SaveBranchMeta(path, agent.BranchMeta{Recovered: true, ParentID: "parent", TopicID: "recovered-topic", Scope: "global"}); err != nil {
21 t.Fatal(err)
22 }
23 c, err := Open(t.Context(), Options{InMemory: true, MetadataOnly: true})
24 if err != nil {
25 t.Fatal(err)
26 }
27 t.Cleanup(func() { _ = c.Close(context.Background()) })
28 c.testSessionContentLoadHook = func(string) { t.Error("metadata discovery read content") }
29 if !c.opts.DisableRepair {
30 t.Fatal("metadata mode admitted background content repair")
31 }
32 if err := c.ReconcileDirectory(t.Context(), DirectoryTarget{Path: dir, Scope: "global"}); err != nil {
33 t.Fatal(err)
34 }
35 record, found, err := c.GetSession(t.Context(), path)
36 if err != nil || !found || !record.OrdinaryVisible || record.TurnsState != TurnsUnknown || record.RecoveryCopy {
37 t.Fatalf("unverified recovery must remain reachable: %+v %v %v", record, found, err)
38 }
39 if err := c.IndexSessionPath(t.Context(), DirectoryTarget{Path: dir, Scope: "global"}, path); err != nil {
40 t.Fatal(err)
41 }
42 got, _ := os.ReadFile(path)
43 if string(got) != string(body) {
44 t.Fatal("metadata discovery changed authoritative content")
45 }
46 if !c.DirectoryScanReady(t.Context(), dir) {
47 t.Fatal("unknown content count prevented directory readiness")
48 }
49 }
50
51 func TestMetadataDiscoveryOversizedSidecarStillVisible(t *testing.T) {
52 dir := t.TempDir()
53 path := filepath.Join(dir, "old.jsonl")
54 if err := os.WriteFile(path, []byte("invalid\n"), 0600); err != nil {
55 t.Fatal(err)
56 }
57 if err := os.WriteFile(agent.BranchMetaPath(path), []byte(strings.Repeat("x", 70<<10)), 0600); err != nil {
58 t.Fatal(err)
59 }
60 c, err := Open(t.Context(), Options{InMemory: true, MetadataOnly: true})
61 if err != nil {
62 t.Fatal(err)
63 }
64 t.Cleanup(func() { _ = c.Close(context.Background()) })
65 if err := c.ReconcileDirectory(t.Context(), DirectoryTarget{Path: dir, Scope: "global"}); err != nil {
66 t.Fatal(err)
67 }
68 page, err := c.ListTopics(t.Context(), TopicPageRequest{Scope: "global", Limit: 50})
69 if err != nil || len(page.Items) != 1 {
70 t.Fatalf("metadata fallback disappeared: %+v %v", page, err)
71 }
72 }
73
74 func TestMetadataDiscoveryCancellationCannotMarkRowsMissing(t *testing.T) {
75 dir := t.TempDir()
76 path := filepath.Join(dir, "old.jsonl")
77 if err := os.WriteFile(path, []byte("invalid\n"), 0600); err != nil {
78 t.Fatal(err)
79 }
80 c, err := Open(t.Context(), Options{InMemory: true, MetadataOnly: true})
81 if err != nil {
82 t.Fatal(err)
83 }
84 t.Cleanup(func() { _ = c.Close(context.Background()) })
85 target := DirectoryTarget{Path: dir, Scope: "global"}
86 if err := c.ReconcileDirectory(t.Context(), target); err != nil {
87 t.Fatal(err)
88 }
89 if err := os.Remove(path); err != nil {
90 t.Fatal(err)
91 }
92 ctx, cancel := context.WithCancel(t.Context())
93 cancel()
94 if err := c.ReconcileDirectory(ctx, target); err == nil {
95 t.Fatal("cancelled scan succeeded")
96 }
97 row, found, err := c.GetSession(t.Context(), path)
98 if err != nil || !found || row.MissingSince != 0 {
99 t.Fatalf("cancelled scan marked missing: %+v %v", row, err)
100 }
101 }
102
103 func TestMetadataDiscoveryMissingUnusedRootIsReady(t *testing.T) {
104 dir := filepath.Join(t.TempDir(), "not-created")
105 c, err := Open(t.Context(), Options{InMemory: true, MetadataOnly: true})
106 if err != nil {
107 t.Fatal(err)
108 }
109 t.Cleanup(func() { _ = c.Close(context.Background()) })
110 target := DirectoryTarget{Path: dir, Scope: "global"}
111 if err := c.ReconcileDirectory(t.Context(), target); err != nil {
112 t.Fatal(err)
113 }
114 if !c.DirectoryScanReady(t.Context(), dir) || c.Status().State == StateDegraded {
115 t.Fatalf("unused root is not empty and ready: %+v", c.Status())
116 }
117 if _, err := os.Stat(dir); !os.IsNotExist(err) {
118 t.Fatal("discovery created the optional root")
119 }
120 if err := os.Mkdir(dir, 0700); err != nil {
121 t.Fatal(err)
122 }
123 path := filepath.Join(dir, "later.jsonl")
124 if err := os.WriteFile(path, []byte("unreadable body\n"), 0600); err != nil {
125 t.Fatal(err)
126 }
127 if err := c.ReconcileDirectory(t.Context(), target); err != nil {
128 t.Fatal(err)
129 }
130 if _, found, err := c.GetSession(t.Context(), path); err != nil || !found {
131 t.Fatalf("later source was not discovered: %v", err)
132 }
133 if err := os.Rename(dir, dir+"-unavailable"); err != nil {
134 t.Fatal(err)
135 }
136 if err := c.ReconcileDirectory(t.Context(), target); !os.IsNotExist(err) {
137 t.Fatalf("known root disappearance accepted: %v", err)
138 }
139 row, found, err := c.GetSession(t.Context(), path)
140 if err != nil || !found || row.MissingSince != 0 || c.DirectoryScanReady(t.Context(), dir) {
141 t.Fatalf("unavailable root hid history: %+v %v", row, err)
142 }
143 }
144
145 func TestMetadataDiscoveryEmptyRootCannotHideConcurrentSave(t *testing.T) {
146 dir := filepath.Join(t.TempDir(), "new-root")
147 c, err := Open(t.Context(), Options{InMemory: true, MetadataOnly: true})
148 if err != nil {
149 t.Fatal(err)
150 }
151 t.Cleanup(func() { _ = c.Close(context.Background()) })
152 target := DirectoryTarget{Path: dir, Scope: "global"}
153 scan, err := c.startMetadataScan(t.Context(), target, c.mutationSeq.Add(1), true)
154 if err != nil {
155 t.Fatal(err)
156 }
157 defer scan.close(t.Context(), nil)
158 if err := os.Mkdir(dir, 0700); err != nil {
159 t.Fatal(err)
160 }
161 path := filepath.Join(dir, "saved.jsonl")
162 if err := os.WriteFile(path, []byte("unread body\n"), 0600); err != nil {
163 t.Fatal(err)
164 }
165 if err := c.IndexSessionPath(t.Context(), target, path); err != nil {
166 t.Fatal(err)
167 }
168 if done, _, err := scan.step(t.Context()); err != nil || !done {
169 t.Fatalf("empty snapshot did not finish: %v %v", done, err)
170 }
171 row, found, err := c.GetSession(t.Context(), path)
172 if err != nil || !found || row.MissingSince != 0 {
173 t.Fatalf("older empty discovery hid the save: %+v %v", row, err)
174 }
175 }
176
176 lines GO