diff --git a/uts/docs/completion-status.md b/uts/docs/completion-status.md index c475bc838..40a0ae465 100644 --- a/uts/docs/completion-status.md +++ b/uts/docs/completion-status.md @@ -334,7 +334,7 @@ This matrix lists all spec items from the [Ably features spec](../../specificati | TN1–TN3 | Token string | | | AD1–AD2 | AuthDetails | | | TS1–TS14 | Stats | | -| TI1–TI5 | ErrorInfo | Yes — `rest/unit/types/error_types.md` | +| TI1, TI2, TI4 | ErrorInfo | Yes — `rest/unit/types/error_types.md` | | TA1–TA5 | ConnectionStateChange | | | TH1–TH6 | ChannelStateChange | Yes — `realtime/unit/channels/channel_state_events.md` | | TC1–TC2 | Capability | | @@ -356,7 +356,7 @@ This matrix lists all spec items from the [Ably features spec](../../specificati | Spec item | Description | UTS test spec | |-----------|-------------|---------------| | TO1–TO3 | ClientOptions | Yes — `rest/unit/types/options_types.md` | -| TK1–TK6 | TokenParams | Yes — `rest/unit/types/token_types.md` | +| TK1, TK2, TK2a–TK2e | TokenParams | Yes — `rest/unit/types/token_types.md` | | AO1–AO2 | AuthOptions | Yes — `rest/unit/types/options_types.md` | | TB1–TB4 | ChannelOptions | Yes — `realtime/unit/channels/channel_options.md` | | DO1–DO2 | DeriveOptions | Yes — `realtime/unit/channels/channel_options.md` | diff --git a/uts/rest/unit/auth/authorize.md b/uts/rest/unit/auth/authorize.md index dc7937765..492cd6e0e 100644 --- a/uts/rest/unit/auth/authorize.md +++ b/uts/rest/unit/auth/authorize.md @@ -1,6 +1,6 @@ # Auth.authorize() Tests -Spec points: `RSA10`, `RSA10a`, `RSA10b`, `RSA10e`, `RSA10g`, `RSA10h`, `RSA10i`, `RSA10j`, `RSA10k`, `RSA10l` +Spec points: `RSA10`, `RSA10a`, `RSA10b`, `RSA10e`, `RSA10g`, `RSA10i`, `RSA10j`, `RSA10k`, `RSA10l`, `RSA16c` ## Test Type Unit test with mocked HTTP client and/or mocked authCallback @@ -111,9 +111,9 @@ ASSERT params.ttl == 7200000 --- -## RSA10e - authorize() saves tokenParams for reuse +## RSA10g - authorize() saves tokenParams for reuse -**Test ID**: `rest/unit/RSA10e/authorize-saves-params-0` +**Test ID**: `rest/unit/RSA10g/authorize-saves-params-0` **Spec requirement:** `tokenParams` provided to `authorize()` are saved and reused on subsequent token requests. @@ -166,9 +166,9 @@ ASSERT callback_invocations[1].ttl == 3600000 --- -## RSA10g - authorize() updates Auth.tokenDetails +## RSA16c - authorize() updates Auth.tokenDetails -**Test ID**: `rest/unit/RSA10g/authorize-updates-token-details-0` +**Test ID**: `rest/unit/RSA16c/authorize-updates-token-details-0` **Spec requirement:** After `authorize()`, `auth.tokenDetails` reflects the new token. @@ -209,9 +209,9 @@ ASSERT client.auth.tokenDetails == result # Same object --- -## RSA10h - authorize() with authOptions replaces defaults +## RSA10j - authorize() with authOptions replaces defaults -**Test ID**: `rest/unit/RSA10h/authorize-replaces-auth-options-0` +**Test ID**: `rest/unit/RSA10j/authorize-replaces-auth-options-0` **Spec requirement:** `authOptions` in `authorize()` replaces stored auth options. @@ -312,9 +312,9 @@ AWAIT client.auth.authorize( --- -## RSA10j - authorize() when already authorized +## RSA10a - authorize() when already authorized -**Test ID**: `rest/unit/RSA10j/authorize-replaces-existing-token-0` +**Test ID**: `rest/unit/RSA10a/authorize-replaces-existing-token-1` **Spec requirement:** Calling `authorize()` when a valid token exists obtains a new token. diff --git a/uts/rest/unit/channel/idempotency.md b/uts/rest/unit/channel/idempotency.md index b21a9cfdb..68c86f203 100644 --- a/uts/rest/unit/channel/idempotency.md +++ b/uts/rest/unit/channel/idempotency.md @@ -43,9 +43,9 @@ ASSERT client.options.idempotentRestPublishing == true --- -## RSL1k2 - Message ID format when idempotent publishing enabled +## RSL1k1 - Message ID format when idempotent publishing enabled -**Test ID**: `rest/unit/RSL1k2/message-id-format-0` +**Test ID**: `rest/unit/RSL1k1/message-id-format-1` **Spec requirement:** When `idempotentRestPublishing` is enabled, library-generated message IDs must follow the format `:` where base64 is a URL-safe base64-encoded random value and serial is a zero-based sequential integer. @@ -99,9 +99,9 @@ ASSERT parts[1] == "0" --- -## RSL1k2 - Serial increments for batch publish +## RSL1k1 - Serial increments for batch publish -**Test ID**: `rest/unit/RSL1k2/serial-increments-batch-1` +**Test ID**: `rest/unit/RSL1k1/serial-increments-batch-2` **Spec requirement:** When publishing multiple messages in a batch, all messages must share the same base ID with incrementing serial numbers starting from 0. @@ -161,9 +161,9 @@ ASSERT serials == [0, 1, 2] --- -## RSL1k3 - Separate publishes get unique base IDs +## RSL1k1 - Separate publishes get unique base IDs -**Test ID**: `rest/unit/RSL1k3/unique-base-ids-0` +**Test ID**: `rest/unit/RSL1k1/unique-base-ids-3` **Spec requirement:** Each separate publish call must generate a new unique base ID, even for messages published to the same channel. @@ -210,9 +210,9 @@ ASSERT base1 != base2 --- -## RSL1k3 - No ID generated when idempotent publishing disabled +## RSL1k1 - No ID generated when idempotent publishing disabled -**Test ID**: `rest/unit/RSL1k3/no-id-when-disabled-1` +**Test ID**: `rest/unit/RSL1k1/no-id-when-disabled-4` **Spec requirement:** When `idempotentRestPublishing` is false, the library must not automatically generate message IDs. @@ -255,9 +255,9 @@ ASSERT "id" NOT IN body --- -## RSL1k - Client-supplied ID preserved +## RSL1k2 - Client-supplied ID preserved -**Test ID**: `rest/unit/RSL1k/client-id-preserved-0` +**Test ID**: `rest/unit/RSL1k2/client-id-preserved-0` **Spec requirement:** Client-supplied message IDs must be preserved and transmitted exactly as provided, even when `idempotentRestPublishing` is enabled. @@ -302,9 +302,9 @@ ASSERT body["id"] == "my-custom-id" --- -## RSL1k2 - Same ID used on retry +## RSL1k1 - Same ID used on retry -**Test ID**: `rest/unit/RSL1k2/same-id-on-retry-2` +**Test ID**: `rest/unit/RSL1k1/same-id-on-retry-5` **Spec requirement:** When a publish request is retried after a failure, the same message ID(s) must be used to ensure idempotent behavior. @@ -357,9 +357,9 @@ ASSERT body1["id"] == body2["id"] --- -## RSL1k - Mixed client and library IDs in batch +## RSL1k3 - Mixed client and library IDs in batch -**Test ID**: `rest/unit/RSL1k/mixed-ids-in-batch-1` +**Test ID**: `rest/unit/RSL1k3/mixed-ids-in-batch-0` **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. diff --git a/uts/rest/unit/types/error_types.md b/uts/rest/unit/types/error_types.md index ed85212ee..ed98840e7 100644 --- a/uts/rest/unit/types/error_types.md +++ b/uts/rest/unit/types/error_types.md @@ -1,6 +1,6 @@ # Error Types Tests -Spec points: `TI1`, `TI2`, `TI3`, `TI4`, `TI5` +Spec points: `TI1`, `TI2`, `TI4` ## Test Type Unit test - pure type/model validation @@ -10,19 +10,19 @@ No mocks required - these verify type structure. --- -## TI1-TI5 - ErrorInfo attributes +## TI1, TI4 - ErrorInfo attributes **Test ID**: `rest/unit/TI1/errorinfo-attributes-0` -**Spec requirement:** ErrorInfo type must provide all required attributes according to TI1-TI5 specifications. +**Spec requirement:** ErrorInfo type must provide all required attributes according to TI1 (and TI4 for `href`). | Spec | Attribute | Description | |------|-----------|-------------| | TI1 | code | Ably-specific error code | -| TI2 | statusCode | HTTP status code | -| TI3 | message | Human-readable error message | -| TI4 | href | URL for more information | -| TI5 | cause | Underlying cause error/exception | +| TI1 | statusCode | HTTP status code | +| TI1 | message | Human-readable error message | +| TI1, TI4 | href | URL for more information | +| TI1 | cause | Underlying cause error/exception | Tests that `ErrorInfo` (or `AblyException`) has all required attributes. @@ -31,10 +31,10 @@ Tests that `ErrorInfo` (or `AblyException`) has all required attributes. | ID | Spec | Attribute | Type | Description | |----|------|-----------|------|-------------| | 1 | TI1 | `code` | Integer | Ably-specific error code | -| 2 | TI2 | `statusCode` | Integer | HTTP status code | -| 3 | TI3 | `message` | String | Human-readable error message | -| 4 | TI4 | `href` | String | URL for more information | -| 5 | TI5 | `cause` | Error/Exception | Underlying cause | +| 2 | TI1 | `statusCode` | Integer | HTTP status code | +| 3 | TI1 | `message` | String | Human-readable error message | +| 4 | TI1, TI4 | `href` | String | URL for more information | +| 5 | TI1 | `cause` | Error/Exception | Underlying cause | ### Test Steps ```pseudo @@ -42,11 +42,11 @@ Tests that `ErrorInfo` (or `AblyException`) has all required attributes. error = ErrorInfo(code: 40000) ASSERT error.code == 40000 -# TI2 - statusCode attribute +# TI1 - statusCode attribute error = ErrorInfo(code: 40100, statusCode: 401) ASSERT error.statusCode == 401 -# TI3 - message attribute +# TI1 - message attribute error = ErrorInfo( code: 40000, statusCode: 400, @@ -54,14 +54,14 @@ error = ErrorInfo( ) ASSERT error.message == "Bad request: invalid parameter" -# TI4 - href attribute (optional) +# TI1, TI4 - href attribute (optional) error = ErrorInfo( code: 40000, href: "https://help.ably.io/error/40000" ) ASSERT error.href == "https://help.ably.io/error/40000" -# TI5 - cause attribute (optional) +# TI1 - cause attribute (optional) original_error = Exception("Network failure") error = ErrorInfo( code: 50003, @@ -74,9 +74,9 @@ ASSERT error.cause == original_error --- -## TI - ErrorInfo from JSON response +## TI2 - ErrorInfo from JSON response -**Test ID**: `rest/unit/TI/errorinfo-from-json-0` +**Test ID**: `rest/unit/TI2/errorinfo-from-json-0` **Spec requirement:** ErrorInfo type must support deserialization from Ably JSON error responses. @@ -136,9 +136,9 @@ IF error.cause IS ErrorInfo: --- -## TI - AblyException wraps ErrorInfo +## TI2 - AblyException wraps ErrorInfo -**Test ID**: `rest/unit/TI/ably-exception-wraps-errorinfo-2` +**Test ID**: `rest/unit/TI2/ably-exception-wraps-errorinfo-2` **Spec requirement:** AblyException (throwable) must wrap ErrorInfo and expose its attributes. diff --git a/uts/rest/unit/types/token_types.md b/uts/rest/unit/types/token_types.md index 9f422916d..76b77c61b 100644 --- a/uts/rest/unit/types/token_types.md +++ b/uts/rest/unit/types/token_types.md @@ -1,6 +1,6 @@ # Token Types Tests -Spec points: `TD1`, `TD2`, `TD3`, `TD4`, `TD5`, `TK1`, `TK2`, `TK3`, `TK4`, `TK5`, `TK6`, `TE1`, `TE2`, `TE3`, `TE4`, `TE5`, `TE6` +Spec points: `TD1`, `TD2`, `TD3`, `TD4`, `TD5`, `TD6`, `TD7`, `TK1`, `TK2`, `TK2a`, `TK2b`, `TK2c`, `TK2d`, `TK2e`, `TE1`, `TE2`, `TE3`, `TE4`, `TE5`, `TE6` ## Test Type Unit test - pure type/model validation @@ -10,35 +10,35 @@ No mocks required for most tests - these verify type structure and serialization --- -## TD1-TD5 - TokenDetails structure +## TD2-TD6 - TokenDetails structure -**Test ID**: `rest/unit/TD1/token-details-attributes-0` +**Test ID**: `rest/unit/TD2/token-details-attributes-0` -**Spec requirement:** TokenDetails type must provide all required attributes according to TD1-TD5 specifications. +**Spec requirement:** TokenDetails type must provide all required attributes according to TD2-TD6 specifications. | Spec | Attribute | Description | |------|-----------|-------------| -| TD1 | token | The token string | -| TD2 | expires | Expiry time in milliseconds since epoch | -| TD3 | issued | Issue time in milliseconds since epoch | -| TD4 | capability | Capability JSON string | -| TD5 | clientId | Client ID associated with the token | +| TD2 | token | The token string | +| TD3 | expires | Expiry time in milliseconds since epoch | +| TD4 | issued | Issue time in milliseconds since epoch | +| TD5 | capability | Capability JSON string | +| TD6 | clientId | Client ID associated with the token | Tests that `TokenDetails` has all required attributes. ### Test Steps ```pseudo -# TD1 - token attribute +# TD2 - token attribute token_details = TokenDetails( token: "test-token", expires: 1234567890000 ) ASSERT token_details.token == "test-token" -# TD2 - expires attribute (milliseconds since epoch) +# TD3 - expires attribute (milliseconds since epoch) ASSERT token_details.expires == 1234567890000 -# TD3 - issued attribute +# TD4 - issued attribute token_with_issued = TokenDetails( token: "test-token", expires: 1234567890000, @@ -46,7 +46,7 @@ token_with_issued = TokenDetails( ) ASSERT token_with_issued.issued == 1234567800000 -# TD4 - capability attribute (JSON string) +# TD5 - capability attribute (JSON string) token_with_capability = TokenDetails( token: "test-token", expires: 1234567890000, @@ -54,7 +54,7 @@ token_with_capability = TokenDetails( ) ASSERT token_with_capability.capability == "{\"*\":[\"*\"]}" -# TD5 - clientId attribute +# TD6 - clientId attribute token_with_client = TokenDetails( token: "test-token", expires: 1234567890000, @@ -95,54 +95,54 @@ ASSERT token_details.clientId == "json-client" --- -## TK1-TK6 - TokenParams structure +## TK2, TK2a-TK2e - TokenParams structure -**Test ID**: `rest/unit/TK1/token-params-attributes-0` +**Test ID**: `rest/unit/TK2a/token-params-attributes-0` -**Spec requirement:** TokenParams type must provide all required attributes according to TK1-TK6 specifications. +**Spec requirement:** TokenParams type must provide all required attributes according to TK2 and TK2a-TK2e specifications. | Spec | Attribute | Description | |------|-----------|-------------| -| TK1 | ttl | Time to live in milliseconds | -| TK2 | capability | Capability JSON string | -| TK3 | clientId | Client ID for the token | -| TK4 | timestamp | Timestamp in milliseconds since epoch | -| TK5 | nonce | Unique nonce value | -| TK6 | (all) | All attributes combined | +| TK2a | ttl | Time to live in milliseconds | +| TK2b | capability | Capability JSON string | +| TK2c | clientId | Client ID for the token | +| TK2d | timestamp | Timestamp in milliseconds since epoch | +| TK2e | nonce | Unique nonce value | +| TK2 | (all) | All attributes combined | Tests that `TokenParams` has all required attributes. ### Test Steps ```pseudo -# TK1 - ttl attribute (milliseconds, nullable) +# TK2a - ttl attribute (milliseconds, nullable) params = TokenParams(ttl: 3600000) ASSERT params.ttl == 3600000 -# TK1 - ttl defaults to null when not specified (RSA5 depends on this) +# TK2a - ttl defaults to null when not specified (RSA5 depends on this) params = TokenParams() ASSERT params.ttl IS null -# TK2 - capability attribute (nullable) +# TK2b - capability attribute (nullable) params = TokenParams(capability: "{\"*\":[\"subscribe\"]}") ASSERT params.capability == "{\"*\":[\"subscribe\"]}" -# TK2 - capability defaults to null when not specified (RSA6 depends on this) +# TK2b - capability defaults to null when not specified (RSA6 depends on this) params = TokenParams() ASSERT params.capability IS null -# TK3 - clientId attribute +# TK2c - clientId attribute params = TokenParams(clientId: "param-client") ASSERT params.clientId == "param-client" -# TK4 - timestamp attribute (milliseconds since epoch) +# TK2d - timestamp attribute (milliseconds since epoch) params = TokenParams(timestamp: 1234567890000) ASSERT params.timestamp == 1234567890000 -# TK5 - nonce attribute +# TK2e - nonce attribute params = TokenParams(nonce: "unique-nonce-value") ASSERT params.nonce == "unique-nonce-value" -# TK6 - All attributes together +# TK2 - All attributes together params = TokenParams( ttl: 7200000, capability: "{\"*\":[\"*\"]}", @@ -184,26 +184,26 @@ ASSERT query_map["capability"] == "{\"ch\":[\"pub\"]}" --- -## TE1-TE6 - TokenRequest structure +## TE2-TE5 - TokenRequest structure -**Test ID**: `rest/unit/TE1/token-request-attributes-0` +**Test ID**: `rest/unit/TE2/token-request-attributes-0` -**Spec requirement:** TokenRequest type must provide all required attributes according to TE1-TE6 specifications. +**Spec requirement:** TokenRequest type must provide all required attributes according to TE2-TE5 specifications. | Spec | Attribute | Description | |------|-----------|-------------| -| TE1 | keyName | API key name (appId.keyId) | -| TE2 | ttl | Time to live in milliseconds | +| TE2 | keyName | API key name (appId.keyId) | +| TE4 | ttl | Time to live in milliseconds | | TE3 | capability | Capability JSON string | -| TE4 | clientId | Client ID for the token | +| TE2 | clientId | Client ID for the token | | TE5 | timestamp | Timestamp in milliseconds since epoch | -| TE6 | nonce | Unique nonce value | +| TE2 | nonce | Unique nonce value | Tests that `TokenRequest` has all required attributes. ### Test Steps ```pseudo -# TE1 - keyName attribute +# TE2 - keyName attribute request = TokenRequest( keyName: "appId.keyId", timestamp: 1234567890000, @@ -211,7 +211,7 @@ request = TokenRequest( ) ASSERT request.keyName == "appId.keyId" -# TE2 - ttl attribute (nullable) +# TE4 - ttl attribute (nullable) request = TokenRequest( keyName: "appId.keyId", ttl: 3600000, @@ -220,7 +220,7 @@ request = TokenRequest( ) ASSERT request.ttl == 3600000 -# TE2 - ttl defaults to null when not specified (RSA5 depends on this) +# TE4 - ttl defaults to null when not specified (RSA5 depends on this) request = TokenRequest( keyName: "appId.keyId", timestamp: 1234567890000, @@ -245,7 +245,7 @@ request = TokenRequest( ) ASSERT request.capability IS null -# TE4 - clientId attribute +# TE2 - clientId attribute request = TokenRequest( keyName: "appId.keyId", clientId: "request-client", @@ -262,7 +262,7 @@ request = TokenRequest( ) ASSERT request.timestamp == 1234567890000 -# TE6 - nonce attribute +# TE2 - nonce attribute request = TokenRequest( keyName: "appId.keyId", timestamp: 1234567890000,