返回 DeepSeek-Reasonix
session_history_native_navigation_test.go
根目录 / desktop / session_history_native_navigation_test.go
1 package main
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "os"
8 "strings"
9 "testing"
10
11 "reasonix/internal/provider"
12 "reasonix/internal/session"
13 )
14
15 func TestNativeHistoryPromptBoundsPreview(t *testing.T) {
16 text, err := nativeHistoryPrompt(t.Context(), "\n\t hello world "+strings.Repeat(" x", 100000))
17 if err != nil || !strings.HasPrefix(text, "hello world x") || len(text) > 128 {
18 t.Fatalf("preview: %q %v", text, err)
19 }
20 ctx, cancel := context.WithCancel(t.Context())
21 cancel()
22 if _, err := nativeHistoryPrompt(ctx, strings.Repeat("\u2003", 100000)); !errors.Is(err, context.Canceled) {
23 t.Fatalf("canceled normalization: %v", err)
24 }
25 }
26
27 func TestNativeHistoryColdOutlineAndAnchorsShareCut(t *testing.T) {
28 a := historySliceTestApp(t)
29 t.Cleanup(a.closeHistoryReaders)
30 tab := newColdHistoryTab(t, a)
31 var messages []provider.Message
32 for i := range 140 {
33 messages = append(messages, historySliceUser(i, fmt.Sprintf("question %d", i)), historySliceAssistant(i, fmt.Sprintf("answer %d", i)))
34 }
35 _, tab.SessionPath = saveHistorySliceSession(t, tabSessionDir(tab), "outline.jsonl", messages)
36 before, err := os.ReadFile(tab.SessionPath)
37 if err != nil {
38 t.Fatal(err)
39 }
40 handle, err := a.BeginSessionHistoryReadForTab(tab.ID)
41 if err != nil {
42 t.Fatal(err)
43 }
44 first, err := a.ReadSessionHistoryOutline(handle.ID, session.HistoryOutlineRequest{Limit: 128})
45 if err != nil || first.Status != "ready" || len(first.Entries) != 128 || first.Done || first.NextTurn != 129 || first.TotalTurns != 140 {
46 t.Fatalf("first outline: %+v %v", first, err)
47 }
48 last, err := a.ReadSessionHistoryOutline(handle.ID, session.HistoryOutlineRequest{Generation: first.Generation, SnapshotSequence: &first.SnapshotSequence, StartTurn: first.NextTurn, Limit: 128})
49 if err != nil || last.Status != "ready" || len(last.Entries) != 12 || !last.Done || last.Entries[0].Prompt != "question 128" {
50 t.Fatalf("last outline: %+v %v", last, err)
51 }
52 target := first.Entries[3]
53 location, err := a.LocateSessionHistoryMessage(handle.ID, target.MessageID, first.SnapshotSequence)
54 if err != nil || location.Status != "ready" || location.Position != target.Position || location.VisibleTurn != target.Turn || location.Generation != first.Generation {
55 t.Fatalf("locate: %+v %v", location, err)
56 }
57 for _, request := range []HistorySliceRequest{
58 {Cursor: location.Cursor},
59 {Anchor: "turn", Turn: target.Turn},
60 {Anchor: "message", MessageID: target.MessageID},
61 } {
62 request.Generation, request.SnapshotSequence, request.Entries = first.Generation, &first.SnapshotSequence, 2
63 page, err := a.ReadSessionHistorySlice(handle.ID, request)
64 if err != nil || page.Status != "ready" || len(page.Page.Entries) == 0 || page.Page.Entries[len(page.Page.Entries)-1].EntryID != target.MessageID {
65 t.Fatalf("target page: %+v %v", page, err)
66 }
67 if !page.Page.HasNewer || page.Page.NewerCursor == "" {
68 t.Fatal("anchored window lost access to the newer suffix")
69 }
70 }
71 for _, id := range []string{target.MessageID + "junk", "sother:r0:m6:o0", "soutline:r999:m6:o0", "soutline:r0:m9999:o0"} {
72 location, err := a.LocateSessionHistoryMessage(handle.ID, id, first.SnapshotSequence)
73 if err != nil || location.Status != "not_found" {
74 t.Fatalf("invalid identity %q: %+v %v", id, location, err)
75 }
76 }
77 if tab.Ctrl != nil {
78 t.Fatal("navigation constructed an execution controller")
79 }
80 after, _ := os.ReadFile(tab.SessionPath)
81 if string(before) != string(after) {
82 t.Fatal("navigation changed authoritative history")
83 }
84 wrong := first.SnapshotSequence + 1
85 for _, request := range []session.HistoryOutlineRequest{{Generation: "other"}, {SnapshotSequence: &wrong}} {
86 page, err := a.ReadSessionHistoryOutline(handle.ID, request)
87 if err != nil || page.Status != "stale_cursor" || len(page.Entries) != 0 {
88 t.Fatalf("outline accepted another cut: %+v %v", page, err)
89 }
90 }
91 stale, err := a.ReadSessionHistorySlice(handle.ID, HistorySliceRequest{Anchor: "turn", Turn: 4, Generation: "other"})
92 if err != nil || stale.Status != "stale_cursor" || len(stale.Page.Entries) != 0 {
93 t.Fatalf("jump accepted another cut: %+v %v", stale, err)
94 }
95 missing, err := a.ReadSessionHistorySlice(handle.ID, HistorySliceRequest{Anchor: "turn", Turn: 999})
96 if err != nil || missing.Status != "not_found" {
97 t.Fatalf("missing turn: %+v %v", missing, err)
98 }
99 // A retained binding must detect replacement even before a new Begin call.
100 if err := os.WriteFile(tab.SessionPath, []byte("{\"role\":\"user\",\"content\":\"replacement\"}\n"), 0600); err != nil {
101 t.Fatal(err)
102 }
103 changed, err := a.ReadSessionHistoryOutline(handle.ID, session.HistoryOutlineRequest{})
104 if err != nil || changed.Status != "stale_cursor" || len(changed.Entries) != 0 {
105 t.Fatalf("replaced outline: %+v %v", changed, err)
106 }
107 location, err = a.LocateSessionHistoryMessage(handle.ID, target.MessageID, first.SnapshotSequence)
108 if err != nil || location.Status != "stale_cursor" {
109 t.Fatalf("replaced locate: %+v %v", location, err)
110 }
111 }
112
113 func TestNativeHistoryCanceledOutlineCannotPublish(t *testing.T) {
114 a := historySliceTestApp(t)
115 t.Cleanup(a.closeHistoryReaders)
116 tab := newColdHistoryTab(t, a)
117 _, tab.SessionPath = saveHistorySliceSession(t, tabSessionDir(tab), "cancel-outline.jsonl", []provider.Message{historySliceUser(0, "one")})
118 resume, err := a.historyMaintenance.Foreground(t.Context())
119 if err != nil {
120 t.Fatal(err)
121 }
122 defer resume()
123 handle, err := a.BeginSessionHistoryReadForTab(tab.ID)
124 if err != nil {
125 t.Fatal(err)
126 }
127 reader, err := a.historyReader(handle.ID)
128 if err != nil {
129 t.Fatal(err)
130 }
131 result := make(chan session.HistoryOutlinePage, 1)
132 go func() {
133 page, _ := a.readNativeHistoryOutline(reader, session.HistoryOutlineRequest{})
134 result <- page
135 }()
136 a.ReleaseSessionHistoryRead(handle.ID)
137 select {
138 case page := <-result:
139 if page.Status != "stale_cursor" || len(page.Entries) != 0 {
140 t.Fatalf("canceled outline published: %+v", page)
141 }
142 case <-t.Context().Done():
143 t.Fatal(context.Cause(t.Context()))
144 }
145 }
146
146 lines GO