返回 DeepSeek-Reasonix
recovery_endpoints_test.go
根目录 / internal / serve / recovery_endpoints_test.go
1 package serve
2
3 import (
4 "context"
5 "encoding/json"
6 "net/http"
7 "net/http/httptest"
8 "strings"
9 "testing"
10
11 "reasonix/internal/config"
12 "reasonix/internal/control"
13 "reasonix/internal/event"
14 "reasonix/internal/eventwire"
15 )
16
17 type pendingPromptAPI struct {
18 control.SessionAPI
19 compactInstructions string
20 }
21
22 func (p *pendingPromptAPI) ReplayPendingPromptsTo(sink event.Sink) {
23 sink.Emit(event.Event{Kind: event.ApprovalRequest, Approval: event.Approval{ID: "approval-1", Tool: "bash", Subject: "run tests"}})
24 }
25
26 func (p *pendingPromptAPI) Compact(_ context.Context, instructions string) error {
27 p.compactInstructions = instructions
28 return nil
29 }
30
31 func TestServeRecoveryEndpointsFailClosedAndExposeRuntime(t *testing.T) {
32 bc := NewBroadcaster()
33 ctrl := control.New(control.Options{Sink: bc})
34 ctrl.SetGoal("ship remote parity")
35 api := &pendingPromptAPI{SessionAPI: ctrl}
36 srv := httptest.NewServer(New(api, bc, config.ServeConfig{}).Handler())
37 defer srv.Close()
38
39 resp, err := http.Get(srv.URL + "/pending-prompts")
40 if err != nil {
41 t.Fatal(err)
42 }
43 defer resp.Body.Close()
44 var prompts []eventwire.Event
45 if err := json.NewDecoder(resp.Body).Decode(&prompts); err != nil || len(prompts) != 1 || prompts[0].Approval == nil || prompts[0].Approval.ID != "approval-1" {
46 t.Fatalf("pending prompts = %+v, err %v", prompts, err)
47 }
48
49 resp, err = http.Get(srv.URL + "/status")
50 if err != nil {
51 t.Fatal(err)
52 }
53 defer resp.Body.Close()
54 var status struct {
55 GoalRuntime *control.GoalRuntimeView `json:"goalRuntime"`
56 }
57 if err := json.NewDecoder(resp.Body).Decode(&status); err != nil || status.GoalRuntime == nil {
58 t.Fatalf("goal runtime = %+v, err %v", status.GoalRuntime, err)
59 }
60 resp, err = http.Post(srv.URL+"/compact", "application/json", strings.NewReader(`{"instructions":"preserve tests"}`))
61 if err != nil {
62 t.Fatal(err)
63 }
64 if resp.StatusCode != http.StatusNoContent || api.compactInstructions != "preserve tests" {
65 t.Fatalf("compact = status:%v instructions:%q", resp.StatusCode, api.compactInstructions)
66 }
67 resp.Body.Close()
68
69 resp, err = http.Post(srv.URL+"/rewind", "application/json", strings.NewReader(`{"turn":0,"scope":"conversationn"}`))
70 if err != nil {
71 t.Fatal(err)
72 }
73 defer resp.Body.Close()
74 if resp.StatusCode != http.StatusBadRequest {
75 t.Fatalf("invalid rewind scope status = %d, want 400", resp.StatusCode)
76 }
77 }
78
78 lines GO