返回 DeepSeek-Reasonix
reconcile_integrity_test.go
根目录 / internal / sessioncatalog / reconcile_integrity_test.go
1 package sessioncatalog
2
3 import (
4 "context"
5 "os"
6 "path/filepath"
7 "testing"
8
9 "reasonix/internal/agent"
10 )
11
12 func TestReconcileRepairsPersistedReadyDirectoryMissingCatalogRows(t *testing.T) {
13 t.Parallel()
14 ctx := context.Background()
15 dir := t.TempDir()
16 path := filepath.Join(dir, "chat.jsonl")
17 if err := os.WriteFile(path, []byte(`{"role":"user","content":"hi"}`+"\n"), 0o600); err != nil {
18 t.Fatal(err)
19 }
20 if err := agent.SaveBranchMeta(path, agent.BranchMeta{
21 Scope: "global", TopicID: "topic", TopicTitle: "Existing conversation",
22 SchemaVersion: agent.BranchMetaCountsVersion, Turns: 1,
23 }); err != nil {
24 t.Fatal(err)
25 }
26
27 catalogPath := filepath.Join(t.TempDir(), "catalog.sqlite")
28 catalog := openIntegrityTestCatalog(t, ctx, catalogPath)
29 t.Cleanup(func() { _ = catalog.Close(context.Background()) })
30 target := DirectoryTarget{Path: dir, Scope: "global"}
31 if err := catalog.ReconcileDirectory(ctx, target); err != nil {
32 t.Fatal(err)
33 }
34
35 if _, err := catalog.db.ExecContext(ctx, `DELETE FROM catalog_sessions WHERE directory=?`, dir); err != nil {
36 t.Fatal(err)
37 }
38 catalog = reopenIntegrityTestCatalog(t, ctx, catalog, catalogPath)
39 assertIntegrityRepair(t, ctx, catalog, target)
40
41 if _, err := catalog.db.ExecContext(ctx, `DELETE FROM catalog_topics WHERE topic_id='topic'`); err != nil {
42 t.Fatal(err)
43 }
44 catalog = reopenIntegrityTestCatalog(t, ctx, catalog, catalogPath)
45 assertIntegrityRepair(t, ctx, catalog, target)
46 }
47
48 func TestReconcileRepairsReadyDirectoryWithEqualCountWrongPath(t *testing.T) {
49 t.Parallel()
50 ctx := context.Background()
51 dir := t.TempDir()
52 path := filepath.Join(dir, "authoritative.jsonl")
53 if err := os.WriteFile(path, []byte(`{"role":"user","content":"authoritative"}`+"\n"), 0o600); err != nil {
54 t.Fatal(err)
55 }
56 if err := agent.SaveBranchMeta(path, agent.BranchMeta{
57 Scope: "global", TopicID: "topic", TopicTitle: "Authoritative",
58 SchemaVersion: agent.BranchMetaCountsVersion, Turns: 1,
59 }); err != nil {
60 t.Fatal(err)
61 }
62
63 catalogPath := filepath.Join(t.TempDir(), "catalog.sqlite")
64 catalog := openIntegrityTestCatalog(t, ctx, catalogPath)
65 t.Cleanup(func() { _ = catalog.Close(context.Background()) })
66 target := DirectoryTarget{Path: dir, Scope: "global"}
67 if err := catalog.ReconcileDirectory(ctx, target); err != nil {
68 t.Fatal(err)
69 }
70 if _, err := catalog.db.ExecContext(ctx, `DELETE FROM catalog_sessions WHERE directory=?`, dir); err != nil {
71 t.Fatal(err)
72 }
73 if err := catalog.UpsertSession(ctx, SessionRecord{
74 Path: filepath.Join(dir, "wrong.jsonl"), Directory: dir, Scope: "global",
75 TopicID: "wrong", TopicTitle: "Wrong", Turns: 1, TurnsState: TurnsValid,
76 Health: HealthOK,
77 }); err != nil {
78 t.Fatal(err)
79 }
80 catalog = reopenIntegrityTestCatalog(t, ctx, catalog, catalogPath)
81 if err := catalog.ReconcileDirectory(ctx, target); err != nil {
82 t.Fatal(err)
83 }
84 page, err := catalog.ListSessions(ctx, SessionPageRequest{Scope: "global", Directory: dir, Limit: 50})
85 if err != nil {
86 t.Fatal(err)
87 }
88 if len(page.Items) != 1 || page.Items[0].Path != path {
89 t.Fatalf("repaired sessions = %#v, want authoritative path %q", page.Items, path)
90 }
91 }
92
93 func openIntegrityTestCatalog(t *testing.T, ctx context.Context, path string) *Catalog {
94 t.Helper()
95 catalog, err := Open(ctx, Options{Path: path, DisableRepair: true})
96 if err != nil {
97 t.Fatal(err)
98 }
99 return catalog
100 }
101
102 func reopenIntegrityTestCatalog(t *testing.T, ctx context.Context, catalog *Catalog, path string) *Catalog {
103 t.Helper()
104 if err := catalog.Close(ctx); err != nil {
105 t.Fatal(err)
106 }
107 return openIntegrityTestCatalog(t, ctx, path)
108 }
109
110 func assertIntegrityRepair(t *testing.T, ctx context.Context, catalog *Catalog, target DirectoryTarget) {
111 t.Helper()
112 if err := catalog.ReconcileDirectory(ctx, target); err != nil {
113 t.Fatal(err)
114 }
115 page, err := catalog.ListTopics(ctx, TopicPageRequest{Scope: "global", Limit: 50})
116 if err != nil {
117 t.Fatal(err)
118 }
119 if len(page.Items) != 1 || page.Items[0].TopicID != "topic" || len(page.Items[0].Sessions) != 1 {
120 t.Fatalf("repaired page = %#v, want the persisted conversation restored", page)
121 }
122 }
123
123 lines GO