Skip to content

Commit f355624

Browse files
paddybyersclaude
andcommitted
Add RSL6a3 UTS spec for msgpack interoperability fixtures
Portable test spec for verifying decode and round-trip of ably-common msgpack_test_fixtures.json across SDK implementations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5ac5cb4 commit f355624

1 file changed

Lines changed: 111 additions & 0 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# MessagePack Interoperability Tests
2+
3+
Spec points: `RSL6a3`
4+
5+
## Test Type
6+
Unit test — no server or mock needed. Operates on static fixture data.
7+
8+
## Fixtures
9+
Tests use `ably-common/test-resources/msgpack_test_fixtures.json`.
10+
11+
Each fixture has:
12+
- `name`: human-readable description
13+
- `data`: the expected decoded data value
14+
- `numRepeat`: if > 0, the expected data is `data` repeated `numRepeat` times
15+
- `type`: one of `"string"`, `"binary"`, `"jsonArray"`, `"jsonObject"`
16+
- `encoding`: the encoding field on the wire message (empty string means none)
17+
- `msgpack`: base64-encoded msgpack bytes of an entire ProtocolMessage
18+
19+
The ProtocolMessage contains a single Message in its `messages` array. The `data`
20+
field in the fixture describes the expected decoded content of that message.
21+
22+
---
23+
24+
## RSL6a3 - Decode binary-encoded protocol messages using interop fixtures
25+
26+
**Spec requirement:** A set of tests should exist to ensure that the client library
27+
can successfully encode and decode binary encoded protocol messages.
28+
29+
### Setup
30+
```pseudo
31+
fixtures = load_json("ably-common/test-resources/msgpack_test_fixtures.json")
32+
```
33+
34+
### Test: each fixture decodes correctly
35+
```pseudo
36+
FOR EACH fixture IN fixtures:
37+
# 1. Decode the msgpack ProtocolMessage
38+
msgpack_bytes = base64_decode(fixture["msgpack"])
39+
protocol_message = msgpack_deserialize(msgpack_bytes)
40+
41+
# 2. Extract the first (only) message
42+
wire_message = protocol_message["messages"][0]
43+
44+
# 3. Build the expected data
45+
IF fixture["type"] == "string":
46+
IF fixture["numRepeat"] > 0:
47+
expected = fixture["data"] * fixture["numRepeat"] # repeat string
48+
ELSE:
49+
expected = fixture["data"]
50+
END
51+
ELSE IF fixture["type"] == "binary":
52+
raw_string = fixture["data"] * fixture["numRepeat"]
53+
expected = encode_utf8(raw_string) # Uint8List / byte array
54+
ELSE IF fixture["type"] == "jsonArray" OR fixture["type"] == "jsonObject":
55+
expected = fixture["data"] # native array or map
56+
END
57+
58+
# 4. Decode the wire message using the standard decoding pipeline
59+
message = Message.fromMap(wire_message)
60+
61+
# 5. Verify
62+
ASSERT message.data == expected
63+
ASSERT message.encoding IS null # all encoding consumed
64+
END
65+
```
66+
67+
### Assertions per fixture type
68+
69+
**String fixtures** (`type == "string"`):
70+
- `message.data` is a String equal to `fixture["data"]` repeated `fixture["numRepeat"]` times
71+
72+
**Binary fixtures** (`type == "binary"`):
73+
- The wire message has `encoding: "base64"` and base64-encoded `data`
74+
- After decoding, `message.data` is a byte array (Uint8List)
75+
- The byte content equals the UTF-8 encoding of `fixture["data"]` repeated `fixture["numRepeat"]` times
76+
77+
**JSON fixtures** (`type == "jsonArray"` or `type == "jsonObject"`):
78+
- The wire message has `encoding: "json"` and JSON-encoded `data`
79+
- After decoding, `message.data` is a native List or Map matching `fixture["data"]`
80+
81+
---
82+
83+
## RSL6a3 - Re-encode decoded messages back to msgpack (round-trip)
84+
85+
### Test: each fixture round-trips through encode/decode
86+
```pseudo
87+
FOR EACH fixture IN fixtures:
88+
# 1. Decode the original
89+
msgpack_bytes = base64_decode(fixture["msgpack"])
90+
protocol_message = msgpack_deserialize(msgpack_bytes)
91+
wire_message = protocol_message["messages"][0]
92+
93+
# 2. Decode to a Message
94+
message = Message.fromMap(wire_message)
95+
96+
# 3. Re-encode the message for msgpack wire format
97+
re_encoded = message.toMap(useBinaryProtocol: true)
98+
99+
# 4. Wrap in a ProtocolMessage and serialize
100+
re_pm = { "messages": [re_encoded], "msgSerial": 0 }
101+
re_bytes = msgpack_serialize(re_pm)
102+
103+
# 5. Deserialize and decode again
104+
re_pm2 = msgpack_deserialize(re_bytes)
105+
re_message = Message.fromMap(re_pm2["messages"][0])
106+
107+
# 6. Verify round-trip
108+
ASSERT re_message.data == message.data
109+
ASSERT re_message.encoding IS null
110+
END
111+
```

0 commit comments

Comments
 (0)