返回 DeepSeek-Reasonix
session_switch_freshness_test.go
根目录 / desktop / session_switch_freshness_test.go
1 package main
2
3 import (
4 "path/filepath"
5 "strings"
6 "testing"
7 "time"
8
9 "reasonix/internal/agent"
10 "reasonix/internal/control"
11 "reasonix/internal/event"
12 "reasonix/internal/provider"
13 "reasonix/internal/transcript"
14 )
15
16 func TestPreloadedPageDoesNotEraseNewlyCommittedTurn(t *testing.T) {
17 isolateDesktopUserDirs(t)
18 path := filepath.Join(t.TempDir(), "session.jsonl")
19 session := agent.NewSession("system")
20 session.Add(provider.Message{Role: provider.RoleUser, Content: "first"})
21 if err := session.Save(path); err != nil {
22 t.Fatal(err)
23 }
24 executor := agent.New(nil, nil, session, agent.Options{}, event.Discard)
25 ctrl := control.New(control.Options{Executor: executor, SessionDir: filepath.Dir(path), SessionPath: path, Sink: event.Discard})
26 defer ctrl.Close()
27 // A same-session or detached-runtime switch reads before the owner settles.
28 preloaded, err := agent.LoadSession(path)
29 if err != nil {
30 t.Fatal(err)
31 }
32 session.Add(provider.Message{Role: provider.RoleUser, Content: "second"})
33 session.Add(provider.Message{Role: provider.RoleAssistant, Content: "completed while switching"})
34 if err := ctrl.Snapshot(); err != nil {
35 t.Fatal(err)
36 }
37 if ctrl.RuntimeStatus().Running || ctrl.SessionHasUnsavedChanges() {
38 t.Fatal("fixture must be idle and fully persisted")
39 }
40 tab := &WorkspaceTab{ID: "tab", Ctrl: ctrl, SessionPath: path}
41 page, reread := historyPageForController(tab, ctrl, preloaded, path, 0, defaultHistoryPageTurns)
42 if !reread {
43 t.Fatal("obsolete preload must be refreshed before installation")
44 }
45 current, _ := historyPageForController(tab, ctrl, nil, "", 0, defaultHistoryPageTurns)
46 if current.TotalTurns != 2 {
47 t.Fatalf("invalid current history: %d", current.TotalTurns)
48 }
49 if page.TotalTurns != current.TotalTurns {
50 t.Fatalf("reused an obsolete preload: switch=%d current=%d", page.TotalTurns, current.TotalTurns)
51 }
52 }
53
54 func TestTranscriptSwitchReportsActualLoadWithoutLegacyPage(t *testing.T) {
55 for _, channel := range []bool{false, true} {
56 t.Run(map[bool]string{false: "resume", true: "channel"}[channel], func(t *testing.T) {
57 app, tab, _, _, _, _ := newAtomicRebindTestApp(t)
58 path := resumedCleanTarget(t, app, tab, "snapshot-target.jsonl")
59 var phases HistorySwitchPhases
60 var err error
61 if channel {
62 phases, err = app.OpenChannelTranscriptSessionForTab(tab.ID, path)
63 } else {
64 phases, err = app.ResumeTranscriptSessionForTab(tab.ID, path)
65 }
66 if err != nil {
67 t.Fatal(err)
68 }
69 if phases.Outcome != "ok" || phases.DurableReads != 1 || phases.LoadedCount == 0 || phases.LoadedBytes == 0 {
70 t.Fatalf("missing load evidence: %+v", phases)
71 }
72 if phases.HistoryCount != 0 || phases.HistoryMs != 0 {
73 t.Fatalf("snapshot adoption built a legacy page: %+v", phases)
74 }
75 snapshot, err := app.TranscriptSnapshotForTab(tab.ID, transcript.PageRequest{})
76 if err != nil || tab.SessionID == "" || snapshot.Identity.SessionID != tab.SessionID || len(snapshot.Records) == 0 {
77 t.Fatalf("snapshot did not adopt target: %v", err)
78 }
79 if tab.currentSessionPath() != "" {
80 t.Fatalf("v3 tab retained legacy execution path %q", tab.currentSessionPath())
81 }
82 if tab.ReadOnly != channel {
83 t.Fatal("switch changed channel write policy")
84 }
85 })
86 }
87 }
88
89 func TestLargeTranscriptSwitchPhaseMeasurement(t *testing.T) {
90 app, tab, _, _, _, _ := newAtomicRebindTestApp(t)
91 path := resumedCleanTarget(t, app, tab, "large-snapshot-target.jsonl")
92 loaded, err := agent.LoadSession(path)
93 if err != nil {
94 t.Fatal(err)
95 }
96 for range 500 {
97 loaded.Add(provider.Message{Role: provider.RoleUser, Content: "question"})
98 loaded.Add(provider.Message{Role: provider.RoleAssistant, Content: strings.Repeat("x", 10<<10)})
99 }
100 if err := loaded.Save(path); err != nil {
101 t.Fatal(err)
102 }
103 phases, err := app.ResumeTranscriptSessionForTab(tab.ID, path)
104 if err != nil {
105 t.Fatal(err)
106 }
107 started := time.Now()
108 follow, err := app.TranscriptFollowForTab(tab.ID, transcript.FollowRequest{})
109 if err != nil || follow.Snapshot == nil || follow.History == nil || !follow.History.HasOlder {
110 t.Fatalf("large snapshot: %v", err)
111 }
112 defer app.TranscriptFollowForTab(tab.ID, transcript.FollowRequest{Subscription: follow.Subscription, Close: true})
113 snapshot := follow.Snapshot
114 if phases.DurableReads != 1 || phases.HistoryCount != 0 {
115 t.Fatalf("large switch repeated history work: %+v", phases)
116 }
117 t.Logf("loaded_bytes=%d loaded_messages=%d load_ms=%d rebind_ms=%d snapshot_ms=%d records=%d durable_reads=%d", phases.LoadedBytes, phases.LoadedCount, phases.LoadMs, phases.RebindMs, time.Since(started).Milliseconds(), len(snapshot.Records), phases.DurableReads)
118 }
119
119 lines GO