Move all database queries off the ui thread & add a ViewModel for MainActivity (#4786)
- Move all database queries off the ui thread - this is a massive performance improvement - ViewModel for MainActivity - this makes MainActivity smaller and network requests won't be retried when rotating the screen - removes the Push Notification Migration feature. We had it long enough, all users who want push notifications should be migrated by now - AccountEntity is now immutable - converted BaseActivity to Kotlin - The header image of Accounts is now cached as well
This commit is contained in:
parent
d93ec6822b
commit
9e597800c9
47 changed files with 2421 additions and 1127 deletions
|
|
@ -3,7 +3,10 @@ package com.keylesspalace.tusky
|
|||
import android.app.Activity
|
||||
import android.app.NotificationManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
|
|
@ -12,13 +15,15 @@ import at.connyduck.calladapter.networkresult.NetworkResult
|
|||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.components.accountlist.AccountListActivity
|
||||
import com.keylesspalace.tusky.components.systemnotifications.NotificationHelper
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.db.entity.AccountEntity
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.entity.Notification
|
||||
import com.keylesspalace.tusky.entity.TimelineAccount
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.util.getSerializableExtraCompat
|
||||
import java.util.Date
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
|
|
@ -128,17 +133,20 @@ class MainActivityTest {
|
|||
private fun startMainActivity(intent: Intent): Activity {
|
||||
val controller = Robolectric.buildActivity(MainActivity::class.java, intent)
|
||||
val activity = controller.get()
|
||||
activity.eventHub = EventHub()
|
||||
activity.accountManager = mock {
|
||||
val eventHub = EventHub()
|
||||
activity.eventHub = eventHub
|
||||
val accountManager: AccountManager = mock {
|
||||
on { accounts } doReturn listOf(accountEntity)
|
||||
on { accountsFlow } doReturn MutableStateFlow(listOf(accountEntity))
|
||||
on { activeAccount } doReturn accountEntity
|
||||
}
|
||||
activity.draftsAlert = mock {}
|
||||
activity.shareShortcutHelper = mock {}
|
||||
activity.externalScope = TestScope()
|
||||
activity.mastodonApi = mock {
|
||||
activity.accountManager = accountManager
|
||||
activity.draftsAlert = mock { }
|
||||
val api: MastodonApi = mock {
|
||||
onBlocking { accountVerifyCredentials() } doReturn NetworkResult.success(account)
|
||||
onBlocking { announcements() } doReturn NetworkResult.success(emptyList())
|
||||
}
|
||||
activity.mastodonApi = api
|
||||
activity.preferences = mock(defaultAnswer = {
|
||||
when (it.method.returnType) {
|
||||
String::class.java -> "test"
|
||||
|
|
@ -146,6 +154,20 @@ class MainActivityTest {
|
|||
else -> null
|
||||
}
|
||||
})
|
||||
val viewModel = MainViewModel(
|
||||
context = mock {
|
||||
on { getSystemService(Context.NOTIFICATION_SERVICE) } doReturn mock<NotificationManager>()
|
||||
},
|
||||
api = api,
|
||||
eventHub = eventHub,
|
||||
accountManager = accountManager,
|
||||
shareShortcutHelper = mock()
|
||||
)
|
||||
val testViewModelFactory = viewModelFactory {
|
||||
initializer { viewModel }
|
||||
}
|
||||
activity.viewModelProviderFactory = testViewModelFactory
|
||||
|
||||
controller.create().start()
|
||||
return activity
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import com.squareup.moshi.adapter
|
|||
import java.util.Locale
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import okhttp3.ResponseBody
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
import org.junit.Assert.assertEquals
|
||||
|
|
@ -108,6 +109,8 @@ class ComposeActivityTest {
|
|||
activity = controller.get()
|
||||
|
||||
accountManagerMock = mock {
|
||||
on { accounts } doReturn listOf(account)
|
||||
on { accountsFlow } doReturn MutableStateFlow(listOf(account))
|
||||
on { activeAccount } doReturn account
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.keylesspalace.tusky.db.entity.NotificationDataEntity
|
|||
import com.keylesspalace.tusky.di.NetworkModule
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
import org.junit.After
|
||||
|
|
@ -42,15 +43,18 @@ import retrofit2.Response
|
|||
@RunWith(AndroidJUnit4::class)
|
||||
class NotificationsRemoteMediatorTest {
|
||||
|
||||
private val account = AccountEntity(
|
||||
id = 1,
|
||||
domain = "mastodon.example",
|
||||
accessToken = "token",
|
||||
clientId = "id",
|
||||
clientSecret = "secret",
|
||||
isActive = true
|
||||
)
|
||||
|
||||
private val accountManager: AccountManager = mock {
|
||||
on { activeAccount } doReturn AccountEntity(
|
||||
id = 1,
|
||||
domain = "mastodon.example",
|
||||
accessToken = "token",
|
||||
clientId = "id",
|
||||
clientSecret = "secret",
|
||||
isActive = true
|
||||
)
|
||||
on { activeAccount } doReturn account
|
||||
on { accountsFlow } doReturn MutableStateFlow(listOf(account))
|
||||
}
|
||||
|
||||
private lateinit var db: AppDatabase
|
||||
|
|
@ -78,12 +82,12 @@ class NotificationsRemoteMediatorTest {
|
|||
@ExperimentalPagingApi
|
||||
fun `should return error when network call returns error code`() = runTest {
|
||||
val remoteMediator = NotificationsRemoteMediator(
|
||||
viewModel = mockViewModel(),
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
onBlocking { notifications(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doReturn Response.error(500, "".toResponseBody())
|
||||
},
|
||||
db = db,
|
||||
excludes = emptySet()
|
||||
db = db
|
||||
)
|
||||
|
||||
val result = remoteMediator.load(LoadType.REFRESH, state())
|
||||
|
|
@ -97,12 +101,12 @@ class NotificationsRemoteMediatorTest {
|
|||
@ExperimentalPagingApi
|
||||
fun `should return error when network call fails`() = runTest {
|
||||
val remoteMediator = NotificationsRemoteMediator(
|
||||
viewModel = mockViewModel(),
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
onBlocking { notifications(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doThrow IOException()
|
||||
},
|
||||
db = db,
|
||||
excludes = emptySet()
|
||||
db = db
|
||||
)
|
||||
|
||||
val result = remoteMediator.load(LoadType.REFRESH, state())
|
||||
|
|
@ -115,10 +119,10 @@ class NotificationsRemoteMediatorTest {
|
|||
@ExperimentalPagingApi
|
||||
fun `should not prepend notifications`() = runTest {
|
||||
val remoteMediator = NotificationsRemoteMediator(
|
||||
viewModel = mockViewModel(),
|
||||
accountManager = accountManager,
|
||||
api = mock(),
|
||||
db = db,
|
||||
excludes = emptySet()
|
||||
db = db
|
||||
)
|
||||
|
||||
val state = state(
|
||||
|
|
@ -151,6 +155,7 @@ class NotificationsRemoteMediatorTest {
|
|||
db.insert(notificationsAlreadyInDb)
|
||||
|
||||
val remoteMediator = NotificationsRemoteMediator(
|
||||
viewModel = mockViewModel(),
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
onBlocking { notifications(limit = 3, excludes = emptySet()) } doReturn Response.success(
|
||||
|
|
@ -168,8 +173,7 @@ class NotificationsRemoteMediatorTest {
|
|||
)
|
||||
)
|
||||
},
|
||||
db = db,
|
||||
excludes = emptySet()
|
||||
db = db
|
||||
)
|
||||
|
||||
val state = state(
|
||||
|
|
@ -212,6 +216,7 @@ class NotificationsRemoteMediatorTest {
|
|||
db.insert(notificationsAlreadyInDb)
|
||||
|
||||
val remoteMediator = NotificationsRemoteMediator(
|
||||
viewModel = mockViewModel(),
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
onBlocking { notifications(limit = 20, excludes = emptySet()) } doReturn Response.success(
|
||||
|
|
@ -239,8 +244,7 @@ class NotificationsRemoteMediatorTest {
|
|||
)
|
||||
)
|
||||
},
|
||||
db = db,
|
||||
excludes = emptySet()
|
||||
db = db
|
||||
)
|
||||
|
||||
val state = state(
|
||||
|
|
@ -288,6 +292,7 @@ class NotificationsRemoteMediatorTest {
|
|||
db.insert(notificationsAlreadyInDb)
|
||||
|
||||
val remoteMediator = NotificationsRemoteMediator(
|
||||
viewModel = mockViewModel(),
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
onBlocking { notifications(limit = 3, excludes = emptySet()) } doReturn Response.success(
|
||||
|
|
@ -305,8 +310,7 @@ class NotificationsRemoteMediatorTest {
|
|||
)
|
||||
)
|
||||
},
|
||||
db = db,
|
||||
excludes = emptySet()
|
||||
db = db
|
||||
)
|
||||
|
||||
val state = state(
|
||||
|
|
@ -340,6 +344,7 @@ class NotificationsRemoteMediatorTest {
|
|||
@ExperimentalPagingApi
|
||||
fun `should not try to refresh already cached notifications when db is empty`() = runTest {
|
||||
val remoteMediator = NotificationsRemoteMediator(
|
||||
viewModel = mockViewModel(),
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
onBlocking { notifications(limit = 20, excludes = emptySet()) } doReturn Response.success(
|
||||
|
|
@ -350,8 +355,7 @@ class NotificationsRemoteMediatorTest {
|
|||
)
|
||||
)
|
||||
},
|
||||
db = db,
|
||||
excludes = emptySet()
|
||||
db = db
|
||||
)
|
||||
|
||||
val state = state(
|
||||
|
|
@ -393,6 +397,7 @@ class NotificationsRemoteMediatorTest {
|
|||
db.timelineStatusDao().setContentCollapsed(1, "1", false)
|
||||
|
||||
val remoteMediator = NotificationsRemoteMediator(
|
||||
viewModel = mockViewModel(),
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
onBlocking { notifications(limit = 20, excludes = emptySet()) } doReturn Response.success(emptyList())
|
||||
|
|
@ -404,8 +409,7 @@ class NotificationsRemoteMediatorTest {
|
|||
)
|
||||
)
|
||||
},
|
||||
db = db,
|
||||
excludes = emptySet()
|
||||
db = db
|
||||
)
|
||||
|
||||
val state = state(
|
||||
|
|
@ -449,6 +453,7 @@ class NotificationsRemoteMediatorTest {
|
|||
db.notificationsDao().insertNotification(placeholder)
|
||||
|
||||
val remoteMediator = NotificationsRemoteMediator(
|
||||
viewModel = mockViewModel(),
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
onBlocking { notifications(sinceId = "6", limit = 20, excludes = emptySet()) } doReturn Response.success(
|
||||
|
|
@ -465,8 +470,7 @@ class NotificationsRemoteMediatorTest {
|
|||
)
|
||||
)
|
||||
},
|
||||
db = db,
|
||||
excludes = emptySet()
|
||||
db = db
|
||||
)
|
||||
|
||||
val state = state(
|
||||
|
|
@ -507,6 +511,7 @@ class NotificationsRemoteMediatorTest {
|
|||
db.insert(notificationsAlreadyInDb)
|
||||
|
||||
val remoteMediator = NotificationsRemoteMediator(
|
||||
viewModel = mockViewModel(),
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
onBlocking { notifications(maxId = "5", limit = 20, excludes = emptySet()) } doReturn Response.success(
|
||||
|
|
@ -517,8 +522,7 @@ class NotificationsRemoteMediatorTest {
|
|||
)
|
||||
)
|
||||
},
|
||||
db = db,
|
||||
excludes = emptySet()
|
||||
db = db
|
||||
)
|
||||
|
||||
val state = state(
|
||||
|
|
@ -558,4 +562,11 @@ class NotificationsRemoteMediatorTest {
|
|||
),
|
||||
leadingPlaceholderCount = 0
|
||||
)
|
||||
|
||||
private fun mockViewModel(): NotificationsViewModel {
|
||||
return mock {
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
on { excludes } doReturn MutableStateFlow(emptySet())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import androidx.room.Room
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.keylesspalace.tusky.components.timeline.viewmodel.CachedTimelineRemoteMediator
|
||||
import com.keylesspalace.tusky.components.timeline.viewmodel.CachedTimelineViewModel
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.db.AppDatabase
|
||||
import com.keylesspalace.tusky.db.Converters
|
||||
|
|
@ -19,6 +20,7 @@ import com.keylesspalace.tusky.db.entity.HomeTimelineData
|
|||
import com.keylesspalace.tusky.di.NetworkModule
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
import org.junit.After
|
||||
|
|
@ -41,17 +43,6 @@ import retrofit2.Response
|
|||
@RunWith(AndroidJUnit4::class)
|
||||
class CachedTimelineRemoteMediatorTest {
|
||||
|
||||
private val accountManager: AccountManager = mock {
|
||||
on { activeAccount } doReturn AccountEntity(
|
||||
id = 1,
|
||||
domain = "mastodon.example",
|
||||
accessToken = "token",
|
||||
clientId = "id",
|
||||
clientSecret = "secret",
|
||||
isActive = true
|
||||
)
|
||||
}
|
||||
|
||||
private lateinit var db: AppDatabase
|
||||
|
||||
private val moshi = NetworkModule.providesMoshi()
|
||||
|
|
@ -77,7 +68,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
@ExperimentalPagingApi
|
||||
fun `should return error when network call returns error code`() = runTest {
|
||||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
viewModel = mockViewModel(),
|
||||
api = mock {
|
||||
onBlocking { homeTimeline(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doReturn Response.error(500, "".toResponseBody())
|
||||
},
|
||||
|
|
@ -95,7 +86,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
@ExperimentalPagingApi
|
||||
fun `should return error when network call fails`() = runTest {
|
||||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
viewModel = mockViewModel(),
|
||||
api = mock {
|
||||
onBlocking { homeTimeline(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doThrow IOException()
|
||||
},
|
||||
|
|
@ -112,7 +103,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
@ExperimentalPagingApi
|
||||
fun `should not prepend statuses`() = runTest {
|
||||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
viewModel = mockViewModel(),
|
||||
api = mock(),
|
||||
db = db,
|
||||
)
|
||||
|
|
@ -147,7 +138,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
db.insert(statusesAlreadyInDb)
|
||||
|
||||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
viewModel = mockViewModel(),
|
||||
api = mock {
|
||||
onBlocking { homeTimeline(limit = 3) } doReturn Response.success(
|
||||
listOf(
|
||||
|
|
@ -207,7 +198,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
db.insert(statusesAlreadyInDb)
|
||||
|
||||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
viewModel = mockViewModel(),
|
||||
api = mock {
|
||||
onBlocking { homeTimeline(limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
|
|
@ -266,7 +257,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
db.insert(statusesAlreadyInDb)
|
||||
|
||||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
viewModel = mockViewModel(),
|
||||
api = mock {
|
||||
onBlocking { homeTimeline(limit = 3) } doReturn Response.success(
|
||||
listOf(
|
||||
|
|
@ -317,7 +308,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
@ExperimentalPagingApi
|
||||
fun `should not try to refresh already cached statuses when db is empty`() = runTest {
|
||||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
viewModel = mockViewModel(),
|
||||
api = mock {
|
||||
onBlocking { homeTimeline(limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
|
|
@ -366,7 +357,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
db.insert(statusesAlreadyInDb)
|
||||
|
||||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
viewModel = mockViewModel(),
|
||||
api = mock {
|
||||
onBlocking { homeTimeline(limit = 20) } doReturn Response.success(emptyList())
|
||||
|
||||
|
|
@ -416,7 +407,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
db.insert(statusesAlreadyInDb)
|
||||
|
||||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
viewModel = mockViewModel(),
|
||||
api = mock {
|
||||
onBlocking { homeTimeline(sinceId = "6", limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
|
|
@ -473,7 +464,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
db.insert(statusesAlreadyInDb)
|
||||
|
||||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
viewModel = mockViewModel(),
|
||||
api = mock {
|
||||
onBlocking { homeTimeline(maxId = "5", limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
|
|
@ -523,4 +514,23 @@ class CachedTimelineRemoteMediatorTest {
|
|||
),
|
||||
leadingPlaceholderCount = 0
|
||||
)
|
||||
|
||||
private fun mockViewModel(): CachedTimelineViewModel {
|
||||
val account = AccountEntity(
|
||||
id = 1,
|
||||
domain = "mastodon.example",
|
||||
accessToken = "token",
|
||||
clientId = "id",
|
||||
clientSecret = "secret",
|
||||
isActive = true
|
||||
)
|
||||
val accManager: AccountManager = mock {
|
||||
on { activeAccount } doReturn account
|
||||
on { accountsFlow } doReturn MutableStateFlow(listOf(account))
|
||||
}
|
||||
return mock {
|
||||
on { accountManager } doReturn accManager
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import com.keylesspalace.tusky.db.AccountManager
|
|||
import com.keylesspalace.tusky.db.entity.AccountEntity
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okhttp3.Headers
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
|
|
@ -34,15 +35,17 @@ import retrofit2.Response
|
|||
@RunWith(AndroidJUnit4::class)
|
||||
class NetworkTimelineRemoteMediatorTest {
|
||||
|
||||
private val account = AccountEntity(
|
||||
id = 1,
|
||||
domain = "mastodon.example",
|
||||
accessToken = "token",
|
||||
clientId = "id",
|
||||
clientSecret = "secret",
|
||||
isActive = true
|
||||
)
|
||||
|
||||
private val accountManager: AccountManager = mock {
|
||||
on { activeAccount } doReturn AccountEntity(
|
||||
id = 1,
|
||||
domain = "mastodon.example",
|
||||
accessToken = "token",
|
||||
clientId = "id",
|
||||
clientSecret = "secret",
|
||||
isActive = true
|
||||
)
|
||||
on { activeAccount } doReturn account
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -53,7 +56,7 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
onBlocking { fetchStatusesForKind(anyOrNull(), anyOrNull(), anyOrNull()) } doReturn Response.error(500, "".toResponseBody())
|
||||
}
|
||||
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(accountManager, timelineViewModel)
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(timelineViewModel)
|
||||
|
||||
val result = remoteMediator.load(LoadType.REFRESH, state())
|
||||
|
||||
|
|
@ -66,11 +69,13 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
@ExperimentalPagingApi
|
||||
fun `should return error when network call fails`() = runTest {
|
||||
val timelineViewModel: NetworkTimelineViewModel = mock {
|
||||
on { accountManager } doReturn accountManager
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
on { statusData } doReturn mutableListOf()
|
||||
onBlocking { fetchStatusesForKind(anyOrNull(), anyOrNull(), anyOrNull()) } doThrow IOException()
|
||||
}
|
||||
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(accountManager, timelineViewModel)
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(timelineViewModel)
|
||||
|
||||
val result = remoteMediator.load(LoadType.REFRESH, state())
|
||||
|
||||
|
|
@ -84,6 +89,9 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
val statuses: MutableList<StatusViewData> = mutableListOf()
|
||||
|
||||
val timelineViewModel: NetworkTimelineViewModel = mock {
|
||||
on { accountManager } doReturn accountManager
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
on { statusData } doReturn statuses
|
||||
on { nextKey } doReturn null
|
||||
onBlocking { fetchStatusesForKind(null, null, 20) } doReturn Response.success(
|
||||
|
|
@ -99,7 +107,7 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
}
|
||||
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(accountManager, timelineViewModel)
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(timelineViewModel)
|
||||
|
||||
val state = state(
|
||||
listOf(
|
||||
|
|
@ -135,6 +143,8 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
|
||||
val timelineViewModel: NetworkTimelineViewModel = mock {
|
||||
on { accountManager } doReturn accountManager
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
on { statusData } doReturn statuses
|
||||
on { nextKey } doReturn "0"
|
||||
onBlocking { fetchStatusesForKind(null, null, 20) } doReturn Response.success(
|
||||
|
|
@ -146,7 +156,7 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
}
|
||||
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(accountManager, timelineViewModel)
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(timelineViewModel)
|
||||
|
||||
val state = state(
|
||||
listOf(
|
||||
|
|
@ -187,6 +197,8 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
|
||||
val timelineViewModel: NetworkTimelineViewModel = mock {
|
||||
on { accountManager } doReturn accountManager
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
on { statusData } doReturn statuses
|
||||
on { nextKey } doReturn "0"
|
||||
onBlocking { fetchStatusesForKind(null, null, 20) } doReturn Response.success(
|
||||
|
|
@ -198,7 +210,7 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
}
|
||||
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(accountManager, timelineViewModel)
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(timelineViewModel)
|
||||
|
||||
val state = state(
|
||||
listOf(
|
||||
|
|
@ -240,6 +252,8 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
|
||||
val timelineViewModel: NetworkTimelineViewModel = mock {
|
||||
on { accountManager } doReturn accountManager
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
on { statusData } doReturn statuses
|
||||
on { nextKey } doReturn "3"
|
||||
onBlocking { fetchStatusesForKind("3", null, 20) } doReturn Response.success(
|
||||
|
|
@ -251,7 +265,7 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
}
|
||||
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(accountManager, timelineViewModel)
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(timelineViewModel)
|
||||
|
||||
val state = state(
|
||||
listOf(
|
||||
|
|
@ -293,6 +307,8 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
|
||||
val timelineViewModel: NetworkTimelineViewModel = mock {
|
||||
on { accountManager } doReturn accountManager
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
on { statusData } doReturn statuses
|
||||
on { nextKey } doReturn "3"
|
||||
onBlocking { fetchStatusesForKind("3", null, 20) } doReturn Response.success(
|
||||
|
|
@ -308,7 +324,7 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
}
|
||||
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(accountManager, timelineViewModel)
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(timelineViewModel)
|
||||
|
||||
val state = state(
|
||||
listOf(
|
||||
|
|
@ -350,11 +366,13 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
|
||||
val timelineViewModel: NetworkTimelineViewModel = mock {
|
||||
on { accountManager } doReturn accountManager
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
on { statusData } doReturn statuses
|
||||
on { nextKey } doReturn null
|
||||
}
|
||||
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(accountManager, timelineViewModel)
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(timelineViewModel)
|
||||
|
||||
val state = state(
|
||||
listOf(
|
||||
|
|
@ -393,6 +411,8 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
|
||||
val timelineViewModel: NetworkTimelineViewModel = mock {
|
||||
on { accountManager } doReturn accountManager
|
||||
on { activeAccountFlow } doReturn MutableStateFlow(account)
|
||||
on { statusData } doReturn statuses
|
||||
on { nextKey } doReturn "3"
|
||||
on { kind } doReturn TimelineViewModel.Kind.PUBLIC_TRENDING_STATUSES
|
||||
|
|
@ -409,7 +429,7 @@ class NetworkTimelineRemoteMediatorTest {
|
|||
)
|
||||
}
|
||||
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(accountManager, timelineViewModel)
|
||||
val remoteMediator = NetworkTimelineRemoteMediator(timelineViewModel)
|
||||
|
||||
val state = state(
|
||||
listOf(
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import com.keylesspalace.tusky.di.StorageModule
|
|||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
|
@ -24,7 +26,7 @@ class MigrationsTest {
|
|||
)
|
||||
|
||||
@Test
|
||||
fun testMigrations() {
|
||||
fun testMigrations() = runTest {
|
||||
/** the db name must match the one in [StorageModule.providesDatabase] */
|
||||
val db = migrationHelper.createDatabase("tuskyDB", 10)
|
||||
val moshi = Moshi.Builder().build()
|
||||
|
|
@ -73,7 +75,7 @@ class MigrationsTest {
|
|||
Converters(moshi)
|
||||
)
|
||||
|
||||
val account = roomDb.accountDao().loadAll().first()
|
||||
val account = roomDb.accountDao().allAccounts().first().first()
|
||||
|
||||
roomDb.close()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue