You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iceraven-browser/app/src/test/java/org/mozilla/fenix/library/history/state/HistoryStorageMiddlewareTes...

229 lines
9.5 KiB
Kotlin

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.library.history.state
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.advanceUntilIdle
import mozilla.components.browser.state.action.BrowserAction
import mozilla.components.browser.state.action.EngineAction
import mozilla.components.browser.state.action.HistoryMetadataAction
import mozilla.components.browser.state.action.RecentlyClosedAction
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.libstate.ext.waitUntilIdle
import mozilla.components.support.test.middleware.CaptureActionsMiddleware
import mozilla.components.support.test.mock
import mozilla.components.support.test.rule.MainCoroutineRule
import mozilla.components.support.test.rule.runTestOnMain
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito.anyLong
import org.mockito.Mockito.verify
import org.mozilla.fenix.components.AppStore
import org.mozilla.fenix.components.appstate.AppAction
import org.mozilla.fenix.components.history.DefaultPagedHistoryProvider
import org.mozilla.fenix.library.history.History
import org.mozilla.fenix.library.history.HistoryFragmentAction
import org.mozilla.fenix.library.history.HistoryFragmentState
import org.mozilla.fenix.library.history.HistoryFragmentStore
import org.mozilla.fenix.library.history.HistoryItemTimeGroup
import org.mozilla.fenix.library.history.RemoveTimeFrame
import org.mozilla.fenix.library.history.toPendingDeletionHistory
class HistoryStorageMiddlewareTest {
@get:Rule
val coroutinesTestRule = MainCoroutineRule()
private val appStore = mock<AppStore>()
private lateinit var captureBrowserActions: CaptureActionsMiddleware<BrowserState, BrowserAction>
private lateinit var browserStore: BrowserStore
private val provider = mock<DefaultPagedHistoryProvider>()
private lateinit var storage: PlacesHistoryStorage
@Before
fun setup() {
storage = mock()
captureBrowserActions = CaptureActionsMiddleware()
browserStore = BrowserStore(middleware = listOf(captureBrowserActions))
}
@Test
fun `WHEN items are deleted THEN action to add to pending deletion is dispatched and snackbar is shown`() = runTestOnMain {
var snackbarCalled = false
val history = setOf(History.Regular(0, "title", "url", 0, HistoryItemTimeGroup.timeGroupForTimestamp(0)))
val middleware = HistoryStorageMiddleware(
appStore = appStore,
browserStore = browserStore,
historyProvider = provider,
historyStorage = storage,
undoDeleteSnackbar = { _, _, _ -> snackbarCalled = true },
onTimeFrameDeleted = { },
scope = this,
)
val store = HistoryFragmentStore(
initialState = HistoryFragmentState.initial,
middleware = listOf(middleware),
)
store.dispatch(HistoryFragmentAction.DeleteItems(history)).joinBlocking()
store.waitUntilIdle()
assertTrue(snackbarCalled)
verify(appStore).dispatch(AppAction.AddPendingDeletionSet(history.toPendingDeletionHistory()))
}
@Test
fun `WHEN items are deleted THEN undo dispatches action to remove them from pending deletion state`() = runTestOnMain {
var snackbarCalled = false
val history = setOf(History.Regular(0, "title", "url", 0, HistoryItemTimeGroup.timeGroupForTimestamp(0)))
val middleware = HistoryStorageMiddleware(
appStore = appStore,
browserStore = browserStore,
historyProvider = provider,
historyStorage = storage,
undoDeleteSnackbar = { _, undo, _ ->
runBlocking { undo(history) }
snackbarCalled = true
},
onTimeFrameDeleted = { },
scope = this,
)
val store = HistoryFragmentStore(
initialState = HistoryFragmentState.initial,
middleware = listOf(middleware),
)
store.dispatch(HistoryFragmentAction.DeleteItems(history)).joinBlocking()
store.waitUntilIdle()
assertTrue(snackbarCalled)
verify(appStore).dispatch(AppAction.AddPendingDeletionSet(history.toPendingDeletionHistory()))
verify(appStore).dispatch(AppAction.UndoPendingDeletionSet(history.toPendingDeletionHistory()))
}
@Test
fun `WHEN regular items are deleted and not undone THEN items are removed from storage`() = runTestOnMain {
var snackbarCalled = false
val history = setOf(History.Regular(0, "title", "url", 0, HistoryItemTimeGroup.timeGroupForTimestamp(0)))
val middleware = HistoryStorageMiddleware(
appStore = appStore,
browserStore = browserStore,
historyProvider = provider,
historyStorage = storage,
undoDeleteSnackbar = { _, _, delete ->
runBlocking { delete(history) }
snackbarCalled = true
},
onTimeFrameDeleted = { },
scope = this,
)
val store = HistoryFragmentStore(
initialState = HistoryFragmentState.initial,
middleware = listOf(middleware),
)
store.dispatch(HistoryFragmentAction.DeleteItems(history)).joinBlocking()
store.waitUntilIdle()
assertTrue(snackbarCalled)
verify(storage).deleteVisitsFor(history.first().url)
}
@Test
fun `WHEN group items are deleted and not undone THEN items are removed from provider and browser store updated`() = runTestOnMain {
var snackbarCalled = false
val history = setOf(History.Group(0, "title", 0, HistoryItemTimeGroup.timeGroupForTimestamp(0), listOf()))
val middleware = HistoryStorageMiddleware(
appStore = appStore,
browserStore = browserStore,
historyProvider = provider,
historyStorage = storage,
undoDeleteSnackbar = { _, _, delete ->
runBlocking { delete(history) }
snackbarCalled = true
},
onTimeFrameDeleted = { },
scope = this,
)
val store = HistoryFragmentStore(
initialState = HistoryFragmentState.initial,
middleware = listOf(middleware),
)
store.dispatch(HistoryFragmentAction.DeleteItems(history)).joinBlocking()
store.waitUntilIdle()
browserStore.waitUntilIdle()
assertTrue(snackbarCalled)
captureBrowserActions.assertFirstAction(HistoryMetadataAction.DisbandSearchGroupAction::class)
verify(provider).deleteMetadataSearchGroup(history.first())
}
@Test
fun `WHEN a null time frame is deleted THEN browser store is informed, storage deletes everything, and callback is invoked`() = runTestOnMain {
var callbackInvoked = false
val middleware = HistoryStorageMiddleware(
appStore = appStore,
browserStore = browserStore,
historyProvider = provider,
historyStorage = storage,
undoDeleteSnackbar = mock(),
onTimeFrameDeleted = { callbackInvoked = true },
scope = this,
)
val store = HistoryFragmentStore(
initialState = HistoryFragmentState.initial,
middleware = listOf(middleware),
)
store.dispatch(HistoryFragmentAction.DeleteTimeRange(null)).joinBlocking()
store.waitUntilIdle()
browserStore.waitUntilIdle()
assertTrue(callbackInvoked)
assertEquals(HistoryFragmentState.Mode.Normal, store.state.mode)
captureBrowserActions.assertFirstAction(RecentlyClosedAction.RemoveAllClosedTabAction::class)
captureBrowserActions.assertLastAction(EngineAction.PurgeHistoryAction::class) {}
verify(storage).deleteEverything()
}
@Ignore("Intermittent failure; see Bug 1848436.")
@Test
fun `WHEN a specified time frame is deleted THEN browser store is informed, storage deletes time frame, and callback is invoked`() = runTestOnMain {
var callbackInvoked = false
val middleware = HistoryStorageMiddleware(
appStore = appStore,
browserStore = browserStore,
historyProvider = provider,
historyStorage = storage,
undoDeleteSnackbar = mock(),
onTimeFrameDeleted = { callbackInvoked = true },
scope = this,
)
val store = HistoryFragmentStore(
initialState = HistoryFragmentState.initial,
middleware = listOf(middleware),
)
store.dispatch(HistoryFragmentAction.DeleteTimeRange(RemoveTimeFrame.LastHour)).joinBlocking()
store.waitUntilIdle()
browserStore.waitUntilIdle()
this.advanceUntilIdle()
assertTrue(callbackInvoked)
assertFalse(store.state.isDeletingItems)
captureBrowserActions.assertFirstAction(RecentlyClosedAction.RemoveAllClosedTabAction::class)
captureBrowserActions.assertLastAction(EngineAction.PurgeHistoryAction::class) {}
verify(storage).deleteVisitsBetween(anyLong(), anyLong())
}
}