Skip to content

Commit aca0137

Browse files
committed
Decoupled MessageReceiptReporter from ChatClient by passing ChatApi directly to its constructor. This simplifies dependencies and removes the need for ChatClient as an intermediary for API calls.
Updated tests to reflect this change, mocking `ChatApi` instead of `ChatClient`.
1 parent aa09f50 commit aca0137

File tree

9 files changed

+46
-41
lines changed

9 files changed

+46
-41
lines changed

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ internal constructor(
281281
public val audioPlayer: AudioPlayer,
282282
private val now: () -> Date = ::Date,
283283
private val repository: ChatClientRepository,
284+
private val messageReceiptReporter: MessageReceiptReporter,
284285
) {
285286
private val logger by taggedLogger(TAG)
286287
private val waitConnection = MutableSharedFlow<Result<ConnectionData>>()
@@ -340,12 +341,6 @@ internal constructor(
340341
messageReceiptRepository = repository,
341342
)
342343

343-
private val messageReceiptReporter = MessageReceiptReporter(
344-
scope = userScope,
345-
chatClient = this,
346-
messageReceiptRepository = repository,
347-
)
348-
349344
private var pushNotificationReceivedListener: PushNotificationReceivedListener =
350345
PushNotificationReceivedListener { _, _ -> }
351346

@@ -4756,7 +4751,8 @@ internal constructor(
47564751
appVersion = this.appVersion,
47574752
)
47584753

4759-
val appSettingsManager = AppSettingManager(module.api())
4754+
val api = module.api()
4755+
val appSettingsManager = AppSettingManager(api)
47604756

47614757
val audioPlayer: AudioPlayer = StreamMediaPlayer(
47624758
mediaPlayer = NativeMediaPlayerImpl {
@@ -4772,10 +4768,11 @@ internal constructor(
47724768
)
47734769

47744770
val database = ChatClientDatabase.build(appContext)
4771+
val repository = ChatClientRepository.from(database)
47754772

47764773
return ChatClient(
47774774
config = config,
4778-
api = module.api(),
4775+
api = api,
47794776
dtoMapping = module.dtoMapping,
47804777
notifications = module.notifications(),
47814778
tokenManager = tokenManager,
@@ -4796,7 +4793,12 @@ internal constructor(
47964793
mutableClientState = MutableClientState(module.networkStateProvider),
47974794
currentUserFetcher = module.currentUserFetcher,
47984795
audioPlayer = audioPlayer,
4799-
repository = ChatClientRepository.from(database),
4796+
repository = repository,
4797+
messageReceiptReporter = MessageReceiptReporter(
4798+
scope = userScope,
4799+
messageReceiptRepository = repository,
4800+
api = api,
4801+
),
48004802
).apply {
48014803
attachmentsSender = AttachmentsSender(
48024804
context = appContext,

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/receipts/MessageReceiptReporter.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package io.getstream.chat.android.client.receipts
1818

19-
import io.getstream.chat.android.client.ChatClient
19+
import io.getstream.chat.android.client.api.ChatApi
2020
import io.getstream.chat.android.client.persistence.repository.MessageReceiptRepository
2121
import io.getstream.chat.android.models.Message
2222
import io.getstream.log.taggedLogger
@@ -32,8 +32,8 @@ import kotlinx.coroutines.launch
3232
*/
3333
internal class MessageReceiptReporter(
3434
private val scope: CoroutineScope,
35-
private val chatClient: ChatClient,
3635
private val messageReceiptRepository: MessageReceiptRepository,
36+
private val api: ChatApi,
3737
) {
3838

3939
private val logger by taggedLogger("Chat:MessageReceiptReporter")
@@ -55,7 +55,7 @@ internal class MessageReceiptReporter(
5555

5656
if (messages.isNotEmpty()) {
5757
logger.d { "Reporting delivery receipts for ${messages.size} messages…" }
58-
chatClient.markMessagesAsDelivered(messages)
58+
api.markDelivered(messages)
5959
.execute()
6060
.onSuccessSuspend {
6161
logger.d { "Successfully reported delivery receipts for ${messages.size} messages" }

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/ChatClientConnectionTests.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import io.getstream.chat.android.client.events.ErrorEvent
2626
import io.getstream.chat.android.client.network.NetworkStateProvider
2727
import io.getstream.chat.android.client.parser2.adapters.internal.StreamDateFormatter
2828
import io.getstream.chat.android.client.persistance.repository.noop.NoOpRepositoryFactory
29-
import io.getstream.chat.android.client.persistence.repository.ChatClientRepository
3029
import io.getstream.chat.android.client.scope.ClientTestScope
3130
import io.getstream.chat.android.client.scope.UserTestScope
3231
import io.getstream.chat.android.client.setup.state.internal.MutableClientState
@@ -60,7 +59,6 @@ import org.amshove.kluent.shouldBeInstanceOf
6059
import org.junit.jupiter.api.BeforeEach
6160
import org.junit.jupiter.api.Test
6261
import org.junit.jupiter.api.extension.RegisterExtension
63-
import org.mockito.kotlin.any
6462
import org.mockito.kotlin.doReturn
6563
import org.mockito.kotlin.eq
6664
import org.mockito.kotlin.mock
@@ -114,9 +112,6 @@ internal class ChatClientConnectionTests {
114112
tokenManager = tokenManager,
115113
networkStateProvider = networkStateProvider,
116114
)
117-
val mockRepository = mock<ChatClientRepository> {
118-
onBlocking { getAllMessageReceiptsByType(type = any(), limit = any()) } doReturn emptyList()
119-
}
120115
client = ChatClient(
121116
config = config,
122117
api = chatApi,
@@ -136,7 +131,8 @@ internal class ChatClientConnectionTests {
136131
mutableClientState = mutableClientState,
137132
currentUserFetcher = mock(),
138133
audioPlayer = mock(),
139-
repository = mockRepository,
134+
repository = mock(),
135+
messageReceiptReporter = mock(),
140136
).apply {
141137
attachmentsSender = mock()
142138
}

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/ChatClientTest.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,6 @@ internal class ChatClientTest {
134134
wssUrl = wssUrl,
135135
networkStateProvider = networkStateProvider,
136136
)
137-
val mockRepository = mock<ChatClientRepository> {
138-
onBlocking { getAllMessageReceiptsByType(type = any(), limit = any()) } doReturn emptyList()
139-
}
140137
client = ChatClient(
141138
config = config,
142139
api = api,
@@ -156,7 +153,8 @@ internal class ChatClientTest {
156153
repositoryFactoryProvider = NoOpRepositoryFactory.Provider,
157154
currentUserFetcher = mock(),
158155
audioPlayer = mock(),
159-
repository = mockRepository,
156+
repository = mock(),
157+
messageReceiptReporter = mock(),
160158
).apply {
161159
attachmentsSender = mock()
162160
connectUser(user, token).enqueue()

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/DependencyResolverTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ public class DependencyResolverTest {
180180
currentUserFetcher = mock(),
181181
audioPlayer = mock(),
182182
repository = mock(),
183+
messageReceiptReporter = mock(),
183184
).apply {
184185
this.plugins = this@Fixture.plugins
185186
}

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/MockClientBuilder.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ internal class MockClientBuilder(
127127
currentUserFetcher = mock(),
128128
audioPlayer = streamPlayer,
129129
repository = mock(),
130+
messageReceiptReporter = mock(),
130131
)
131132

132133
client.attachmentsSender = attachmentSender

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/chatclient/BaseChatClientTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ internal open class BaseChatClientTest {
129129
audioPlayer = mock(),
130130
now = { now },
131131
repository = mock(),
132+
messageReceiptReporter = mock(),
132133
)
133134
chatClient.attachmentsSender = attachmentsSender
134135
chatClient.plugins = plugins

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/debugger/ChatClientDebuggerTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ internal class ChatClientDebuggerTest {
148148
currentUserFetcher = mock(),
149149
audioPlayer = mock(),
150150
repository = mockRepository,
151+
messageReceiptReporter = mock(),
151152
).apply {
152153
attachmentsSender = this@ChatClientDebuggerTest.attachmentsSender
153154
connectUser(user, token).enqueue()

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/receipts/MessageReceiptReporterTest.kt

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package io.getstream.chat.android.client.receipts
1818

19-
import io.getstream.chat.android.client.ChatClient
19+
import io.getstream.chat.android.client.api.ChatApi
2020
import io.getstream.chat.android.client.persistence.repository.MessageReceiptRepository
2121
import io.getstream.chat.android.client.randomMessageReceipt
2222
import io.getstream.chat.android.models.Message
@@ -56,13 +56,13 @@ internal class MessageReceiptReporterTest {
5656
}
5757
val fixture = Fixture()
5858
.givenMessageReceipts(receipts)
59-
.givenMarkMessagesAsDelivered(messages)
59+
.givenMarkDelivered(messages)
6060
val sut = fixture.get(backgroundScope)
6161

6262
sut.start()
6363
advanceTimeBy(100) // Allow initial execution
6464

65-
fixture.verifyMarkMessagesAsDeliveredCalled(messages = messages)
65+
fixture.verifyMarkDeliveredCalled(messages = messages)
6666
val messageIds = messages.map(Message::id)
6767
fixture.verifyDeleteByMessageIdsCalled(messageIds = messageIds)
6868
}
@@ -72,7 +72,7 @@ internal class MessageReceiptReporterTest {
7272
val fixture = Fixture()
7373
.givenMessageReceipts(listOf(randomMessageReceipt()))
7474
// Simulate an error when marking messages as delivered
75-
.givenMarkMessagesAsDelivered(error = mock())
75+
.givenMarkDelivered(error = mock())
7676
val sut = fixture.get(backgroundScope)
7777

7878
sut.start()
@@ -81,10 +81,10 @@ internal class MessageReceiptReporterTest {
8181
fixture.verifyDeleteByMessageIdsCalled(never())
8282

8383
// Keep processing in the next time window
84-
fixture.givenMarkMessagesAsDelivered()
84+
fixture.givenMarkDelivered()
8585
advanceTimeBy(1000)
8686

87-
fixture.verifyMarkMessagesAsDeliveredCalled(times(2))
87+
fixture.verifyMarkDeliveredCalled(times(2))
8888
fixture.verifyDeleteByMessageIdsCalled()
8989
}
9090

@@ -97,15 +97,15 @@ internal class MessageReceiptReporterTest {
9797
sut.start()
9898
advanceTimeBy(100) // Allow initial execution
9999

100-
fixture.verifyMarkMessagesAsDeliveredCalled(never())
100+
fixture.verifyMarkDeliveredCalled(never())
101101
fixture.verifyDeleteByMessageIdsCalled(never())
102102
}
103103

104104
@Test
105105
fun `should execute periodically with correct delay`() = runTest {
106106
val fixture = Fixture()
107107
.givenMessageReceipts(listOf(randomMessageReceipt()))
108-
.givenMarkMessagesAsDelivered()
108+
.givenMarkDelivered()
109109
val sut = fixture.get(backgroundScope)
110110

111111
sut.start()
@@ -117,14 +117,14 @@ internal class MessageReceiptReporterTest {
117117

118118
advanceTimeBy(1000) // Advance to the fourth interval
119119

120-
fixture.verifyMarkMessagesAsDeliveredCalled(times(4))
120+
fixture.verifyMarkDeliveredCalled(times(4))
121121
}
122122

123123
@Test
124124
fun `should stop execution when coroutine scope is cancelled`() = runTest {
125125
val fixture = Fixture()
126126
.givenMessageReceipts(listOf(randomMessageReceipt()))
127-
.givenMarkMessagesAsDelivered()
127+
.givenMarkDelivered()
128128
val sut = fixture.get(backgroundScope)
129129

130130
sut.start()
@@ -134,13 +134,12 @@ internal class MessageReceiptReporterTest {
134134

135135
advanceTimeBy(1000) // Try to advance time after cancellation
136136

137-
fixture.verifyMarkMessagesAsDeliveredCalled(times(1))
137+
fixture.verifyMarkDeliveredCalled(times(1))
138138
}
139139

140140
private class Fixture {
141-
private val mockChatClient = mock<ChatClient>()
142-
143141
private val mockMessageReceiptRepository = mock<MessageReceiptRepository>()
142+
private val mockApi = mock<ChatApi>()
144143

145144
fun givenMessageReceipts(receipts: List<MessageReceipt>) = apply {
146145
wheneverBlocking {
@@ -151,25 +150,31 @@ internal class MessageReceiptReporterTest {
151150
} doReturn receipts
152151
}
153152

154-
fun givenMarkMessagesAsDelivered(messages: List<Message>? = null, error: Error? = null) = apply {
155-
whenever(mockChatClient.markMessagesAsDelivered(messages ?: any())) doReturn
153+
fun givenMarkDelivered(messages: List<Message>? = null, error: Error? = null) = apply {
154+
whenever(mockApi.markDelivered(messages ?: any())) doReturn
156155
(error?.asCall() ?: Unit.asCall())
157156
}
158157

159-
fun verifyMarkMessagesAsDeliveredCalled(mode: VerificationMode = times(1), messages: List<Message>? = null) {
160-
verify(mockChatClient, mode).markMessagesAsDelivered(messages ?: any())
158+
fun verifyMarkDeliveredCalled(
159+
mode: VerificationMode = times(1),
160+
messages: List<Message>? = null,
161+
) {
162+
verify(mockApi, mode).markDelivered(messages ?: any())
161163
}
162164

163-
fun verifyDeleteByMessageIdsCalled(mode: VerificationMode = times(1), messageIds: List<String>? = null) {
165+
fun verifyDeleteByMessageIdsCalled(
166+
mode: VerificationMode = times(1),
167+
messageIds: List<String>? = null,
168+
) {
164169
verifyBlocking(mockMessageReceiptRepository, mode) {
165170
deleteMessageReceiptsByMessageIds(messageIds ?: any())
166171
}
167172
}
168173

169174
fun get(scope: CoroutineScope) = MessageReceiptReporter(
170175
scope = scope,
171-
chatClient = mockChatClient,
172176
messageReceiptRepository = mockMessageReceiptRepository,
177+
api = mockApi,
173178
)
174179
}
175180
}

0 commit comments

Comments
 (0)