返回 DeepSeek-Reasonix
history_slice_concurrent_save_test.go
根目录 / desktop / history_slice_concurrent_save_test.go
1 package main
2
3 import (
4 "fmt"
5 "reasonix/internal/provider"
6 "sync"
7 "testing"
8 )
9
10 func TestHistorySliceConcurrentReadsDuringSave(t *testing.T) {
11 app := historySliceTestApp(t)
12 dir := t.TempDir()
13 var msgs []provider.Message
14 for i := range 30 {
15 msgs = append(msgs, historySliceToolTurn(i)...)
16 }
17 sess, path := saveHistorySliceSession(t, dir, "race.jsonl", msgs)
18 newLiveHistoryTab(t, app, dir, path, sess)
19
20 const readers = 4
21 start := make(chan struct{})
22 stop := make(chan struct{})
23 var wg sync.WaitGroup
24 errs := make(chan error, readers)
25 for r := range readers {
26 wg.Add(1)
27 go func(r int) {
28 defer wg.Done()
29 <-start
30 cursor := ""
31 for {
32 select {
33 case <-stop:
34 return
35 default:
36 }
37 page := app.HistorySliceForTab("test", HistorySliceRequest{Turns: 3, Entries: 25, Cursor: cursor})
38 if page.Entries == nil {
39 errs <- fmt.Errorf("reader %d: nil entries", r)
40 return
41 }
42 if page.Stale {
43 // A save landed between pages: restart from latest, as the
44 // frontend would.
45 cursor = ""
46 continue
47 }
48 if !page.HasOlder {
49 cursor = ""
50 continue
51 }
52 cursor = page.NextCursor
53 }
54 }(r)
55 }
56
57 // Writer: append + save in a loop while readers page.
58 close(start)
59 for i := 30; i < 38; i++ {
60 sess.Add(historySliceUser(i, fmt.Sprintf("q%d", i)))
61 sess.Add(historySliceAssistant(i, fmt.Sprintf("a%d", i)))
62 if err := sess.Save(path); err != nil {
63 close(stop)
64 wg.Wait()
65 t.Fatalf("save: %v", err)
66 }
67 }
68 close(stop)
69 wg.Wait()
70 close(errs)
71 for err := range errs {
72 t.Fatal(err)
73 }
74 // The final state must page cleanly end to end.
75 pages := collectHistorySlicePages(t, app, "test", HistorySliceRequest{Turns: 5, Entries: 40})
76 assertPagesMatchReference(t, pages, referenceHistoryRows(t, dir, path))
77 }
78
78 lines GO