返回 DeepSeek-Reasonix
metadata_membership_test.go
根目录 / internal / sessioncatalog / metadata_membership_test.go
1 package sessioncatalog
2
3 import (
4 "context"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9 )
10
11 func TestMetadataRefreshDoesNotRewriteDiscoveredTopics(t *testing.T) {
12 c, err := Open(t.Context(), Options{InMemory: true, MetadataOnly: true, StartPaused: true})
13 if err != nil {
14 t.Fatal(err)
15 }
16 defer c.Close(context.Background())
17 _, err = c.db.Exec(`WITH RECURSIVE n(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM n WHERE i<1000)
18 INSERT INTO catalog_sessions(path,path_key,directory,directory_key,scope,topic_id,topic_title,ordinary_visible)
19 SELECT printf('/old/%d.jsonl',i),printf('/old/%d.jsonl',i),'/old','/old','global',printf('source-%d',i),'Old',1 FROM n;
20 INSERT INTO catalog_topics(scope,workspace_root,workspace_root_key,topic_id,title)
21 SELECT scope,workspace_root,workspace_root_key,topic_id,topic_title FROM catalog_sessions;
22 CREATE TABLE metadata_writes(topic_id TEXT);
23 CREATE TRIGGER record_metadata_write AFTER UPDATE ON catalog_topics BEGIN INSERT INTO metadata_writes VALUES(NEW.topic_id); END;`)
24 if err != nil {
25 t.Fatal(err)
26 }
27 for range 2 {
28 if err := c.SyncMetadata(t.Context(), nil, []TopicMetadata{{Scope: "global", TopicID: "registry", Title: "Named"}}); err != nil {
29 t.Fatal(err)
30 }
31 }
32 var writes, sources int
33 if err := c.db.QueryRow(`SELECT count(*) FROM metadata_writes WHERE topic_id LIKE 'source-%'`).Scan(&writes); err != nil || writes != 0 {
34 t.Fatalf("metadata refresh rewrote unrelated history: %d %v", writes, err)
35 }
36 if err := c.db.QueryRow(`SELECT count(*) FROM catalog_topics WHERE topic_id LIKE 'source-%'`).Scan(&sources); err != nil || sources != 1000 {
37 t.Fatalf("source projection changed: %d %v", sources, err)
38 }
39 rows, err := c.db.Query(`EXPLAIN QUERY PLAN ` + registeredMetadataTopics)
40 if err != nil {
41 t.Fatal(err)
42 }
43 defer rows.Close()
44 usedIndex := false
45 for rows.Next() {
46 var id, parent, unused int
47 var detail string
48 if err := rows.Scan(&id, &parent, &unused, &detail); err != nil {
49 t.Fatal(err)
50 }
51 usedIndex = usedIndex || strings.Contains(detail, "idx_catalog_topics_registered_metadata")
52 }
53 if err := rows.Err(); err != nil || !usedIndex {
54 t.Fatalf("metadata membership scanned all history: %v", err)
55 }
56 }
57
58 func TestMetadataRefreshLeavesSourceRetirementToMutationOwner(t *testing.T) {
59 c, err := Open(t.Context(), Options{InMemory: true, MetadataOnly: true, StartPaused: true})
60 if err != nil {
61 t.Fatal(err)
62 }
63 defer c.Close(context.Background())
64 dir := t.TempDir()
65 path := filepath.Join(dir, "source.jsonl")
66 if err := os.WriteFile(path, []byte("body is not metadata"), 0600); err != nil {
67 t.Fatal(err)
68 }
69 if err := c.ReconcileDirectory(t.Context(), DirectoryTarget{Path: dir, Scope: "global"}); err != nil {
70 t.Fatal(err)
71 }
72 record, exists, err := c.GetSession(t.Context(), path)
73 if err != nil || !exists {
74 t.Fatalf("source missing: %v %v", exists, err)
75 }
76 if err := c.SyncMetadata(t.Context(), nil, []TopicMetadata{{Scope: "global", TopicID: record.TopicID, Title: "Registered"}}); err != nil {
77 t.Fatal(err)
78 }
79 if err := c.SyncMetadata(t.Context(), nil, nil); err != nil {
80 t.Fatal(err)
81 }
82 if _, exists, err := c.GetTopic(t.Context(), TopicKey{Scope: "global", TopicID: record.TopicID}); err != nil || !exists {
83 t.Fatalf("retiring registry membership lost a live source: %v %v", exists, err)
84 }
85 if err := c.RemoveSession(t.Context(), path, "fixture"); err != nil {
86 t.Fatal(err)
87 }
88 var count int
89 if err := c.db.QueryRow(`SELECT count(*) FROM catalog_topics WHERE topic_id=?`, record.TopicID).Scan(&count); err != nil || count != 0 {
90 t.Fatalf("source removal left an orphan: %d %v", count, err)
91 }
92 }
93
94 func TestMetadataRefreshUsesOldWritersFlagsAndRollsBackFailedSlice(t *testing.T) {
95 c, err := Open(t.Context(), Options{InMemory: true, MetadataOnly: true, StartPaused: true})
96 if err != nil {
97 t.Fatal(err)
98 }
99 defer c.Close(context.Background())
100 if err := c.SyncMetadata(t.Context(), nil, []TopicMetadata{{Scope: "global", TopicID: "keep", Title: "Saved"}}); err != nil {
101 t.Fatal(err)
102 }
103 _, err = c.db.Exec(`INSERT INTO catalog_topics(scope,workspace_root,workspace_root_key,topic_id,title,metadata_present)
104 VALUES('global','','','older-writer','Old writer',1);
105 CREATE TRIGGER reject_metadata BEFORE INSERT ON catalog_topics WHEN NEW.topic_id='reject' BEGIN SELECT RAISE(ABORT,'fixture rejection'); END;`)
106 if err != nil {
107 t.Fatal(err)
108 }
109 if err := c.SyncMetadata(t.Context(), nil, []TopicMetadata{{Scope: "global", TopicID: "reject"}}); err == nil {
110 t.Fatal("failed refresh committed")
111 }
112 var registered int
113 if err := c.db.QueryRow(`SELECT count(*) FROM catalog_topics WHERE metadata_present=1`).Scan(&registered); err != nil || registered != 2 {
114 t.Fatalf("failed refresh lost prior membership: %d %v", registered, err)
115 }
116 if err := c.SyncMetadata(t.Context(), nil, []TopicMetadata{{Scope: "global", TopicID: "keep", Title: "Updated"}}); err != nil {
117 t.Fatal(err)
118 }
119 var retired int
120 if err := c.db.QueryRow(`SELECT count(*) FROM catalog_topics WHERE topic_id='older-writer'`).Scan(&retired); err != nil || retired != 0 {
121 t.Fatalf("older writer row was not retired: %d %v", retired, err)
122 }
123 // GetTopic deliberately suppresses shells without source rows. Verify the
124 // stored registry projection itself, not that unrelated visibility rule.
125 var title string
126 if err := c.db.QueryRow(`SELECT title FROM catalog_topics WHERE topic_id='keep' AND metadata_present=1`).Scan(&title); err != nil || title != "Updated" {
127 t.Fatalf("current metadata missing: %q %v", title, err)
128 }
129 }
130
130 lines GO