返回 DeepSeek-Reasonix
manual_creation_scan_test.go
根目录 / desktop / manual_creation_scan_test.go
1 package main
2
3 import (
4 "context"
5 "sync/atomic"
6 "testing"
7 "time"
8
9 "reasonix/desktop/internal/sessionui"
10 )
11
12 type manualCreationScanStore struct {
13 manualCreationStore
14 reads chan struct{}
15 failed atomic.Bool
16 }
17
18 func (s *manualCreationScanStore) List(ctx context.Context, kind string) ([]sessionui.Record, error) {
19 if !s.failed.Swap(true) {
20 s.reads <- struct{}{}
21 return nil, creationBusyError{}
22 }
23 return s.manualCreationStore.List(ctx, kind)
24 }
25
26 func TestManualCreationPeriodicScanRecoversAfterReadFailure(t *testing.T) {
27 a := newManualSessionTestApp(t)
28 v, _ := seedManualCreation(t, a, "periodic-recovery-intent", "starting")
29 m := a.creationManager()
30 store := &manualCreationScanStore{manualCreationStore: m.store, reads: make(chan struct{}, 1)}
31 m.store = store
32 m.execute = func(context.Context, ManualSessionCreationView, func(string)) error { return nil }
33 var offset atomic.Int64
34 m.mu.Lock()
35 m.now = func() time.Time { return time.Now().Add(time.Duration(offset.Load())) }
36 m.mu.Unlock()
37 m.armRecovery()
38 <-store.reads
39 // Advance the injected scheduler clock and wake it; no wall-clock sleep is
40 // needed to exercise the thirty-second rescan contract.
41 offset.Store(int64(31 * time.Second))
42 m.notify()
43 waitFor(t, "periodic recovery", func() bool { got, _ := a.GetManualSessionCreation(v.OperationID); return got.Phase == "ready" })
44 }
45
46 func TestManualCreationDuplicateBeginRegistersOrphanedIntent(t *testing.T) {
47 a := newManualSessionTestApp(t)
48 v, _ := seedManualCreation(t, a, "duplicate-begin-recovery", "starting")
49 got, err := a.BeginManualSessionCreation(ManualSessionCreationRequest{OperationID: v.OperationID, Scope: "global"})
50 if err != nil || got.Ref != v.Ref {
51 t.Fatalf("begin=%+v %v", got, err)
52 }
53 a.manualCreationTasks.Wait()
54 got, err = a.GetManualSessionCreation(v.OperationID)
55 if err != nil || got.Phase != "ready" {
56 t.Fatalf("orphan not recovered: %+v %v", got, err)
57 }
58 }
59
59 lines GO