返回 DeepSeek-Reasonix
session_diagnostics_test.go
根目录 / internal / control / session_diagnostics_test.go
1 package control
2
3 import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "errors"
8 "os"
9 "reasonix/internal/agent"
10 "reasonix/internal/event"
11 "reasonix/internal/session"
12 "reasonix/internal/tool"
13 "reasonix/internal/transcript"
14 "strings"
15 "testing"
16 )
17
18 func TestSessionLifecycleDiagnosticsBoundedAndContentFree(t *testing.T) {
19 controller := &Controller{}
20 for i := range 300 {
21 controller.recordLifecycle("cancel_requested", "unknown", "turn", uint64(i), "")
22 }
23 data, err := json.Marshal(controller.lifecycleDiagnosticSnapshot())
24 if err != nil {
25 t.Fatal(err)
26 }
27 var view struct {
28 Events []lifecycleDiagnostic `json:"events"`
29 Dropped uint64 `json:"dropped"`
30 }
31 if err = json.Unmarshal(data, &view); err != nil {
32 t.Fatal(err)
33 }
34 if len(view.Events) != 256 || view.Dropped != 44 || view.Events[0].Sequence != 44 {
35 t.Fatalf("unbounded/miscounted lifecycle trace: %s", data)
36 }
37 for _, event := range view.Events {
38 if event.Source != "unknown" {
39 t.Fatal("unknown cancellation was attributed to a user")
40 }
41 }
42 }
43
44 func TestMCPAttributionNoticeUsesOptionalDisplayEvidence(t *testing.T) {
45 controller := &Controller{}
46 events, err := controller.sessionEventsFor(event.Event{Kind: event.Notice, Code: event.NoticeCodeMCPToolsList, MessageID: "notice:1", Text: "MCP tools/list", Detail: `{"source":"shared_host","network_call":false}`}, session.Projection{})
47 if err != nil || len(events) != 1 || events[0].Kind != "diagnostic" || !events[0].Optional {
48 t.Fatalf("display evidence=%+v %v", events, err)
49 }
50 var payload struct {
51 Type string `json:"type"`
52 Record transcript.Message `json:"displayRecord"`
53 }
54 if err = json.Unmarshal(events[0].Payload, &payload); err != nil {
55 t.Fatal(err)
56 }
57 if payload.Type != "display-notice-v1" || payload.Record.Code != event.NoticeCodeMCPToolsList || payload.Record.MessageID != "notice:1" {
58 t.Fatalf("lost shared display metadata: %+v", payload)
59 }
60 }
61
62 func TestSessionDiagnosticsRetainAcceptedEventsWhenPersistenceFails(t *testing.T) {
63 store, err := session.CreateWithOptions(t.TempDir()+"/failed-diagnostic", "failed-diagnostic", session.OpenOptions{Sync: func(*os.File) error { return errors.New("injected disk failure") }})
64 if err != nil {
65 t.Fatal(err)
66 }
67 service, err := session.NewService("desktop", failingFlushPersistence{session: store})
68 if err != nil {
69 t.Fatal(err)
70 }
71 defer service.CloseAll(context.Background())
72 runtime, err := service.Create(t.Context(), session.CreateOptions{SessionID: "failed-diagnostic"})
73 if err != nil {
74 t.Fatal(err)
75 }
76 if _, err = runtime.Session().AppendBatch(t.Context(), "accepted", []session.Event{{Kind: "tool/result", Payload: json.RawMessage(`{"id":"tool","name":"bash","output":"ACCEPTED-EVIDENCE"}`)}}); err != nil {
77 t.Fatal(err)
78 }
79 executor := agent.New(nil, tool.NewRegistry(), agent.NewSession("system"), agent.Options{}, event.Discard)
80 controller := newOwnedTestController(t, Options{Executor: executor, Sink: event.Discard, SessionService: service, SessionRuntime: runtime, ExclusiveSession: true})
81 defer controller.ReleaseResources()
82 var data bytes.Buffer
83 sensitive := "api" + "_key=sk-proj-" + "1234567890abcdef"
84 err = controller.WriteSessionDiagnostics(t.Context(), &data, GoalDiagnosticMetadata{}, map[string]any{"frontendObservation": map[string]string{"error": sensitive}})
85 if err != nil {
86 t.Fatal(err)
87 }
88 if !json.Valid(data.Bytes()) || !strings.Contains(data.String(), "ACCEPTED-EVIDENCE") || !strings.Contains(data.String(), "durability checkpoint failed") {
89 t.Fatalf("lost failure evidence: %s", data.String())
90 }
91 if strings.Contains(data.String(), sensitive) {
92 t.Fatal("diagnostic extension leaked a credential")
93 }
94 if err = controller.WriteSessionDiagnostics(t.Context(), diagnosticBrokenWriter{}, GoalDiagnosticMetadata{}, nil); err == nil {
95 t.Fatal("destination failure reported success")
96 }
97 }
98
99 type diagnosticBrokenWriter struct{}
100
101 func (diagnosticBrokenWriter) Write([]byte) (int, error) { return 0, errors.New("destination full") }
102
102 lines GO