Skip to content

Commit

Permalink
Added companion default for RoomOptions, added tests for the same
Browse files Browse the repository at this point in the history
  • Loading branch information
sacOO7 committed Nov 19, 2024
1 parent bdccd57 commit dcc9538
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 46 deletions.
5 changes: 5 additions & 0 deletions chat-android/src/main/java/com/ably/chat/ErrorCodes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ enum class ErrorCodes(val errorCode: Int) {
*/
RoomIsReleased(102_103),

/**
* Room was released before the operation could complete.
*/
RoomReleasedBeforeOperationCompleted(102_106),

/**
* Cannot perform operation because the previous operation failed.
*/
Expand Down
33 changes: 4 additions & 29 deletions chat-android/src/main/java/com/ably/chat/Room.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

package com.ably.chat

import io.ably.lib.types.AblyException
import io.ably.lib.types.ErrorInfo
import io.ably.lib.util.Log.LogHandler
import kotlinx.coroutines.CoroutineName
Expand Down Expand Up @@ -144,13 +143,7 @@ internal class DefaultRoom(
override val presence: Presence
get() {
if (_presence == null) {
throw AblyException.fromErrorInfo(
ErrorInfo(
"Presence is not enabled for this room",
ErrorCodes.BadRequest.errorCode,
HttpStatusCodes.BadRequest,
),
)
throw ablyException("Presence is not enabled for this room", ErrorCodes.BadRequest)
}
return _presence as Presence
}
Expand All @@ -159,13 +152,7 @@ internal class DefaultRoom(
override val reactions: RoomReactions
get() {
if (_reactions == null) {
throw AblyException.fromErrorInfo(
ErrorInfo(
"Reactions are not enabled for this room",
ErrorCodes.BadRequest.errorCode,
HttpStatusCodes.BadRequest,
),
)
throw ablyException("Reactions are not enabled for this room", ErrorCodes.BadRequest)
}
return _reactions as RoomReactions
}
Expand All @@ -174,13 +161,7 @@ internal class DefaultRoom(
override val typing: Typing
get() {
if (_typing == null) {
throw AblyException.fromErrorInfo(
ErrorInfo(
"Typing is not enabled for this room",
ErrorCodes.BadRequest.errorCode,
HttpStatusCodes.BadRequest,
),
)
throw ablyException("Typing is not enabled for this room", ErrorCodes.BadRequest)
}
return _typing as Typing
}
Expand All @@ -189,13 +170,7 @@ internal class DefaultRoom(
override val occupancy: Occupancy
get() {
if (_occupancy == null) {
throw AblyException.fromErrorInfo(
ErrorInfo(
"Occupancy is not enabled for this room",
ErrorCodes.BadRequest.errorCode,
HttpStatusCodes.BadRequest,
),
)
throw ablyException("Occupancy is not enabled for this room", ErrorCodes.BadRequest)
}
return _occupancy as Occupancy
}
Expand Down
25 changes: 14 additions & 11 deletions chat-android/src/main/java/com/ably/chat/RoomOptions.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package com.ably.chat

import io.ably.lib.types.AblyException
import io.ably.lib.types.ErrorInfo

/**
* Represents the options for a given chat room.
*/
Expand Down Expand Up @@ -31,7 +28,19 @@ data class RoomOptions(
* {@link RoomOptionsDefaults.occupancy} to enable occupancy with default options.
*/
val occupancy: OccupancyOptions? = null,
)
) {
companion object {
/**
* Supports all room options with default values
*/
val default = RoomOptions(
typing = TypingOptions(),
presence = PresenceOptions(),
reactions = RoomReactionsOptions,
occupancy = OccupancyOptions,
)
}
}

/**
* Represents the presence options for a chat room.
Expand Down Expand Up @@ -81,12 +90,6 @@ object OccupancyOptions
*/
fun RoomOptions.validateRoomOptions() {
if (typing != null && typing.timeoutMs <= 0) {
throw AblyException.fromErrorInfo(
ErrorInfo(
"Typing timeout must be greater than 0",
ErrorCodes.InvalidRequestBody.errorCode,
HttpStatusCodes.BadRequest,
),
)
throw ablyException("Typing timeout must be greater than 0", ErrorCodes.InvalidRequestBody)
}
}
7 changes: 7 additions & 0 deletions chat-android/src/main/java/com/ably/chat/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,10 @@ internal class DeferredValue<T> {
return result
}
}

fun ablyException(
errorMessage: String,
code: ErrorCodes,
statusCode: Int = HttpStatusCodes.BadRequest,
cause: Throwable? = null,
): AblyException = AblyException.fromErrorInfo(cause, ErrorInfo(errorMessage, statusCode, code.errorCode))
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.ably.chat.room

import com.ably.chat.ChatApi
import com.ably.chat.DefaultRoom
import com.ably.chat.RoomOptions
import com.ably.chat.RoomStatus
import com.ably.chat.TypingOptions
import com.ably.utils.createMockRealtimeClient
import io.ably.lib.types.AblyException
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.junit.Assert
import org.junit.Assert.assertThrows
import org.junit.Test

/**
* Chat rooms are configurable, so as to enable or disable certain features.
* When requesting a room, options as to which features should be enabled, and
* the configuration they should take, must be provided
* Spec: CHA-RC2
*/
class ConfigureRoomOptionsTest {

@Test
fun `(CHA-RC2a) If a room is requested with a negative typing timeout, an ErrorInfo with code 40001 must be thrown`() = runTest {
val mockRealtimeClient = createMockRealtimeClient()
val chatApi = mockk<ChatApi>(relaxed = true)

// Room success when positive typing timeout
val room = DefaultRoom("1234", RoomOptions(typing = TypingOptions(timeoutMs = 100)), mockRealtimeClient, chatApi, null)
Assert.assertNotNull(room)
Assert.assertEquals(RoomStatus.Initialized, room.status)

// Room failure when negative timeout
val exception = assertThrows(AblyException::class.java) {
DefaultRoom("1234", RoomOptions(typing = TypingOptions(timeoutMs = -1)), mockRealtimeClient, chatApi, null)
}
Assert.assertEquals("Typing timeout must be greater than 0", exception.errorInfo.message)
Assert.assertEquals(40_001, exception.errorInfo.code)
Assert.assertEquals(400, exception.errorInfo.statusCode)
}

@Test
fun `(CHA-RC2b) Attempting to use disabled feature must result in an ErrorInfo with code 40000 being thrown`() = runTest {
val mockRealtimeClient = createMockRealtimeClient()
val chatApi = mockk<ChatApi>(relaxed = true)

// Room only supports messages feature, since by default other features are turned off
val room = DefaultRoom("1234", RoomOptions(), mockRealtimeClient, chatApi, null)
Assert.assertNotNull(room)
Assert.assertEquals(RoomStatus.Initialized, room.status)

// Access presence throws exception
var exception = assertThrows(AblyException::class.java) {
room.presence
}
Assert.assertEquals("Presence is not enabled for this room", exception.errorInfo.message)
Assert.assertEquals(40_000, exception.errorInfo.code)
Assert.assertEquals(400, exception.errorInfo.statusCode)

// Access reactions throws exception
exception = assertThrows(AblyException::class.java) {
room.reactions
}
Assert.assertEquals("Reactions are not enabled for this room", exception.errorInfo.message)
Assert.assertEquals(40_000, exception.errorInfo.code)
Assert.assertEquals(400, exception.errorInfo.statusCode)

// Access typing throws exception
exception = assertThrows(AblyException::class.java) {
room.typing
}
Assert.assertEquals("Typing is not enabled for this room", exception.errorInfo.message)
Assert.assertEquals(40_000, exception.errorInfo.code)
Assert.assertEquals(400, exception.errorInfo.statusCode)

// Access occupancy throws exception
exception = assertThrows(AblyException::class.java) {
room.occupancy
}
Assert.assertEquals("Occupancy is not enabled for this room", exception.errorInfo.message)
Assert.assertEquals(40_000, exception.errorInfo.code)
Assert.assertEquals(400, exception.errorInfo.statusCode)

// room with all features
val roomWithAllFeatures = DefaultRoom("1234", RoomOptions.default, mockRealtimeClient, chatApi, null)
Assert.assertNotNull(roomWithAllFeatures.presence)
Assert.assertNotNull(roomWithAllFeatures.reactions)
Assert.assertNotNull(roomWithAllFeatures.typing)
Assert.assertNotNull(roomWithAllFeatures.occupancy)
}
}
3 changes: 3 additions & 0 deletions chat-android/src/test/java/com/ably/chat/room/RoomGetTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.ably.chat.room

class RoomGetTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.ably.chat.room

class RoomReleaseTest
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ably.chat.room
package com.ably.chat.room.lifecycle

import com.ably.chat.ContributesToRoomLifecycle
import com.ably.chat.DefaultRoomLifecycle
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ably.chat.room
package com.ably.chat.room.lifecycle

import com.ably.chat.ContributesToRoomLifecycle
import com.ably.chat.DefaultRoomLifecycle
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ably.chat.room
package com.ably.chat.room.lifecycle

import com.ably.chat.ContributesToRoomLifecycle
import com.ably.chat.DefaultRoomAttachmentResult
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ably.chat.room
package com.ably.chat.room.lifecycle

import com.ably.chat.DefaultRoomLifecycle
import com.ably.chat.RoomLifecycleManager
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ably.chat.room
package com.ably.chat.room.lifecycle

import com.ably.chat.DefaultRoomLifecycle
import com.ably.chat.HttpStatusCodes
Expand Down
4 changes: 3 additions & 1 deletion chat-android/src/test/java/com/ably/utils/RoomTestHelpers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ fun AblyRealtimeChannel.setState(state: ChannelState, errorInfo: ErrorInfo? = nu
this.reason = errorInfo
}

fun createMockRealtimeClient(): AblyRealtime = spyk(AblyRealtime(ClientOptions("id:key").apply { autoConnect = false }))

fun createRoomFeatureMocks(roomId: String = "1234"): List<ContributesToRoomLifecycle> {
val realtimeClient = spyk(AblyRealtime(ClientOptions("id:key").apply { autoConnect = false }))
val realtimeClient = createMockRealtimeClient()
val chatApi = mockk<ChatApi>(relaxed = true)

val messagesContributor = spyk(DefaultMessages(roomId, realtimeClient.channels, chatApi), recordPrivateCalls = true)
Expand Down

0 comments on commit dcc9538

Please sign in to comment.