This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / spindle / mill / proto / protocol_test.go
4.7 kB 227 lines
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}