Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP, ECO-4952] Implement room lifecycle spec #30

Closed
wants to merge 1 commit into from
Closed
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
37 changes: 37 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,43 @@ To check formatting and code quality, run `swift run BuildTool lint`. Run with `
- We should aim to make it easy for consumers of the SDK to be able to mock out the SDK in the tests for their own code. A couple of things that will aid with this:
- Describe the SDK’s functionality via protocols (when doing so would still be sufficiently idiomatic to Swift).
- When defining a `struct` that is emitted by the public API of the library, make sure to define a public memberwise initializer so that users can create one to be emitted by their mocks. (There is no way to make Swift’s autogenerated memberwise initializer public, so you will need to write one yourself. In Xcode, you can do this by clicking at the start of the type declaration and doing Editor → Refactor → Generate Memberwise Initializer.)
- When writing code that implements behaviour specified by the Chat SDK features spec, add a comment that references the identifier of the relevant spec item.

### Testing guidelines

#### Attributing tests to a spec point

When writing a test that relates to a spec point from the Chat SDK features spec, add a comment that contains one of the following tags:

- `@spec <spec-item-id>` — The test case directly tests all the functionality documented in the spec item.
- `@specOneOf(m/n) <spec-item-id>` — The test case is the m<sup>th</sup> of n test cases which, together, test all of the functionality documented in the spec item.
- `@specPartial <spec-item-id>` — The test case tests some, but not all, of the functionality documented in the spec item. This is different to `@specOneOf` in that it implies that the test suite does not fully test this spec item.

`<spec-item-id>` should be a spec item identifier such as `CHA-RL3g`.

Each of the above tags can optionally be followed by a hyphen and a comment which explains how the test relates to the given spec item.

Examples:

```swift
// @spec CHA-EX3f
func test1 { … }
```

```swift
// @specOneOf(1/2) CHA-EX2h — Tests the case where the room is FAILED
func test2 { … }

