Unit test for method to get live data of active lives

This commit is contained in:
Maxime NATUREL 2022-06-13 16:32:45 +02:00
parent 752434acb4
commit 7d4df8be09
5 changed files with 184 additions and 13 deletions

View File

@ -16,15 +16,17 @@
package org.matrix.android.sdk.internal.database.mapper package org.matrix.android.sdk.internal.database.mapper
import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import javax.inject.Inject import javax.inject.Inject
internal class LiveLocationShareAggregatedSummaryMapper @Inject constructor() { internal class LiveLocationShareAggregatedSummaryMapper @Inject constructor() :
Monarchy.Mapper<LiveLocationShareAggregatedSummary, LiveLocationShareAggregatedSummaryEntity> {
fun map(entity: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary { override fun map(entity: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary {
return LiveLocationShareAggregatedSummary( return LiveLocationShareAggregatedSummary(
userId = entity.userId, userId = entity.userId,
isActive = entity.isActive, isActive = entity.isActive,

View File

@ -29,7 +29,6 @@ import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationS
import org.matrix.android.sdk.internal.database.query.findRunningLiveInRoom import org.matrix.android.sdk.internal.database.query.findRunningLiveInRoom
import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionDatabase
// TODO add unit tests
internal class DefaultLocationSharingService @AssistedInject constructor( internal class DefaultLocationSharingService @AssistedInject constructor(
@Assisted private val roomId: String, @Assisted private val roomId: String,
@SessionDatabase private val monarchy: Monarchy, @SessionDatabase private val monarchy: Monarchy,
@ -85,7 +84,7 @@ internal class DefaultLocationSharingService @AssistedInject constructor(
override fun getRunningLiveLocationShareSummaries(): LiveData<List<LiveLocationShareAggregatedSummary>> { override fun getRunningLiveLocationShareSummaries(): LiveData<List<LiveLocationShareAggregatedSummary>> {
return monarchy.findAllMappedWithChanges( return monarchy.findAllMappedWithChanges(
{ LiveLocationShareAggregatedSummaryEntity.findRunningLiveInRoom(it, roomId = roomId) }, { LiveLocationShareAggregatedSummaryEntity.findRunningLiveInRoom(it, roomId = roomId) },
{ liveLocationShareAggregatedSummaryMapper.map(it) } liveLocationShareAggregatedSummaryMapper
) )
} }
} }

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.room.location
import io.mockk.mockk
import io.mockk.unmockkAll
import org.amshove.kluent.shouldBeEqualTo
import org.junit.After
import org.junit.Test
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
import org.matrix.android.sdk.internal.database.mapper.LiveLocationShareAggregatedSummaryMapper
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
import org.matrix.android.sdk.test.fakes.FakeMonarchy
import org.matrix.android.sdk.test.fakes.givenEqualTo
import org.matrix.android.sdk.test.fakes.givenIsNotEmpty
import org.matrix.android.sdk.test.fakes.givenIsNotNull
private const val A_ROOM_ID = "room_id"
internal class DefaultLocationSharingServiceTest {
private val fakeRoomId = A_ROOM_ID
private val fakeMonarchy = FakeMonarchy()
private val sendStaticLocationTask = mockk<SendStaticLocationTask>()
private val sendLiveLocationTask = mockk<SendLiveLocationTask>()
private val startLiveLocationShareTask = mockk<StartLiveLocationShareTask>()
private val stopLiveLocationShareTask = mockk<StopLiveLocationShareTask>()
private val fakeLiveLocationShareAggregatedSummaryMapper = mockk<LiveLocationShareAggregatedSummaryMapper>()
private val defaultLocationSharingService = DefaultLocationSharingService(
roomId = fakeRoomId,
monarchy = fakeMonarchy.instance,
sendStaticLocationTask = sendStaticLocationTask,
sendLiveLocationTask = sendLiveLocationTask,
startLiveLocationShareTask = startLiveLocationShareTask,
stopLiveLocationShareTask = stopLiveLocationShareTask,
liveLocationShareAggregatedSummaryMapper = fakeLiveLocationShareAggregatedSummaryMapper
)
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `livedata of live summaries is correctly computed`() {
val entity = LiveLocationShareAggregatedSummaryEntity()
val summary = LiveLocationShareAggregatedSummary(
userId = "",
isActive = true,
endOfLiveTimestampMillis = 123,
lastLocationDataContent = null
)
fakeMonarchy.givenWhere<LiveLocationShareAggregatedSummaryEntity>()
.givenEqualTo(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, fakeRoomId)
.givenEqualTo(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true)
.givenIsNotEmpty(LiveLocationShareAggregatedSummaryEntityFields.USER_ID)
.givenIsNotNull(LiveLocationShareAggregatedSummaryEntityFields.LAST_LOCATION_CONTENT)
fakeMonarchy.givenFindAllMappedWithChangesReturns(
realmEntities = listOf(entity),
mappedResult = listOf(summary),
fakeLiveLocationShareAggregatedSummaryMapper
)
val result = defaultLocationSharingService.getRunningLiveLocationShareSummaries().value
result shouldBeEqualTo listOf(summary)
}
}

View File

@ -16,40 +16,62 @@
package org.matrix.android.sdk.test.fakes package org.matrix.android.sdk.test.fakes
import androidx.lifecycle.MutableLiveData
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.mockk.MockKVerificationScope import io.mockk.MockKVerificationScope
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.verify import io.mockk.slot
import io.realm.Realm import io.realm.Realm
import io.realm.RealmModel import io.realm.RealmModel
import io.realm.RealmQuery import io.realm.RealmQuery
import io.realm.kotlin.where
import org.matrix.android.sdk.internal.util.awaitTransaction import org.matrix.android.sdk.internal.util.awaitTransaction
internal class FakeMonarchy { internal class FakeMonarchy {
val instance = mockk<Monarchy>() val instance = mockk<Monarchy>()
private val realm = mockk<Realm>(relaxed = true) private val fakeRealm = FakeRealm()
init { init {
mockkStatic("org.matrix.android.sdk.internal.util.MonarchyKt") mockkStatic("org.matrix.android.sdk.internal.util.MonarchyKt")
coEvery { coEvery {
instance.awaitTransaction(any<suspend (Realm) -> Any>()) instance.awaitTransaction(any<suspend (Realm) -> Any>())
} coAnswers { } coAnswers {
secondArg<suspend (Realm) -> Any>().invoke(realm) secondArg<suspend (Realm) -> Any>().invoke(fakeRealm.instance)
} }
} }
inline fun <reified T : RealmModel> givenWhereReturns(result: T?) { inline fun <reified T : RealmModel> givenWhere(): RealmQuery<T> {
val queryResult = mockk<RealmQuery<T>>(relaxed = true) return fakeRealm.givenWhere()
every { queryResult.findFirst() } returns result }
every { realm.where<T>() } returns queryResult
inline fun <reified T : RealmModel> givenWhereReturns(result: T?): RealmQuery<T> {
return fakeRealm.givenWhere<T>()
.givenFindFirst(result)
} }
inline fun <reified T : RealmModel> verifyInsertOrUpdate(crossinline verification: MockKVerificationScope.() -> T) { inline fun <reified T : RealmModel> verifyInsertOrUpdate(crossinline verification: MockKVerificationScope.() -> T) {
verify { realm.insertOrUpdate(verification()) } fakeRealm.verifyInsertOrUpdate(verification)
}
inline fun <reified R, reified T : RealmModel> givenFindAllMappedWithChangesReturns(
realmEntities: List<T>,
mappedResult: List<R>,
mapper: Monarchy.Mapper<R, T>
) {
every { mapper.map(any()) } returns mockk()
val monarchyQuery = slot<Monarchy.Query<T>>()
val monarchyMapper = slot<Monarchy.Mapper<R, T>>()
every {
instance.findAllMappedWithChanges(capture(monarchyQuery), capture(monarchyMapper))
} answers {
monarchyQuery.captured.createQuery(fakeRealm.instance)
realmEntities.forEach {
monarchyMapper.captured.map(it)
}
MutableLiveData(mappedResult)
}
} }
} }

View File

@ -16,8 +16,10 @@
package org.matrix.android.sdk.test.fakes package org.matrix.android.sdk.test.fakes
import io.mockk.MockKVerificationScope
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.verify
import io.realm.Realm import io.realm.Realm
import io.realm.RealmModel import io.realm.RealmModel
import io.realm.RealmQuery import io.realm.RealmQuery
@ -33,6 +35,67 @@ internal class FakeRealm {
every { instance.where<T>() } returns query every { instance.where<T>() } returns query
return query return query
} }
inline fun <reified T : RealmModel> verifyInsertOrUpdate(crossinline verification: MockKVerificationScope.() -> T) {
verify { instance.insertOrUpdate(verification()) }
}
}
inline fun <reified T : RealmModel> RealmQuery<T>.givenFindFirst(
result: T?
): RealmQuery<T> {
every { findFirst() } returns result
return this
}
inline fun <reified T : RealmModel> RealmQuery<T>.givenFindAll(
result: List<T>
): RealmQuery<T> {
val realmResults = mockk<RealmResults<T>>()
result.forEachIndexed { index, t ->
every { realmResults[index] } returns t
}
every { realmResults.size } returns result.size
every { findAll() } returns realmResults
return this
}
inline fun <reified T : RealmModel> RealmQuery<T>.givenEqualTo(
fieldName: String,
value: String
): RealmQuery<T> {
every { equalTo(fieldName, value) } returns this
return this
}
inline fun <reified T : RealmModel> RealmQuery<T>.givenEqualTo(
fieldName: String,
value: Boolean
): RealmQuery<T> {
every { equalTo(fieldName, value) } returns this
return this
}
inline fun <reified T : RealmModel> RealmQuery<T>.givenNotEqualTo(
fieldName: String,
value: String
): RealmQuery<T> {
every { notEqualTo(fieldName, value) } returns this
return this
}
inline fun <reified T : RealmModel> RealmQuery<T>.givenIsNotEmpty(
fieldName: String
): RealmQuery<T> {
every { isNotEmpty(fieldName) } returns this
return this
}
inline fun <reified T : RealmModel> RealmQuery<T>.givenIsNotNull(
fieldName: String
): RealmQuery<T> {
every { isNotNull(fieldName) } returns this
return this
} }
inline fun <reified T : RealmModel> RealmQuery<T>.givenFindFirst( inline fun <reified T : RealmModel> RealmQuery<T>.givenFindFirst(