返回 DeepSeek-Reasonix
session_workspace_navigation_test.go
根目录 / desktop / session_workspace_navigation_test.go
1 package main
2
3 import (
4 "errors"
5 "testing"
6
7 "reasonix/internal/boot"
8 "reasonix/internal/control"
9 "reasonix/internal/event"
10 "reasonix/internal/session"
11 )
12
13 func TestCanonicalNavigationLastRequestWins(t *testing.T) {
14 app, tab, target, _, _ := canonicalWorkspaceOpenFixture(t)
15 ctrl := tab.Ctrl
16 tab.Ctrl = &activeNavigationController{SessionAPI: ctrl, IdentityLifecycle: ctrl.(control.IdentityLifecycle), status: control.RuntimeStatus{Running: true}}
17 source := session.SessionRef{HostID: localDesktopHostID, SessionID: tab.SessionID}
18 app.runtimeRebuildMu.Lock()
19 locked := true
20 defer func() {
21 if locked {
22 app.runtimeRebuildMu.Unlock()
23 }
24 }()
25 first, second := make(chan error, 1), make(chan error, 1)
26 go func() { _, err := app.OpenSession(target.Ref()); first <- err }()
27 waitFor(t, "first navigation admission", func() bool { return app.desktopSessions.navigationSeq.Load() == 1 })
28 go func() { _, err := app.OpenSession(source); second <- err }()
29 waitFor(t, "second navigation admission", func() bool { return app.desktopSessions.navigationSeq.Load() == 2 })
30 app.runtimeRebuildMu.Unlock()
31 locked = false
32 if err := <-first; !errors.Is(err, errSessionNavigationSuperseded) {
33 t.Fatalf("first open = %v", err)
34 }
35 if err := <-second; err != nil {
36 t.Fatalf("last open = %v", err)
37 }
38 if tab.SessionID != source.SessionID {
39 t.Fatal("superseded open won")
40 }
41 }
42
43 func TestTicketedCanonicalNavigationKeepsOriginalIntent(t *testing.T) {
44 app, _, target, _, _ := canonicalWorkspaceOpenFixture(t)
45 if _, err := app.StartTopicActivation(TopicActivationRequest{SessionPath: sessionRoute(target.Ref().SessionID)}); err != nil {
46 t.Fatal(err)
47 }
48 if got := app.desktopSessions.navigationSeq.Load(); got != 1 {
49 t.Fatalf("one navigation claimed %d intents; a nested open can overtake a newer queued request", got)
50 }
51 }
52
53 func TestDelayedCanonicalNavigationCannotReclaimSupersededIntent(t *testing.T) {
54 app, tab, target, _, _ := canonicalWorkspaceOpenFixture(t)
55 intent := app.desktopSessions.navigationSeq.Add(1)
56 if err := app.SetActiveTab(tab.ID); err != nil {
57 t.Fatal(err)
58 }
59 before := tab.SessionID
60 if _, err := app.openTopicSessionWithNavigation("project", tab.WorkspaceRoot, "", sessionRoute(target.Ref().SessionID), intent); !errors.Is(err, errSessionNavigationSuperseded) {
61 t.Fatalf("late adopted source open = %v", err)
62 }
63 if tab.SessionID != before {
64 t.Fatal("late source adoption displaced the newer selection")
65 }
66 }
67
68 func TestCanonicalOpenReattachesDetachedWorkspace(t *testing.T) {
69 app, tab, target, root, workspaceID := canonicalWorkspaceOpenFixture(t)
70 ctrl, err := app.buildTabControllerBoot(app.ctx, boot.Options{Model: tab.model, WorkspaceRoot: root, SessionDir: desktopSessionDir(root), Sink: event.Discard})
71 if err != nil {
72 t.Fatal(err)
73 }
74 t.Cleanup(ctrl.Close)
75 if _, err := ctrl.(control.IdentityLifecycle).OpenSession(t.Context(), target.Ref()); err != nil {
76 t.Fatal(err)
77 }
78 detached := &WorkspaceTab{ID: "detached-B", Scope: "project", WorkspaceRoot: root, SessionID: target.Ref().SessionID, Ready: true, Ctrl: ctrl, model: tab.model, sink: &tabEventSink{tabID: "detached-B", app: app}}
79 detached.SessionWorkspace.ID = workspaceID
80 key := sessionRuntimeKey(sessionRoute(target.Ref().SessionID))
81 app.ensureDetachedSessionsLocked()
82 app.detachedSessions[key] = detached
83 app.newSessionRuntimeLocked(detached, key)
84 if _, err := app.OpenSession(target.Ref()); err != nil {
85 t.Fatal(err)
86 }
87 if tab.Ctrl != ctrl || !sameDesktopPath(tab.WorkspaceRoot, root) || app.detachedSessions[key] != nil {
88 t.Fatal("did not transfer the exact detached owner")
89 }
90 if runtime := app.runtimeBySessionKey[key]; runtime == nil || runtime.Owner != tab {
91 t.Fatal("runtime map has a stale owner")
92 }
93 }
94
95 func TestCanonicalLegacyResumeUsesTargetWorkspace(t *testing.T) {
96 for _, page := range []bool{false, true} {
97 t.Run(map[bool]string{false: "messages", true: "page"}[page], func(t *testing.T) {
98 app, tab, target, root, _ := canonicalWorkspaceOpenFixture(t)
99 tab.HistoricalSource = &SessionSourceRef{Path: "/fixture/old.jsonl"}
100 var err error
101 if page {
102 _, err = app.ResumeSessionPageForTab(tab.ID, sessionRoute(target.Ref().SessionID), 32)
103 } else {
104 _, err = app.ResumeSessionForTab(tab.ID, sessionRoute(target.Ref().SessionID))
105 }
106 if err != nil {
107 t.Fatal(err)
108 }
109 if !sameDesktopPath(tab.WorkspaceRoot, root) {
110 t.Fatal("compatibility entry kept source workspace")
111 }
112 if tab.HistoricalSource != nil {
113 t.Fatal("compatibility entry retained the preparation action")
114 }
115 })
116 }
117 }
118
119 func TestCanonicalOpenGlobalWorkspace(t *testing.T) {
120 app, tab, _, _, _ := canonicalWorkspaceOpenFixture(t)
121 workspaceID, err := app.ensureDesktopWorkspace(t.Context(), "global", "")
122 if err != nil {
123 t.Fatal(err)
124 }
125 target, err := app.desktopSessionService("").Create(t.Context(), session.CreateOptions{SessionID: "global-target", CWD: globalWorkspaceRoot(), Origin: session.SessionOriginNew})
126 if err != nil {
127 t.Fatal(err)
128 }
129 if err := app.workspaceRegistry().AttachSession(t.Context(), "", workspaceID, target.Ref().SessionID, ""); err != nil {
130 t.Fatal(err)
131 }
132 if _, err := app.OpenSession(target.Ref()); err != nil {
133 t.Fatal(err)
134 }
135 if tab.Scope != "global" || tab.SessionWorkspace.ID != workspaceID || !sameDesktopPath(tab.WorkspaceRoot, globalWorkspaceRoot()) {
136 t.Fatal("global target inherited project context")
137 }
138 }
139
139 lines GO