Commit 09c02cca authored by MozLando's avatar MozLando
Browse files

Merge #4268



4268: Pass redirect source and target flags to history tracking delegates r=rocketsroger a=linacambridge

There's some confusion in `GeckoEngineSession` about redirect flags.
The `VISIT_REDIRECT_SOURCE` and `VISIT_REDIRECT_SOURCE_PERMANENT` flags
that we get from GeckoView's history delegate are for the redirect
_source_, not the visit type. They indicate if the URL passed to
`onVisited` is redirecting _to_ another URL, most likely because the
server returned an HTTP 3xy status code with a `Location` header.
Rust Places decides whether to mark the URL as hidden based on
these flags.

`VISIT_REDIRECT_{PERMANENT, TEMPORARY}`, however, indicate if the
URL passed to `onVisited` is the _target_ of a redirect (in other
words, the page that's _in_ the `Location` header). These get
translated into `VisitType` flags, which Rust Places stores as the
visit transition type. These two flags don't affect whether a URL
is hidden.

Note that, in a redirect chain, the middle links are both sources and
targets. For example, in "mozilla.org" -> "www.mozilla.org" ->
"www.mozilla.org/en-US", "www.mozilla.org" is both a redirect target
(since "mozilla.org" redirected to it), and a source (it redirected
to "www.mozilla.org/en-US").

See mozilla-mobile/fenix#3526.
Co-authored-by: default avatarLina Cambridge <lina@yakshaving.ninja>
parents e30b3071 15b873fe
......@@ -25,6 +25,8 @@ import mozilla.components.concept.engine.history.HistoryTrackingDelegate
import mozilla.components.concept.engine.manifest.WebAppManifestParser
import mozilla.components.concept.engine.request.RequestInterceptor
import mozilla.components.concept.engine.request.RequestInterceptor.InterceptionResponse
import mozilla.components.concept.storage.PageVisit
import mozilla.components.concept.storage.RedirectSource
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.ktx.android.util.Base64
import mozilla.components.support.ktx.kotlin.isEmail
......@@ -488,14 +490,31 @@ class GeckoEngineSession(
val visitType = if (isReload) {
VisitType.RELOAD
} else {
if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE_PERMANENT != 0) {
// Note the difference between `VISIT_REDIRECT_PERMANENT`,
// `VISIT_REDIRECT_TEMPORARY`, `VISIT_REDIRECT_SOURCE`, and
// `VISIT_REDIRECT_SOURCE_PERMANENT`.
//
// The former two indicate if the visited page is the *target*
// of a redirect; that is, another page redirected to it.
//
// The latter two indicate if the visited page is the *source*
// of a redirect: it's redirecting to another page, because the
// server returned an HTTP 3xy status code.
if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_PERMANENT != 0) {
VisitType.REDIRECT_PERMANENT
} else if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE != 0) {
} else if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_TEMPORARY != 0) {
VisitType.REDIRECT_TEMPORARY
} else {
VisitType.LINK
}
}
val redirectSource = when {
flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE_PERMANENT != 0 ->
RedirectSource.PERMANENT
flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE != 0 ->
RedirectSource.TEMPORARY
else -> RedirectSource.NOT_A_SOURCE
}
val delegate = settings.historyTrackingDelegate ?: return GeckoResult.fromValue(false)
......@@ -505,7 +524,7 @@ class GeckoEngineSession(
}
return launchGeckoResult {
delegate.onVisited(url, visitType)
delegate.onVisited(url, PageVisit(visitType, redirectSource))
true
}
}
......
......@@ -25,6 +25,8 @@ import mozilla.components.concept.engine.manifest.WebAppManifest
import mozilla.components.concept.engine.permission.PermissionRequest
import mozilla.components.concept.engine.request.RequestInterceptor
import mozilla.components.concept.engine.window.WindowRequest
import mozilla.components.concept.storage.PageVisit
import mozilla.components.concept.storage.RedirectSource
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.test.any
import mozilla.components.support.test.eq
......@@ -660,7 +662,7 @@ class GeckoEngineSessionTest {
historyDelegate.value.onVisited(geckoSession, "https://www.mozilla.com", null, GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE)))
}
@Test
......@@ -677,7 +679,7 @@ class GeckoEngineSessionTest {
historyDelegate.value.onVisited(geckoSession, "https://www.mozilla.com", "https://www.mozilla.com", GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(VisitType.RELOAD))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(PageVisit(VisitType.RELOAD, RedirectSource.NOT_A_SOURCE)))
}
@Test
......@@ -697,7 +699,7 @@ class GeckoEngineSessionTest {
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).shouldStoreUri("https://www.mozilla.com/allowed")
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/allowed"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/allowed"), eq(PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE)))
historyDelegate.value.onVisited(geckoSession, "https://www.mozilla.com/not-allowed", null, GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL)
......@@ -728,7 +730,7 @@ class GeckoEngineSessionTest {
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/tempredirect"), eq(VisitType.REDIRECT_TEMPORARY))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/tempredirect"), eq(PageVisit(VisitType.LINK, RedirectSource.TEMPORARY)))
historyDelegate.value.onVisited(
geckoSession,
......@@ -739,7 +741,7 @@ class GeckoEngineSessionTest {
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/permredirect"), eq(VisitType.REDIRECT_PERMANENT))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/permredirect"), eq(PageVisit(VisitType.LINK, RedirectSource.PERMANENT)))
// Visits below are targets of redirects, not redirects themselves.
// Check that they're mapped to "link".
......@@ -752,18 +754,18 @@ class GeckoEngineSessionTest {
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targettemp"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targettemp"), eq(PageVisit(VisitType.REDIRECT_TEMPORARY, RedirectSource.NOT_A_SOURCE)))
historyDelegate.value.onVisited(
geckoSession,
"https://www.mozilla.com/targetperm",
null,
GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL
or GeckoSession.HistoryDelegate.VISIT_REDIRECT_TEMPORARY
or GeckoSession.HistoryDelegate.VISIT_REDIRECT_PERMANENT
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targetperm"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targetperm"), eq(PageVisit(VisitType.REDIRECT_PERMANENT, RedirectSource.NOT_A_SOURCE)))
}
@Test
......
......@@ -25,6 +25,8 @@ import mozilla.components.concept.engine.history.HistoryTrackingDelegate
import mozilla.components.concept.engine.manifest.WebAppManifestParser
import mozilla.components.concept.engine.request.RequestInterceptor
import mozilla.components.concept.engine.request.RequestInterceptor.InterceptionResponse
import mozilla.components.concept.storage.PageVisit
import mozilla.components.concept.storage.RedirectSource
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.ktx.android.util.Base64
import mozilla.components.support.ktx.kotlin.isEmail
......@@ -487,14 +489,31 @@ class GeckoEngineSession(
val visitType = if (isReload) {
VisitType.RELOAD
} else {
if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE_PERMANENT != 0) {
// Note the difference between `VISIT_REDIRECT_PERMANENT`,
// `VISIT_REDIRECT_TEMPORARY`, `VISIT_REDIRECT_SOURCE`, and
// `VISIT_REDIRECT_SOURCE_PERMANENT`.
//
// The former two indicate if the visited page is the *target*
// of a redirect; that is, another page redirected to it.
//
// The latter two indicate if the visited page is the *source*
// of a redirect: it's redirecting to another page, because the
// server returned an HTTP 3xy status code.
if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_PERMANENT != 0) {
VisitType.REDIRECT_PERMANENT
} else if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE != 0) {
} else if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_TEMPORARY != 0) {
VisitType.REDIRECT_TEMPORARY
} else {
VisitType.LINK
}
}
val redirectSource = when {
flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE_PERMANENT != 0 ->
RedirectSource.PERMANENT
flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE != 0 ->
RedirectSource.TEMPORARY
else -> RedirectSource.NOT_A_SOURCE
}
val delegate = settings.historyTrackingDelegate ?: return GeckoResult.fromValue(false)
......@@ -504,7 +523,7 @@ class GeckoEngineSession(
}
return launchGeckoResult {
delegate.onVisited(url, visitType)
delegate.onVisited(url, PageVisit(visitType, redirectSource))
true
}
}
......
......@@ -25,6 +25,8 @@ import mozilla.components.concept.engine.manifest.WebAppManifest
import mozilla.components.concept.engine.permission.PermissionRequest
import mozilla.components.concept.engine.request.RequestInterceptor
import mozilla.components.concept.engine.window.WindowRequest
import mozilla.components.concept.storage.PageVisit
import mozilla.components.concept.storage.RedirectSource
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.test.any
import mozilla.components.support.test.eq
......@@ -660,7 +662,7 @@ class GeckoEngineSessionTest {
historyDelegate.value.onVisited(geckoSession, "https://www.mozilla.com", null, GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE)))
}
@Test
......@@ -677,7 +679,7 @@ class GeckoEngineSessionTest {
historyDelegate.value.onVisited(geckoSession, "https://www.mozilla.com", "https://www.mozilla.com", GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(VisitType.RELOAD))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(PageVisit(VisitType.RELOAD, RedirectSource.NOT_A_SOURCE)))
}
@Test
......@@ -697,7 +699,7 @@ class GeckoEngineSessionTest {
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).shouldStoreUri("https://www.mozilla.com/allowed")
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/allowed"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/allowed"), eq(PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE)))
historyDelegate.value.onVisited(geckoSession, "https://www.mozilla.com/not-allowed", null, GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL)
......@@ -728,7 +730,7 @@ class GeckoEngineSessionTest {
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/tempredirect"), eq(VisitType.REDIRECT_TEMPORARY))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/tempredirect"), eq(PageVisit(VisitType.LINK, RedirectSource.TEMPORARY)))
historyDelegate.value.onVisited(
geckoSession,
......@@ -739,7 +741,7 @@ class GeckoEngineSessionTest {
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/permredirect"), eq(VisitType.REDIRECT_PERMANENT))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/permredirect"), eq(PageVisit(VisitType.LINK, RedirectSource.PERMANENT)))
// Visits below are targets of redirects, not redirects themselves.
// Check that they're mapped to "link".
......@@ -752,18 +754,18 @@ class GeckoEngineSessionTest {
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targettemp"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targettemp"), eq(PageVisit(VisitType.REDIRECT_TEMPORARY, RedirectSource.NOT_A_SOURCE)))
historyDelegate.value.onVisited(
geckoSession,
"https://www.mozilla.com/targetperm",
null,
GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL
or GeckoSession.HistoryDelegate.VISIT_REDIRECT_TEMPORARY
or GeckoSession.HistoryDelegate.VISIT_REDIRECT_PERMANENT
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targetperm"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targetperm"), eq(PageVisit(VisitType.REDIRECT_PERMANENT, RedirectSource.NOT_A_SOURCE)))
}
@Test
......
......@@ -22,6 +22,8 @@ import mozilla.components.concept.engine.history.HistoryTrackingDelegate
import mozilla.components.concept.engine.manifest.WebAppManifestParser
import mozilla.components.concept.engine.request.RequestInterceptor
import mozilla.components.concept.engine.request.RequestInterceptor.InterceptionResponse
import mozilla.components.concept.storage.PageVisit
import mozilla.components.concept.storage.RedirectSource
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.ktx.android.util.Base64
import mozilla.components.support.ktx.kotlin.isEmail
......@@ -437,14 +439,31 @@ class GeckoEngineSession(
val visitType = if (isReload) {
VisitType.RELOAD
} else {
if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE_PERMANENT != 0) {
// Note the difference between `VISIT_REDIRECT_PERMANENT`,
// `VISIT_REDIRECT_TEMPORARY`, `VISIT_REDIRECT_SOURCE`, and
// `VISIT_REDIRECT_SOURCE_PERMANENT`.
//
// The former two indicate if the visited page is the *target*
// of a redirect; that is, another page redirected to it.
//
// The latter two indicate if the visited page is the *source*
// of a redirect: it's redirecting to another page, because the
// server returned an HTTP 3xy status code.
if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_PERMANENT != 0) {
VisitType.REDIRECT_PERMANENT
} else if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE != 0) {
} else if (flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_TEMPORARY != 0) {
VisitType.REDIRECT_TEMPORARY
} else {
VisitType.LINK
}
}
val redirectSource = when {
flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE_PERMANENT != 0 ->
RedirectSource.PERMANENT
flags and GeckoSession.HistoryDelegate.VISIT_REDIRECT_SOURCE != 0 ->
RedirectSource.TEMPORARY
else -> RedirectSource.NOT_A_SOURCE
}
val delegate = settings.historyTrackingDelegate ?: return GeckoResult.fromValue(false)
......@@ -454,7 +473,7 @@ class GeckoEngineSession(
}
return launchGeckoResult {
delegate.onVisited(url, visitType)
delegate.onVisited(url, PageVisit(visitType, redirectSource))
true
}
}
......
......@@ -23,6 +23,8 @@ import mozilla.components.concept.engine.history.HistoryTrackingDelegate
import mozilla.components.concept.engine.manifest.WebAppManifest
import mozilla.components.concept.engine.permission.PermissionRequest
import mozilla.components.concept.engine.request.RequestInterceptor
import mozilla.components.concept.storage.PageVisit
import mozilla.components.concept.storage.RedirectSource
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.test.any
import mozilla.components.support.test.eq
......@@ -607,7 +609,7 @@ class GeckoEngineSessionTest {
historyDelegate.value.onVisited(geckoSession, "https://www.mozilla.com", null, GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE)))
}
@Test
......@@ -624,7 +626,7 @@ class GeckoEngineSessionTest {
historyDelegate.value.onVisited(geckoSession, "https://www.mozilla.com", "https://www.mozilla.com", GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(VisitType.RELOAD))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com"), eq(PageVisit(VisitType.RELOAD, RedirectSource.NOT_A_SOURCE)))
}
@Test
......@@ -644,7 +646,7 @@ class GeckoEngineSessionTest {
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).shouldStoreUri("https://www.mozilla.com/allowed")
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/allowed"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/allowed"), eq(PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE)))
historyDelegate.value.onVisited(geckoSession, "https://www.mozilla.com/not-allowed", null, GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL)
......@@ -675,7 +677,7 @@ class GeckoEngineSessionTest {
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/tempredirect"), eq(VisitType.REDIRECT_TEMPORARY))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/tempredirect"), eq(PageVisit(VisitType.LINK, RedirectSource.TEMPORARY)))
historyDelegate.value.onVisited(
geckoSession,
......@@ -686,7 +688,7 @@ class GeckoEngineSessionTest {
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/permredirect"), eq(VisitType.REDIRECT_PERMANENT))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/permredirect"), eq(PageVisit(VisitType.LINK, RedirectSource.PERMANENT)))
// Visits below are targets of redirects, not redirects themselves.
// Check that they're mapped to "link".
......@@ -699,18 +701,18 @@ class GeckoEngineSessionTest {
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targettemp"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targettemp"), eq(PageVisit(VisitType.REDIRECT_TEMPORARY, RedirectSource.NOT_A_SOURCE)))
historyDelegate.value.onVisited(
geckoSession,
"https://www.mozilla.com/targetperm",
null,
GeckoSession.HistoryDelegate.VISIT_TOP_LEVEL
or GeckoSession.HistoryDelegate.VISIT_REDIRECT_TEMPORARY
or GeckoSession.HistoryDelegate.VISIT_REDIRECT_PERMANENT
)
engineSession.job.children.forEach { it.join() }
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targetperm"), eq(VisitType.LINK))
verify(historyTrackingDelegate).onVisited(eq("https://www.mozilla.com/targetperm"), eq(PageVisit(VisitType.REDIRECT_PERMANENT, RedirectSource.NOT_A_SOURCE)))
}
@Test
......
......@@ -55,6 +55,8 @@ import mozilla.components.concept.engine.HitResult
import mozilla.components.concept.engine.content.blocking.Tracker
import mozilla.components.concept.engine.prompt.PromptRequest
import mozilla.components.concept.engine.request.RequestInterceptor.InterceptionResponse
import mozilla.components.concept.storage.PageVisit
import mozilla.components.concept.storage.RedirectSource
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.ktx.android.view.getRectWithViewLocation
import mozilla.components.support.utils.DownloadUtils
......@@ -152,7 +154,8 @@ class SystemEngineView @JvmOverloads constructor(
}
runBlocking {
session?.settings?.historyTrackingDelegate?.onVisited(url, visitType)
session?.settings?.historyTrackingDelegate?.onVisited(url,
PageVisit(visitType, RedirectSource.NOT_A_SOURCE))
}
}
......
......@@ -39,6 +39,8 @@ import mozilla.components.concept.engine.permission.PermissionRequest
import mozilla.components.concept.engine.prompt.PromptRequest
import mozilla.components.concept.engine.request.RequestInterceptor
import mozilla.components.concept.engine.window.WindowRequest
import mozilla.components.concept.storage.PageVisit
import mozilla.components.concept.storage.RedirectSource
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.test.any
import mozilla.components.support.test.argumentCaptor
......@@ -296,10 +298,10 @@ class SystemEngineViewTest {
whenever(historyDelegate.shouldStoreUri(any())).thenReturn(true)
engineSession.webView.webViewClient.doUpdateVisitedHistory(webView, "https://www.mozilla.com", false)
verify(historyDelegate).onVisited(eq("https://www.mozilla.com"), eq(VisitType.LINK))
verify(historyDelegate).onVisited(eq("https://www.mozilla.com"), eq(PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE)))
engineSession.webView.webViewClient.doUpdateVisitedHistory(webView, "https://www.mozilla.com", true)
verify(historyDelegate).onVisited(eq("https://www.mozilla.com"), eq(VisitType.RELOAD))
verify(historyDelegate).onVisited(eq("https://www.mozilla.com"), eq(PageVisit(VisitType.RELOAD, RedirectSource.NOT_A_SOURCE)))
}
@Test
......@@ -316,7 +318,7 @@ class SystemEngineViewTest {
// Verify that engine session asked delegate if uri should be stored.
engineSession.webView.webViewClient.doUpdateVisitedHistory(webView, "https://www.mozilla.com", false)
verify(historyDelegate).onVisited(eq("https://www.mozilla.com"), eq(VisitType.LINK))
verify(historyDelegate).onVisited(eq("https://www.mozilla.com"), eq(PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE)))
verify(historyDelegate).shouldStoreUri("https://www.mozilla.com")
// Verify that engine won't try to store a uri that delegate doesn't want.
......@@ -332,7 +334,7 @@ class SystemEngineViewTest {
val engineView = SystemEngineView(testContext)
val historyDelegate = object : HistoryTrackingDelegate {
override suspend fun onVisited(uri: String, type: VisitType) {
override suspend fun onVisited(uri: String, visit: PageVisit) {
fail()
}
......
......@@ -9,6 +9,8 @@ import mozilla.components.concept.storage.HistoryAutocompleteResult
import mozilla.components.concept.storage.HistoryStorage
import mozilla.components.concept.storage.PageObservation
import mozilla.components.concept.storage.SearchResult
import mozilla.components.concept.storage.PageVisit
import mozilla.components.concept.storage.RedirectSource
import mozilla.components.concept.storage.VisitInfo
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.utils.StorageUtils.levenshteinDistance
......@@ -28,14 +30,17 @@ class InMemoryHistoryStorage : HistoryStorage {
@VisibleForTesting
internal val pageMeta: HashMap<String, PageObservation> = hashMapOf()
override suspend fun recordVisit(uri: String, visitType: VisitType) {
override suspend fun recordVisit(uri: String, visit: PageVisit) {
val now = System.currentTimeMillis()
if (visit.redirectSource != RedirectSource.NOT_A_SOURCE) {
return
}
synchronized(pages) {
if (!pages.containsKey(uri)) {
pages[uri] = mutableListOf(Visit(now, visitType))
pages[uri] = mutableListOf(Visit(now, visit.visitType))
} else {
pages[uri]!!.add(Visit(now, visitType))
pages[uri]!!.add(Visit(now, visit.visitType))
}
}
}
......
......@@ -7,6 +7,8 @@ package mozilla.components.browser.storage.memory
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.runBlocking
import mozilla.components.concept.storage.PageObservation
import mozilla.components.concept.storage.PageVisit
import mozilla.components.concept.storage.RedirectSource
import mozilla.components.concept.storage.VisitType
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
......@@ -23,20 +25,20 @@ class InMemoryHistoryStorageTest {
assertEquals(0, history.pages.size)
history.recordVisit("http://www.mozilla.org", VisitType.LINK)
history.recordVisit("http://www.mozilla.org", PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE))
assertEquals(1, history.pages.size)
assertEquals(1, history.pages["http://www.mozilla.org"]!!.size)
assertEquals(VisitType.LINK, history.pages["http://www.mozilla.org"]!![0].type)
// Reloads are recorded.
history.recordVisit("http://www.mozilla.org", VisitType.RELOAD)
history.recordVisit("http://www.mozilla.org", PageVisit(VisitType.RELOAD, RedirectSource.NOT_A_SOURCE))
assertEquals(1, history.pages.size)
assertEquals(2, history.pages["http://www.mozilla.org"]!!.size)
assertEquals(VisitType.LINK, history.pages["http://www.mozilla.org"]!![0].type)
assertEquals(VisitType.RELOAD, history.pages["http://www.mozilla.org"]!![1].type)
// Visits for multiple pages are tracked.
history.recordVisit("http://www.firefox.com", VisitType.LINK)
history.recordVisit("http://www.firefox.com", PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE))
assertEquals(2, history.pages.size)
assertEquals(2, history.pages["http://www.mozilla.org"]!!.size)
assertEquals(VisitType.LINK, history.pages["http://www.mozilla.org"]!![0].type)
......@@ -49,12 +51,12 @@ class InMemoryHistoryStorageTest {
fun `store can be used to query detailed visit information`() = runBlocking {
val history = InMemoryHistoryStorage()
history.recordVisit("http://www.mozilla.org", VisitType.LINK)
history.recordVisit("http://www.mozilla.org", VisitType.RELOAD)
history.recordVisit("http://www.mozilla.org", PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE))
history.recordVisit("http://www.mozilla.org", PageVisit(VisitType.RELOAD, RedirectSource.NOT_A_SOURCE))
history.recordObservation("http://www.mozilla.org", PageObservation("Mozilla"))
history.recordVisit("http://www.firefox.com", VisitType.LINK)
history.recordVisit("http://www.firefox.com", PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE))
history.recordVisit("http://www.firefox.com", VisitType.REDIRECT_TEMPORARY)
history.recordVisit("http://www.firefox.com", PageVisit(VisitType.REDIRECT_TEMPORARY, RedirectSource.NOT_A_SOURCE))
val visits = history.getDetailedVisits(0, excludeTypes = listOf(VisitType.REDIRECT_TEMPORARY))
assertEquals(3, visits.size)
......@@ -82,21 +84,21 @@ class InMemoryHistoryStorageTest {
assertEquals(0, history.getVisited().size)
// Regular visits are tracked.
history.recordVisit("https://www.mozilla.org", VisitType.LINK)
history.recordVisit("https://www.mozilla.org", PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE))
assertEquals(listOf("https://www.mozilla.org"), history.getVisited())
// Multiple visits can be tracked, results ordered by "URL's first seen first".
history.recordVisit("https://www.firefox.com", VisitType.LINK)
history.recordVisit("https://www.firefox.com", PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE))
assertEquals(listOf("https://www.mozilla.org", "https://www.firefox.com"), history.getVisited())
// Visits marked as reloads can be tracked.
history.recordVisit("https://www.firefox.com", VisitType.RELOAD)
history.recordVisit("https://www.firefox.com", PageVisit(VisitType.RELOAD, RedirectSource.NOT_A_SOURCE))