Skip to content

Commit e235eb4

Browse files
committed
Enhance UserRepositoryTests: Add tests for user insertion and selection with privacy settings and mutes
1 parent 93f99ea commit e235eb4

File tree

2 files changed

+202
-7
lines changed

2 files changed

+202
-7
lines changed

stream-chat-android-offline/src/test/java/io/getstream/chat/android/offline/Mother.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ import io.getstream.chat.android.offline.repository.domain.message.internal.Remi
3535
import io.getstream.chat.android.offline.repository.domain.queryChannels.internal.QueryChannelsEntity
3636
import io.getstream.chat.android.offline.repository.domain.reaction.internal.ReactionEntity
3737
import io.getstream.chat.android.offline.repository.domain.threads.internal.ThreadEntity
38+
import io.getstream.chat.android.offline.repository.domain.user.internal.DeliveryReceiptsEntity
3839
import io.getstream.chat.android.offline.repository.domain.user.internal.PrivacySettingsEntity
40+
import io.getstream.chat.android.offline.repository.domain.user.internal.ReadReceiptsEntity
41+
import io.getstream.chat.android.offline.repository.domain.user.internal.TypingIndicatorsEntity
3942
import io.getstream.chat.android.offline.repository.domain.user.internal.UserEntity
4043
import io.getstream.chat.android.offline.repository.domain.user.internal.UserMuteEntity
4144
import io.getstream.chat.android.randomBoolean
@@ -45,6 +48,7 @@ import io.getstream.chat.android.randomDateOrNull
4548
import io.getstream.chat.android.randomDouble
4649
import io.getstream.chat.android.randomInt
4750
import io.getstream.chat.android.randomString
51+
import io.getstream.chat.android.randomStringOrNull
4852
import kotlinx.coroutines.Dispatchers
4953
import kotlinx.coroutines.asExecutor
5054
import java.util.Date
@@ -84,6 +88,30 @@ internal fun randomUserEntity(
8488
extraData = extraData,
8589
)
8690

