返回 DeepSeek-Reasonix
recovery_close_test.go
根目录 / internal / control / recovery_close_test.go
1 package control
2
3 import (
4 "context"
5 "testing"
6 "time"
7
8 "reasonix/internal/session"
9 )
10
11 func TestRecoveryCloseWaitsForTerminalFanout(t *testing.T) {
12 entered := make(chan struct{}, 1)
13 release := make(chan struct{})
14 c := newOwnedTestController(t, Options{Sink: holdFinishingWindow(release, entered, nil)})
15 // Always release the sink before the controller cleanup joins it.
16 t.Cleanup(func() { close(release) })
17 started := make(chan struct{})
18 body := make(chan struct{})
19 c.runGuarded(func(context.Context) error {
20 close(started)
21 <-body
22 return nil
23 })
24 <-started
25 // Force the state published by the cancellation watchdog, then hold the
26 // recovered body's terminal fanout while Close races its completion.
27 c.mu.Lock()
28 c.turns.phase = session.RuntimeRecoveryRequired
29 c.mu.Unlock()
30 close(body)
31 select {
32 case <-entered:
33 case <-time.After(5 * time.Second):
34 t.Fatal("recovery terminal fanout did not start")
35 }
36 c.Close()
37 select {
38 case <-c.closeFinalized:
39 t.Fatal("controller resources closed while recovery terminal fanout was active")
40 default:
41 }
42 }
43
44 func TestRecoveryCloseWaitsForWatchdogFanout(t *testing.T) {
45 entered := make(chan struct{}, 1)
46 release := make(chan struct{})
47 c := newOwnedTestController(t, Options{Sink: holdFinishingWindow(release, entered, nil)})
48 t.Cleanup(func() { close(release) })
49 c.testCancelGrace = time.Millisecond
50 started := make(chan struct{})
51 body := make(chan struct{})
52 c.runGuarded(func(ctx context.Context) error {
53 close(started)
54 <-body
55 return ctx.Err()
56 })
57 <-started
58 idle, _ := c.TurnIdleDone()
59 c.CancelSession()
60 select {
61 case <-entered:
62 case <-time.After(5 * time.Second):
63 close(body)
64 t.Fatal("watchdog terminal fanout did not start")
65 }
66 c.Close()
67 close(body)
68 select {
69 case <-idle:
70 case <-time.After(5 * time.Second):
71 t.Fatal("recovery body did not settle")
72 }
73 select {
74 case <-c.closeFinalized:
75 t.Fatal("controller resources closed while watchdog terminal fanout was active")
76 default:
77 }
78 }
79
79 lines GO