diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt index 3a73bfef1..0c372299e 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt @@ -242,13 +242,58 @@ internal class ReleaseMetricController( Component.FEATURE_SEARCH to InContentTelemetry.IN_CONTENT_SEARCH -> { BrowserSearch.inContent[value!!].add() } + Component.SUPPORT_WEBEXTENSIONS to WebExtensionFacts.Items.WEB_EXTENSIONS_INITIALIZED -> { + metadata?.get("installed")?.let { installedAddons -> + if (installedAddons is List<*>) { + settings.installedAddonsCount = installedAddons.size + settings.installedAddonsList = installedAddons.joinToString(",") + } + } - else -> { - this.toEvent()?.also { - track(it) + metadata?.get("enabled")?.let { enabledAddons -> + if (enabledAddons is List<*>) { + settings.enabledAddonsCount = enabledAddons.size + settings.enabledAddonsList = enabledAddons.joinToString(",") + } + } + Unit + } + Component.COMPOSE_AWESOMEBAR to ComposeAwesomeBarFacts.Items.PROVIDER_DURATION -> { + metadata?.get(ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR)?.let { providerTiming -> + require(providerTiming is Pair<*, *>) { "Expected providerTiming to be a Pair" } + when (val provider = providerTiming.first as AwesomeBar.SuggestionProvider) { + is HistoryStorageSuggestionProvider -> PerfAwesomebar.historySuggestions + is BookmarksStorageSuggestionProvider -> PerfAwesomebar.bookmarkSuggestions + is SessionSuggestionProvider -> PerfAwesomebar.sessionSuggestions + is SearchSuggestionProvider -> PerfAwesomebar.searchEngineSuggestions + is ClipboardSuggestionProvider -> PerfAwesomebar.clipboardSuggestions + is ShortcutsSuggestionProvider -> PerfAwesomebar.shortcutsSuggestions + // NB: add PerfAwesomebar.syncedTabsSuggestions once we're using SyncedTabsSuggestionProvider + else -> { + Logger("Metrics").error("Unknown suggestion provider: $provider") + null + } + }?.accumulateSamples(longArrayOf(providerTiming.second as Long)) + } + Unit + } + Component.FEATURE_TOP_SITES to TopSitesFacts.Items.COUNT -> { + value?.let { + var count = 0 + try { + count = it.toInt() + } catch (e: NumberFormatException) { + // Do nothing + } + + settings.topSitesSize = count } Unit } + + else -> { + // no-op + } } override fun start(type: MetricServiceType) { @@ -293,13 +338,6 @@ internal class ReleaseMetricController( } } - @VisibleForTesting - internal fun factToEvent( - fact: Fact - ): Event? { - return fact.toEvent() - } - private fun isInitialized(type: MetricServiceType): Boolean = initialized.contains(type) private fun isTelemetryEnabled(type: MetricServiceType): Boolean = when (type) { @@ -307,62 +345,6 @@ internal class ReleaseMetricController( MetricServiceType.Marketing -> isMarketingDataTelemetryEnabled() } - @Suppress("LongMethod", "MaxLineLength") - private fun Fact.toEvent(): Event? = when { - Component.SUPPORT_WEBEXTENSIONS == component && WebExtensionFacts.Items.WEB_EXTENSIONS_INITIALIZED == item -> { - metadata?.get("installed")?.let { installedAddons -> - if (installedAddons is List<*>) { - settings.installedAddonsCount = installedAddons.size - settings.installedAddonsList = installedAddons.joinToString(",") - } - } - - metadata?.get("enabled")?.let { enabledAddons -> - if (enabledAddons is List<*>) { - settings.enabledAddonsCount = enabledAddons.size - settings.enabledAddonsList = enabledAddons.joinToString(",") - } - } - - null - } - Component.COMPOSE_AWESOMEBAR == component && ComposeAwesomeBarFacts.Items.PROVIDER_DURATION == item -> { - metadata?.get(ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR)?.let { providerTiming -> - require(providerTiming is Pair<*, *>) { "Expected providerTiming to be a Pair" } - when (val provider = providerTiming.first as AwesomeBar.SuggestionProvider) { - is HistoryStorageSuggestionProvider -> PerfAwesomebar.historySuggestions - is BookmarksStorageSuggestionProvider -> PerfAwesomebar.bookmarkSuggestions - is SessionSuggestionProvider -> PerfAwesomebar.sessionSuggestions - is SearchSuggestionProvider -> PerfAwesomebar.searchEngineSuggestions - is ClipboardSuggestionProvider -> PerfAwesomebar.clipboardSuggestions - is ShortcutsSuggestionProvider -> PerfAwesomebar.shortcutsSuggestions - // NB: add PerfAwesomebar.syncedTabsSuggestions once we're using SyncedTabsSuggestionProvider - else -> { - Logger("Metrics").error("Unknown suggestion provider: $provider") - null - } - }?.accumulateSamples(longArrayOf(providerTiming.second as Long)) - } - null - } - - Component.FEATURE_TOP_SITES == component && TopSitesFacts.Items.COUNT == item -> { - value?.let { - var count = 0 - try { - count = it.toInt() - } catch (e: NumberFormatException) { - // Do nothing - } - - settings.topSitesSize = count - } - null - } - - else -> null - } - companion object { /** * Text selection long press context items to be tracked. diff --git a/app/src/test/java/org/mozilla/fenix/components/metrics/MetricControllerTest.kt b/app/src/test/java/org/mozilla/fenix/components/metrics/MetricControllerTest.kt index bba1e3459..0d13ef532 100644 --- a/app/src/test/java/org/mozilla/fenix/components/metrics/MetricControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/metrics/MetricControllerTest.kt @@ -12,6 +12,11 @@ import io.mockk.verifyAll import io.mockk.impl.annotations.MockK import mozilla.components.feature.autofill.facts.AutofillFacts import mozilla.components.feature.awesomebar.facts.AwesomeBarFacts +import mozilla.components.feature.awesomebar.provider.BookmarksStorageSuggestionProvider +import mozilla.components.feature.awesomebar.provider.ClipboardSuggestionProvider +import mozilla.components.feature.awesomebar.provider.HistoryStorageSuggestionProvider +import mozilla.components.feature.awesomebar.provider.SearchSuggestionProvider +import mozilla.components.feature.awesomebar.provider.SessionSuggestionProvider import mozilla.components.feature.contextmenu.facts.ContextMenuFacts import mozilla.components.feature.media.facts.MediaFacts import mozilla.components.feature.prompts.dialog.LoginDialogFacts @@ -43,11 +48,14 @@ import org.mozilla.fenix.GleanMetrics.ContextualMenu import org.mozilla.fenix.GleanMetrics.CreditCards import org.mozilla.fenix.GleanMetrics.LoginDialog import org.mozilla.fenix.GleanMetrics.MediaNotification +import org.mozilla.fenix.GleanMetrics.PerfAwesomebar import org.mozilla.fenix.GleanMetrics.ProgressiveWebApp import org.mozilla.fenix.GleanMetrics.SyncedTabs import org.mozilla.fenix.components.metrics.ReleaseMetricController.Companion import org.mozilla.fenix.helpers.FenixRobolectricTestRunner +import org.mozilla.fenix.search.awesomebar.ShortcutsSuggestionProvider import org.mozilla.fenix.utils.Settings +import mozilla.components.compose.browser.awesomebar.AwesomeBarFacts as ComposeAwesomeBarFacts @RunWith(FenixRobolectricTestRunner::class) class MetricControllerTest { @@ -147,6 +155,113 @@ class MetricControllerTest { verify(exactly = 1) { dataService1.stop() } } + @Test + fun `WHEN AwesomeBar duration fact is processed THEN the correct metric is recorded`() { + val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk()) + val action = mockk() + val duration = 1000L + var metadata = mapOf>( + ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair( + mockk(), + duration + ) + ) + var fact = Fact( + Component.COMPOSE_AWESOMEBAR, + action, + ComposeAwesomeBarFacts.Items.PROVIDER_DURATION, + metadata = metadata + ) + // Verify history based suggestions + assertFalse(PerfAwesomebar.historySuggestions.testHasValue()) + + with(controller) { + fact.process() + } + + assertTrue(PerfAwesomebar.historySuggestions.testHasValue()) + + // Verify bookmark based suggestions + metadata = mapOf( + ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair( + mockk(), + duration + ) + ) + fact = fact.copy(metadata = metadata) + assertFalse(PerfAwesomebar.bookmarkSuggestions.testHasValue()) + + with(controller) { + fact.process() + } + + assertTrue(PerfAwesomebar.bookmarkSuggestions.testHasValue()) + + // Verify session based suggestions + metadata = mapOf( + ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair( + mockk(), + duration + ) + ) + fact = fact.copy(metadata = metadata) + assertFalse(PerfAwesomebar.sessionSuggestions.testHasValue()) + + with(controller) { + fact.process() + } + + assertTrue(PerfAwesomebar.sessionSuggestions.testHasValue()) + + // Verify search engine suggestions + metadata = mapOf( + ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair( + mockk(), + duration + ) + ) + fact = fact.copy(metadata = metadata) + assertFalse(PerfAwesomebar.searchEngineSuggestions.testHasValue()) + + with(controller) { + fact.process() + } + + assertTrue(PerfAwesomebar.searchEngineSuggestions.testHasValue()) + + // Verify clipboard based suggestions + metadata = mapOf( + ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair( + mockk(), + duration + ) + ) + fact = fact.copy(metadata = metadata) + assertFalse(PerfAwesomebar.clipboardSuggestions.testHasValue()) + + with(controller) { + fact.process() + } + + assertTrue(PerfAwesomebar.clipboardSuggestions.testHasValue()) + + // Verify shortcut based suggestions + metadata = mapOf( + ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair( + mockk(), + duration + ) + ) + fact = fact.copy(metadata = metadata) + assertFalse(PerfAwesomebar.shortcutsSuggestions.testHasValue()) + + with(controller) { + fact.process() + } + + assertTrue(PerfAwesomebar.shortcutsSuggestions.testHasValue()) + } + @Test fun `release metric controller starts and stops all marketing services`() { var enabled = true @@ -194,7 +309,9 @@ class MetricControllerTest { ) verify(exactly = 0) { settings.topSitesSize = any() } - controller.factToEvent(fact) + with(controller) { + fact.process() + } verify(exactly = 1) { settings.topSitesSize = any() } } @@ -222,7 +339,9 @@ class MetricControllerTest { assertEquals(settings.installedAddonsList, "") assertEquals(settings.enabledAddonsCount, 0) assertEquals(settings.enabledAddonsList, "") - controller.factToEvent(fact) + with(controller) { + fact.process() + } assertEquals(settings.installedAddonsCount, 4) assertEquals(settings.installedAddonsList, "test1,test2,test3,test4") assertEquals(settings.enabledAddonsCount, 2)