返回 DeepSeek-Reasonix
closure_events_test.go
根目录 / internal / session / closure_events_test.go
1 package session
2
3 import (
4 "bytes"
5 "encoding/json"
6 "reasonix/internal/provider"
7 "reflect"
8 "testing"
9 )
10
11 func TestClosureEventsEvidenceOrderingAndIdempotence(t *testing.T) {
12 event := func(kind, payload string) Event { return Event{Kind: kind, Payload: json.RawMessage(payload)} }
13 initial := Commit{Events: []Event{
14 event("tool/call", `{"id":"z-unstarted","name":"lookup"}`),
15 event("tool/call", `{"id":"a-started","name":"write"}`),
16 event("tool/start", `{"id":"a-started","name":"write"}`),
17 event("tool/call", `{"id":"done","name":"read"}`),
18 event("tool/start", `{"id":"done","name":"read"}`),
19 event("tool/result", `{"id":"done","name":"read","runState":"completed"}`),
20 event("interaction/created", `{"id":"z-interaction"}`),
21 event("interaction/created", `{"id":"a-interaction"}`),
22 event("step/start", `{"id":"z-step"}`),
23 event("step/start", `{"id":"a-step"}`),
24 event("step/start", `{"id":"done-step"}`),
25 event("step/end", `{"id":"done-step"}`),
26 }}
27 projection, err := Project([]Commit{initial})
28 if err != nil {
29 t.Fatal(err)
30 }
31 before, _ := json.Marshal(projection)
32 closures := ClosureEvents(projection, "unavailable", "runtime exited")
33 after, _ := json.Marshal(projection)
34 if !bytes.Equal(before, after) {
35 t.Fatal("closure planner mutated input projection")
36 }
37 var got []string
38 for _, e := range closures {
39 var body struct {
40 ID string `json:"id"`
41 RunState provider.ToolRunState `json:"runState"`
42 State string `json:"state"`
43 }
44 if err := json.Unmarshal(e.Payload, &body); err != nil {
45 t.Fatal(err)
46 }
47 got = append(got, e.Kind+":"+body.ID)
48 switch body.ID {
49 case "a-started":
50 if body.RunState != provider.ToolRunUnknown {
51 t.Fatalf("started tool state=%q", body.RunState)
52 }
53 case "z-unstarted":
54 if body.RunState != provider.ToolRunNotStarted {
55 t.Fatalf("unstarted tool state=%q", body.RunState)
56 }
57 }
58 if e.Kind == "interaction/resolved" && body.State != "unavailable" {
59 t.Fatalf("interaction state=%q", body.State)
60 }
61 }
62 want := []string{"tool/result:a-started", "tool/result:z-unstarted", "interaction/resolved:a-interaction", "interaction/resolved:z-interaction", "step/end:a-step", "step/end:z-step"}
63 if !reflect.DeepEqual(got, want) {
64 t.Fatalf("closures=%v, want=%v", got, want)
65 }
66 second := ClosureEvents(projection, "unavailable", "runtime exited")
67 if !reflect.DeepEqual(second, closures) {
68 t.Fatal("repeated plan changed ordering or payload")
69 }
70 closed, err := Project([]Commit{initial, {Events: closures}})
71 if err != nil {
72 t.Fatal(err)
73 }
74 if again := ClosureEvents(closed, "unavailable", "runtime exited"); len(again) != 0 {
75 t.Fatalf("closed authority generated duplicate closures: %+v", again)
76 }
77 if got := ClosureEvents(Projection{}, "unavailable", "runtime exited"); len(got) != 0 {
78 t.Fatalf("empty projection invented authority: %+v", got)
79 }
80 }
81
81 lines GO