91+
internal fun randomPrivacySettingsEntity(
92+
typingIndicators: TypingIndicatorsEntity = TypingIndicatorsEntity(enabled = randomBoolean()),
93+
readReceipts: ReadReceiptsEntity = ReadReceiptsEntity(enabled = randomBoolean()),
94+
deliveryReceipts: DeliveryReceiptsEntity = DeliveryReceiptsEntity(enabled = randomBoolean()),
95+
): PrivacySettingsEntity = PrivacySettingsEntity(
96+
typingIndicators = typingIndicators,
97+
readReceipts = readReceipts,
98+
deliveryReceipts = deliveryReceipts,
99+
)
100+
101+
internal fun randomUserMuteEntity(
102+
userId: String? = randomStringOrNull(),
103+
targetId: String? = randomStringOrNull(),
104+
createdAt: Date = randomDate(),
105+
updatedAt: Date = randomDate(),
106+
expires: Date? = randomDateOrNull(),
107+
): UserMuteEntity = UserMuteEntity(
108+
userId = userId,
109+
targetId = targetId,
110+
createdAt = createdAt,
111+
updatedAt = updatedAt,
112+
expires = expires,
113+
)
114+
87115
internal fun randomMessageEntity(
88116
id: String = randomString(),
89117
cid: String = randomCID(),

stream-chat-android-offline/src/test/java/io/getstream/chat/android/offline/repository/UserRepositoryTests.kt

Lines changed: 174 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,29 @@
1717
package io.getstream.chat.android.offline.repository
1818

1919
import app.cash.turbine.test
20+
import io.getstream.chat.android.DeliveryReceipts
21+
import io.getstream.chat.android.PrivacySettings
22+
import io.getstream.chat.android.ReadReceipts
23+
import io.getstream.chat.android.TypingIndicators
2024
import io.getstream.chat.android.client.persistance.repository.UserRepository
25+
import io.getstream.chat.android.models.Mute
2126
import io.getstream.chat.android.models.User
27+
import io.getstream.chat.android.offline.randomPrivacySettingsEntity
28+
import io.getstream.chat.android.offline.randomUserEntity
29+
import io.getstream.chat.android.offline.randomUserMuteEntity
30+
import io.getstream.chat.android.offline.repository.domain.push.internal.toEntity
2231
import io.getstream.chat.android.offline.repository.domain.user.internal.DatabaseUserRepository
32+
import io.getstream.chat.android.offline.repository.domain.user.internal.DeliveryReceiptsEntity
33+
import io.getstream.chat.android.offline.repository.domain.user.internal.PrivacySettingsEntity
34+
import io.getstream.chat.android.offline.repository.domain.user.internal.ReadReceiptsEntity
35+
import io.getstream.chat.android.offline.repository.domain.user.internal.TypingIndicatorsEntity
2336
import io.getstream.chat.android.offline.repository.domain.user.internal.UserDao
37+
import io.getstream.chat.android.offline.repository.domain.user.internal.UserEntity
38+
import io.getstream.chat.android.offline.repository.domain.user.internal.UserMuteEntity
39+
import io.getstream.chat.android.offline.repository.domain.user.internal.toEntity
40+
import io.getstream.chat.android.randomMute
41+
import io.getstream.chat.android.randomPrivacySettings
42+
import io.getstream.chat.android.randomString
2443
import io.getstream.chat.android.randomUser
2544
import io.getstream.chat.android.test.TestCoroutineRule
2645
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -29,13 +48,15 @@ import kotlinx.coroutines.flow.onEach
2948
import kotlinx.coroutines.test.runTest
3049
import org.amshove.kluent.shouldBeEqualTo
3150
import org.junit.Rule
51+
import org.junit.jupiter.api.Assertions.assertEquals
3252
import org.junit.jupiter.api.BeforeEach
3353
import org.junit.jupiter.api.Test
3454
import org.mockito.kotlin.any
35-
import org.mockito.kotlin.argThat
3655
import org.mockito.kotlin.mock
3756
import org.mockito.kotlin.never
57+
import org.mockito.kotlin.times
3858
import org.mockito.kotlin.verify
59+
import org.mockito.kotlin.whenever
3960

4061
@ExperimentalCoroutinesApi
4162
internal class UserRepositoryTests {
@@ -45,7 +66,6 @@ internal class UserRepositoryTests {
4566
private lateinit var sut: UserRepository
4667

4768
private lateinit var userDao: UserDao
48-
private val currentUser: User = randomUser(id = "currentUserId")
4969

5070
@BeforeEach
5171
fun setup() {
@@ -55,11 +75,55 @@ internal class UserRepositoryTests {
5575

5676
@Test
5777
fun `When insert users Should insert to dao`() = runTest {
58-
val users = listOf(randomUser(), randomUser())
78+
val users = listOf(
79+
randomUser(
80+
privacySettings = randomPrivacySettings(),
81+
mutes = List(10) { randomMute() },
82+
),
83+
)
5984

6085
sut.insertUsers(users)
6186

62-
verify(userDao).insertMany(argThat { size == 2 })
87+
val expected = users.map { user ->
88+
UserEntity(
89+
id = user.id,
90+
originalId = user.id,
91+
name = user.name,
92+
image = user.image,
93+
role = user.role,
94+
createdAt = user.createdAt,
95+
updatedAt = user.updatedAt,
96+
lastActive = user.lastActive,
97+
invisible = user.isInvisible,
98+
privacySettings = PrivacySettingsEntity(
99+
typingIndicators = TypingIndicatorsEntity(
100+
enabled = user.privacySettings?.typingIndicators?.enabled ?: false,
101+
),
102+
readReceipts = ReadReceiptsEntity(
103+
enabled = user.privacySettings?.readReceipts?.enabled ?: false,
104+
),
105+
deliveryReceipts = DeliveryReceiptsEntity(
106+
enabled = user.privacySettings?.deliveryReceipts?.enabled ?: false,
107+
),
108+
),
109+
banned = user.isBanned,
110+
mutes = user.mutes.map { mute ->
111+
UserMuteEntity(
112+
userId = mute.user?.id,
113+
targetId = mute.target?.id,
114+
createdAt = mute.createdAt,
115+
updatedAt = mute.updatedAt,
116+
expires = mute.expires,
117+
)
118+
},
119+
teams = user.teams,
120+
teamsRole = user.teamsRole,
121+
extraData = user.extraData,
122+
avgResponseTime = user.avgResponseTime,
123+
pushPreference = user.pushPreference?.toEntity(),
124+
)
125+
}
126+
verify(userDao).insertMany(expected)
63127
}
64128

65129
@Test
@@ -70,12 +134,44 @@ internal class UserRepositoryTests {
70134
}
71135

72136
@Test
73-
fun `When insert me Should insert entity with me id to dao`() = runTest {
74-
val user = randomUser(id = "userId")
137+
fun `When insert current user Should insert entity with me id to dao`() = runTest {
138+
val user = randomUser(
139+
privacySettings = randomPrivacySettings(),
140+
mutes = List(10) { randomMute() },
141+
)
75142

76143
sut.insertCurrentUser(user)
77144

78-
verify(userDao).insert(argThat { id == "me" && originalId == "userId" })
145+
val expected = UserEntity(
146+
id = "me",
147+
originalId = user.id,
148+
name = user.name,
149+
image = user.image,
150+
role = user.role,
151+
createdAt = user.createdAt,
152+
updatedAt = user.updatedAt,
153+
lastActive = user.lastActive,
154+
invisible = user.isInvisible,
155+
privacySettings = PrivacySettingsEntity(
156+
typingIndicators = TypingIndicatorsEntity(
157+
enabled = user.privacySettings?.typingIndicators?.enabled ?: false,
158+
),
159+
readReceipts = ReadReceiptsEntity(
160+
enabled = user.privacySettings?.readReceipts?.enabled ?: false,
161+
),
162+
deliveryReceipts = DeliveryReceiptsEntity(
163+
enabled = user.privacySettings?.deliveryReceipts?.enabled ?: false,
164+
),
165+
),
166+
banned = user.isBanned,
167+
mutes = user.mutes.map(Mute::toEntity),
168+
teams = user.teams,
169+
teamsRole = user.teamsRole,
170+
extraData = user.extraData,
171+
avgResponseTime = user.avgResponseTime,
172+
pushPreference = user.pushPreference?.toEntity(),
173+
)
174+
verify(userDao).insert(expected)
79175
}
80176

81177
@Test
@@ -168,4 +264,75 @@ internal class UserRepositoryTests {
168264
cancelAndConsumeRemainingEvents()
169265
}
170266
}
267+
268+
@Test
269+
fun `When selectUser If user in cache Should return from cache without querying dao`() = runTest {
270+
val user = randomUser(
271+
privacySettings = randomPrivacySettings(),
272+
mutes = List(10) { randomMute() },
273+
)
274+
sut.insertUser(user)
275+
276+
val result = sut.selectUser(user.id)
277+
278+
assertEquals(user, result)
279+
verify(userDao, never()).select(any<String>())
280+
}
281+
282+
@Test
283+
fun `When selectUser If user not in cache but in dao Should query dao and cache result`() = runTest {
284+
val userId = randomString()
285+
val userEntity = randomUserEntity(
286+
id = userId,
287+
originalId = userId,
288+
privacySettings = randomPrivacySettingsEntity(),
289+
mutes = List(10) { randomUserMuteEntity() },
290+
)
291+
whenever(userDao.select(userId)).thenReturn(userEntity)
292+
293+
val result = sut.selectUser(userId)
294+
295+
val expected = User(
296+
id = userEntity.id,
297+
name = userEntity.name,
298+
image = userEntity.image,
299+
role = userEntity.role,
300+
createdAt = userEntity.createdAt,
301+
updatedAt = userEntity.updatedAt,
302+
lastActive = userEntity.lastActive,
303+
invisible = userEntity.invisible,
304+
privacySettings = PrivacySettings(
305+
typingIndicators = TypingIndicators(
306+
enabled = userEntity.privacySettings?.typingIndicators?.enabled ?: false,
307+
),
308+
readReceipts = ReadReceipts(
309+
enabled = userEntity.privacySettings?.readReceipts?.enabled ?: false,
310+
),
311+
deliveryReceipts = DeliveryReceipts(
312+
enabled = userEntity.privacySettings?.deliveryReceipts?.enabled ?: false,
313+
),
314+
),
315+
banned = userEntity.banned,
316+
mutes = userEntity.mutes.map { mute ->
317+
Mute(
318+
user = mute.userId?.let(::User),
319+
target = mute.targetId?.let(::User),
320+
createdAt = mute.createdAt,
321+
updatedAt = mute.updatedAt,
322+
expires = mute.expires,
323+
)
324+
},
325+
teams = userEntity.teams,
326+
teamsRole = userEntity.teamsRole,
327+
avgResponseTime = userEntity.avgResponseTime,
328+
pushPreference = null,
329+
extraData = userEntity.extraData,
330+
)
331+
assertEquals(expected, result)
332+
// Verify it's now in cache - second call should not query dao
333+
val cachedResult = sut.selectUser(userId)
334+
assertEquals(expected, cachedResult)
335+
// Should only query dao once (first call), second call uses cache
336+
verify(userDao, times(1)).select(userId)
337+
}
171338
}

0 commit comments

Comments
 (0)