返回 DeepSeek-Reasonix
session_concurrency_test.go
根目录 / internal / agent / session_concurrency_test.go
1 package agent
2
3 import (
4 "sync"
5 "testing"
6
7 "reasonix/internal/provider"
8 )
9
10 // TestSessionConcurrentAddAndRead models the real hazard: the run loop appends
11 // messages while a frontend (serve /history, autosave) reads the log from another
12 // goroutine. Snapshot must copy under the lock; before it, an append racing the
13 // copy could tear the slice header and crash.
14 func TestSessionConcurrentAddAndRead(t *testing.T) {
15 // Every Snapshot copies the whole log, so the work is readers*reads*appends.
16 // -race instruments each of those accesses and the package shares one
17 // 10-minute timeout; overlap is what detects the race, volume only buys
18 // wall-clock.
19 const (
20 appends = 1000
21 readers = 8
22 reads = 500
23 )
24
25 s := NewSession("sys")
26
27 var wg sync.WaitGroup
28 // One writer mimicking the turn goroutine.
29 wg.Go(func() {
30 for range appends {
31 s.Add(provider.Message{Role: provider.RoleUser, Content: "msg"})
32 }
33 })
34 // Many readers mimicking frontends polling history.
35 for range readers {
36 wg.Go(func() {
37 for range reads {
38 snap := s.Snapshot()
39 for _, m := range snap { // iterate the copy: must never tear
40 _ = m.Content
41 }
42 _ = s.HasContent()
43 }
44 })
45 }
46 wg.Wait()
47
48 if got := len(s.Snapshot()); got != appends+1 { // appends + the system prompt
49 t.Fatalf("final message count = %d, want %d", got, appends+1)
50 }
51 }
52
52 lines GO