// @specOneOf(2/2) CHA-EX2h — Tests the case where the room is SUSPENDED
func test3 { … }
```

```swift
// @specIncomplete CHA-EX1h4 - Tests that we retry, but not the retry attempt limit because we’ve not implemented it yet
func test4 { … }
```

In [#46](https://github.com/ably-labs/ably-chat-swift/issues/46), we’ll write a script that uses these tags to generate a report about how much of the feature spec we’ve implemented.

## Building for Swift 6

Expand Down
95 changes: 93 additions & 2 deletions Sources/AblyChat/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,25 @@ public enum ErrorCode: Int {
/// TODO this code is a guess, revisit in https://github.com/ably-labs/ably-chat-swift/issues/32
case inconsistentRoomOptions = 1

// TODO: describe, and code is a guess
case channelAttachResultedInSuspended = 2
case channelAttachResultedInFailed = 3

case roomInFailedState = 102_101 // CHA-RL2d
case roomIsReleasing = 102_102 // CHA-RL1b, CHA-RL2b
case roomIsReleased = 102_103 // CHA-RL1c, CHA-RL2c

case messagesDetachmentFailed = 102_050
case presenceDetachmentFailed = 102_051
case reactionsDetachmentFailed = 102_052
case occupancyDetachmentFailed = 102_053
case typingDetachmentFailed = 102_054

/// The ``ARTErrorInfo.statusCode`` that should be returned for this error.
internal var statusCode: Int {
// TODO: These are currently a guess, revisit in https://github.com/ably-labs/ably-chat-swift/issues/32
switch self {
case .inconsistentRoomOptions:
case .inconsistentRoomOptions, .channelAttachResultedInSuspended, .channelAttachResultedInFailed, .roomInFailedState, .roomIsReleasing, .roomIsReleased, .messagesDetachmentFailed, .presenceDetachmentFailed, .reactionsDetachmentFailed, .occupancyDetachmentFailed, .typingDetachmentFailed:
400
}
}
Expand All @@ -29,16 +43,45 @@ public enum ErrorCode: Int {
/**
The errors thrown by the Chat SDK.

This type exists in addition to ``ErrorCode`` to allow us to attach metadata which can be incorporated into the error’s `localizedDescription`.
This type exists in addition to ``ErrorCode`` to allow us to attach metadata which can be incorporated into the error’s `localizedDescription` and `cause`.
*/
internal enum ChatError {
case inconsistentRoomOptions(requested: RoomOptions, existing: RoomOptions)
case channelAttachResultedInSuspended(underlyingError: ARTErrorInfo)
case channelAttachResultedInFailed(underlyingError: ARTErrorInfo)
case roomInFailedState
case roomIsReleasing
case roomIsReleased
case detachmentFailed(feature: RoomFeature, underlyingError: ARTErrorInfo)

/// The ``ARTErrorInfo.code`` that should be returned for this error.
internal var code: ErrorCode {
switch self {
case .inconsistentRoomOptions:
.inconsistentRoomOptions
case .channelAttachResultedInSuspended:
.channelAttachResultedInSuspended
case .channelAttachResultedInFailed:
.channelAttachResultedInFailed
case .roomInFailedState:
.roomInFailedState
case .roomIsReleasing:
.roomIsReleasing
case .roomIsReleased:
.roomIsReleased
case let .detachmentFailed(feature, _):
switch feature {
case .messages:
.messagesDetachmentFailed
case .occupancy:
.occupancyDetachmentFailed
case .presence:
.presenceDetachmentFailed
case .reactions:
.reactionsDetachmentFailed
case .typing:
.typingDetachmentFailed
}
}
}

Expand All @@ -47,6 +90,49 @@ internal enum ChatError {
switch self {
case let .inconsistentRoomOptions(requested, existing):
"Rooms.get(roomID:options:) was called with a different set of room options than was used on a previous call. You must first release the existing room instance using Rooms.release(roomID:). Requested options: \(requested), existing options: \(existing)"
case .channelAttachResultedInSuspended:
"TODO"
case .channelAttachResultedInFailed:
"TODO"
case .roomInFailedState:
"Cannot perform operation because the room is in a failed state."
case .roomIsReleasing:
"Cannot perform operation because the room is in a releasing state."
case .roomIsReleased:
"Cannot perform operation because the room is in a released state."
case let .detachmentFailed(feature, _):
{
let description = switch feature {
case .messages:
"messages"
case .occupancy:
"occupancy"
case .presence:
"presence"
case .reactions:
"reactions"
case .typing:
"typing"
}
return "The \(description) feature failed to detach."
}()
}
}

/// The ``ARTErrorInfo.cause`` that should be returned for this error.
internal var cause: ARTErrorInfo? {
switch self {
case let .channelAttachResultedInSuspended(underlyingError):
underlyingError
case let .channelAttachResultedInFailed(underlyingError):
underlyingError
case let .detachmentFailed(_, underlyingError):
underlyingError
case .inconsistentRoomOptions,
.roomInFailedState,
.roomIsReleasing,
.roomIsReleased:
nil
}
}
}
Expand All @@ -58,6 +144,11 @@ internal extension ARTErrorInfo {
userInfo["ARTErrorInfoStatusCode"] = chatError.code.statusCode
userInfo[NSLocalizedDescriptionKey] = chatError.localizedDescription

// TODO: This is kind of an implementation detail (that NSUnderlyingErrorKey is what populates `cause`); consider documenting in ably-cocoa as part of https://github.com/ably-labs/ably-chat-swift/issues/32.
if let cause = chatError.cause {
userInfo[NSUnderlyingErrorKey] = cause
}

self.init(
domain: errorDomain,
code: chatError.code.rawValue,
Expand Down
8 changes: 8 additions & 0 deletions Sources/AblyChat/RoomFeature.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/// The features offered by a chat room.
internal enum RoomFeature {
case messages
case presence
case reactions
case occupancy
case typing
}
Loading