test(brokerwire): pin StreamWindowUpdate bytes with prefix and trailing coverage
- commit
- 16716df7e81a1f72be0f0107a9c782e97b9850b8
- author
- brice · · 2026-10-08 20:07 UTC
- parent
- 5dde9c6
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +38 -0
M internal/adapters/brokerwire/codec_test.go +38 -0
| @@ -1236,6 +1236,44 @@ func TestBrokerTruncatedAndTrailing(t *testing.T) { | |||
| 1236 | 1236 | require.Error(t, err) | |
| 1237 | 1237 | } | |
| 1238 | 1238 | ||
| 1239 | + | // TestBrokerStreamWindowUpdateByteForByte pins the window update layout in | |
| 1240 | + | // both directions, then rejects every truncated prefix and trailing garbage. | |
| 1241 | + | func TestBrokerStreamWindowUpdateByteForByte(t *testing.T) { | |
| 1242 | + | connection := testConnectionID(0x11) | |
| 1243 | + | message := StreamWindowUpdate{Epoch: 7, Connection: connection, Stream: 3, Credit: 4096} | |
| 1244 | + | scope := append([]byte{0x08, 0x07, 0x12, 0x10}, connection[:]...) | |
| 1245 | + | ref := append(append([]byte{0x0a, byte(len(scope))}, scope...), 0x10, 0x03) | |
| 1246 | + | body := append(append([]byte{0x0a, byte(len(ref))}, ref...), 0x10, 0x80, 0x20) | |
| 1247 | + | for _, tc := range []struct { | |
| 1248 | + | name string | |
| 1249 | + | key []byte // field 114 (client) or 211 (server), wire type 2 | |
| 1250 | + | encode func(*testing.T, any) []byte | |
| 1251 | + | decode func([]byte) (any, error) | |
| 1252 | + | }{ | |
| 1253 | + | {"client", []byte{0x92, 0x07}, func(t *testing.T, m any) []byte { return mustEncodeClient(t, m.(ClientMessage)) }, func(raw []byte) (any, error) { | |
| 1254 | + | return DecodeClient(raw, testEnvelopeCeiling, testChunkCeiling) | |
| 1255 | + | }}, | |
| 1256 | + | {"server", []byte{0x9a, 0x0d}, func(t *testing.T, m any) []byte { return mustEncodeServer(t, m.(ServerMessage)) }, func(raw []byte) (any, error) { | |
| 1257 | + | return DecodeServer(raw, testEnvelopeCeiling, testChunkCeiling) | |
| 1258 | + | }}, | |
| 1259 | + | } { | |
| 1260 | + | t.Run(tc.name, func(t *testing.T) { | |
| 1261 | + | want := append(append(append([]byte(nil), tc.key...), byte(len(body))), body...) | |
| 1262 | + | raw := tc.encode(t, message) | |
| 1263 | + | require.Equal(t, want, raw) | |
| 1264 | + | decoded, err := tc.decode(raw) | |
| 1265 | + | require.NoError(t, err) | |
| 1266 | + | require.Equal(t, message, decoded) | |
| 1267 | + | for size := range len(raw) { | |
| 1268 | + | _, err := tc.decode(raw[:size]) | |
| 1269 | + | require.Error(t, err, "prefix[:%d] accepted", size) | |
| 1270 | + | } | |
| 1271 | + | _, err = tc.decode(append(append([]byte(nil), raw...), 0xFF)) | |
| 1272 | + | require.Error(t, err, "trailing garbage accepted") | |
| 1273 | + | }) | |
| 1274 | + | } | |
| 1275 | + | } | |
| 1276 | + | ||
| 1239 | 1277 | // TestBrokerWrongDirection proves wrong-direction decode is rejected: | |
| 1240 | 1278 | // client bytes never decode as server output and vice versa. | |
| 1241 | 1279 | func TestBrokerWrongDirection(t *testing.T) { | |
| @@ -1236,6 +1236,44 @@ func TestBrokerTruncatedAndTrailing(t *testing.T) { | |||||
| 1236 | require.Error(t, err) | 1236 | require.Error(t, err) | ||
| 1237 | } | 1237 | } | ||
| 1238 | 1238 | ||||
| 1239 | + | // TestBrokerStreamWindowUpdateByteForByte pins the window update layout in | |||
| 1240 | + | // both directions, then rejects every truncated prefix and trailing garbage. | |||
| 1241 | + | func TestBrokerStreamWindowUpdateByteForByte(t *testing.T) { | |||
| 1242 | + | connection := testConnectionID(0x11) | |||
| 1243 | + | message := StreamWindowUpdate{Epoch: 7, Connection: connection, Stream: 3, Credit: 4096} | |||
| 1244 | + | scope := append([]byte{0x08, 0x07, 0x12, 0x10}, connection[:]...) | |||
| 1245 | + | ref := append(append([]byte{0x0a, byte(len(scope))}, scope...), 0x10, 0x03) | |||
| 1246 | + | body := append(append([]byte{0x0a, byte(len(ref))}, ref...), 0x10, 0x80, 0x20) | |||
| 1247 | + | for _, tc := range []struct { | |||
| 1248 | + | name string | |||
| 1249 | + | key []byte // field 114 (client) or 211 (server), wire type 2 | |||
| 1250 | + | encode func(*testing.T, any) []byte | |||
| 1251 | + | decode func([]byte) (any, error) | |||
| 1252 | + | }{ | |||
| 1253 | + | {"client", []byte{0x92, 0x07}, func(t *testing.T, m any) []byte { return mustEncodeClient(t, m.(ClientMessage)) }, func(raw []byte) (any, error) { | |||
| 1254 | + | return DecodeClient(raw, testEnvelopeCeiling, testChunkCeiling) | |||
| 1255 | + | }}, | |||
| 1256 | + | {"server", []byte{0x9a, 0x0d}, func(t *testing.T, m any) []byte { return mustEncodeServer(t, m.(ServerMessage)) }, func(raw []byte) (any, error) { | |||
| 1257 | + | return DecodeServer(raw, testEnvelopeCeiling, testChunkCeiling) | |||
| 1258 | + | }}, | |||
| 1259 | + | } { | |||
| 1260 | + | t.Run(tc.name, func(t *testing.T) { | |||
| 1261 | + | want := append(append(append([]byte(nil), tc.key...), byte(len(body))), body...) | |||
| 1262 | + | raw := tc.encode(t, message) | |||
| 1263 | + | require.Equal(t, want, raw) | |||
| 1264 | + | decoded, err := tc.decode(raw) | |||
| 1265 | + | require.NoError(t, err) | |||
| 1266 | + | require.Equal(t, message, decoded) | |||
| 1267 | + | for size := range len(raw) { | |||
| 1268 | + | _, err := tc.decode(raw[:size]) | |||
| 1269 | + | require.Error(t, err, "prefix[:%d] accepted", size) | |||
| 1270 | + | } | |||
| 1271 | + | _, err = tc.decode(append(append([]byte(nil), raw...), 0xFF)) | |||
| 1272 | + | require.Error(t, err, "trailing garbage accepted") | |||
| 1273 | + | }) | |||
| 1274 | + | } | |||
| 1275 | + | } | |||
| 1276 | + | ||||
| 1239 | // TestBrokerWrongDirection proves wrong-direction decode is rejected: | 1277 | // TestBrokerWrongDirection proves wrong-direction decode is rejected: | ||
| 1240 | // client bytes never decode as server output and vice versa. | 1278 | // client bytes never decode as server output and vice versa. | ||
| 1241 | func TestBrokerWrongDirection(t *testing.T) { | 1279 | func TestBrokerWrongDirection(t *testing.T) { | ||