Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions uts/docs/writing-test-specs.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This guide provides comprehensive guidance for writing portable test specificati
- Test client-side validation and error handling
- Token strings are opaque - any arbitrary string works for unit tests
- No network calls - fast and deterministic
- **Protocol (JSON vs msgpack):** `useBinaryProtocol` defaults to `true` (TO3f), so a plain-key client sends msgpack request bodies. A spec that reads the request body — e.g. `body = parse_json(request.body)` — or otherwise makes assertions that depend on the encoding (a stringified `data`, an `encoding` value, base64 for binary payloads) must pin the protocol on the client under test. Set `useBinaryProtocol: false` in `ClientOptions` to derive against JSON; see `rest/unit/encoding/message_encoding.md` for the pattern in both directions. A spec that does not pin `useBinaryProtocol` is to be derived against JSON.

### Integration Tests (Ably Sandbox)
- Run against `https://sandbox.realtime.ably-nonprod.net`
Expand Down
4 changes: 2 additions & 2 deletions uts/rest/unit/batch_publish.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,13 @@ Then the BatchResult contains results for all three channels
```pseudo
channel_name = "test-RSC22c6-${random_id()}"

Given a REST client with mock HTTP
Given a REST client with mock HTTP configured with useBinaryProtocol: false
And the mock is configured to capture requests
When batchPublish is called with messages containing:
- String data
- Binary data (Uint8List/[]byte)
- JSON object data
Then the captured request shows each message is encoded per RSL4:
Then the captured request shows each message is encoded per RSL4 (JSON protocol branch):
- String: data as-is, no encoding
- Binary: base64 encoded, encoding: "base64"
- JSON: JSON stringified, encoding: "json"
Expand Down
17 changes: 14 additions & 3 deletions uts/rest/unit/channel/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -152,7 +155,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -201,6 +207,7 @@ install_mock(mock_http)

client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false, # pins JSON so parse_json(request.body) applies
idempotentRestPublishing: true
))
channel = client.channels.get(channel_name)
Expand Down Expand Up @@ -255,6 +262,7 @@ install_mock(mock_http)

client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false, # pins JSON so parse_json(request.body) applies
idempotentRestPublishing: false
))
channel = client.channels.get(channel_name)
Expand Down Expand Up @@ -297,7 +305,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down
13 changes: 10 additions & 3 deletions uts/rest/unit/channel/idempotency.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ install_mock(mock_http)

client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false, # pins JSON so parse_json(request.body) applies
idempotentRestPublishing: true
))
channel = client.channels.get(channel_name)
Expand Down Expand Up @@ -123,6 +124,7 @@ install_mock(mock_http)

client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false, # pins JSON so parse_json(request.body) applies
idempotentRestPublishing: true
))
channel = client.channels.get(channel_name)
Expand Down Expand Up @@ -185,6 +187,7 @@ install_mock(mock_http)

client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false, # pins JSON so parse_json(request.body) applies
idempotentRestPublishing: true
))
channel = client.channels.get(channel_name)
Expand Down Expand Up @@ -234,6 +237,7 @@ install_mock(mock_http)

client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false, # pins JSON so parse_json(request.body) applies
idempotentRestPublishing: false
))
channel = client.channels.get(channel_name)
Expand Down Expand Up @@ -279,6 +283,7 @@ install_mock(mock_http)

client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false, # pins JSON so parse_json(request.body) applies
idempotentRestPublishing: true # Even with this enabled
))
channel = client.channels.get(channel_name)
Expand Down Expand Up @@ -334,6 +339,7 @@ install_mock(mock_http)

client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false, # pins JSON so parse_json(request.body) applies
idempotentRestPublishing: true
))
channel = client.channels.get(channel_name)
Expand Down Expand Up @@ -361,7 +367,7 @@ ASSERT body1["id"] == body2["id"]

**Test ID**: `rest/unit/RSL1k/mixed-ids-in-batch-1`

**Spec requirement:** In a batch publish, messages with client-supplied IDs must be preserved, while messages without IDs receive library-generated IDs using the standard format.
**Spec requirement:** RSL1k3 - if more than one message is passed to `publish()` and one or more of those messages has a non-empty `id`, then all message ids (present or absent) are preserved on sending the batch. No ids are generated for the id-less messages.

Tests batch publishing with some messages having client IDs and some not.

Expand All @@ -381,6 +387,7 @@ install_mock(mock_http)

client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false, # pins JSON so parse_json(request.body) applies
idempotentRestPublishing: true
))
channel = client.channels.get(channel_name)
Expand All @@ -405,6 +412,6 @@ body = parse_json(request.body)
ASSERT body[0]["id"] == "client-id-1"
ASSERT body[2]["id"] == "client-id-2"

# Library-generated ID for middle message
ASSERT body[1]["id"] matches pattern "[A-Za-z0-9_-]+:[0-9]+"
# RSL1k3: an absent id is preserved as absent
ASSERT "id" NOT IN body[1]
```
49 changes: 36 additions & 13 deletions uts/rest/unit/channel/publish.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -100,7 +103,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand All @@ -126,7 +132,9 @@ ASSERT body.length == 3
ASSERT body[0]["name"] == "event1"
ASSERT body[0]["data"] == "data1"
ASSERT body[1]["name"] == "event2"
ASSERT body[1]["data"] == { "key": "value" }
ASSERT body[1]["data"] IS String
ASSERT parse_json(body[1]["data"]) == { "key": "value" }
ASSERT body[1]["encoding"] == "json"
# Note: binary data encoding tested separately in encoding tests
```

Expand Down Expand Up @@ -154,17 +162,20 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

### Test Cases

| ID | name | data | Expected body |
|----|------|------|---------------|
| 1 | `null` | `"hello"` | `[{"data": "hello"}]` |
| 2 | `"event"` | `null` | `[{"name": "event"}]` |
| 3 | `null` | `null` | `[{}]` |
| ID | name | data |
|----|------|------|
| 1 | `null` | `"hello"` |
| 2 | `"event"` | `null` |
| 3 | `null` | `null` |

### Test Steps
```pseudo
Expand All @@ -174,7 +185,9 @@ FOR EACH test_case IN test_cases:
AWAIT channel.publish(name: test_case.name, data: test_case.data)

