返回 DeepSeek-Reasonix
session_locator_test.go
根目录 / desktop / session_locator_test.go
1 package main
2
3 import (
4 "context"
5 "errors"
6 "os"
7 "path/filepath"
8 "strings"
9 "testing"
10
11 "reasonix/internal/store"
12 )
13
14 func TestSessionLocatorSeparatesCanonicalRoutesFromLegacyPaths(t *testing.T) {
15 legacy := filepath.Join(t.TempDir(), "session-id:real.jsonl")
16 tests := []struct {
17 name string
18 raw string
19 kind sessionLocatorKind
20 id string
21 }{
22 {name: "empty", raw: " ", kind: sessionLocatorEmpty},
23 {name: "canonical", raw: " session-id:valid-id ", kind: sessionLocatorCanonical, id: "valid-id"},
24 {name: "empty canonical id", raw: "session-id:", kind: sessionLocatorInvalid},
25 {name: "canonical separator", raw: "session-id:bad/id", kind: sessionLocatorInvalid},
26 {name: "canonical reserved name", raw: "session-id:CON", kind: sessionLocatorInvalid},
27 {name: "canonical control", raw: "session-id:bad\x01id", kind: sessionLocatorInvalid},
28 {name: "canonical windows punctuation", raw: `session-id:bad<id>`, kind: sessionLocatorInvalid},
29 {name: "canonical question mark", raw: `session-id:bad?id`, kind: sessionLocatorInvalid},
30 {name: "canonical too long", raw: "session-id:" + strings.Repeat("x", 256), kind: sessionLocatorInvalid},
31 {name: "legacy colon filename", raw: legacy, kind: sessionLocatorLegacy},
32 }
33 for _, test := range tests {
34 t.Run(test.name, func(t *testing.T) {
35 got := classifySessionLocator(test.raw)
36 if got.kind != test.kind || got.ref.SessionID != test.id {
37 t.Fatalf("locator = kind:%v id:%q reason:%q", got.kind, got.ref.SessionID, got.reason)
38 }
39 })
40 }
41 }
42
43 func TestSavedTabRouteCandidateUsesOnlyExactRouteComponents(t *testing.T) {
44 tests := []struct {
45 name, raw, kind, id string
46 }{
47 {name: "exact", raw: "session-id:valid-id", kind: "canonical_route", id: "valid-id"},
48 {name: "windows drive", raw: `C:\old\session-id:valid-id`, kind: "pseudo_route_path", id: "valid-id"},
49 {name: "windows UNC", raw: `\\server\share\session-id:valid-id`, kind: "pseudo_route_path", id: "valid-id"},
50 {name: "posix", raw: "/old/session-id:valid-id", kind: "pseudo_route_path", id: "valid-id"},
51 {name: "relative", raw: "old/session-id:valid-id"},
52 {name: "intermediate component", raw: "/old/session-id:valid-id/history"},
53 {name: "transcript", raw: "/old/session-id:valid-id.jsonl"},
54 {name: "sidecar", raw: "/old/session-id:valid-id.jsonl.meta"},
55 {name: "invalid exact", raw: "session-id:bad/id", kind: "invalid_route"},
56 {name: "invalid pseudo", raw: "/old/session-id:bad?id", kind: "invalid_route"},
57 }
58 for _, test := range tests {
59 t.Run(test.name, func(t *testing.T) {
60 got := savedTabRouteCandidateForPath(test.raw)
61 if got.kind != test.kind || got.sessionID != test.id {
62 t.Fatalf("candidate = kind:%q id:%q", got.kind, got.sessionID)
63 }
64 })
65 }
66 }
67
68 func TestTabSessionMetaRejectsRouteBeforeCreatingSidecars(t *testing.T) {
69 isolateDesktopUserDirs(t)
70 app := NewApp()
71 t.Cleanup(func() { _ = app.draftStore().Close() })
72 tab := &WorkspaceTab{ID: "route", Scope: "global", SessionPath: "session-id:valid-id"}
73 app.tabs[tab.ID] = tab
74
75 if err := app.saveTabSessionMetaForCurrentSession(tab); err != nil {
76 t.Fatalf("canonical compatibility route should skip legacy metadata: %v", err)
77 }
78 if _, err := os.Stat(store.SessionMeta(filepath.Join(desktopSessionDir(""), "session-id:valid-id"))); !errors.Is(err, os.ErrNotExist) {
79 t.Fatalf("canonical route produced a metadata sidecar: %v", err)
80 }
81
82 tab.SessionPath = "session-id:bad/id"
83 if err := app.saveTabSessionMetaForCurrentSession(tab); err == nil {
84 t.Fatal("invalid canonical route was silently accepted")
85 }
86 }
87
88 func TestCanonicalTabSessionMetaNeverWritesLegacySidecar(t *testing.T) {
89 isolateDesktopUserDirs(t)
90 app := NewApp()
91 t.Cleanup(func() { _ = app.draftStore().Close() })
92 tab := &WorkspaceTab{ID: "canonical", Scope: "global", SessionID: "canonical-id", SessionPath: "session-id:canonical-id"}
93 app.tabs[tab.ID] = tab
94
95 if err := app.saveTabSessionMetaForCurrentSession(tab); err != nil {
96 t.Fatal(err)
97 }
98 if err := app.saveTabSessionMeta(tab, "session-id:canonical-id"); err != nil {
99 t.Fatal(err)
100 }
101 if _, err := os.Stat("session-id:canonical-id.meta"); !errors.Is(err, os.ErrNotExist) {
102 t.Fatalf("canonical tab wrote legacy metadata: %v", err)
103 }
104 }
105
106 func TestSessionLocatorNeverCanonicalizesRouteAsPath(t *testing.T) {
107 if got := canonicalTabSessionPath("session-id:valid-id"); got != "" {
108 t.Fatalf("canonical route became path %q", got)
109 }
110 if got := canonicalTabSessionPath("session-id:bad/id"); got != "" {
111 t.Fatalf("invalid canonical route became path %q", got)
112 }
113 if got := sessionRuntimeKey("session-id:valid-id"); got != "session-id:valid-id" {
114 t.Fatalf("canonical runtime key = %q", got)
115 }
116 if got := sessionRuntimeKey("session-id:bad/id"); got != "" {
117 t.Fatalf("invalid route runtime key = %q", got)
118 }
119 if got := sessionRuntimeKey(filepath.Join(t.TempDir(), "not-a-transcript.meta")); got != "" {
120 t.Fatalf("invalid legacy runtime key = %q", got)
121 }
122 }
123
124 func TestResolveLegacySessionPathRejectsRoutesBeforePathResolution(t *testing.T) {
125 dir := t.TempDir()
126 if _, err := resolveLegacySessionPath("session-id:valid-id", dir); err == nil {
127 t.Fatal("canonical route was accepted as a legacy path")
128 }
129 if _, err := resolveLegacySessionPath("session-id:bad/id", dir); err == nil {
130 t.Fatal("invalid route was accepted as a legacy path")
131 }
132 legacy := filepath.Join(dir, "history.jsonl")
133 got, err := resolveLegacySessionPath(legacy, dir)
134 if err != nil || string(got) != legacy {
135 t.Fatalf("legacy path = %q, %v", got, err)
136 }
137 }
138
139 func TestLegacyReadersRejectCanonicalAndInvalidRoutes(t *testing.T) {
140 for _, route := range []string{"session-id:valid-id", "session-id:bad/id"} {
141 if _, ok := validatedLegacySessionPathForRead(route); ok {
142 t.Fatalf("route %q was accepted for legacy reads", route)
143 }
144 if profile := loadTabSessionProfile(route); profile != defaultTabSessionProfile() {
145 t.Fatalf("route %q loaded a legacy profile: %+v", route, profile)
146 }
147 if got := runningTabSessionGoal(route, "persisted goal"); got != "persisted goal" {
148 t.Fatalf("route %q read a legacy goal: %q", route, got)
149 }
150 if _, _, ok := topicTitleFallbackForOpen("", "topic", route); ok {
151 t.Fatalf("route %q loaded a legacy title", route)
152 }
153 }
154 }
155
156 func TestSessionLeaseRejectsRouteBeforeFileAccess(t *testing.T) {
157 tab := &WorkspaceTab{}
158 if err := tab.ensureSessionLease("session-id:valid-id"); err != nil {
159 t.Fatalf("canonical route should use Session Service ownership: %v", err)
160 }
161 if tab.sessionLease != nil {
162 t.Fatal("canonical route acquired a legacy file lease")
163 }
164 if err := tab.ensureSessionLease("session-id:bad/id"); err == nil {
165 t.Fatal("invalid route was silently accepted by the lease boundary")
166 }
167 for _, artifact := range []string{"session-id:valid-id.lease.lock", "session-id:valid-id.lease.json"} {
168 if _, err := os.Lstat(artifact); !errors.Is(err, os.ErrNotExist) {
169 t.Fatalf("canonical route created %q: %v", artifact, err)
170 }
171 }
172 }
173
174 func TestCanonicalHiddenTabPruneSkipsLegacyMetadataWriter(t *testing.T) {
175 app := newSavedTabReconcileTestApp(t)
176 root := t.TempDir()
177 ref, workspaceID := createLegacyCleanupSession(t, app, root, "hidden-canonical", true)
178 tab := &WorkspaceTab{
179 ID: "hidden", Scope: "project", WorkspaceRoot: root, SessionWorkspace: desktopTabWorkspace{ID: workspaceID},
180 SessionID: ref.SessionID, SessionPath: sessionRoute(ref.SessionID),
181 }
182 app.tabs[tab.ID] = tab
183 if err := app.persistHiddenTabBeforePrune(tab.ID, tab); err != nil {
184 t.Fatal(err)
185 }
186 for _, artifact := range []string{"session-id:hidden-canonical.meta", "session-id:hidden-canonical.lock"} {
187 if _, err := os.Lstat(artifact); !errors.Is(err, os.ErrNotExist) {
188 t.Fatalf("canonical hidden-tab prune created %q: %v", artifact, err)
189 }
190 }
191 }
192
193 func TestCanonicalDetachCloneAndReattachKeepExclusiveIdentity(t *testing.T) {
194 source := &WorkspaceTab{ID: "source", Scope: "global", SessionID: "canonical-transfer", SessionPath: sessionRoute("canonical-transfer")}
195 detached := cloneDetachedRuntimeTab(source, sessionRoute("canonical-transfer"), source.currentSessionIdentity())
196 if detached == nil || detached.SessionID != "canonical-transfer" || detached.SessionPath != "" {
197 t.Fatalf("detached identity = id:%q path:%q", detached.SessionID, detached.SessionPath)
198 }
199 target := &WorkspaceTab{ID: "target", Scope: "global"}
200 applyRuntimeTab(target, detached, sessionRoute("canonical-transfer"), context.Background(), nil)
201 if target.SessionID != "canonical-transfer" || target.SessionPath != "" {
202 t.Fatalf("reattached identity = id:%q path:%q", target.SessionID, target.SessionPath)
203 }
204 }
205
205 lines GO