Bug 1920176 Adding google search codes for vivo deal. Saving distribution Id in the browser store r=android-reviewers,amejiamarmol,gmalekpour

Differential Revision: https://phabricator.services.mozilla.com/D223856
This commit is contained in:
John Oberhauser 2024-10-07 21:26:13 +00:00
parent 988f83dc49
commit 7c7396a75b
16 changed files with 912 additions and 140 deletions

View File

@ -1883,6 +1883,11 @@ sealed class SearchAction : BrowserAction() {
object RestoreHiddenSearchEnginesAction : SearchAction()
}
/**
* [BrowserAction] implements setting and updating the distribution
*/
data class UpdateDistribution(val distributionId: String?) : BrowserAction()
/**
* [BrowserAction] implementations for updating state needed for debugging. These actions should
* be carefully considered before being used.

View File

@ -33,6 +33,7 @@ import mozilla.components.browser.state.action.TabListAction
import mozilla.components.browser.state.action.TrackingProtectionAction
import mozilla.components.browser.state.action.TranslationsAction
import mozilla.components.browser.state.action.UndoAction
import mozilla.components.browser.state.action.UpdateDistribution
import mozilla.components.browser.state.action.WebExtensionAction
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.CustomTabSessionState
@ -79,6 +80,7 @@ internal object BrowserStateReducer {
is DebugAction -> DebugReducer.reduce(state, action)
is ExtensionsProcessAction -> ExtensionsProcessStateReducer.reduce(state, action)
is AwesomeBarAction -> AwesomeBarStateReducer.reduce(state, action)
is UpdateDistribution -> state.copy(distributionId = action.distributionId)
}
}
}

View File

@ -36,6 +36,7 @@ import java.util.Locale
* @property locale The current locale of the app. Will be null when following the system default.
* @property awesomeBarState Holds state for interactions with the [AwesomeBar].
* @property translationEngine Holds translation state that applies to the browser.
* @property distributionId Holds the distribution Id from [Distribution]
*/
data class BrowserState(
val tabs: List<TabSessionState> = emptyList(),
@ -56,4 +57,5 @@ data class BrowserState(
val extensionsProcessDisabled: Boolean = false,
val awesomeBarState: AwesomeBarState = AwesomeBarState(),
val translationEngine: TranslationsBrowserState = TranslationsBrowserState(),
val distributionId: String? = null,
) : State

View File

@ -4,6 +4,7 @@
package mozilla.components.browser.state.reducer
import mozilla.components.browser.state.action.UpdateDistribution
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.ContentState
import mozilla.components.browser.state.state.CustomTabSessionState
@ -239,4 +240,14 @@ class BrowserStateReducerKtTest {
assertEquals(updatedUrl, browserState.customTabs[0].content.url)
assertEquals(initialUrl, browserState.customTabs[1].content.url)
}
@Test
fun `WHEN the browser state is reduced with an UpdateDistribution action THEN the distribution Id of the state is updated`() {
val browserState = BrowserState()
val action = UpdateDistribution("testId")
val reducedState = BrowserStateReducer.reduce(browserState, action)
assertEquals(reducedState.distributionId, "testId")
}
}

View File

@ -0,0 +1,17 @@
<!-- 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/. -->
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>Google</ShortName>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16">data:image/png;base64,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</Image>
<Url type="application/x-suggestions+json" method="GET" template="https://www.google.com/complete/search?client=firefox&amp;q={searchTerms}"/>
<Url type="text/html" method="GET" template="https://www.google.com/search">
<Param name="q" value="{searchTerms}"/>
<Param name="ie" value="utf-8"/>
<Param name="oe" value="utf-8"/>
<Param name="client" value="firefox-b-vv"/>
</Url>
<SearchForm>https://www.google.com</SearchForm>
</SearchPlugin>

View File

