Skip to content
Merged
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
2 changes: 1 addition & 1 deletion build/data/versions.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
specification: "6.1.0"
specification: "6.1.1"
protocol: 6
2 changes: 1 addition & 1 deletion specifications/api-docstrings.md
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ Describes the properties of the channel state.

| Method / Property | Parameter | Returns | Spec | Description |
|---|---|---|---|---|
| attachSerial: String? ||| CP2a | Starts unset when a channel is instantiated, then updated with the `channelSerial` from each [`ATTACHED`]{@link ChannelState#ATTACHED} event that matches the channel. Used as the value for [`untilAttach`]{@link RealtimeChannel#history}. |
| attachSerial: String? ||| CP2a | Starts unset when a channel is instantiated, then set to the `channelSerial` marking the point at which the channel's current period of message continuity began. Used as the value for [`untilAttach`]{@link RealtimeChannel#history}. |

## class PushChannel

Expand Down
7 changes: 4 additions & 3 deletions specifications/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -780,12 +780,13 @@ The threading and/or asynchronous model for each realtime library will vary by l
- `(RTL27b)` It is a programmer error to access this property without first providing the `LiveObjects` plugin ([PC5](#PC5)) in the client options. This programmer error should be handled in an idiomatic fashion; if this means accessing the property should throw an error, then the error should be an `ErrorInfo` with `statusCode` 400 and `code` 40019.
- `(RTL10)` `RealtimeChannel#history` function:
- `(RTL10a)` Supports all the same params as `RestChannel#history`
- `(RTL10b)` Additionally supports the param `untilAttach`, which if true, will only retrieve messages prior to the moment that the channel was attached or emitted an `UPDATE` indicating loss of continuity. This bound is specified by passing the querystring param `fromSerial` with the `RealtimeChannel#properties.attachSerial` assigned to the channel in the `ATTACHED` `ProtocolMessage` (see [RTL15a](#RTL15a)). If the `untilAttach` param is specified when the channel is not attached, it results in an error
- `(RTL10b)` Additionally supports the param `untilAttach`, which if true, will only retrieve messages prior to the moment that the channel was attached or emitted an `UPDATE` indicating loss of continuity. This bound is specified by passing the querystring param `fromSerial` with the `RealtimeChannel#properties.attachSerial` (see [RTL15c](#RTL15c)). If the `untilAttach` param is specified when the channel is not attached, it results in an error
- `(RTL10c)` Returns a `PaginatedResult` page containing the first page of messages in the `PaginatedResult#items` attribute returned from the history request
- `(RTL10d)` A test should exist that publishes messages from one client, and upon confirmation of message delivery, a history request should be made on another client to ensure all messages are available
- `(RTL12)` An attached channel may receive an additional `ATTACHED` `ProtocolMessage` from Ably at any point. (This is typically triggered following a transport being resumed to indicate a partial loss of message continuity on that channel, in which case the `ProtocolMessage` will have a `resumed` flag set to false). If and only if the `resumed` flag is false, this should result in the channel emitting an `UPDATE` event with a `ChannelStateChange` object. The `ChannelStateChange` object should have both `previous` and `current` attributes set to `attached`, the `reason` attribute set to to the `error` member of the `ATTACHED` `ProtocolMessage` (if any), and the `resumed` attribute set per the `RESUMED` bitflag of the `ATTACHED` `ProtocolMessage`. (Note that `UPDATE` should be the only event emitted: in particular, the library must not emit an `ATTACHED` event if the channel was already attached, see `RTL2g`).
- `(RTL15)` `RealtimeChannel#properties` attribute is a `ChannelProperties` object representing properties of the channel state. `properties` is a publicly accessible member of the channel, but it is an experimental and unstable API. It has the following attributes:
- `(RTL15a)` `attachSerial` is unset when the channel is instantiated, and is updated with the `channelSerial` from each `ATTACHED` `ProtocolMessage` received from Ably with a matching `channel` attribute. The `attachSerial` value is used for `untilAttach` queries, see [RTL10b](#RTL10b)
- `(RTL15a)` This clause has been replaced by [`RTL15c`](#RTL15c) as of specification version 6.1.1.
- `(RTL15c)` `attachSerial` is unset when the channel is instantiated, and is updated with the `channelSerial` from each `ATTACHED` `ProtocolMessage` received from Ably with a matching `channel` attribute whose [RTL2f](#RTL2f) `resumed` attribute is `false`. The `attachSerial` value is used for `untilAttach` queries, see [RTL10b](#RTL10b)
- `(RTL15b)` `channelSerial` is updated whenever a `ProtocolMessage` with either `MESSAGE`, `PRESENCE`, `ANNOTATION`, `OBJECT`, or `ATTACHED` actions is received on a channel, and is set to the `TR4c` `channelSerial` of that `ProtocolMessage`, if and only if that field (`ProtocolMessage.channelSerial`) is populated.
- `(RTL15b1)` This clause has been replaced by [`RTL15b2`](#RTL15b2) as of specification version 6.1.0.
- `(RTL15b2)` If the channel enters the `DETACHED` or `FAILED` state, it must clear its `channelSerial`. (Unlike previous spec versions, it must not clear it when entering the `SUSPENDED` state).
Expand Down Expand Up @@ -1760,7 +1761,7 @@ The core SDK provides an API for wrapper SDKs to supply Ably with analytics info
h4. ChannelProperties
- `(CP1)` properties of a channel and its state
- `(CP2)` The attributes of `ChannelProperties` consist of:
- `(CP2a)` `attachSerial` string - contains the `channelSerial` that the current attachment started at, set per [RTL15a](#RTL15a)
- `(CP2a)` `attachSerial` string - contains the `channelSerial` that the current attachment started at, set per [RTL15c](#RTL15c)
- `(CP2b)` `channelSerial` string - contains the last `channelSerial` received on the channel, set per [RTL15b](#RTL15b)

#### ChannelDetails
Expand Down
2 changes: 1 addition & 1 deletion uts/docs/completion-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ This matrix lists all spec items from the [Ably features spec](../../specificati
| RTL12 | Additional ATTACHED message handling | Yes — `realtime/unit/channels/channel_additional_attached.md`; `realtime/integration/proxy/channel_faults.md` covers RTL12 |
| RTL13 | Server-initiated DETACHED handling (RTL13a–RTL13c) | Yes — `realtime/unit/channels/channel_server_initiated_detach.md` |
| RTL14 | ERROR message handling | Yes — `realtime/unit/channels/channel_error.md`; `realtime/integration/channels/channel_attach_test.md` covers RTL14; `realtime/integration/proxy/channel_faults.md` covers RTL14 |
| RTL15 | Channel#properties attribute (RTL15a–RTL15b1) | Yes — `realtime/unit/channels/channel_properties.md` |
| RTL15 | Channel#properties attribute (RTL15b–RTL15c) | Yes — `realtime/unit/channels/channel_properties.md` |
| RTL16 | SetOptions function (RTL16a) | Yes — `realtime/unit/channels/channel_options.md` |
| RTL17 | No messages outside ATTACHED state | Yes — `realtime/unit/channels/channel_subscribe.md` |
| RTL18 | Vcdiff decoding failure recovery (RTL18a–RTL18c) | Yes — `realtime/unit/channels/channel_delta_decoding.md`, `realtime/integration/delta_decoding_test.md` |
Expand Down
2 changes: 1 addition & 1 deletion uts/realtime/unit/channels/channel_history.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Unit test with mocked HTTP client

## RTL10b - untilAttach parameter

**Spec requirement:** Additionally supports the param `untilAttach`, which if true, will only retrieve messages prior to the moment that the channel was attached or emitted an UPDATE indicating loss of continuity. This bound is specified by passing the querystring param `fromSerial` with the `RealtimeChannel#properties.attachSerial` assigned to the channel in the ATTACHED ProtocolMessage (see RTL15a). If the `untilAttach` param is specified when the channel is not attached, it results in an error.
**Spec requirement:** Additionally supports the param `untilAttach`, which if true, will only retrieve messages prior to the moment that the channel was attached or emitted an UPDATE indicating loss of continuity. This bound is specified by passing the querystring param `fromSerial` with the `RealtimeChannel#properties.attachSerial` (see RTL15c). If the `untilAttach` param is specified when the channel is not attached, it results in an error.

### RTL10b - untilAttach adds fromSerial query parameter

Expand Down
88 changes: 76 additions & 12 deletions uts/realtime/unit/channels/channel_properties.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Channel Properties Tests

Spec points: `RTL15`, `RTL15a`, `RTL15b`, `RTL15b1`
Spec points: `RTL15`, `RTL15b`, `RTL15b1`, `RTL15c`

## Test Type
Unit test with mocked WebSocket
Expand All @@ -11,27 +11,28 @@ See `uts/realtime/unit/helpers/mock_websocket.md` for the full Mock WebSocket In

---

## RTL15a - attachSerial is updated from ATTACHED message
## RTL15c - attachSerial is updated from non-resumed ATTACHED message

**Test ID**: `realtime/unit/RTL15a/attach-serial-from-attached-0`
**Test ID**: `realtime/unit/RTL15c/attach-serial-from-attached-0`

| Spec | Requirement |
|------|-------------|
| RTL15 | `RealtimeChannel#properties` is a `ChannelProperties` object with `attachSerial` and `channelSerial` |
| RTL15a | `attachSerial` is unset when instantiated, and updated with the `channelSerial` from each ATTACHED ProtocolMessage received |
| RTL15c | `attachSerial` is unset when instantiated, and updated with the `channelSerial` from each ATTACHED ProtocolMessage received whose `resumed` attribute is false |

Tests that the channel's `attachSerial` property is initially unset, is set from the `channelSerial` field of the ATTACHED response, and is updated on subsequent ATTACHED messages (e.g. after reattach).
Tests that the channel's `attachSerial` property is initially unset, is set from the `channelSerial` field of the ATTACHED response, and is updated on subsequent non-resumed ATTACHED messages (e.g. after reattach).

### Setup
```pseudo
channel_name = "test-RTL15a-${random_id()}"
channel_name = "test-RTL15c-${random_id()}"
attach_count = 0

mock_ws = MockWebSocket(
onConnectionAttempt: (conn) => conn.respond_with_success(CONNECTED_MESSAGE),
onMessageFromClient: (msg) => {
IF msg.action == ATTACH:
attach_count++
# No RESUMED flag, so resumed is false
mock_ws.send_to_client(ProtocolMessage(
action: ATTACHED,
channel: msg.channel,
Expand Down Expand Up @@ -81,17 +82,17 @@ CLOSE_CLIENT(client)

---

## RTL15a - attachSerial updated on server-initiated reattach
## RTL15c - attachSerial updated on server-initiated non-resumed reattach

**Test ID**: `realtime/unit/RTL15a/attach-serial-server-reattach-1`
**Test ID**: `realtime/unit/RTL15c/attach-serial-server-reattach-1`

**Spec requirement:** `attachSerial` is updated with the `channelSerial` from each ATTACHED ProtocolMessage received.
**Spec requirement:** `attachSerial` is updated with the `channelSerial` from each ATTACHED ProtocolMessage received whose `resumed` attribute is false.

Tests that when the server sends an unsolicited ATTACHED message (e.g. RTL2g update), the `attachSerial` is updated.
Tests that when the server sends an unsolicited ATTACHED message without the RESUMED flag (e.g. RTL12 update indicating loss of continuity), the `attachSerial` is updated.

### Setup
```pseudo
channel_name = "test-RTL15a-update-${random_id()}"
channel_name = "test-RTL15c-update-${random_id()}"

mock_ws = MockWebSocket(
onConnectionAttempt: (conn) => conn.respond_with_success(CONNECTED_MESSAGE),
Expand Down Expand Up @@ -121,7 +122,7 @@ AWAIT_STATE client.connection.state == ConnectionState.connected
AWAIT channel.attach()
ASSERT channel.properties.attachSerial == "initial-serial"

# Server sends unsolicited ATTACHED (e.g. RTL2g update)
# Server sends unsolicited ATTACHED without the RESUMED flag (e.g. RTL12 update)
mock_ws.active_connection.send_to_client(ProtocolMessage(
action: ATTACHED,
channel: channel_name,
Expand All @@ -138,6 +139,69 @@ CLOSE_CLIENT(client)

---

## RTL15c - attachSerial not updated from resumed ATTACHED message

**Test ID**: `realtime/unit/RTL15c/attach-serial-not-updated-resumed-2`

**Spec requirement:** `attachSerial` is updated with the `channelSerial` from each ATTACHED ProtocolMessage received whose `resumed` attribute is false — so an ATTACHED message with the RESUMED flag set must leave `attachSerial` unchanged.

Tests that when the server sends an unsolicited ATTACHED message with the RESUMED flag (indicating a successful resume with no loss of continuity), the `attachSerial` is not updated. Uses the RTL15b `channelSerial` update (which happens regardless of the RESUMED flag) to detect that the message has been processed.

### Setup
```pseudo
channel_name = "test-RTL15c-resumed-${random_id()}"

mock_ws = MockWebSocket(
onConnectionAttempt: (conn) => conn.respond_with_success(CONNECTED_MESSAGE),
onMessageFromClient: (msg) => {
IF msg.action == ATTACH:
mock_ws.send_to_client(ProtocolMessage(
action: ATTACHED,
channel: msg.channel,
channelSerial: "initial-serial"
))
}
)
install_mock(mock_ws)

client = Realtime(options: ClientOptions(
key: "appId.keyId:keySecret",
autoConnect: false
))
channel = client.channels.get(channel_name)
```

### Test Steps
```pseudo
client.connect()
AWAIT_STATE client.connection.state == ConnectionState.connected

AWAIT channel.attach()
ASSERT channel.properties.attachSerial == "initial-serial"

# Server sends unsolicited ATTACHED WITH the RESUMED flag
# (successful resume, no loss of continuity)
mock_ws.active_connection.send_to_client(ProtocolMessage(
action: ATTACHED,
channel: channel_name,
channelSerial: "resumed-serial",
flags: RESUMED
))

# channelSerial is updated per RTL15b regardless of the RESUMED flag,
# confirming the message has been processed
AWAIT_STATE channel.properties.channelSerial == "resumed-serial"
```

### Assertions
```pseudo
# attachSerial must be unchanged, since the ATTACHED message had resumed=true
ASSERT channel.properties.attachSerial == "initial-serial"
CLOSE_CLIENT(client)
```

---

## RTL15b - channelSerial updated from ATTACHED message

**Test ID**: `realtime/unit/RTL15b/channel-serial-from-attached-0`
Expand Down
Loading