Post: Add experiment flags, push and telemetry tests for BackgroundServices
parent
eeaeb973ff
commit
d67fb3eed2
|
@ -6,6 +6,8 @@ package org.mozilla.fenix.components
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import androidx.annotation.VisibleForTesting.PRIVATE
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -36,6 +38,7 @@ import mozilla.components.support.base.log.logger.Logger
|
||||||
import org.mozilla.fenix.Experiments
|
import org.mozilla.fenix.Experiments
|
||||||
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.components.metrics.MetricController
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.isInExperiment
|
import org.mozilla.fenix.isInExperiment
|
||||||
|
@ -47,7 +50,7 @@ import org.mozilla.fenix.test.Mockable
|
||||||
*/
|
*/
|
||||||
@Mockable
|
@Mockable
|
||||||
class BackgroundServices(
|
class BackgroundServices(
|
||||||
context: Context,
|
private val context: Context,
|
||||||
historyStorage: PlacesHistoryStorage,
|
historyStorage: PlacesHistoryStorage,
|
||||||
bookmarkStorage: PlacesBookmarksStorage
|
bookmarkStorage: PlacesBookmarksStorage
|
||||||
) {
|
) {
|
||||||
|
@ -79,35 +82,17 @@ class BackgroundServices(
|
||||||
capabilities = setOf(DeviceCapability.SEND_TAB)
|
capabilities = setOf(DeviceCapability.SEND_TAB)
|
||||||
)
|
)
|
||||||
// If sync has been turned off on the server then disable syncing.
|
// If sync has been turned off on the server then disable syncing.
|
||||||
private val syncConfig = if (context.isInExperiment(Experiments.asFeatureSyncDisabled)) {
|
@VisibleForTesting(otherwise = PRIVATE)
|
||||||
|
val syncConfig = if (context.isInExperiment(Experiments.asFeatureSyncDisabled)) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
SyncConfig(setOf(SyncEngine.HISTORY, SyncEngine.BOOKMARKS), syncPeriodInMinutes = 240L) // four hours
|
SyncConfig(setOf(SyncEngine.HISTORY, SyncEngine.BOOKMARKS), syncPeriodInMinutes = 240L) // four hours
|
||||||
}
|
}
|
||||||
|
|
||||||
val pushConfig by lazy {
|
val pushConfig by lazy { makePushConfig() }
|
||||||
val logger = Logger("PushConfig")
|
|
||||||
val projectIdKey = context.getString(R.string.pref_key_push_project_id)
|
|
||||||
val resId = context.resources.getIdentifier(projectIdKey, "string", context.packageName)
|
|
||||||
if (resId == 0) {
|
|
||||||
logger.warn("No firebase configuration found; cannot support push service.")
|
|
||||||
return@lazy null
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("Creating push configuration for autopush.")
|
|
||||||
val projectId = context.resources.getString(resId)
|
|
||||||
PushConfig(projectId)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val pushService by lazy { FirebasePush() }
|
private val pushService by lazy { FirebasePush() }
|
||||||
|
|
||||||
val push by lazy {
|
val push by lazy { makePush() }
|
||||||
AutoPushFeature(
|
|
||||||
context = context,
|
|
||||||
service = pushService,
|
|
||||||
config = pushConfig!!
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Make the "history" and "bookmark" stores accessible to workers spawned by the sync manager.
|
// Make the "history" and "bookmark" stores accessible to workers spawned by the sync manager.
|
||||||
|
@ -125,73 +110,46 @@ class BackgroundServices(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val telemetryAccountObserver = object : AccountObserver {
|
private val telemetryAccountObserver = TelemetryAccountObserver(
|
||||||
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
|
context,
|
||||||
when (authType) {
|
context.components.analytics.metrics
|
||||||
// User signed-in into an existing FxA account.
|
)
|
||||||
AuthType.Signin ->
|
|
||||||
context.components.analytics.metrics.track(Event.SyncAuthSignIn)
|
|
||||||
|
|
||||||
// User created a new FxA account.
|
private val pushAccountObserver = PushAccountObserver(push)
|
||||||
AuthType.Signup ->
|
|
||||||
context.components.analytics.metrics.track(Event.SyncAuthSignUp)
|
|
||||||
|
|
||||||
// User paired to an existing account via QR code scanning.
|
val accountManager = makeAccountManager(context, serverConfig, deviceConfig, syncConfig)
|
||||||
AuthType.Pairing ->
|
|
||||||
context.components.analytics.metrics.track(Event.SyncAuthPaired)
|
|
||||||
|
|
||||||
// User signed-in into an FxA account shared from another locally installed app
|
@VisibleForTesting(otherwise = PRIVATE)
|
||||||
// (e.g. Fennec).
|
fun makePush(): AutoPushFeature {
|
||||||
AuthType.Shared ->
|
return AutoPushFeature(
|
||||||
context.components.analytics.metrics.track(Event.SyncAuthFromShared)
|
context = context,
|
||||||
|
service = pushService,
|
||||||
// Account Manager recovered a broken FxA auth state, without direct user involvement.
|
config = pushConfig!!
|
||||||
AuthType.Recovered ->
|
)
|
||||||
context.components.analytics.metrics.track(Event.SyncAuthRecovered)
|
|
||||||
|
|
||||||
// User signed-in into an FxA account via unknown means.
|
|
||||||
// Exact mechanism identified by the 'action' param.
|
|
||||||
is AuthType.OtherExternal ->
|
|
||||||
context.components.analytics.metrics.track(Event.SyncAuthOtherExternal)
|
|
||||||
}
|
|
||||||
// Used by Leanplum as a context variable.
|
|
||||||
context.settings.fxaSignedIn = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onLoggedOut() {
|
|
||||||
context.components.analytics.metrics.track(Event.SyncAuthSignOut)
|
|
||||||
// Used by Leanplum as a context variable.
|
|
||||||
context.settings.fxaSignedIn = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@VisibleForTesting(otherwise = PRIVATE)
|
||||||
* When we login/logout of FxA, we need to update our push subscriptions to match the newly
|
fun makePushConfig(): PushConfig? {
|
||||||
* logged in account.
|
val logger = Logger("PushConfig")
|
||||||
*
|
val projectIdKey = context.getString(R.string.pref_key_push_project_id)
|
||||||
* We added the push service to the AccountManager observer so that we can control when the
|
val resId = context.resources.getIdentifier(projectIdKey, "string", context.packageName)
|
||||||
* service will start/stop. Firebase was added when landing the push service to ensure it works
|
if (resId == 0) {
|
||||||
* as expected without causing any (as many) side effects.
|
logger.warn("No firebase configuration found; cannot support push service.")
|
||||||
*
|
return null
|
||||||
* In order to use Firebase with Leanplum and other marketing features, we need it always
|
|
||||||
* running so we cannot leave this code in place when we implement those features.
|
|
||||||
*
|
|
||||||
* We should have this removed when we are more confident
|
|
||||||
* of the send-tab/push feature: https://github.com/mozilla-mobile/fenix/issues/4063
|
|
||||||
*/
|
|
||||||
private val pushAccountObserver = object : AccountObserver {
|
|
||||||
override fun onLoggedOut() {
|
|
||||||
push.unsubscribeForType(PushType.Services)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
|
logger.debug("Creating push configuration for autopush.")
|
||||||
if (authType != AuthType.Existing) {
|
val projectId = context.resources.getString(resId)
|
||||||
push.subscribeForType(PushType.Services)
|
return PushConfig(projectId)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val accountManager = FxaAccountManager(
|
@VisibleForTesting(otherwise = PRIVATE)
|
||||||
|
fun makeAccountManager(
|
||||||
|
context: Context,
|
||||||
|
serverConfig: ServerConfig,
|
||||||
|
deviceConfig: DeviceConfig,
|
||||||
|
syncConfig: SyncConfig?
|
||||||
|
) = FxaAccountManager(
|
||||||
context,
|
context,
|
||||||
serverConfig,
|
serverConfig,
|
||||||
deviceConfig,
|
deviceConfig,
|
||||||
|
@ -255,3 +213,74 @@ class BackgroundServices(
|
||||||
NotificationManager(context)
|
NotificationManager(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting(otherwise = PRIVATE)
|
||||||
|
class TelemetryAccountObserver(
|
||||||
|
private val context: Context,
|
||||||
|
private val metricController: MetricController
|
||||||
|
) : AccountObserver {
|
||||||
|
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
|
||||||
|
when (authType) {
|
||||||
|
// User signed-in into an existing FxA account.
|
||||||
|
AuthType.Signin ->
|
||||||
|
metricController.track(Event.SyncAuthSignIn)
|
||||||
|
|
||||||
|
// User created a new FxA account.
|
||||||
|
AuthType.Signup ->
|
||||||
|
metricController.track(Event.SyncAuthSignUp)
|
||||||
|
|
||||||
|
// User paired to an existing account via QR code scanning.
|
||||||
|
AuthType.Pairing ->
|
||||||
|
metricController.track(Event.SyncAuthPaired)
|
||||||
|
|
||||||
|
// User signed-in into an FxA account shared from another locally installed app
|
||||||
|
// (e.g. Fennec).
|
||||||
|
AuthType.Shared ->
|
||||||
|
metricController.track(Event.SyncAuthFromShared)
|
||||||
|
|
||||||
|
// Account Manager recovered a broken FxA auth state, without direct user involvement.
|
||||||
|
AuthType.Recovered ->
|
||||||
|
metricController.track(Event.SyncAuthRecovered)
|
||||||
|
|
||||||
|
// User signed-in into an FxA account via unknown means.
|
||||||
|
// Exact mechanism identified by the 'action' param.
|
||||||
|
is AuthType.OtherExternal ->
|
||||||
|
metricController.track(Event.SyncAuthOtherExternal)
|
||||||
|
}
|
||||||
|
// Used by Leanplum as a context variable.
|
||||||
|
context.settings.fxaSignedIn = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoggedOut() {
|
||||||
|
metricController.track(Event.SyncAuthSignOut)
|
||||||
|
// Used by Leanplum as a context variable.
|
||||||
|
context.settings.fxaSignedIn = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we login/logout of FxA, we need to update our push subscriptions to match the newly
|
||||||
|
* logged in account.
|
||||||
|
*
|
||||||
|
* We added the push service to the AccountManager observer so that we can control when the
|
||||||
|
* service will start/stop. Firebase was added when landing the push service to ensure it works
|
||||||
|
* as expected without causing any (as many) side effects.
|
||||||
|
*
|
||||||
|
* In order to use Firebase with Leanplum and other marketing features, we need it always
|
||||||
|
* running so we cannot leave this code in place when we implement those features.
|
||||||
|
*
|
||||||
|
* We should have this removed when we are more confident
|
||||||
|
* of the send-tab/push feature: https://github.com/mozilla-mobile/fenix/issues/4063
|
||||||
|
*/
|
||||||
|
@VisibleForTesting(otherwise = PRIVATE)
|
||||||
|
class PushAccountObserver(private val push: AutoPushFeature) : AccountObserver {
|
||||||
|
override fun onLoggedOut() {
|
||||||
|
push.unsubscribeForType(PushType.Services)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
|
||||||
|
if (authType != AuthType.Existing) {
|
||||||
|
push.subscribeForType(PushType.Services)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,215 @@
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import mozilla.components.concept.sync.AccountObserver
|
||||||
|
import mozilla.components.concept.sync.AuthType
|
||||||
|
import mozilla.components.concept.sync.OAuthAccount
|
||||||
|
import mozilla.components.feature.push.AutoPushFeature
|
||||||
|
import mozilla.components.feature.push.PushConfig
|
||||||
|
import mozilla.components.feature.push.PushType
|
||||||
|
import mozilla.components.service.fxa.DeviceConfig
|
||||||
|
import mozilla.components.service.fxa.ServerConfig
|
||||||
|
import mozilla.components.service.fxa.SyncConfig
|
||||||
|
import mozilla.components.service.fxa.SyncEngine
|
||||||
|
import mozilla.components.service.fxa.manager.FxaAccountManager
|
||||||
|
import mozilla.components.support.base.observer.ObserverRegistry
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.Experiments
|
||||||
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
import org.mozilla.fenix.components.metrics.MetricController
|
||||||
|
import org.mozilla.fenix.isInExperiment
|
||||||
|
|
||||||
|
class BackgroundServicesTest {
|
||||||
|
class TestableBackgroundServices(
|
||||||
|
val context: Context
|
||||||
|
) : BackgroundServices(context, mockk(), mockk()) {
|
||||||
|
override fun makeAccountManager(
|
||||||
|
context: Context,
|
||||||
|
serverConfig: ServerConfig,
|
||||||
|
deviceConfig: DeviceConfig,
|
||||||
|
syncConfig: SyncConfig?
|
||||||
|
) = mockk<FxaAccountManager>(relaxed = true)
|
||||||
|
|
||||||
|
override fun makePushConfig() = mockk<PushConfig>(relaxed = true)
|
||||||
|
override fun makePush() = mockk<AutoPushFeature>(relaxed = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `experiment flags`() {
|
||||||
|
val context = mockk<Context>(relaxed = true)
|
||||||
|
|
||||||
|
every { context.isInExperiment(eq(Experiments.asFeatureWebChannelsDisabled)) } returns false
|
||||||
|
assertEquals("urn:ietf:wg:oauth:2.0:oob:oauth-redirect-webchannel", BackgroundServices.redirectUrl(context))
|
||||||
|
|
||||||
|
every { context.isInExperiment(eq(Experiments.asFeatureWebChannelsDisabled)) } returns true
|
||||||
|
assertEquals("https://accounts.firefox.com/oauth/success/a2270f727f45f648", BackgroundServices.redirectUrl(context))
|
||||||
|
|
||||||
|
every { context.isInExperiment(eq(Experiments.asFeatureSyncDisabled)) } returns false
|
||||||
|
var backgroundServices = TestableBackgroundServices(context)
|
||||||
|
assertEquals(
|
||||||
|
SyncConfig(setOf(SyncEngine.HISTORY, SyncEngine.BOOKMARKS), syncPeriodInMinutes = 240L),
|
||||||
|
backgroundServices.syncConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
every { context.isInExperiment(eq(Experiments.asFeatureSyncDisabled)) } returns true
|
||||||
|
backgroundServices = TestableBackgroundServices(context)
|
||||||
|
assertNull(backgroundServices.syncConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `push account observer`() {
|
||||||
|
val push = mockk<AutoPushFeature>()
|
||||||
|
val observer = PushAccountObserver(push)
|
||||||
|
val registry = ObserverRegistry<AccountObserver>()
|
||||||
|
registry.register(observer)
|
||||||
|
val account = mockk<OAuthAccount>()
|
||||||
|
|
||||||
|
// Being explicit here (vs using 'any()') ensures that any change to which PushType variants
|
||||||
|
// are being subscribed/unsubscribed will break these tests, forcing developer to expand them.
|
||||||
|
every { push.subscribeForType(PushType.Services) } just Runs
|
||||||
|
every { push.unsubscribeForType(PushType.Services) } just Runs
|
||||||
|
|
||||||
|
// 'Existing' auth type doesn't trigger subscription - we're already subscribed.
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Existing) }
|
||||||
|
verify(exactly = 0) { push.subscribeForType(any()) }
|
||||||
|
|
||||||
|
// Every other auth type does.
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Signin) }
|
||||||
|
verify(exactly = 1) { push.subscribeForType(eq(PushType.Services)) }
|
||||||
|
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Signup) }
|
||||||
|
verify(exactly = 2) { push.subscribeForType(eq(PushType.Services)) }
|
||||||
|
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Recovered) }
|
||||||
|
verify(exactly = 3) { push.subscribeForType(eq(PushType.Services)) }
|
||||||
|
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Shared) }
|
||||||
|
verify(exactly = 4) { push.subscribeForType(eq(PushType.Services)) }
|
||||||
|
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Pairing) }
|
||||||
|
verify(exactly = 5) { push.subscribeForType(eq(PushType.Services)) }
|
||||||
|
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.OtherExternal(null)) }
|
||||||
|
verify(exactly = 6) { push.subscribeForType(eq(PushType.Services)) }
|
||||||
|
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.OtherExternal("someAction")) }
|
||||||
|
verify(exactly = 7) { push.subscribeForType(eq(PushType.Services)) }
|
||||||
|
|
||||||
|
// None of the above unsubscribed.
|
||||||
|
verify(exactly = 0) { push.unsubscribeForType(any()) }
|
||||||
|
|
||||||
|
// Finally, log-out should unsubscribe.
|
||||||
|
registry.notifyObservers { onLoggedOut() }
|
||||||
|
verify(exactly = 1) { push.unsubscribeForType(eq(PushType.Services)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `telemetry account observer`() {
|
||||||
|
val metrics = mockk<MetricController>()
|
||||||
|
every { metrics.track(any()) } just Runs
|
||||||
|
val observer = TelemetryAccountObserver(mockk(relaxed = true), metrics)
|
||||||
|
val registry = ObserverRegistry<AccountObserver>()
|
||||||
|
registry.register(observer)
|
||||||
|
val account = mockk<OAuthAccount>()
|
||||||
|
|
||||||
|
// Sign-in
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Signin) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignIn)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthSignUp)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthPaired)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthFromShared)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthRecovered)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthOtherExternal)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthSignOut)) }
|
||||||
|
|
||||||
|
// Sign-up
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Signup) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignIn)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignUp)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthPaired)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthFromShared)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthRecovered)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthOtherExternal)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthSignOut)) }
|
||||||
|
|
||||||
|
// Pairing
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Pairing) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignIn)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignUp)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthPaired)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthFromShared)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthRecovered)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthOtherExternal)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthSignOut)) }
|
||||||
|
|
||||||
|
// Auto-login/shared account
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Shared) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignIn)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignUp)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthPaired)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthFromShared)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthRecovered)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthOtherExternal)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthSignOut)) }
|
||||||
|
|
||||||
|
// Internally recovered
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Recovered) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignIn)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignUp)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthPaired)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthFromShared)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthRecovered)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthOtherExternal)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthSignOut)) }
|
||||||
|
|
||||||
|
// Other external
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.OtherExternal(null)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignIn)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignUp)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthPaired)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthFromShared)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthRecovered)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthOtherExternal)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthSignOut)) }
|
||||||
|
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.OtherExternal("someAction")) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignIn)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignUp)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthPaired)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthFromShared)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthRecovered)) }
|
||||||
|
verify(exactly = 2) { metrics.track(eq(Event.SyncAuthOtherExternal)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthSignOut)) }
|
||||||
|
|
||||||
|
// NB: 'Existing' auth type isn't expected to record any auth telemetry.
|
||||||
|
registry.notifyObservers { onAuthenticated(account, AuthType.Existing) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignIn)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignUp)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthPaired)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthFromShared)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthRecovered)) }
|
||||||
|
verify(exactly = 2) { metrics.track(eq(Event.SyncAuthOtherExternal)) }
|
||||||
|
verify(exactly = 0) { metrics.track(eq(Event.SyncAuthSignOut)) }
|
||||||
|
|
||||||
|
// Logout
|
||||||
|
registry.notifyObservers { onLoggedOut() }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignIn)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignUp)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthPaired)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthFromShared)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthRecovered)) }
|
||||||
|
verify(exactly = 2) { metrics.track(eq(Event.SyncAuthOtherExternal)) }
|
||||||
|
verify(exactly = 1) { metrics.track(eq(Event.SyncAuthSignOut)) }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue