This repository has no description
1package millproto
2
3import (
4 "bytes"
5 "encoding/binary"
6 "testing"
7
8 millv1 "tangled.org/core/spindle/mill/proto/gen"
9)
10
11func TestEncodeDecodeRoundTrip(t *testing.T) {
12 var buf bytes.Buffer
13 enc := NewEncoder(&buf)
14
15 want := &Message{
16 ReserveSeat: &millv1.ReserveSeat{
17 LeaseId: "lease-1",
18 TargetEngine: "microvm",
19 RawWorkflowJson: `{"name":"build"}`,
20 Knot: "knot.example",
21 Rkey: "abc123",
22 TtlSeconds: 30,
23 },
24 }
25 if err := enc.Encode(want); err != nil {
26 t.Fatalf("Encode() error = %v", err)
27 }
28
29 got, err := NewDecoder(&buf).Decode()
30 if err != nil {
31 t.Fatalf("Decode() error = %v", err)
32 }
33 rs := got.GetReserveSeat()
34 if rs == nil {
35 t.Fatal("decoded message missing reserve_seat")
36 }
37 if rs.LeaseId != "lease-1" || rs.TargetEngine != "microvm" || rs.TtlSeconds != 30 {
38 t.Fatalf("round-trip mismatch: %+v", rs)
39 }
40}
41
42func TestDecoderRejectsOversizedMessage(t *testing.T) {
43 var tooLarge bytes.Buffer
44 var header [4]byte
45 binary.BigEndian.PutUint32(header[:], MaxMessageBytes+1)
46 tooLarge.Write(header[:])
47
48 if _, err := NewDecoder(&tooLarge).Decode(); err == nil {
49 t.Fatal("expected oversized message error")
50 }
51}
52
53func TestValidationRules(t *testing.T) {
54 tests := []struct {
55 name string
56 msg *Message
57 wantErr bool
58 }{
59 {
60 name: "valid ack message",
61 msg: &Message{
62 Ack: &millv1.Ack{
63 Epoch: "inc-1",
64 UpToSeqno: 5,
65 },
66 },
67 wantErr: false,
68 },
69 {
70 name: "valid hello message",
71 msg: &Message{
72 Hello: &millv1.Hello{
73 ProtocolVersion: 1,
74 Arch: "amd64",
75 Labels: []string{"linux"},
76 Epoch: "inc-1",
77 },
78 },
79 wantErr: false,
80 },
81 {
82 name: "invalid message with zero payloads",
83 msg: &Message{},
84 wantErr: true,
85 },
86 {
87 name: "invalid message with multiple payloads",
88 msg: &Message{
89 Ack: &millv1.Ack{Epoch: "inc-1", UpToSeqno: 5},
90 Committed: &millv1.Committed{LeaseId: "x"},
91 },
92 wantErr: true,
93 },
94 {
95 name: "invalid ack message missing epoch",
96 msg: &Message{
97 Ack: &millv1.Ack{
98 UpToSeqno: 5,
99 },
100 },
101 wantErr: true,
102 },
103 {
104 name: "invalid node snapshot with zero seqno",
105 msg: &Message{
106 NodeSnapshot: &millv1.NodeSnapshot{
107 Seqno: 0,
108 },
109 },
110 wantErr: true,
111 },
112 {
113 name: "valid node snapshot with positive seqno",
114 msg: &Message{
115 NodeSnapshot: &millv1.NodeSnapshot{
116 Seqno: 1,
117 },
118 },
119 wantErr: false,
120 },
121 {
122 name: "invalid stream batch with zero seqno entry",
123 msg: &Message{
124 EventBatch: &millv1.EventBatch{
125 Epoch: "inc-1",
126 Events: []*millv1.Event{
127 {
128 Seqno: 0,
129 LeaseId: "lease-1",
130 Payload: &millv1.Event_StatusEvent{
131 StatusEvent: &millv1.StatusEvent{
132 Status: millv1.NonterminalStatus_RUNNING,
133 },
134 },
135 },
136 },
137 },
138 },
139 wantErr: true,
140 },
141 {
142 name: "invalid stream batch with empty entries",
143 msg: &Message{
144 EventBatch: &millv1.EventBatch{
145 Epoch: "inc-1",
146 Events: []*millv1.Event{},
147 },
148 },
149 wantErr: true,
150 },
151 {
152 name: "invalid reserve result with unknown enum",
153 msg: &Message{
154 ReserveResult: &millv1.ReserveResult{
155 LeaseId: "lease-1",
156 RejectClass: millv1.RejectClass(99),
157 },
158 },
159 wantErr: true,
160 },
161 {
162 name: "invalid stream entry with malformed oneof (empty payload)",
163 msg: &Message{
164 EventBatch: &millv1.EventBatch{
165 Epoch: "inc-1",
166 Events: []*millv1.Event{
167 {
168 Seqno: 1,
169 LeaseId: "lease-1",
170 Payload: nil,
171 },
172 },
173 },
174 },
175 wantErr: true,
176 },
177 {
178 name: "valid stream batch status event",
179 msg: &Message{
180 EventBatch: &millv1.EventBatch{
181 Epoch: "inc-1",
182 Events: []*millv1.Event{
183 {
184 Seqno: 1,
185 LeaseId: "lease-1",
186 Payload: &millv1.Event_StatusEvent{
187 StatusEvent: &millv1.StatusEvent{
188 Status: millv1.NonterminalStatus_RUNNING,
189 },
190 },
191 },
192 },
193 },
194 },
195 wantErr: false,
196 },
197 {
198 name: "valid stream batch attempt result",
199 msg: &Message{
200 EventBatch: &millv1.EventBatch{
201 Epoch: "inc-1",
202 Events: []*millv1.Event{
203 {
204 Seqno: 1,
205 LeaseId: "lease-1",
206 Payload: &millv1.Event_AttemptResult{
207 AttemptResult: &millv1.AttemptResult{
208 Status: millv1.TerminalStatus_SUCCESS,
209 },
210 },
211 },
212 },
213 },
214 },
215 wantErr: false,
216 },
217 }
218
219 for _, tc := range tests {
220 t.Run(tc.name, func(t *testing.T) {
221 err := validator.Validate(tc.msg)
222 if (err != nil) != tc.wantErr {
223 t.Fatalf("Validate() error = %v, wantErr = %v", err, tc.wantErr)
224 }
225 })
226 }
227}