body = parse_json(captured_requests[0].body)
ASSERT body == [test_case.expected_body]
ASSERT body.length == 1
ASSERT body[0]["name"] == test_case.name IF test_case.name IS NOT null
ASSERT body[0]["data"] == test_case.data IF test_case.data IS NOT null
ASSERT "name" NOT IN body[0] IF test_case.name IS null
ASSERT "data" NOT IN body[0] IF test_case.data IS null
```
Expand Down Expand Up @@ -205,7 +218,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -308,7 +324,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -439,6 +458,7 @@ captured_requests = []

client_with_id = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false, # pins JSON so parse_json(request.body) applies
clientId: "lib-client"
))
AWAIT client_with_id.channels.get(channel_name_m1).publish(name: "e", data: "d")
Expand All @@ -461,7 +481,10 @@ ASSERT body["clientId"] == "lib-client" # Explicit clientId preserved
# RSL1m3 - Unidentified client with message clientId
captured_requests = []

client_no_id = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client_no_id = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
AWAIT client_no_id.channels.get(channel_name_m3).publish(
message: Message(name: "e", data: "d", clientId: "msg-client")
)
Expand Down
35 changes: 28 additions & 7 deletions uts/rest/unit/channel/update_delete_message.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -88,7 +91,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -136,7 +142,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -182,7 +191,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -231,7 +243,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -272,7 +287,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down Expand Up @@ -487,7 +505,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
channel = client.channels.get(channel_name)
```

Expand Down
15 changes: 12 additions & 3 deletions uts/rest/unit/push/push_admin_publish.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
```

### Test Steps
Expand Down Expand Up @@ -118,7 +121,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
```

### Test Steps
Expand Down Expand Up @@ -167,7 +173,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
```

### Test Steps
Expand Down
5 changes: 4 additions & 1 deletion uts/rest/unit/push/push_channel_subscriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,10 @@ mock_http = MockHttpClient(
)
install_mock(mock_http)

client = Rest(options: ClientOptions(key: "appId.keyId:keySecret"))
client = Rest(options: ClientOptions(
key: "appId.keyId:keySecret",
useBinaryProtocol: false # pins JSON so parse_json(request.body) applies
))
```

### Test Steps
Expand Down
Loading
Loading