@ -15,6 +15,7 @@ import kotlinx.coroutines.launch
import mozilla.components.browser.state.action.BrowserAction
import mozilla.components.browser.state.action.InitAction
import mozilla.components.browser.state.action.SearchAction
import mozilla.components.browser.state.action.UpdateDistribution
import mozilla.components.browser.state.search.RegionState
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.lib.state.Middleware
@ -42,7 +43,7 @@ class RegionMiddleware(
next: (BrowserAction) -> Unit,
action: BrowserAction,
) {
if (action is InitAction || action is SearchAction.RefreshSearchEnginesAction) {
if (action is InitAction || action is SearchAction.RefreshSearchEnginesAction || action is UpdateDistribution) {
updateJob = determineRegion(context.store)
}
@ -55,18 +56,19 @@ class RegionMiddleware(
) = GlobalScope.launch(ioDispatcher) {
// Get the region state from the RegionManager. If there's none then dispatch the default
// region to be used.
val distributionId = store.state.distributionId
val region = regionManager.region()
if (region != null) {
store.dispatch(SearchAction.SetRegionAction(region))
store.dispatch(SearchAction.SetRegionAction(region, distributionId))
} else {
store.dispatch(SearchAction.SetRegionAction(RegionState.Default))
store.dispatch(SearchAction.SetRegionAction(RegionState.Default, distributionId))
}
// Ask the RegionManager to perform an update. If the "home" region changed then it will
// return a new RegionState.
val update = regionManager.update()
if (update != null) {
store.dispatch(SearchAction.SetRegionAction(update))
store.dispatch(SearchAction.SetRegionAction(update, distributionId))
}
}
}

View File

@ -4,16 +4,22 @@
package mozilla.components.feature.search.region
import mozilla.components.browser.state.action.BrowserAction
import mozilla.components.browser.state.action.InitAction
import mozilla.components.browser.state.action.SearchAction
import mozilla.components.browser.state.action.SearchAction.RefreshSearchEnginesAction
import mozilla.components.browser.state.action.UpdateDistribution
import mozilla.components.browser.state.search.RegionState
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.lib.state.MiddlewareContext
import mozilla.components.service.location.LocationService
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.fakes.FakeClock
import mozilla.components.support.test.fakes.android.FakeContext
import mozilla.components.support.test.fakes.android.FakeSharedPreferences
import mozilla.components.support.test.libstate.ext.waitUntilIdle
import mozilla.components.support.test.mock
import mozilla.components.support.test.rule.MainCoroutineRule
import mozilla.components.support.test.rule.runTestOnMain
import org.junit.Assert.assertEquals
@ -21,6 +27,8 @@ import org.junit.Assert.assertNotEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
class RegionMiddlewareTest {
@ -150,4 +158,59 @@ class RegionMiddlewareTest {
assertEquals("FR", store.state.search.region!!.home)
assertEquals("DE", store.state.search.region!!.current)
}
@Test
fun `WHEN the UpdateDistribution action is received THEN the distribution is updated`() = runTestOnMain {
val middleware = RegionMiddleware(FakeContext(), locationService, dispatcher)
val middlewareContext: MiddlewareContext<BrowserState, BrowserAction> = mock()
val regionManager: RegionManager = mock()
middleware.regionManager = regionManager
val store: BrowserStore = mock()
// null RegionState
`when`(middlewareContext.store).thenReturn(store)
`when`(regionManager.region()).thenReturn(null)
`when`(store.state).thenReturn(BrowserState(distributionId = "testId"))
middleware.invoke(
middlewareContext,
{},
UpdateDistribution("testId"),
)
dispatcher.scheduler.advanceUntilIdle()
verify(store).dispatch(SearchAction.SetRegionAction(RegionState.Default, "testId"))
// non null RegionState
`when`(middlewareContext.store).thenReturn(store)
`when`(regionManager.region()).thenReturn(RegionState("US", "US"))
`when`(store.state).thenReturn(BrowserState(distributionId = "testId"))
middleware.invoke(
middlewareContext,
{},
UpdateDistribution("testId"),
)
dispatcher.scheduler.advanceUntilIdle()
verify(store).dispatch(SearchAction.SetRegionAction(RegionState("US", "US"), "testId"))
// region manager update has a new RegionState
`when`(middlewareContext.store).thenReturn(store)
`when`(regionManager.region()).thenReturn(null)
`when`(regionManager.update()).thenReturn(RegionState("DE", "DE"))
`when`(store.state).thenReturn(BrowserState(distributionId = "testId"))
middleware.invoke(
middlewareContext,
{},
UpdateDistribution("testId"),
)
dispatcher.scheduler.advanceUntilIdle()
verify(store).dispatch(SearchAction.SetRegionAction(RegionState("DE", "DE"), "testId"))
}
}

View File

@ -193,4 +193,332 @@ class BundledSearchEnginesStorageTest {
assertEquals("https://www.google.com/complete/search?client=firefox&q={searchTerms}", google.suggestUrl)
assertTrue(google.resultUrls.isNotEmpty())
}
@Test
fun `Verify search engines for vivo-001 distributions in US`() = runTest {
val searchEngines = loadSearchEngines(
region = "US",
localeLang = "en",
localeCountry = "US",
distribution = "vivo-001",
)
assertEquals(
listOf("google-b-vv", "bing", "ddg", "ebay", "wikipedia"),
searchEngines,
)
}
@Test
fun `Verify search engines for vivo-001 distributions in Austria`() = runTest {
val searchEngines = loadSearchEngines(
region = "AT",
localeLang = "de",
localeCountry = "AT",
distribution = "vivo-001",
)
assertEquals(
listOf(
"google-b-vv",
"bing",
"ddg",
"ecosia",
"qwant",
"wikipedia-de",
"ebay-at",
),
searchEngines,
)
}
@Test
fun `Verify search engines for vivo-001 distributions in Spain`() = runTest {
val searchEngines = loadSearchEngines(
region = "ES",
localeLang = "es",
localeCountry = "ES",
distribution = "vivo-001",
)
assertEquals(
listOf("google-b-vv", "bing", "ddg", "wikipedia-es", "ebay-es"),
searchEngines,
)
}
@Test
fun `Verify search engines for vivo-001 distributions in Italy`() = runTest {
val searchEngines = loadSearchEngines(
region = "IT",
localeLang = "it",
localeCountry = "IT",
distribution = "vivo-001",
)
assertEquals(
listOf("google-b-vv", "bing", "ddg", "wikipedia-it", "ebay-it"),
searchEngines,
)
}
@Test
fun `Verify search engines for vivo-001 distributions in Germany`() = runTest {
val searchEngines = loadSearchEngines(
region = "DE",
localeLang = "de",
localeCountry = "DE",
distribution = "vivo-001",
)
assertEquals(
listOf(
"google-b-vv",
"bing",
"ddg",
"ecosia",
"qwant",
"wikipedia-de",
"ebay-de",
),
searchEngines,
)
}
@Test
fun `Verify search engines for vivo-001 distributions in France`() = runTest {
val searchEngines = loadSearchEngines(
region = "FR",
localeLang = "fr",
localeCountry = "FR",
distribution = "vivo-001",
)
assertEquals(
listOf(
"google-b-vv",
"bing",
"ddg",
"qwant",
"wikipedia-fr",
"ebay-fr",
),
searchEngines,
)
}
@Test
fun `Verify search engines for vivo-001 distributions in Mexico`() = runTest {
val searchEngines = loadSearchEngines(
region = "MX",
localeLang = "es",
localeCountry = "MX",
distribution = "vivo-001",
)
assertEquals(
listOf(
"google-b-vv",
"bing",
"ddg",
"mercadolibre-mx",
"wikipedia-es",
),
searchEngines,
)
}
@Test
fun `Verify search engines for vivo-001 distributions in Colombia`() = runTest {
val searchEngines = loadSearchEngines(
region = "CO",
localeLang = "es",
localeCountry = "CO",
distribution = "vivo-001",
)
assertEquals(
listOf("google-b-vv", "bing", "ddg", "wikipedia"),
searchEngines,
)
}
@Test
fun `Verify search engines for vivo-001 distributions in an unknown country and language`() = runTest {
val searchEngines = loadSearchEngines(
region = "MEEP",
localeLang = "beepbeep",
localeCountry = "MEEP",
distribution = "vivo-001",
)
assertEquals(
listOf("google-b-vv", "bing", "ddg", "wikipedia"),
searchEngines,
)
}
@Test
fun `Verify search engines for vivo-001 distributions in Russia in russian`() = runTest {
val searchEngines = loadSearchEngines(
region = "RU",
localeLang = "ru",
localeCountry = "RU",
distribution = "vivo-001",
)
assertEquals(
listOf("google-com-nocodes", "ddg", "wikipedia-ru"),
searchEngines,
)
}
@Test
fun `Verify search engines for vivo-001 distributions in USA in russian`() = runTest {
val searchEngines = loadSearchEngines(
region = "US",
localeLang = "ru",
localeCountry = "US",
distribution = "vivo-001",
)
assertEquals(
listOf("google-b-vv", "ddg", "wikipedia-ru"),
searchEngines,
)
}
@Test
fun `Verify search engines for mozilla distribution in USA`() = runTest {
val searchEngines = loadSearchEngines(
region = "US",
localeLang = "en",
localeCountry = "US",
distribution = "Mozilla",
)
assertEquals(
listOf("google-b-1-m", "bing", "ddg", "ebay", "wikipedia"),
searchEngines,
)
}
@Test
fun `Verify search engines for mozilla distribution in Germany in german`() = runTest {
val searchEngines = loadSearchEngines(
region = "DE",
localeLang = "de",
localeCountry = "DE",
distribution = "Mozilla",
)
assertEquals(
listOf(
"google-b-m",
"bing",
"ddg",
"ecosia",
"qwant",
"wikipedia-de",
"ebay-de",
),
searchEngines,
)
}
@Test
fun `Verify search engines for mozilla distribution in Russia in russian`() = runTest {
val searchEngines = loadSearchEngines(
region = "RU",
localeLang = "ru",
localeCountry = "RU",
distribution = "Mozilla",
)
assertEquals(
listOf("google-com-nocodes", "ddg", "wikipedia-ru"),
searchEngines,
)
}
@Test
fun `Verify search engines for mozilla distribution in Germany in russian`() = runTest {
val searchEngines = loadSearchEngines(
region = "DE",
localeLang = "ru",
localeCountry = "DE",
distribution = "Mozilla",
)
assertEquals(
listOf("google-b-m", "ddg", "wikipedia-ru"),
searchEngines,
)
}
@Test
fun `Verify search engines for mozilla distribution in USA in russian`() = runTest {
val searchEngines = loadSearchEngines(
region = "US",
localeLang = "ru",
localeCountry = "US",
distribution = "Mozilla",
)
assertEquals(
listOf("google-b-1-m", "ddg", "wikipedia-ru"),
searchEngines,
)
}
@Test
fun `Verify search engines for unknown distribution in USA`() = runTest {
val searchEngines = loadSearchEngines(
region = "US",
localeLang = "en",
localeCountry = "US",
distribution = "unknown",
)
assertEquals(
listOf(
"google-b-1-m",
"bing",
"ddg",
"ebay",
"wikipedia",
),
searchEngines,
)
}
@Test
fun `Verify search engines for unknown distribution in an unknown country and language`() = runTest {
val searchEngines = loadSearchEngines(
region = "MEEP",
localeLang = "beepbeep",
localeCountry = "MEEP",
distribution = "unknown",
)
assertEquals(
listOf("google-b-m", "bing", "ddg", "wikipedia"),
searchEngines,
)
}
private suspend fun loadSearchEngines(
region: String,
localeLang: String,
localeCountry: String,
distribution: String,
): List<String> {
val storage = BundledSearchEnginesStorage(testContext)
val engines = storage.load(
region = RegionState(region, region),
locale = Locale(localeLang, localeCountry),
distribution = distribution,
)
return engines.list.map { it.id }
}
}

