1package ports
2
3import (
4 "reflect"
5 "testing"
6)
7
8func TestRuntimeObserverContract(t *testing.T) {
9 wantFields := []struct {
10 name string
11 typ reflect.Type
12 }{
13 {"Schema", reflect.TypeFor[uint16]()},
14 {"ProcessID", reflect.TypeFor[string]()},
15 {"Component", reflect.TypeFor[string]()},
16 {"Scenario", reflect.TypeFor[string]()},
17 {"Run", reflect.TypeFor[uint64]()},
18 {"Sequence", reflect.TypeFor[uint64]()},
19 {"RequestID", reflect.TypeFor[uint64]()},
20 {"Epoch", reflect.TypeFor[uint64]()},
21 {"Kind", reflect.TypeFor[RuntimeMarkKind]()},
22 {"Tick", reflect.TypeFor[int64]()},
23 {"Bytes", reflect.TypeFor[uint64]()},
24 {"Fragments", reflect.TypeFor[uint64]()},
25 {"Retransmits", reflect.TypeFor[uint64]()},
26 {"Pending", reflect.TypeFor[uint64]()},
27 {"AckRTTNanos", reflect.TypeFor[int64]()},
28 {"Valid", reflect.TypeFor[bool]()},
29 }
30
31 typ := reflect.TypeFor[RuntimeMark]()
32 if typ.NumField() != len(wantFields) {
33 t.Fatalf("RuntimeMark has %d fields, want exactly %d", typ.NumField(), len(wantFields))
34 }
35 for i, want := range wantFields {
36 field := typ.Field(i)
37 if field.Name != want.name || field.Type != want.typ {
38 t.Fatalf("RuntimeMark field %d = %s %v, want %s %v", i, field.Name, field.Type, want.name, want.typ)
39 }
40 }
41
42 var _ RuntimeObserver = runtimeObserverFunc(func(RuntimeMark) {})
43}
44
45func TestP4RuntimeScreenMarkKindsValidateSchema1(t *testing.T) {
46 if RuntimeMarkSchema != 1 {
47 t.Fatalf("RuntimeMarkSchema = %d, want 1", RuntimeMarkSchema)
48 }
49 for _, tc := range []struct {
50 kind RuntimeMarkKind
51 want string
52 }{
53 {RuntimeScreenSnapshot, "screen_snapshot"},
54 {RuntimeScreenDelta, "screen_delta"},
55 {RuntimeScreenResetRequested, "screen_reset_requested"},
56 } {
57 if string(tc.kind) != tc.want {
58 t.Fatalf("screen mark kind = %q, want %q", tc.kind, tc.want)
59 }
60 mark := NewRuntimeMark("daemon", tc.kind, 17, true)
61 if !RuntimeMarkValid(mark) {
62 t.Fatalf("screen mark kind %q did not validate: %+v", tc.kind, mark)
63 }
64 }
65}
66
67func TestRuntimeObserverRequiredSpanKinds(t *testing.T) {
68 pairs := []struct {
69 start RuntimeMarkKind
70 end RuntimeMarkKind
71 }{
72 {RuntimeDiffStart, RuntimeDiffEnd},
73 {RuntimeQueueEnqueued, RuntimeQueueDequeued},
74 {RuntimeACKBlockedStart, RuntimeACKBlockedEnd},
75 {RuntimeAdapterSendStart, RuntimeAdapterSendEnd},
76 {RuntimeAdapterReceiveStart, RuntimeAdapterReceiveEnd},
77 }
78 for _, pair := range pairs {
79 if pair.start == "" || pair.end == "" || pair.start == pair.end {
80 t.Fatalf("invalid required span mapping %#v", pair)
81 }
82 }
83}
84
85func TestRuntimeCorrelationObserverUsesHarnessProcessInputs(t *testing.T) {
86 var got []RuntimeMark
87 observer, err := NewRuntimeCorrelationObserver(runtimeObserverFunc(func(mark RuntimeMark) {
88 got = append(got, mark)
89 }), RuntimeCorrelationInputs{Scenario: "1x4-idle-local", Run: 7})
90 if err != nil {
91 t.Fatal(err)
92 }
93
94 observer.ObserveRuntime(RuntimeMark{Schema: RuntimeMarkSchema, Component: "daemon", Scenario: "runtime", Run: 1, Kind: RuntimeEmitEnd, Valid: true})
95 observer.ObserveRuntime(RuntimeMark{Schema: RuntimeMarkSchema, Component: "daemon", Scenario: "runtime", Run: 1, Sequence: 9, RequestID: 10, Epoch: 11, Kind: RuntimeEmitStart, Valid: true})
96
97 if len(got) != 2 {
98 t.Fatalf("marks=%+v", got)
99 }
100 for _, mark := range got {
101 if mark.Scenario != "1x4-idle-local" || mark.Run != 7 {
102 t.Fatalf("harness correlation was not applied: %+v", mark)
103 }
104 if mark.Sequence == 0 || mark.RequestID == 0 || mark.Epoch == 0 {
105 t.Fatalf("missing deterministic operation identity: %+v", mark)
106 }
107 }
108 if got[1].Sequence != 9 || got[1].RequestID != 10 || got[1].Epoch != 11 {
109 t.Fatalf("explicit operation identity changed: %+v", got[1])
110 }
111}
112
113func TestRuntimeCorrelationObserverAllocatesMissingIDsProcessWide(t *testing.T) {
114 var got []RuntimeMark
115 collect := runtimeObserverFunc(func(mark RuntimeMark) { got = append(got, mark) })
116 first, err := NewRuntimeCorrelationObserver(collect, RuntimeCorrelationInputs{Scenario: "scenario", Run: 1})
117 if err != nil {
118 t.Fatal(err)
119 }
120 second, err := NewRuntimeCorrelationObserver(collect, RuntimeCorrelationInputs{Scenario: "scenario", Run: 1})
121 if err != nil {
122 t.Fatal(err)
123 }
124
125 first.ObserveRuntime(RuntimeMark{Schema: RuntimeMarkSchema, Component: "first", Kind: RuntimeEmitStart, Valid: true})
126 second.ObserveRuntime(RuntimeMark{Schema: RuntimeMarkSchema, Component: "second", Kind: RuntimeEmitEnd, Valid: true})
127
128 if len(got) != 2 {
129 t.Fatalf("marks=%+v", got)
130 }
131 if got[0].Sequence == got[1].Sequence {
132 t.Fatalf("wrapper-local sequence collision: %+v", got)
133 }
134 for _, mark := range got {
135 if mark.RequestID != mark.Sequence || mark.Epoch != mark.RequestID {
136 t.Fatalf("missing-ID fallback changed: %+v", mark)
137 }
138 }
139}
140
141func TestRuntimeCorrelationObserverRejectsInvalidHarnessInputs(t *testing.T) {
142 for _, in := range []RuntimeCorrelationInputs{{}, {Scenario: "scenario"}} {
143 if _, err := NewRuntimeCorrelationObserver(runtimeObserverFunc(func(RuntimeMark) {}), in); err == nil {
144 t.Fatalf("invalid inputs accepted: %+v", in)
145 }
146 }
147}
148
149func TestRuntimeMarkHasNoRenderingPayloadOrPolicyFields(t *testing.T) {
150 typ := reflect.TypeFor[RuntimeMark]()
151 for _, forbidden := range []string{"Cell", "Cells", "Payload", "Frame", "Renderer", "Policy", "Transport"} {
152 if _, ok := typ.FieldByName(forbidden); ok {
153 t.Fatalf("RuntimeMark must not carry %s", forbidden)
154 }
155 }
156}
157
158type runtimeObserverFunc func(RuntimeMark)
159
160func (f runtimeObserverFunc) ObserveRuntime(mark RuntimeMark) { f(mark) }