返回 DeepSeek-Reasonix
ordinary_visibility_test.go
根目录 / internal / sessioncatalog / ordinary_visibility_test.go
1 package sessioncatalog
2
3 import (
4 "context"
5 "path/filepath"
6 "testing"
7 )
8
9 func TestPreferredOrdinarySessionPathsHidesCoveredAndSiblingForks(t *testing.T) {
10 parent := SessionRecord{Path: "/s/root.jsonl", Recovered: false, RecoveryRole: RecoveryRoleNormal, Turns: 4}
11 covered := SessionRecord{
12 Path: "/s/root-recovery-a.jsonl", Recovered: true, RecoveryCopy: true,
13 RecoveryRole: RecoveryRoleCoveredCopy, ParentID: "root", RecoveryGroupID: "root", Turns: 2,
14 }
15 forkA := SessionRecord{
16 Path: "/s/root-recovery-b.jsonl", Recovered: true, RecoveryRole: RecoveryRoleDiverged,
17 ParentID: "root", RecoveryGroupID: "root", Turns: 5, LastActivityAt: 10,
18 }
19 forkB := SessionRecord{
20 Path: "/s/root-recovery-c.jsonl", Recovered: true, RecoveryRole: RecoveryRoleDiverged,
21 ParentID: "root", RecoveryGroupID: "root", Turns: 3, LastActivityAt: 20,
22 }
23 // Parent present → only the normal session is preferred.
24 got := PreferredOrdinarySessionPaths([]SessionRecord{parent, covered, forkA, forkB})
25 if _, ok := got[parent.Path]; !ok {
26 t.Fatalf("parent missing from preferred: %+v", got)
27 }
28 for _, path := range []string{covered.Path, forkA.Path, forkB.Path} {
29 if _, ok := got[path]; ok {
30 t.Fatalf("recovery fork %s should stay hidden while parent exists", path)
31 }
32 }
33
34 // Parent gone → keep the longest recovered leaf only.
35 got = PreferredOrdinarySessionPaths([]SessionRecord{covered, forkA, forkB})
36 if len(got) != 1 {
37 t.Fatalf("preferred = %+v, want only the longest leaf", got)
38 }
39 if _, ok := got[forkA.Path]; !ok {
40 t.Fatalf("preferred = %+v, want longest fork %s", got, forkA.Path)
41 }
42 }
43
44 func TestPreferredOrdinarySessionPathsPrefersCanonical(t *testing.T) {
45 short := SessionRecord{
46 Path: "/s/a.jsonl", Recovered: true, RecoveryRole: RecoveryRoleDiverged,
47 RecoveryGroupID: "g", Turns: 9, LastActivityAt: 50,
48 }
49 canonical := SessionRecord{
50 Path: "/s/b.jsonl", Recovered: true, RecoveryRole: RecoveryRoleAdopted,
51 RecoveryCanonical: true, RecoveryGroupID: "g", Turns: 2, LastActivityAt: 1,
52 }
53 got := PreferredOrdinarySessionPaths([]SessionRecord{short, canonical})
54 if _, ok := got[canonical.Path]; !ok || len(got) != 1 {
55 t.Fatalf("preferred = %+v, want canonical only", got)
56 }
57 }
58
59 func TestOrdinaryTreeSessionForceShowsOpenFork(t *testing.T) {
60 fork := SessionRecord{Path: "/s/fork.jsonl", Recovered: true, RecoveryRole: RecoveryRoleDiverged}
61 preferred := map[string]struct{}{}
62 if OrdinaryTreeSession(fork, false, false, preferred) {
63 t.Fatal("idle non-preferred fork must stay hidden")
64 }
65 if !OrdinaryTreeSession(fork, true, false, preferred) {
66 t.Fatal("open fork must stay reachable")
67 }
68 }
69
70 func TestCatalogPreferredOrdinarySessionPaths(t *testing.T) {
71 ctx := context.Background()
72 catalog, err := Open(ctx, Options{Path: filepath.Join(t.TempDir(), "c.sqlite"), DisableRepair: true})
73 if err != nil {
74 t.Fatal(err)
75 }
76 t.Cleanup(func() { _ = catalog.Close(context.Background()) })
77 dir := t.TempDir()
78 records := []SessionRecord{
79 {Path: filepath.Join(dir, "root.jsonl"), Directory: dir, Scope: "global", TopicID: "t1",
80 Turns: 2, TurnsState: TurnsValid, Health: HealthOK, LastActivityAt: 30},
81 {Path: filepath.Join(dir, "fork.jsonl"), Directory: dir, Scope: "global", TopicID: "t2",
82 Turns: 4, TurnsState: TurnsValid, Health: HealthOK, Recovered: true,
83 ParentID: "root", RecoveryGroupID: "root", RecoveryRole: RecoveryRoleDiverged, LastActivityAt: 40},
84 }
85 for _, record := range records {
86 if err := catalog.UpsertSession(ctx, record); err != nil {
87 t.Fatal(err)
88 }
89 }
90 got, err := catalog.PreferredOrdinarySessionPaths(ctx, "global", "")
91 if err != nil {
92 t.Fatal(err)
93 }
94 if _, ok := got[records[0].Path]; !ok {
95 t.Fatalf("preferred = %+v, want parent", got)
96 }
97 if _, ok := got[records[1].Path]; ok {
98 t.Fatalf("preferred = %+v, parent present so fork must hide", got)
99 }
100 }
101
101 lines GO