返回 DeepSeek-Reasonix
provider_diagnostic_scope_test.go
根目录 / internal / control / provider_diagnostic_scope_test.go
1 package control
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "net/http"
8 "net/http/httptest"
9 "testing"
10
11 "reasonix/internal/agent"
12 "reasonix/internal/event"
13 "reasonix/internal/provider"
14 "reasonix/internal/provider/openai"
15 "reasonix/internal/session"
16 "reasonix/internal/tool"
17 )
18
19 func TestProviderDiagnosticsPersistOnlyUnsuccessfulTurns(t *testing.T) {
20 for _, status := range []event.TurnStatus{event.TurnCompleted, event.TurnFailed, event.TurnInterrupted, event.TurnRecoveryRequired} {
21 t.Run(string(status), func(t *testing.T) {
22 c := &Controller{}
23 c.beginProviderDiagnosticTurn("turn")
24 c.recordProviderRequest("turn", provider.RequestObservation{ID: 1, Phase: "request_started", RemoteAddress: "127.0.0.1:443"})
25 events, err := c.terminalSessionEvents(event.Event{TurnID: "turn", Status: status}, session.Projection{})
26 if err != nil {
27 t.Fatal(err)
28 }
29 found := false
30 for _, e := range events {
31 found = found || e.Kind == "diagnostic/provider"
32 }
33 if found != (status != event.TurnCompleted) {
34 t.Fatalf("status=%s events=%+v", status, events)
35 }
36 if len(c.providerDiagnostics.requests) != 1 {
37 t.Fatal("live observation was lost")
38 }
39 })
40 }
41 }
42
43 func TestSuccessfulProviderRequestHasNoDurableTransportRecord(t *testing.T) {
44 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
45 w.Header().Set("Content-Type", "text/event-stream")
46 _, _ = io.WriteString(w, "data: {\"choices\":[{\"delta\":{\"content\":\"done\"},\"finish_reason\":\"stop\"}]}\n\ndata: [DONE]\n\n")
47 }))
48 defer server.Close()
49 service, err := session.NewService("local", session.NewFilesystemPersistence(t.TempDir()))
50 if err != nil {
51 t.Fatal(err)
52 }
53 runtime, err := service.Create(t.Context(), session.CreateOptions{SessionID: "successful-request"})
54 if err != nil {
55 t.Fatal(err)
56 }
57 p, err := openai.New(provider.Config{Name: "test", Protocol: "openai", Model: "test", APIKey: "fixture", BaseURL: server.URL + "/v1", HTTPClient: server.Client()})
58 if err != nil {
59 t.Fatal(err)
60 }
61 exec := agent.New(p, tool.NewRegistry(), agent.NewSession("system"), agent.Options{}, event.Discard)
62 c := newOwnedTestController(t, Options{Runner: exec, Executor: exec, SessionService: service, SessionRuntime: runtime, ExclusiveSession: true})
63 if err := c.RunTurn(t.Context(), "hello"); err != nil {
64 t.Fatal(err)
65 }
66 if len(c.providerDiagnostics.requests) != 1 {
67 t.Fatal("successful request not observed")
68 }
69 for _, commit := range terminationCommitHistory(t, c) {
70 for _, e := range commit.Events {
71 if e.Kind == "diagnostic/provider" {
72 t.Fatal("successful transport evidence was persisted")
73 }
74 }
75 }
76 }
77
78 func TestProviderDiagnosticTurnLossAccounting(t *testing.T) {
79 c := &Controller{}
80 c.beginProviderDiagnosticTurn("long")
81 for id := uint64(1); id <= 130; id++ {
82 c.recordProviderRequest("long", provider.RequestObservation{ID: id, Phase: "request_started"})
83 }
84 c.beginProviderDiagnosticTurn("next")
85 for id := uint64(131); id <= 258; id++ {
86 c.recordProviderRequest("next", provider.RequestObservation{ID: id, Phase: "request_started"})
87 }
88 c.recordProviderRequest("long", provider.RequestObservation{ID: 1, Phase: "body_closed"})
89 for _, tc := range []struct {
90 id string
91 dropped uint64
92 retained int
93 }{{"long", 130, 0}, {"next", 0, 128}} {
94 e, err := c.providerDiagnosticEvent(event.Event{TurnID: tc.id, Status: event.TurnInterrupted})
95 if err != nil || e == nil {
96 t.Fatalf("event=%v err=%v", e, err)
97 }
98 var payload struct {
99 Dropped *uint64
100 Truncated bool
101 Requests []providerDiagnostic
102 }
103 if err := json.Unmarshal(e.Payload, &payload); err != nil {
104 t.Fatal(err)
105 }
106 if payload.Dropped == nil || *payload.Dropped != tc.dropped || payload.Truncated != (tc.dropped > 0) || len(payload.Requests) != tc.retained {
107 t.Fatalf("%s: %s", tc.id, e.Payload)
108 }
109 }
110 for i := range 129 {
111 c.beginProviderDiagnosticTurn(fmt.Sprintf("future-%d", i))
112 }
113 _, dropped, truncated := c.providerDiagnosticTurnSnapshot("long")
114 if len(c.providerDiagnostics.turns) != 128 || dropped != nil || !truncated {
115 t.Fatal("evicted accounting was presented as complete")
116 }
117 }
118
118 lines GO