View File

@ -751,7 +751,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
setPreferenceMetrics(settings)
with(Metrics) {
// Set this early to guarantee it's in every ping from here on.
distributionId.set(getDistributionId())
distributionId.set(getDistributionId(browserStore))
defaultBrowser.set(browsersCache.all(applicationContext).isDefaultBrowser)
mozillaProductDetector.getMozillaBrowserDefault(applicationContext)?.also {

View File

@ -21,6 +21,7 @@ import mozilla.components.lib.crash.CrashReporter
import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.Config
import org.mozilla.fenix.GleanMetrics.FirstSession
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
@Deprecated("Adjust is disabled", level = DeprecationLevel.ERROR)
@ -53,7 +54,7 @@ class AdjustMetricsService(
)
config.setPreinstallTrackingEnabled(true)
val installationPing = FirstSessionPing(application)
val installationPing = FirstSessionPing(application, application.components.core.store)
FirstSession.adjustAttributionTimespan.start()
val timerId = FirstSession.adjustAttributionTime.start()

View File

@ -15,13 +15,17 @@ import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.GleanMetrics.FirstSession
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.distributions.getDistributionId
import org.mozilla.fenix.ext.application
class FirstSessionPing(private val context: Context) {
class FirstSessionPing(
private val context: Context,
private val browserStore: BrowserStore,
) {
private val prefs: SharedPreferences by lazy {
context.getSharedPreferences(
@ -64,7 +68,7 @@ class FirstSessionPing(private val context: Context) {
FirstSession.installSource.set(installSourcePackage())
CoroutineScope(Dispatchers.IO).launch {
FirstSession.distributionId.set(getDistributionId())
FirstSession.distributionId.set(getDistributionId(browserStore))
Pings.firstSession.submit()
markAsTriggered()

View File

@ -14,6 +14,7 @@ import org.json.JSONObject
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.GleanMetrics.MetaAttribution
import org.mozilla.fenix.GleanMetrics.PlayStoreAttribution
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.utils.Settings
import java.io.UnsupportedEncodingException
@ -44,8 +45,7 @@ class InstallReferrerMetricsService(private val context: Context) : MetricsServi
object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
PlayStoreAttribution.attributionTime.stopAndAccumulate(timerId)
val firstSession = FirstSessionPing(context)
val firstSession = FirstSessionPing(context, context.components.core.store)
when (responseCode) {
InstallReferrerClient.InstallReferrerResponse.OK -> {
// Connection established.

View File

@ -5,6 +5,8 @@
package org.mozilla.fenix.distributions
import android.os.Build
import mozilla.components.browser.state.action.UpdateDistribution
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.Config
import org.mozilla.fenix.GleanMetrics.Partnerships
@ -22,16 +24,26 @@ private const val VIVO_PREINSTALLED_FIREFOX_FILE_PATH = "/data/yzfswj/another/vi
private const val VIVO_MANUFACTURER = "vivo"
/**
* @param browserStore the browser store
* @param appPreinstalledOnVivoDevice checks if the vivo preinstalled file exists.
*
* @return the distribution ID if one exists.
*/
fun getDistributionId(appPreinstalledOnVivoDevice: () -> Boolean = { wasAppPreinstalledOnVivoDevice() }): String {
return when {
fun getDistributionId(
browserStore: BrowserStore,
appPreinstalledOnVivoDevice: () -> Boolean = { wasAppPreinstalledOnVivoDevice() },
): String {
browserStore.state.distributionId?.let { return it }
val distributionId = when {
isDeviceVivo() && appPreinstalledOnVivoDevice() -> Distribution.VIVO_001.id
Config.channel.isMozillaOnline -> Distribution.MOZILLA_ONLINE.id
else -> Distribution.DEFAULT.id
}
browserStore.dispatch(UpdateDistribution(distributionId))
return distributionId
}
private fun isDeviceVivo(): Boolean {

View File

@ -15,6 +15,8 @@ import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.store.BrowserStore
import org.junit.Assert.assertEquals
import org.junit.Test
import org.mozilla.fenix.FenixApplication
@ -38,7 +40,13 @@ internal class FirstSessionPingTest {
mockkStatic("org.mozilla.fenix.ext.ContextKt")
every { mockedContext.settings() } returns mockedSettings
val mockAp = spyk(FirstSessionPing(mockedContext), recordPrivateCalls = true)
val mockedState: BrowserState = mockk(relaxed = true)
every { mockedState.distributionId } returns null
val mockedStore: BrowserStore = mockk(relaxed = true)
every { mockedStore.state } returns mockedState
val mockAp = spyk(FirstSessionPing(mockedContext, mockedStore), recordPrivateCalls = true)
every { mockAp.wasAlreadyTriggered() } returns false
every { mockAp.markAsTriggered() } just Runs
@ -52,7 +60,7 @@ internal class FirstSessionPingTest {
@Test
fun `checkAndSend() doesn't trigger the ping again if it was marked as triggered`() {
val mockAp = spyk(FirstSessionPing(mockk()), recordPrivateCalls = true)
val mockAp = spyk(FirstSessionPing(mockk(), mockk()), recordPrivateCalls = true)
every { mockAp.wasAlreadyTriggered() } returns true
mockAp.checkAndSend()
@ -72,7 +80,7 @@ internal class FirstSessionPingTest {
val mockedContext: Context = mockk(relaxed = true)
every { mockedContext.applicationContext } returns mockedApplication
val result = FirstSessionPing(mockedContext).installSourcePackage(Build.VERSION_CODES.R)
val result = FirstSessionPing(mockedContext, mockk()).installSourcePackage(Build.VERSION_CODES.R)
assertEquals(testPackageName, result)
}
@ -87,7 +95,7 @@ internal class FirstSessionPingTest {
val mockedContext: Context = mockk(relaxed = true)
every { mockedContext.applicationContext } returns mockedApplication
val result = FirstSessionPing(mockedContext).installSourcePackage(Build.VERSION_CODES.R)
val result = FirstSessionPing(mockedContext, mockk()).installSourcePackage(Build.VERSION_CODES.R)
assertEquals("", result)
}
@ -104,7 +112,7 @@ internal class FirstSessionPingTest {
every { mockedContext.applicationContext } returns mockedApplication
val result =
FirstSessionPing(mockedContext).installSourcePackage(Build.VERSION_CODES.R.plus(1))
FirstSessionPing(mockedContext, mockk()).installSourcePackage(Build.VERSION_CODES.R.plus(1))
assertEquals(testPackageName, result)
}
@ -120,7 +128,7 @@ internal class FirstSessionPingTest {
every { mockedContext.applicationContext } returns mockedApplication
val result =
FirstSessionPing(mockedContext).installSourcePackage(Build.VERSION_CODES.R.plus(1))
FirstSessionPing(mockedContext, mockk()).installSourcePackage(Build.VERSION_CODES.R.plus(1))
assertEquals("", result)
}
@ -137,7 +145,7 @@ internal class FirstSessionPingTest {
every { mockedContext.applicationContext } returns mockedApplication
val result =
FirstSessionPing(mockedContext).installSourcePackage(Build.VERSION_CODES.R.minus(1))
FirstSessionPing(mockedContext, mockk()).installSourcePackage(Build.VERSION_CODES.R.minus(1))
assertEquals(testPackageName, result)
}
@ -154,7 +162,7 @@ internal class FirstSessionPingTest {
every { mockedContext.applicationContext } returns mockedApplication
val result =
FirstSessionPing(mockedContext).installSourcePackage(Build.VERSION_CODES.R.minus(1))
FirstSessionPing(mockedContext, mockk()).installSourcePackage(Build.VERSION_CODES.R.minus(1))
assertEquals("", result)
}
}

View File

@ -1,8 +1,12 @@
package org.mozilla.fenix.distributions
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.store.BrowserStore
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.Config
@ -12,19 +16,28 @@ import org.robolectric.shadows.ShadowBuild
@RunWith(FenixRobolectricTestRunner::class)
class DistributionIdUtilTest {
private val browserStoreMock: BrowserStore = mockk(relaxed = true)
private val browserStateMock: BrowserState = mockk(relaxed = true)
@Before
fun setup() {
every { browserStoreMock.state } returns browserStateMock
every { browserStateMock.distributionId } returns null
}
@Test
fun `WHEN a device is made by vivo AND the vivo distribution file is found THEN the proper id is returned`() {
// Mock Build.MANUFACTURER to simulate a Vivo device
ShadowBuild.setManufacturer("vivo")
val distributionId = getDistributionId { true }
val distributionId = getDistributionId(browserStoreMock) { true }
assertEquals("vivo-001", distributionId)
}
@Test
fun `WHEN a device is not made by vivo AND the vivo distribution file is found THEN the proper id is returned`() {
val distributionId = getDistributionId { true }
val distributionId = getDistributionId(browserStoreMock) { true }
assertEquals("Mozilla", distributionId)
}
@ -34,7 +47,7 @@ class DistributionIdUtilTest {
// Mock Build.MANUFACTURER to simulate a Vivo device
ShadowBuild.setManufacturer("vivo")
val distributionId = getDistributionId { false }
val distributionId = getDistributionId(browserStoreMock) { false }
assertEquals("Mozilla", distributionId)
}
@ -44,15 +57,24 @@ class DistributionIdUtilTest {
mockkObject(Config)
every { Config.channel.isMozillaOnline } returns true
val distributionId = getDistributionId()
val distributionId = getDistributionId(browserStoreMock)
assertEquals("MozillaOnline", distributionId)
}
@Test
fun `WHEN the device is not vivo AND the channel is not mozilla online THEN the proper id is returned`() {
val distributionId = getDistributionId()
val distributionId = getDistributionId(browserStoreMock)
assertEquals("Mozilla", distributionId)
}
@Test
fun `WHEN the browser stores state already has a distribution Id assigned THEN that ID gets returned`() {
every { browserStateMock.distributionId } returns "testId"
val distributionId = getDistributionId(browserStoreMock)
assertEquals("testId", distributionId)
}
}