For #23893 - Add telemetry for Contile services

upstream-sync
Gabriel Luong 2 years ago committed by mergify[bot]
parent ae1a2f3625
commit 56022546f2

@ -4786,6 +4786,7 @@ voice_search:
tags: tags:
- Search - Search
- Voice - Voice
top_sites: top_sites:
open_default: open_default:
type: event type: event
@ -5088,6 +5089,141 @@ top_sites:
notification_emails: notification_emails:
- android-probes@mozilla.com - android-probes@mozilla.com
expires: 111 expires: 111
context_id:
type: uuid
description: |
A UUID that is unjoinable with other browser metrics. This ID will not be
shared with AdM, only for internal uses. This ID is shared across all
contextual services features.
lifetime: ping
send_in_pings:
- topsites-impression
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- highly_sensitive
notification_emails:
- android-probes@mozilla.com
expires: 112
metadata:
tags:
- TopSites
contile_tile_id:
type: quantity
description: |
A unique identifier provided by the AdM for the sponsored TopSites tile
lifetime: ping
send_in_pings:
- topsites-impression
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- technical
- interaction
notification_emails:
- android-probes@mozilla.com
expires: 112
unit: integer
metadata:
tags:
- TopSites
contile_advertiser:
type: string
description: |
Advertiser brand for the sponsored TopSites tile
lifetime: ping
send_in_pings:
- topsites-impression
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- technical
- interaction
notification_emails:
- android-probes@mozilla.com
expires: 112
metadata:
tags:
- TopSites
contile_reporting_url:
type: url
description: |
The AdM reporting endpoint (impression_url for “impression” event,
click_url for “click” event).
lifetime: ping
send_in_pings:
- topsites-impression
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- technical
- interaction
notification_emails:
- android-probes@mozilla.com
expires: 112
metadata:
tags:
- TopSites
contile_impression:
type: event
description: |
A user saw a Contile top site
extra_keys:
source:
description: The source of the event, example "newtab", "urlbar"
type: string
position:
description: The tile placement (1-based)
type: quantity
send_in_pings:
- topsites-impression
- events
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: 112
metadata:
tags:
- TopSites
contile_click:
type: event
description: |
A user clicked a Contile top site
extra_keys:
source:
description: The source of the event, example "newtab", "urlbar"
type: string
position:
description: The tile placement (1-based)
type: quantity
send_in_pings:
- topsites-impression
- events
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: 112
metadata:
tags:
- TopSites
app_theme: app_theme:
dark_theme_selected: dark_theme_selected:
@ -5113,7 +5249,6 @@ app_theme:
notification_emails: notification_emails:
- android-probes@mozilla.com - android-probes@mozilla.com
expires: 108 expires: 108
metadata: metadata:
tags: tags:
- Themes - Themes

@ -30,3 +30,16 @@ first-session:
- https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202 - https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202
notification_emails: notification_emails:
- android-probes@mozilla.com - android-probes@mozilla.com
topsites-impression:
description: |
Recorded when a sponsored top site is rendered and visible on the home
screen. Visibility is qualified as when the homepage is brought to the
front of the Browser, and sponsored tiles are 100% visible on screen.
include_client_id: false
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
notification_emails:
- android-probes@mozilla.com

@ -62,6 +62,7 @@ import org.mozilla.fenix.GleanMetrics.Metrics
import org.mozilla.fenix.GleanMetrics.PerfStartup import org.mozilla.fenix.GleanMetrics.PerfStartup
import org.mozilla.fenix.GleanMetrics.Preferences import org.mozilla.fenix.GleanMetrics.Preferences
import org.mozilla.fenix.GleanMetrics.SearchDefaultEngine import org.mozilla.fenix.GleanMetrics.SearchDefaultEngine
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.components.Components import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.Core import org.mozilla.fenix.components.Core
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
@ -84,6 +85,7 @@ import org.mozilla.fenix.telemetry.TelemetryLifecycleObserver
import org.mozilla.fenix.utils.BrowsersCache import org.mozilla.fenix.utils.BrowsersCache
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
import org.mozilla.fenix.utils.Settings.Companion.TOP_SITES_PROVIDER_MAX_THRESHOLD import org.mozilla.fenix.utils.Settings.Companion.TOP_SITES_PROVIDER_MAX_THRESHOLD
import java.util.UUID
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
/** /**
@ -578,6 +580,12 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
defaultMozBrowser.set(it) defaultMozBrowser.set(it)
} }
if (settings.contileContextId.isEmpty()) {
settings.contileContextId = TopSites.contextId.generateAndSet().toString()
} else {
TopSites.contextId.set(UUID.fromString(settings.contileContextId))
}
mozillaProducts.set(mozillaProductDetector.getInstalledMozillaProducts(applicationContext)) mozillaProducts.set(mozillaProductDetector.getInstalledMozillaProducts(applicationContext))
adjustCampaign.set(settings.adjustCampaignId) adjustCampaign.set(settings.adjustCampaignId)

@ -331,6 +331,14 @@ sealed class Event {
get() = hashMapOf(TopSites.longPressKeys.type to topSite.name()) get() = hashMapOf(TopSites.longPressKeys.type to topSite.name())
} }
data class TopSiteContileImpression(val position: Int, val source: Source) : Event() {
enum class Source { NEWTAB }
}
data class TopSiteContileClick(val position: Int, val source: Source) : Event() {
enum class Source { NEWTAB }
}
data class OnboardingToolbarPosition(val position: Position) : Event() { data class OnboardingToolbarPosition(val position: Position) : Event() {
enum class Position { TOP, BOTTOM } enum class Position { TOP, BOTTOM }

@ -558,6 +558,26 @@ private val Event.wrapper: EventWrapper<*>?
{ TopSites.swipeCarousel.record(it) }, { TopSites.swipeCarousel.record(it) },
{ TopSites.swipeCarouselKeys.valueOf(it) } { TopSites.swipeCarouselKeys.valueOf(it) }
) )
is Event.TopSiteContileImpression -> EventWrapper<NoExtraKeys>(
{
TopSites.contileImpression.record(
TopSites.ContileImpressionExtra(
position = this.position,
source = this.source.name.lowercase()
)
)
}
)
is Event.TopSiteContileClick -> EventWrapper<NoExtraKeys>(
{
TopSites.contileClick.record(
TopSites.ContileClickExtra(
position = this.position,
source = this.source.name.lowercase()
)
)
}
)
is Event.PocketTopSiteClicked -> EventWrapper<NoExtraKeys>( is Event.PocketTopSiteClicked -> EventWrapper<NoExtraKeys>(
{ Pocket.pocketTopSiteClicked.record(it) } { Pocket.pocketTopSiteClicked.record(it) }
) )

@ -29,6 +29,8 @@ import mozilla.components.support.ktx.android.view.showKeyboard
import mozilla.components.support.ktx.kotlin.isUrl import mozilla.components.support.ktx.kotlin.isUrl
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserFragmentDirections import org.mozilla.fenix.browser.BrowserFragmentDirections
@ -119,7 +121,7 @@ interface SessionControlController {
/** /**
* @see [TopSiteInteractor.onSelectTopSite] * @see [TopSiteInteractor.onSelectTopSite]
*/ */
fun handleSelectTopSite(topSite: TopSite) fun handleSelectTopSite(topSite: TopSite, position: Int)
/** /**
* @see [TopSiteInteractor.onSettingsClicked] * @see [TopSiteInteractor.onSettingsClicked]
@ -391,7 +393,7 @@ class DefaultSessionControlController(
metrics.track(Event.CollectionRenamePressed) metrics.track(Event.CollectionRenamePressed)
} }
override fun handleSelectTopSite(topSite: TopSite) { override fun handleSelectTopSite(topSite: TopSite, position: Int) {
dismissSearchDialogIfDisplayed() dismissSearchDialogIfDisplayed()
metrics.track(Event.TopSiteOpenInNewTab) metrics.track(Event.TopSiteOpenInNewTab)
@ -401,7 +403,9 @@ class DefaultSessionControlController(
is TopSite.Default -> Event.TopSiteOpenDefault is TopSite.Default -> Event.TopSiteOpenDefault
is TopSite.Frecent -> Event.TopSiteOpenFrecent is TopSite.Frecent -> Event.TopSiteOpenFrecent
is TopSite.Pinned -> Event.TopSiteOpenPinned is TopSite.Pinned -> Event.TopSiteOpenPinned
is TopSite.Provided -> Event.TopSiteOpenProvided is TopSite.Provided -> Event.TopSiteOpenProvided.also {
submitTopSitesImpressionPing(topSite, position)
}
} }
) )
@ -435,6 +439,21 @@ class DefaultSessionControlController(
activity.openToBrowser(BrowserDirection.FromHome) activity.openToBrowser(BrowserDirection.FromHome)
} }
@VisibleForTesting
internal fun submitTopSitesImpressionPing(topSite: TopSite.Provided, position: Int) {
metrics.track(
Event.TopSiteContileClick(
position = position + 1,
source = Event.TopSiteContileClick.Source.NEWTAB
)
)
topSite.id?.let { TopSites.contileTileId.set(it) }
topSite.title?.let { TopSites.contileAdvertiser.set(it.lowercase()) }
TopSites.contileReportingUrl.set(topSite.clickUrl)
Pings.topsitesImpression.submit()
}
override fun handleTopSiteSettingsClicked() { override fun handleTopSiteSettingsClicked() {
metrics.track(Event.TopSiteContileSettings) metrics.track(Event.TopSiteContileSettings)
navController.nav( navController.nav(

@ -211,8 +211,9 @@ interface TopSiteInteractor {
* Selects the given top site. Called when a user clicks on a top site. * Selects the given top site. Called when a user clicks on a top site.
* *
* @param topSite The top site that was selected. * @param topSite The top site that was selected.
* @param position The position of the top site.
*/ */
fun onSelectTopSite(topSite: TopSite) fun onSelectTopSite(topSite: TopSite, position: Int)
/** /**
* Navigates to the Homepage Settings. Called when an user clicks on the "Settings" top site * Navigates to the Homepage Settings. Called when an user clicks on the "Settings" top site
@ -310,8 +311,8 @@ class SessionControlInteractor(
controller.handleRenameCollectionTapped(collection) controller.handleRenameCollectionTapped(collection)
} }
override fun onSelectTopSite(topSite: TopSite) { override fun onSelectTopSite(topSite: TopSite, position: Int) {
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position)
} }
override fun onSettingsClicked() { override fun onSettingsClicked() {

@ -8,6 +8,7 @@ import android.annotation.SuppressLint
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.widget.PopupWindow import android.widget.PopupWindow
import androidx.annotation.VisibleForTesting
import androidx.appcompat.content.res.AppCompatResources.getDrawable import androidx.appcompat.content.res.AppCompatResources.getDrawable
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
@ -17,6 +18,8 @@ import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import mozilla.components.feature.top.sites.TopSite import mozilla.components.feature.top.sites.TopSite
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.databinding.TopSiteItemBinding import org.mozilla.fenix.databinding.TopSiteItemBinding
@ -36,10 +39,6 @@ class TopSiteItemViewHolder(
private val binding = TopSiteItemBinding.bind(view) private val binding = TopSiteItemBinding.bind(view)
init { init {
binding.topSiteItem.setOnClickListener {
interactor.onSelectTopSite(topSite)
}
binding.topSiteItem.setOnLongClickListener { binding.topSiteItem.setOnLongClickListener {
interactor.onTopSiteMenuOpened() interactor.onTopSiteMenuOpened()
it.context.components.analytics.metrics.track(Event.TopSiteLongPress(topSite)) it.context.components.analytics.metrics.track(Event.TopSiteLongPress(topSite))
@ -72,7 +71,11 @@ class TopSiteItemViewHolder(
} }
} }
fun bind(topSite: TopSite) { fun bind(topSite: TopSite, position: Int) {
binding.topSiteItem.setOnClickListener {
interactor.onSelectTopSite(topSite, position)
}
binding.topSiteTitle.text = topSite.title binding.topSiteTitle.text = topSite.title
if (topSite is TopSite.Pinned || topSite is TopSite.Default) { if (topSite is TopSite.Pinned || topSite is TopSite.Default) {
@ -89,6 +92,7 @@ class TopSiteItemViewHolder(
itemView.context.components.core.client.bitmapForUrl(topSite.imageUrl)?.let { bitmap -> itemView.context.components.core.client.bitmapForUrl(topSite.imageUrl)?.let { bitmap ->
withContext(Main) { withContext(Main) {
binding.faviconImage.setImageBitmap(bitmap) binding.faviconImage.setImageBitmap(bitmap)
submitTopSitesImpressionPing(topSite, position)
} }
} }
} }
@ -121,6 +125,21 @@ class TopSiteItemViewHolder(
this.topSite = topSite this.topSite = topSite
} }
@VisibleForTesting
internal fun submitTopSitesImpressionPing(topSite: TopSite.Provided, position: Int) {
itemView.context.components.analytics.metrics.track(
Event.TopSiteContileImpression(
position = position + 1,
source = Event.TopSiteContileImpression.Source.NEWTAB
)
)
topSite.id?.let { TopSites.contileTileId.set(it) }
topSite.title?.let { TopSites.contileAdvertiser.set(it.lowercase()) }
TopSites.contileReportingUrl.set(topSite.impressionUrl)
Pings.topsitesImpression.submit()
}
private fun onTouchEvent( private fun onTouchEvent(
v: View, v: View,
event: MotionEvent, event: MotionEvent,

@ -25,7 +25,7 @@ class TopSitesAdapter(
override fun onBindViewHolder(holder: TopSiteItemViewHolder, position: Int) { override fun onBindViewHolder(holder: TopSiteItemViewHolder, position: Int) {
StartupTimeline.onTopSitesItemBound(holder) StartupTimeline.onTopSitesItemBound(holder)
holder.bind(getItem(position)) holder.bind(getItem(position), position)
} }
override fun onBindViewHolder( override fun onBindViewHolder(
@ -38,7 +38,7 @@ class TopSitesAdapter(
} else { } else {
when (payloads[0]) { when (payloads[0]) {
is TopSite -> { is TopSite -> {
holder.bind((payloads[0] as TopSite)) holder.bind((payloads[0] as TopSite), position)
} }
} }
} }

@ -176,6 +176,11 @@ class Settings(private val appContext: Context) : PreferencesHolder {
default = "" default = ""
) )
var contileContextId by stringPreference(
appContext.getPreferenceKey(R.string.pref_key_contile_context_id),
default = ""
)
var currentWallpaper by stringPreference( var currentWallpaper by stringPreference(
appContext.getPreferenceKey(R.string.pref_key_current_wallpaper), appContext.getPreferenceKey(R.string.pref_key_current_wallpaper),
default = WallpaperManager.defaultWallpaper.name default = WallpaperManager.defaultWallpaper.name

@ -188,6 +188,8 @@
<string name="pref_key_adjust_adgroup" translatable="false">pref_key_adjust_adgroup</string> <string name="pref_key_adjust_adgroup" translatable="false">pref_key_adjust_adgroup</string>
<string name="pref_key_adjust_creative" translatable="false">pref_key_adjust_creative</string> <string name="pref_key_adjust_creative" translatable="false">pref_key_adjust_creative</string>
<string name="pref_key_contile_context_id" translatable="false">pref_key_contile_context_id</string>
<!-- Wallpaper Settings --> <!-- Wallpaper Settings -->
<string name="pref_key_wallpapers" translatable="false">pref_key_wallpapers</string> <string name="pref_key_wallpapers" translatable="false">pref_key_wallpapers</string>
<string name="pref_key_current_wallpaper" translatable="false">pref_key_current_wallpaper</string> <string name="pref_key_current_wallpaper" translatable="false">pref_key_current_wallpaper</string>

@ -19,8 +19,10 @@ import mozilla.components.concept.engine.webextension.Metadata
import mozilla.components.concept.engine.webextension.WebExtension import mozilla.components.concept.engine.webextension.WebExtension
import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker
import mozilla.components.service.glean.testing.GleanTestRule import mozilla.components.service.glean.testing.GleanTestRule
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -29,6 +31,7 @@ import org.mozilla.fenix.GleanMetrics.Addons
import org.mozilla.fenix.GleanMetrics.Metrics import org.mozilla.fenix.GleanMetrics.Metrics
import org.mozilla.fenix.GleanMetrics.Preferences import org.mozilla.fenix.GleanMetrics.Preferences
import org.mozilla.fenix.GleanMetrics.SearchDefaultEngine import org.mozilla.fenix.GleanMetrics.SearchDefaultEngine
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.components.metrics.MozillaProductDetector import org.mozilla.fenix.components.metrics.MozillaProductDetector
import org.mozilla.fenix.components.toolbar.ToolbarPosition import org.mozilla.fenix.components.toolbar.ToolbarPosition
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ -87,7 +90,7 @@ class FenixApplicationTest {
fun `WHEN setStartupMetrics is called THEN sets some base metrics`() { fun `WHEN setStartupMetrics is called THEN sets some base metrics`() {
val expectedAppName = "org.mozilla.fenix" val expectedAppName = "org.mozilla.fenix"
val expectedAppInstallSource = "org.mozilla.install.source" val expectedAppInstallSource = "org.mozilla.install.source"
val settings: Settings = mockk() val settings = spyk(Settings(testContext))
val application = spyk(application) val application = spyk(application)
val packageManager: PackageManager = mockk() val packageManager: PackageManager = mockk()
@ -142,6 +145,9 @@ class FenixApplicationTest {
every { application.reportHomeScreenMetrics(settings) } just Runs every { application.reportHomeScreenMetrics(settings) } just Runs
every { settings.inactiveTabsAreEnabled } returns true every { settings.inactiveTabsAreEnabled } returns true
assertTrue(settings.contileContextId.isEmpty())
assertFalse(TopSites.contextId.testHasValue())
application.setStartupMetrics(browserStore, settings, browsersCache, mozillaProductDetector) application.setStartupMetrics(browserStore, settings, browsersCache, mozillaProductDetector)
// Verify that browser defaults metrics are set. // Verify that browser defaults metrics are set.
@ -181,10 +187,20 @@ class FenixApplicationTest {
assertEquals(true, Preferences.inactiveTabsEnabled.testGetValue()) assertEquals(true, Preferences.inactiveTabsEnabled.testGetValue())
assertEquals(expectedAppInstallSource, Metrics.installSource.testGetValue()) assertEquals(expectedAppInstallSource, Metrics.installSource.testGetValue())
val contextId = TopSites.contextId.testGetValue().toString()
assertTrue(TopSites.contextId.testHasValue())
assertEquals(contextId, settings.contileContextId)
// Verify that search engine defaults are NOT set. This test does // Verify that search engine defaults are NOT set. This test does
// not mock most of the objects telemetry is collected from. // not mock most of the objects telemetry is collected from.
assertFalse(SearchDefaultEngine.code.testHasValue()) assertFalse(SearchDefaultEngine.code.testHasValue())
assertFalse(SearchDefaultEngine.name.testHasValue()) assertFalse(SearchDefaultEngine.name.testHasValue())
assertFalse(SearchDefaultEngine.searchUrl.testHasValue()) assertFalse(SearchDefaultEngine.searchUrl.testHasValue())
application.setStartupMetrics(browserStore, settings, browsersCache, mozillaProductDetector)
assertEquals(contextId, TopSites.contextId.testGetValue().toString())
assertEquals(contextId, settings.contileContextId)
} }
} }

@ -23,6 +23,7 @@ import org.mozilla.fenix.GleanMetrics.RecentBookmarks
import org.mozilla.fenix.GleanMetrics.RecentlyVisitedHomepage import org.mozilla.fenix.GleanMetrics.RecentlyVisitedHomepage
import org.mozilla.fenix.GleanMetrics.SyncedTabs import org.mozilla.fenix.GleanMetrics.SyncedTabs
import org.mozilla.fenix.GleanMetrics.TabsTray import org.mozilla.fenix.GleanMetrics.TabsTray
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class) @RunWith(FenixRobolectricTestRunner::class)
@ -373,4 +374,45 @@ class GleanMetricsServiceTest {
gleanService.track(Event.CreditCardManagementCardTapped) gleanService.track(Event.CreditCardManagementCardTapped)
assertTrue(CreditCards.managementCardTapped.testHasValue()) assertTrue(CreditCards.managementCardTapped.testHasValue())
} }
@Test
fun `GIVEN contile top site events WHEN the event is track THEN verify the event is correctly recorded`() {
assertFalse(TopSites.contileImpression.testHasValue())
gleanService.track(
Event.TopSiteContileImpression(
position = 1,
source = Event.TopSiteContileImpression.Source.NEWTAB
)
)
assertTrue(TopSites.contileImpression.testHasValue())
var event = TopSites.contileImpression.testGetValue()
assertEquals(1, event.size)
assertEquals("top_sites", event[0].category)
assertEquals("contile_impression", event[0].name)
assertEquals("1", event[0].extra!!["position"])
assertEquals("newtab", event[0].extra!!["source"])
assertFalse(TopSites.contileClick.testHasValue())
gleanService.track(
Event.TopSiteContileClick(
position = 2,
source = Event.TopSiteContileClick.Source.NEWTAB
)
)
assertTrue(TopSites.contileClick.testHasValue())
event = TopSites.contileClick.testGetValue()
assertEquals(1, event.size)
assertEquals("top_sites", event[0].category)
assertEquals("contile_click", event[0].name)
assertEquals("2", event[0].extra!!["position"])
assertEquals("newtab", event[0].extra!!["source"])
}
} }

@ -43,6 +43,8 @@ import org.junit.Ignore
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserFragmentDirections import org.mozilla.fenix.browser.BrowserFragmentDirections
@ -399,7 +401,7 @@ class DefaultSessionControlControllerTest {
every { controller.getAvailableSearchEngines() } returns listOf(searchEngine) every { controller.getAvailableSearchEngines() } returns listOf(searchEngine)
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) } verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenDefault) } verify { metrics.track(Event.TopSiteOpenDefault) }
@ -425,7 +427,7 @@ class DefaultSessionControlControllerTest {
every { controller.getAvailableSearchEngines() } returns listOf(searchEngine) every { controller.getAvailableSearchEngines() } returns listOf(searchEngine)
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) } verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { verify {
@ -452,7 +454,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("US", "US"))).joinBlocking() store.dispatch(SearchAction.SetRegionAction(RegionState("US", "US"))).joinBlocking()
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) } verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenDefault) } verify { metrics.track(Event.TopSiteOpenDefault) }
@ -481,7 +483,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("DE", "FR"))).joinBlocking() store.dispatch(SearchAction.SetRegionAction(RegionState("DE", "FR"))).joinBlocking()
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) } verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenDefault) } verify { metrics.track(Event.TopSiteOpenDefault) }
@ -514,7 +516,7 @@ class DefaultSessionControlControllerTest {
every { any<SearchState>().selectedOrDefaultSearchEngine } returns googleSearchEngine every { any<SearchState>().selectedOrDefaultSearchEngine } returns googleSearchEngine
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position = 0)
verify { verify {
metrics.track( metrics.track(
@ -550,7 +552,7 @@ class DefaultSessionControlControllerTest {
every { any<SearchState>().selectedOrDefaultSearchEngine } returns googleSearchEngine every { any<SearchState>().selectedOrDefaultSearchEngine } returns googleSearchEngine
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position = 0)
verify { verify {
metrics.track( metrics.track(
@ -582,7 +584,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("US", "US"))).joinBlocking() store.dispatch(SearchAction.SetRegionAction(RegionState("US", "US"))).joinBlocking()
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) } verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenPinned) } verify { metrics.track(Event.TopSiteOpenPinned) }
@ -611,7 +613,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("DE", "FR"))).joinBlocking() store.dispatch(SearchAction.SetRegionAction(RegionState("DE", "FR"))).joinBlocking()
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) } verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenPinned) } verify { metrics.track(Event.TopSiteOpenPinned) }
@ -640,7 +642,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("US", "US"))).joinBlocking() store.dispatch(SearchAction.SetRegionAction(RegionState("US", "US"))).joinBlocking()
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) } verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenFrecent) } verify { metrics.track(Event.TopSiteOpenFrecent) }
@ -669,7 +671,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("DE", "FR"))).joinBlocking() store.dispatch(SearchAction.SetRegionAction(RegionState("DE", "FR"))).joinBlocking()
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) } verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenFrecent) } verify { metrics.track(Event.TopSiteOpenFrecent) }
@ -695,11 +697,12 @@ class DefaultSessionControlControllerTest {
impressionUrl = "", impressionUrl = "",
createdAt = 0 createdAt = 0
) )
val position = 0
val controller = spyk(createController()) val controller = spyk(createController())
every { controller.getAvailableSearchEngines() } returns listOf(searchEngine) every { controller.getAvailableSearchEngines() } returns listOf(searchEngine)
controller.handleSelectTopSite(topSite) controller.handleSelectTopSite(topSite, position)
verify { metrics.track(Event.TopSiteOpenInNewTab) } verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenProvided) } verify { metrics.track(Event.TopSiteOpenProvided) }
@ -710,9 +713,41 @@ class DefaultSessionControlControllerTest {
startLoading = true startLoading = true
) )
} }
verify { controller.submitTopSitesImpressionPing(topSite, position) }
verify { activity.openToBrowser(BrowserDirection.FromHome) } verify { activity.openToBrowser(BrowserDirection.FromHome) }
} }
@Test
fun `GIVEN a provided top site WHEN the provided top site is clicked THEN submit a top site impression ping`() {
val controller = spyk(createController())
val topSite = TopSite.Provided(
id = 3,
title = "Mozilla",
url = "https://mozilla.com",
clickUrl = "https://mozilla.com/click",
imageUrl = "https://test.com/image2.jpg",
impressionUrl = "https://example.com",
createdAt = 3
)
val position = 0
controller.submitTopSitesImpressionPing(topSite, position)
verify {
metrics.track(
Event.TopSiteContileClick(
position = position + 1,
source = Event.TopSiteContileClick.Source.NEWTAB
)
)
TopSites.contileTileId.set(3)
TopSites.contileAdvertiser.set("mozilla")
TopSites.contileReportingUrl.set(topSite.clickUrl)
Pings.topsitesImpression.submit()
}
}
@Test @Test
fun handleStartBrowsingClicked() { fun handleStartBrowsingClicked() {
var hideOnboardingInvoked = false var hideOnboardingInvoked = false

@ -17,6 +17,10 @@ import org.junit.Assert.assertNull
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.databinding.TopSiteItemBinding import org.mozilla.fenix.databinding.TopSiteItemBinding
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ -28,6 +32,7 @@ class TopSiteItemViewHolderTest {
private lateinit var binding: TopSiteItemBinding private lateinit var binding: TopSiteItemBinding
private lateinit var interactor: TopSiteInteractor private lateinit var interactor: TopSiteInteractor
private lateinit var lifecycleOwner: LifecycleOwner private lateinit var lifecycleOwner: LifecycleOwner
private lateinit var metrics: MetricController
private val pocket = TopSite.Default( private val pocket = TopSite.Default(
id = 1L, id = 1L,
@ -41,22 +46,24 @@ class TopSiteItemViewHolderTest {
binding = TopSiteItemBinding.inflate(LayoutInflater.from(testContext)) binding = TopSiteItemBinding.inflate(LayoutInflater.from(testContext))
interactor = mockk(relaxed = true) interactor = mockk(relaxed = true)
lifecycleOwner = mockk(relaxed = true) lifecycleOwner = mockk(relaxed = true)
metrics = mockk(relaxed = true)
every { testContext.components.core.icons } returns BrowserIcons(testContext, mockk(relaxed = true)) every { testContext.components.core.icons } returns BrowserIcons(testContext, mockk(relaxed = true))
every { testContext.components.analytics.metrics } returns metrics
} }
@Test @Test
fun `calls interactor on click`() { fun `calls interactor on click`() {
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pocket) TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pocket, position = 0)
binding.topSiteItem.performClick() binding.topSiteItem.performClick()
verify { interactor.onSelectTopSite(pocket) } verify { interactor.onSelectTopSite(pocket, position = 0) }
} }
@Test @Test
fun `calls interactor on long click`() { fun `calls interactor on long click`() {
every { testContext.components.analytics } returns mockk(relaxed = true) every { testContext.components.analytics } returns mockk(relaxed = true)
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pocket) TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pocket, position = 0)
binding.topSiteItem.performLongClick() binding.topSiteItem.performLongClick()
verify { interactor.onTopSiteMenuOpened() } verify { interactor.onTopSiteMenuOpened() }
@ -71,7 +78,7 @@ class TopSiteItemViewHolderTest {
createdAt = 0 createdAt = 0
) )
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(defaultTopSite) TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(defaultTopSite, position = 0)
val pinIndicator = binding.topSiteTitle.compoundDrawables[0] val pinIndicator = binding.topSiteTitle.compoundDrawables[0]
assertNotNull(pinIndicator) assertNotNull(pinIndicator)
@ -86,7 +93,7 @@ class TopSiteItemViewHolderTest {
createdAt = 0 createdAt = 0
) )
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pinnedTopSite) TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pinnedTopSite, position = 0)
val pinIndicator = binding.topSiteTitle.compoundDrawables[0] val pinIndicator = binding.topSiteTitle.compoundDrawables[0]
assertNotNull(pinIndicator) assertNotNull(pinIndicator)
@ -101,9 +108,39 @@ class TopSiteItemViewHolderTest {
createdAt = 0 createdAt = 0
) )
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(frecentTopSite) TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(frecentTopSite, position = 0)
val pinIndicator = binding.topSiteTitle.compoundDrawables[0] val pinIndicator = binding.topSiteTitle.compoundDrawables[0]
assertNull(pinIndicator) assertNull(pinIndicator)
} }
@Test
fun `GIVEN a provided top site and position WHEN the provided top site is shown THEN submit a top site impression ping`() {
val topSite = TopSite.Provided(
id = 3,
title = "Mozilla",
url = "https://mozilla.com",
clickUrl = "https://mozilla.com/click",
imageUrl = "https://test.com/image2.jpg",
impressionUrl = "https://example.com",
createdAt = 3
)
val position = 0
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).submitTopSitesImpressionPing(topSite, position)
verify {
metrics.track(
Event.TopSiteContileImpression(
position = position + 1,
source = Event.TopSiteContileImpression.Source.NEWTAB
)
)
TopSites.contileTileId.set(3)
TopSites.contileAdvertiser.set("mozilla")
TopSites.contileReportingUrl.set(topSite.impressionUrl)
Pings.topsitesImpression.submit()
}
}
} }

Loading…
Cancel
Save