From f75be41d3a25d7341b63aaf9670eb7bdc213ee37 Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Tue, 28 Jul 2020 13:44:28 -0700 Subject: [PATCH] Add metric tests --- .../fenix/components/metrics/Metrics.kt | 18 +- .../metrics/BreadcrumbRecorderTest.kt | 22 ++- .../metrics/MetricControllerTest.kt | 170 ++++++++++++++++++ 3 files changed, 203 insertions(+), 7 deletions(-) create mode 100644 app/src/test/java/org/mozilla/fenix/components/metrics/MetricControllerTest.kt diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/Metrics.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/Metrics.kt index f6543991a..c914dc24e 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/Metrics.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/Metrics.kt @@ -5,6 +5,7 @@ package org.mozilla.fenix.components.metrics import android.content.Context +import androidx.annotation.VisibleForTesting import mozilla.components.browser.awesomebar.facts.BrowserAwesomeBarFacts import mozilla.components.browser.errorpages.ErrorType import mozilla.components.browser.menu.facts.BrowserMenuFacts @@ -640,21 +641,26 @@ interface MetricController { } } -private class DebugMetricController : MetricController { +@VisibleForTesting +internal class DebugMetricController( + private val logger: Logger = Logger() +) : MetricController { + override fun start(type: MetricServiceType) { - Logger.debug("DebugMetricController: start") + logger.debug("DebugMetricController: start") } override fun stop(type: MetricServiceType) { - Logger.debug("DebugMetricController: stop") + logger.debug("DebugMetricController: stop") } override fun track(event: Event) { - Logger.debug("DebugMetricController: track event: $event") + logger.debug("DebugMetricController: track event: $event") } } -private class ReleaseMetricController( +@VisibleForTesting +internal class ReleaseMetricController( private val services: List, private val isDataTelemetryEnabled: () -> Boolean, private val isMarketingDataTelemetryEnabled: () -> Boolean @@ -706,7 +712,7 @@ private class ReleaseMetricController( val isEnabled = isTelemetryEnabled(it.type) val isInitialized = isInitialized(it.type) if (!isEnabled || !isInitialized) { - return + return@forEach } it.track(event) diff --git a/app/src/test/java/org/mozilla/fenix/components/metrics/BreadcrumbRecorderTest.kt b/app/src/test/java/org/mozilla/fenix/components/metrics/BreadcrumbRecorderTest.kt index 61a62981b..454cd8881 100644 --- a/app/src/test/java/org/mozilla/fenix/components/metrics/BreadcrumbRecorderTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/metrics/BreadcrumbRecorderTest.kt @@ -4,8 +4,11 @@ package org.mozilla.fenix.components.metrics +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleRegistry import androidx.navigation.NavController import androidx.navigation.NavDestination +import io.mockk.Called import io.mockk.mockk import io.mockk.spyk import io.mockk.verify @@ -16,7 +19,24 @@ import mozilla.components.support.base.crash.Breadcrumb import org.junit.Assert.assertEquals import org.junit.Test -internal class BreadcrumbRecorderTest { +class BreadcrumbRecorderTest { + + @Test + fun `sets listener on create and destroy`() { + val navController: NavController = mockk(relaxUnitFun = true) + + val lifecycle = LifecycleRegistry(mockk()) + val breadCrumbRecorder = BreadcrumbsRecorder(mockk(), navController) { "test" } + + lifecycle.addObserver(breadCrumbRecorder) + verify { navController wasNot Called } + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) + verify { navController.addOnDestinationChangedListener(breadCrumbRecorder) } + + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) + verify { navController.removeOnDestinationChangedListener(breadCrumbRecorder) } + } @Test fun `ensure crash reporter recordCrashBreadcrumb is called`() { 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 new file mode 100644 index 000000000..97934c541 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/components/metrics/MetricControllerTest.kt @@ -0,0 +1,170 @@ +/* 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.components.metrics + +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import io.mockk.verify +import io.mockk.verifyAll +import mozilla.components.support.base.log.logger.Logger +import org.junit.Before +import org.junit.Test + +class MetricControllerTest { + + @MockK(relaxUnitFun = true) private lateinit var dataService1: MetricsService + @MockK(relaxUnitFun = true) private lateinit var dataService2: MetricsService + @MockK(relaxUnitFun = true) private lateinit var marketingService1: MetricsService + @MockK(relaxUnitFun = true) private lateinit var marketingService2: MetricsService + + @Before + fun setup() { + MockKAnnotations.init(this) + + every { dataService1.type } returns MetricServiceType.Data + every { dataService2.type } returns MetricServiceType.Data + every { marketingService1.type } returns MetricServiceType.Marketing + every { marketingService2.type } returns MetricServiceType.Marketing + } + + @Test + fun `debug metric controller emits logs`() { + val logger = mockk(relaxed = true) + val controller = DebugMetricController(logger) + + controller.start(MetricServiceType.Data) + verify { logger.debug("DebugMetricController: start") } + + controller.stop(MetricServiceType.Data) + verify { logger.debug("DebugMetricController: stop") } + + controller.track(Event.OpenedAppFirstRun) + verify { logger.debug("DebugMetricController: track event: ${Event.OpenedAppFirstRun}") } + } + + @Test + fun `release metric controller starts and stops all data services`() { + var enabled = true + val controller = ReleaseMetricController( + services = listOf(dataService1, marketingService1, dataService2, marketingService2), + isDataTelemetryEnabled = { enabled }, + isMarketingDataTelemetryEnabled = { enabled } + ) + + controller.start(MetricServiceType.Data) + verify { dataService1.start() } + verify { dataService2.start() } + + enabled = false + + controller.stop(MetricServiceType.Data) + verify { dataService1.stop() } + verify { dataService2.stop() } + + verifyAll(inverse = true) { + marketingService1.start() + marketingService1.stop() + marketingService2.start() + marketingService2.stop() + } + } + + @Test + fun `release metric controller starts data service only if enabled`() { + val controller = ReleaseMetricController( + services = listOf(dataService1), + isDataTelemetryEnabled = { false }, + isMarketingDataTelemetryEnabled = { true } + ) + + controller.start(MetricServiceType.Data) + verify(inverse = true) { dataService1.start() } + + controller.stop(MetricServiceType.Data) + verify(inverse = true) { dataService1.stop() } + } + + @Test + fun `release metric controller starts service only once`() { + var enabled = true + val controller = ReleaseMetricController( + services = listOf(dataService1), + isDataTelemetryEnabled = { enabled }, + isMarketingDataTelemetryEnabled = { true } + ) + + controller.start(MetricServiceType.Data) + controller.start(MetricServiceType.Data) + verify(exactly = 1) { dataService1.start() } + + enabled = false + + controller.stop(MetricServiceType.Data) + controller.stop(MetricServiceType.Data) + verify(exactly = 1) { dataService1.stop() } + } + + @Test + fun `release metric controller starts and stops all marketing services`() { + var enabled = true + val controller = ReleaseMetricController( + services = listOf(dataService1, marketingService1, dataService2, marketingService2), + isDataTelemetryEnabled = { enabled }, + isMarketingDataTelemetryEnabled = { enabled } + ) + + controller.start(MetricServiceType.Marketing) + verify { marketingService1.start() } + verify { marketingService2.start() } + + enabled = false + + controller.stop(MetricServiceType.Marketing) + verify { marketingService1.stop() } + verify { marketingService2.stop() } + + verifyAll(inverse = true) { + dataService1.start() + dataService1.stop() + dataService2.start() + dataService2.stop() + } + } + + @Test + fun `tracking events should be sent to matching service`() { + val controller = ReleaseMetricController( + listOf(dataService1, marketingService1), + isDataTelemetryEnabled = { true }, + isMarketingDataTelemetryEnabled = { true } + ) + every { dataService1.shouldTrack(Event.TabMediaPause) } returns false + every { marketingService1.shouldTrack(Event.TabMediaPause) } returns true + + controller.start(MetricServiceType.Marketing) + controller.track(Event.TabMediaPause) + verify { marketingService1.track(Event.TabMediaPause) } + } + + @Test + fun `tracking events should be sent to enabled service`() { + var enabled = true + val controller = ReleaseMetricController( + listOf(dataService1, marketingService1), + isDataTelemetryEnabled = { enabled }, + isMarketingDataTelemetryEnabled = { true } + ) + every { dataService1.shouldTrack(Event.TabMediaPause) } returns true + every { marketingService1.shouldTrack(Event.TabMediaPause) } returns true + + controller.start(MetricServiceType.Marketing) + enabled = false + + controller.track(Event.TabMediaPause) + verify { marketingService1.track(Event.TabMediaPause) } + } +}