Add tests for sync, wifi, and push (#12581)
This commit is contained in:
parent
2291fb07aa
commit
2d066d77ad
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.components
|
package org.mozilla.fenix.components
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import mozilla.components.feature.addons.AddonManager
|
import mozilla.components.feature.addons.AddonManager
|
||||||
import mozilla.components.feature.addons.amo.AddonCollectionProvider
|
import mozilla.components.feature.addons.amo.AddonCollectionProvider
|
||||||
|
@ -106,5 +106,5 @@ class Components(private val context: Context) {
|
||||||
val migrationStore by lazy { MigrationStore() }
|
val migrationStore by lazy { MigrationStore() }
|
||||||
val performance by lazy { PerformanceComponent() }
|
val performance by lazy { PerformanceComponent() }
|
||||||
val push by lazy { Push(context, analytics.crashReporter) }
|
val push by lazy { Push(context, analytics.crashReporter) }
|
||||||
val wifiConnectionMonitor by lazy { WifiConnectionMonitor(context as Application) }
|
val wifiConnectionMonitor by lazy { WifiConnectionMonitor(context.getSystemService()!!) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,11 @@ import mozilla.components.concept.sync.OAuthAccount
|
||||||
import mozilla.components.service.fxa.manager.FxaAccountManager
|
import mozilla.components.service.fxa.manager.FxaAccountManager
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts and stops SyncedTabsStorage based on the authentication state.
|
||||||
|
* @param context Used to get synced tabs storage, due to cyclic dependency.
|
||||||
|
* @param accountManager Used to check and observe account authentication state.
|
||||||
|
*/
|
||||||
class SyncedTabsIntegration(
|
class SyncedTabsIntegration(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val accountManager: FxaAccountManager
|
private val accountManager: FxaAccountManager
|
||||||
|
|
|
@ -47,8 +47,8 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item
|
||||||
private fun bindHeader(device: AdapterItem.Device) {
|
private fun bindHeader(device: AdapterItem.Device) {
|
||||||
|
|
||||||
val deviceLogoDrawable = when (device.device.deviceType) {
|
val deviceLogoDrawable = when (device.device.deviceType) {
|
||||||
DeviceType.DESKTOP -> { R.drawable.mozac_ic_device_desktop }
|
DeviceType.DESKTOP -> R.drawable.mozac_ic_device_desktop
|
||||||
else -> { R.drawable.mozac_ic_device_mobile }
|
else -> R.drawable.mozac_ic_device_mobile
|
||||||
}
|
}
|
||||||
|
|
||||||
itemView.synced_tabs_group_name.text = device.device.displayName
|
itemView.synced_tabs_group_name.text = device.device.displayName
|
||||||
|
|
|
@ -18,29 +18,21 @@ import org.mozilla.fenix.utils.Settings
|
||||||
class SitePermissionsWifiIntegration(
|
class SitePermissionsWifiIntegration(
|
||||||
private val settings: Settings,
|
private val settings: Settings,
|
||||||
private val wifiConnectionMonitor: WifiConnectionMonitor
|
private val wifiConnectionMonitor: WifiConnectionMonitor
|
||||||
) : LifecycleAwareFeature {
|
) : LifecycleAwareFeature, WifiConnectionMonitor.Observer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds listener for autoplay setting [AUTOPLAY_ALLOW_ON_WIFI]. Sets all autoplay to allowed when
|
* Adds listener for autoplay setting [AUTOPLAY_ALLOW_ON_WIFI]. Sets all autoplay to allowed when
|
||||||
* WIFI is connected, blocked otherwise.
|
* WIFI is connected, blocked otherwise.
|
||||||
*/
|
*/
|
||||||
private val wifiConnectedListener: ((Boolean) -> Unit) by lazy {
|
override fun onWifiConnectionChanged(connected: Boolean) {
|
||||||
{ connected: Boolean ->
|
val setting =
|
||||||
val setting =
|
if (connected) SitePermissionsRules.Action.ALLOWED else SitePermissionsRules.Action.BLOCKED
|
||||||
if (connected) SitePermissionsRules.Action.ALLOWED else SitePermissionsRules.Action.BLOCKED
|
if (settings.getAutoplayUserSetting(default = AUTOPLAY_BLOCK_ALL) == AUTOPLAY_ALLOW_ON_WIFI) {
|
||||||
if (settings.getAutoplayUserSetting(default = AUTOPLAY_BLOCK_ALL) == AUTOPLAY_ALLOW_ON_WIFI) {
|
settings.setSitePermissionsPhoneFeatureAction(PhoneFeature.AUTOPLAY_AUDIBLE, setting)
|
||||||
settings.setSitePermissionsPhoneFeatureAction(
|
settings.setSitePermissionsPhoneFeatureAction(PhoneFeature.AUTOPLAY_INAUDIBLE, setting)
|
||||||
PhoneFeature.AUTOPLAY_AUDIBLE,
|
} else {
|
||||||
setting
|
// The autoplay setting has changed, we can remove the listener
|
||||||
)
|
removeWifiConnectedListener()
|
||||||
settings.setSitePermissionsPhoneFeatureAction(
|
|
||||||
PhoneFeature.AUTOPLAY_INAUDIBLE,
|
|
||||||
setting
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// The autoplay setting has changed, we can remove the listener
|
|
||||||
removeWifiConnectedListener()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,11 +47,11 @@ class SitePermissionsWifiIntegration(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addWifiConnectedListener() {
|
fun addWifiConnectedListener() {
|
||||||
wifiConnectionMonitor.addOnWifiConnectedChangedListener(wifiConnectedListener)
|
wifiConnectionMonitor.register(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeWifiConnectedListener() {
|
fun removeWifiConnectedListener() {
|
||||||
wifiConnectionMonitor.removeOnWifiConnectedChangedListener(wifiConnectedListener)
|
wifiConnectionMonitor.unregister(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Until https://bugzilla.mozilla.org/show_bug.cgi?id=1621825 is fixed, AUTOPLAY_ALLOW_ALL
|
// Until https://bugzilla.mozilla.org/show_bug.cgi?id=1621825 is fixed, AUTOPLAY_ALLOW_ALL
|
||||||
|
|
|
@ -5,11 +5,12 @@
|
||||||
package org.mozilla.fenix.wifi
|
package org.mozilla.fenix.wifi
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.net.Network
|
import android.net.Network
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
import android.net.NetworkRequest
|
import android.net.NetworkRequest
|
||||||
|
import mozilla.components.support.base.observer.Observable
|
||||||
|
import mozilla.components.support.base.observer.ObserverRegistry
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches itself to the [Application] and listens for WIFI available/not available events. This
|
* Attaches itself to the [Application] and listens for WIFI available/not available events. This
|
||||||
|
@ -25,30 +26,28 @@ import android.net.NetworkRequest
|
||||||
* app.components.wifiConnectionListener.start()
|
* app.components.wifiConnectionListener.start()
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class WifiConnectionMonitor(app: Application) {
|
class WifiConnectionMonitor(
|
||||||
private val callbacks = mutableSetOf<(Boolean) -> Unit>()
|
private val connectivityManager: ConnectivityManager
|
||||||
private val connectivityManager = app.getSystemService(Context.CONNECTIVITY_SERVICE) as
|
) : Observable<WifiConnectionMonitor.Observer> by ObserverRegistry() {
|
||||||
ConnectivityManager
|
|
||||||
|
|
||||||
private var lastKnownStateWasAvailable: Boolean? = null
|
private var callbackReceived: Boolean = false
|
||||||
private var isRegistered = false
|
private var isRegistered = false
|
||||||
|
|
||||||
private val frameworkListener = object : ConnectivityManager.NetworkCallback() {
|
private val frameworkListener = object : ConnectivityManager.NetworkCallback() {
|
||||||
override fun onLost(network: Network?) {
|
override fun onLost(network: Network?) {
|
||||||
callbacks.forEach { it(false) }
|
notifyAtLeastOneObserver { onWifiConnectionChanged(connected = false) }
|
||||||
lastKnownStateWasAvailable = false
|
callbackReceived = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAvailable(network: Network?) {
|
override fun onAvailable(network: Network?) {
|
||||||
callbacks.forEach { it(true) }
|
notifyAtLeastOneObserver { onWifiConnectionChanged(connected = true) }
|
||||||
lastKnownStateWasAvailable = true
|
callbackReceived = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches the [WifiConnectionMonitor] to the application. After this has been called, callbacks
|
* Attaches the [WifiConnectionMonitor] to the application. After this has been called, callbacks
|
||||||
* added via [addOnWifiConnectedChangedListener] will be called until either the app exits, or
|
* added via [register] will be called until either the app exits, or [stop] is called.
|
||||||
* [stop] is called.
|
|
||||||
*
|
*
|
||||||
* Any existing callbacks will be called with the current state when this is called.
|
* Any existing callbacks will be called with the current state when this is called.
|
||||||
*/
|
*/
|
||||||
|
@ -62,10 +61,8 @@ class WifiConnectionMonitor(app: Application) {
|
||||||
// AFAICT, the framework does not send an event when a new NetworkCallback is registered
|
// AFAICT, the framework does not send an event when a new NetworkCallback is registered
|
||||||
// while the WIFI is not connected, so we push this manually. If the WIFI is on, it will send
|
// while the WIFI is not connected, so we push this manually. If the WIFI is on, it will send
|
||||||
// a follow up event shortly
|
// a follow up event shortly
|
||||||
val noCallbacksReceivedYet = lastKnownStateWasAvailable == null
|
if (!callbackReceived) {
|
||||||
if (noCallbacksReceivedYet) {
|
notifyAtLeastOneObserver { onWifiConnectionChanged(connected = false) }
|
||||||
lastKnownStateWasAvailable = false
|
|
||||||
callbacks.forEach { it(false) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connectivityManager.registerNetworkCallback(request, frameworkListener)
|
connectivityManager.registerNetworkCallback(request, frameworkListener)
|
||||||
|
@ -74,7 +71,7 @@ class WifiConnectionMonitor(app: Application) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detatches the [WifiConnectionMonitor] from the app. No callbacks added via
|
* Detatches the [WifiConnectionMonitor] from the app. No callbacks added via
|
||||||
* [addOnWifiConnectedChangedListener] will be called after this has been called.
|
* [register] will be called after this has been called.
|
||||||
*/
|
*/
|
||||||
fun stop() {
|
fun stop() {
|
||||||
// Framework code will throw if an unregistered listener attempts to unregister.
|
// Framework code will throw if an unregistered listener attempts to unregister.
|
||||||
|
@ -83,25 +80,7 @@ class WifiConnectionMonitor(app: Application) {
|
||||||
isRegistered = false
|
isRegistered = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
interface Observer {
|
||||||
* Adds [onWifiChanged] to a list of listeners that will be called whenever WIFI connects or
|
fun onWifiConnectionChanged(connected: Boolean)
|
||||||
* disconnects.
|
|
||||||
*
|
|
||||||
* If [onWifiChanged] is successfully added (i.e., it is a new listener), it will be immediately
|
|
||||||
* called with the last known state.
|
|
||||||
*/
|
|
||||||
fun addOnWifiConnectedChangedListener(onWifiChanged: (Boolean) -> Unit) {
|
|
||||||
val lastKnownState = lastKnownStateWasAvailable
|
|
||||||
if (callbacks.add(onWifiChanged) && lastKnownState != null) {
|
|
||||||
onWifiChanged(lastKnownState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes [onWifiChanged] from the list of listeners to be called whenever WIFI connects or
|
|
||||||
* disconnects.
|
|
||||||
*/
|
|
||||||
fun removeOnWifiConnectedChangedListener(onWifiChanged: (Boolean) -> Unit) {
|
|
||||||
callbacks.remove(onWifiChanged)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* 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.push
|
||||||
|
|
||||||
|
import android.app.Notification
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import io.mockk.Called
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
class LeanplumNotificationCustomizerTest {
|
||||||
|
|
||||||
|
private val customizer = LeanplumNotificationCustomizer()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `customize adds icon`() {
|
||||||
|
val builder = mockk<NotificationCompat.Builder>(relaxed = true)
|
||||||
|
customizer.customize(builder, mockk())
|
||||||
|
|
||||||
|
verify { builder.setSmallIcon(R.drawable.ic_status_logo) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `customize for BigPictureStyle does nothing`() {
|
||||||
|
val builder = mockk<Notification.Builder>()
|
||||||
|
customizer.customize(builder, mockk(), mockk())
|
||||||
|
|
||||||
|
verify { builder wasNot Called }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/* 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.sync
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.impl.annotations.MockK
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.slot
|
||||||
|
import io.mockk.verify
|
||||||
|
import mozilla.components.concept.sync.AccountObserver
|
||||||
|
import mozilla.components.feature.syncedtabs.storage.SyncedTabsStorage
|
||||||
|
import mozilla.components.service.fxa.manager.FxaAccountManager
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.FenixApplication
|
||||||
|
|
||||||
|
class SyncedTabsIntegrationTest {
|
||||||
|
|
||||||
|
@MockK private lateinit var context: Context
|
||||||
|
@MockK private lateinit var syncedTabsStorage: SyncedTabsStorage
|
||||||
|
@MockK private lateinit var accountManager: FxaAccountManager
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockKAnnotations.init(this)
|
||||||
|
every { syncedTabsStorage.stop() } just Runs
|
||||||
|
every { accountManager.register(any(), owner = any(), autoPause = true) } just Runs
|
||||||
|
every { context.applicationContext } returns mockk<FenixApplication> {
|
||||||
|
every { components } returns mockk {
|
||||||
|
every { backgroundServices.syncedTabsStorage } returns syncedTabsStorage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `starts and stops syncedTabsStorage on user authentication`() {
|
||||||
|
val observer = slot<AccountObserver>()
|
||||||
|
SyncedTabsIntegration(context, accountManager).launch()
|
||||||
|
verify { accountManager.register(capture(observer), owner = any(), autoPause = true) }
|
||||||
|
|
||||||
|
every { syncedTabsStorage.start() } just Runs
|
||||||
|
observer.captured.onAuthenticated(mockk(), mockk())
|
||||||
|
verify { syncedTabsStorage.start() }
|
||||||
|
|
||||||
|
every { syncedTabsStorage.stop() } just Runs
|
||||||
|
observer.captured.onLoggedOut()
|
||||||
|
verify { syncedTabsStorage.stop() }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
/* 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.sync
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import kotlinx.android.synthetic.main.sync_tabs_list_item.view.*
|
||||||
|
import kotlinx.android.synthetic.main.view_synced_tabs_group.view.*
|
||||||
|
import mozilla.components.browser.storage.sync.Tab
|
||||||
|
import mozilla.components.browser.storage.sync.TabEntry
|
||||||
|
import mozilla.components.concept.sync.Device
|
||||||
|
import mozilla.components.concept.sync.DeviceType
|
||||||
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
|
||||||
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
class SyncedTabsViewHolderTest {
|
||||||
|
|
||||||
|
private lateinit var tabViewHolder: SyncedTabsViewHolder.TabViewHolder
|
||||||
|
private lateinit var tabView: View
|
||||||
|
private lateinit var deviceViewHolder: SyncedTabsViewHolder.DeviceViewHolder
|
||||||
|
private lateinit var deviceView: View
|
||||||
|
private lateinit var deviceViewGroupName: TextView
|
||||||
|
|
||||||
|
private val tab = Tab(
|
||||||
|
history = listOf(
|
||||||
|
mockk(),
|
||||||
|
TabEntry(
|
||||||
|
title = "Firefox",
|
||||||
|
url = "https://firefox.com",
|
||||||
|
iconUrl = "https://firefox.com/favicon.ico"
|
||||||
|
),
|
||||||
|
mockk()
|
||||||
|
),
|
||||||
|
active = 1,
|
||||||
|
lastUsed = 0L
|
||||||
|
)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
val inflater = LayoutInflater.from(testContext)
|
||||||
|
|
||||||
|
tabView = inflater.inflate(SyncedTabsViewHolder.TabViewHolder.LAYOUT_ID, null)
|
||||||
|
tabViewHolder = SyncedTabsViewHolder.TabViewHolder(tabView)
|
||||||
|
|
||||||
|
deviceViewGroupName = mockk(relaxUnitFun = true)
|
||||||
|
deviceView = mockk {
|
||||||
|
every { synced_tabs_group_name } returns deviceViewGroupName
|
||||||
|
}
|
||||||
|
deviceViewHolder = SyncedTabsViewHolder.DeviceViewHolder(deviceView)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `TabViewHolder binds active tab`() {
|
||||||
|
tabViewHolder.bind(SyncedTabsAdapter.AdapterItem.Tab(tab), mockk())
|
||||||
|
|
||||||
|
assertEquals("Firefox", tabView.synced_tab_item_title.text)
|
||||||
|
assertEquals("https://firefox.com", tabView.synced_tab_item_url.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `TabViewHolder calls interactor on click`() {
|
||||||
|
val interactor = mockk<(Tab) -> Unit>(relaxed = true)
|
||||||
|
tabViewHolder.bind(SyncedTabsAdapter.AdapterItem.Tab(tab), interactor)
|
||||||
|
|
||||||
|
tabView.performClick()
|
||||||
|
verify { interactor(tab) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `DeviceViewHolder binds desktop device`() {
|
||||||
|
val device = mockk<Device> {
|
||||||
|
every { displayName } returns "Charcoal"
|
||||||
|
every { deviceType } returns DeviceType.DESKTOP
|
||||||
|
}
|
||||||
|
deviceViewHolder.bind(SyncedTabsAdapter.AdapterItem.Device(device), mockk())
|
||||||
|
|
||||||
|
verify { deviceViewGroupName.text = "Charcoal" }
|
||||||
|
verify {
|
||||||
|
deviceViewGroupName.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
R.drawable.mozac_ic_device_desktop, 0, 0, 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `DeviceViewHolder binds mobile device`() {
|
||||||
|
val device = mockk<Device> {
|
||||||
|
every { displayName } returns "Emerald"
|
||||||
|
every { deviceType } returns DeviceType.MOBILE
|
||||||
|
}
|
||||||
|
deviceViewHolder.bind(SyncedTabsAdapter.AdapterItem.Device(device), mockk())
|
||||||
|
|
||||||
|
verify { deviceViewGroupName.text = "Emerald" }
|
||||||
|
verify {
|
||||||
|
deviceViewGroupName.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
R.drawable.mozac_ic_device_mobile, 0, 0, 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
/* 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.wifi
|
||||||
|
|
||||||
|
import io.mockk.Called
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY_AUDIBLE
|
||||||
|
import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY_INAUDIBLE
|
||||||
|
import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_ALLOW_ALL
|
||||||
|
import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_ALLOW_ON_WIFI
|
||||||
|
import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_BLOCK_ALL
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
|
class SitePermissionsWifiIntegrationTest {
|
||||||
|
|
||||||
|
private lateinit var settings: Settings
|
||||||
|
private lateinit var wifiConnectionMonitor: WifiConnectionMonitor
|
||||||
|
private lateinit var wifiIntegration: SitePermissionsWifiIntegration
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
settings = mockk()
|
||||||
|
wifiConnectionMonitor = mockk(relaxed = true)
|
||||||
|
wifiIntegration = SitePermissionsWifiIntegration(settings, wifiConnectionMonitor)
|
||||||
|
|
||||||
|
every { settings.setSitePermissionsPhoneFeatureAction(any(), any()) } just Runs
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `add and remove wifi connected listener`() {
|
||||||
|
wifiIntegration.addWifiConnectedListener()
|
||||||
|
verify { wifiConnectionMonitor.register(any()) }
|
||||||
|
|
||||||
|
wifiIntegration.removeWifiConnectedListener()
|
||||||
|
verify { wifiConnectionMonitor.unregister(any()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `start and stop wifi connection monitor`() {
|
||||||
|
wifiIntegration.start()
|
||||||
|
verify { wifiConnectionMonitor.start() }
|
||||||
|
|
||||||
|
wifiIntegration.stop()
|
||||||
|
verify { wifiConnectionMonitor.stop() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `add only if autoplay is only allowed on wifi`() {
|
||||||
|
every { settings.getAutoplayUserSetting(default = AUTOPLAY_BLOCK_ALL) } returns AUTOPLAY_ALLOW_ALL
|
||||||
|
wifiIntegration.maybeAddWifiConnectedListener()
|
||||||
|
verify { wifiConnectionMonitor wasNot Called }
|
||||||
|
|
||||||
|
every { settings.getAutoplayUserSetting(default = AUTOPLAY_BLOCK_ALL) } returns AUTOPLAY_ALLOW_ON_WIFI
|
||||||
|
wifiIntegration.maybeAddWifiConnectedListener()
|
||||||
|
verify { wifiConnectionMonitor.register(any()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `listener removes itself if autoplay is not only allowed on wifi`() {
|
||||||
|
every { settings.getAutoplayUserSetting(default = AUTOPLAY_BLOCK_ALL) } returns AUTOPLAY_ALLOW_ALL
|
||||||
|
wifiIntegration.onWifiConnectionChanged(connected = true)
|
||||||
|
verify { wifiConnectionMonitor.unregister(any()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `listener sets audible and inaudible settings to allowed on connect`() {
|
||||||
|
every { settings.getAutoplayUserSetting(default = AUTOPLAY_BLOCK_ALL) } returns AUTOPLAY_ALLOW_ON_WIFI
|
||||||
|
wifiIntegration.onWifiConnectionChanged(connected = true)
|
||||||
|
verify { settings.setSitePermissionsPhoneFeatureAction(AUTOPLAY_AUDIBLE, Action.ALLOWED) }
|
||||||
|
verify { settings.setSitePermissionsPhoneFeatureAction(AUTOPLAY_INAUDIBLE, Action.ALLOWED) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `listener sets audible and inaudible settings to blocked on disconnected`() {
|
||||||
|
every { settings.getAutoplayUserSetting(default = AUTOPLAY_BLOCK_ALL) } returns AUTOPLAY_ALLOW_ON_WIFI
|
||||||
|
wifiIntegration.onWifiConnectionChanged(connected = false)
|
||||||
|
verify { settings.setSitePermissionsPhoneFeatureAction(AUTOPLAY_AUDIBLE, Action.BLOCKED) }
|
||||||
|
verify { settings.setSitePermissionsPhoneFeatureAction(AUTOPLAY_INAUDIBLE, Action.BLOCKED) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
/* 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.wifi
|
||||||
|
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.NetworkRequest
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.mockkConstructor
|
||||||
|
import io.mockk.slot
|
||||||
|
import io.mockk.unmockkConstructor
|
||||||
|
import io.mockk.verify
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class WifiConnectionMonitorTest {
|
||||||
|
|
||||||
|
private lateinit var connectivityManager: ConnectivityManager
|
||||||
|
private lateinit var wifiConnectionMonitor: WifiConnectionMonitor
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
mockkConstructor(NetworkRequest.Builder::class)
|
||||||
|
connectivityManager = mockk(relaxUnitFun = true)
|
||||||
|
wifiConnectionMonitor = WifiConnectionMonitor(connectivityManager)
|
||||||
|
|
||||||
|
every {
|
||||||
|
anyConstructed<NetworkRequest.Builder>().addTransportType(any())
|
||||||
|
} answers { self as NetworkRequest.Builder }
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun teardown() {
|
||||||
|
unmockkConstructor(NetworkRequest.Builder::class)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `start runs only once`() {
|
||||||
|
wifiConnectionMonitor.start()
|
||||||
|
wifiConnectionMonitor.start()
|
||||||
|
|
||||||
|
verify(exactly = 1) {
|
||||||
|
connectivityManager.registerNetworkCallback(any(), any<ConnectivityManager.NetworkCallback>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `stop only runs after start`() {
|
||||||
|
wifiConnectionMonitor.stop()
|
||||||
|
verify(exactly = 0) {
|
||||||
|
connectivityManager.unregisterNetworkCallback(any<ConnectivityManager.NetworkCallback>())
|
||||||
|
}
|
||||||
|
|
||||||
|
wifiConnectionMonitor.start()
|
||||||
|
wifiConnectionMonitor.stop()
|
||||||
|
verify {
|
||||||
|
connectivityManager.unregisterNetworkCallback(any<ConnectivityManager.NetworkCallback>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `passes results from connectivity manager to observers`() {
|
||||||
|
val slot = slot<ConnectivityManager.NetworkCallback>()
|
||||||
|
every { connectivityManager.registerNetworkCallback(any(), capture(slot)) } just Runs
|
||||||
|
|
||||||
|
wifiConnectionMonitor.start()
|
||||||
|
|
||||||
|
// Immediately notifies observer when registered
|
||||||
|
val observer = mockk<WifiConnectionMonitor.Observer>(relaxed = true)
|
||||||
|
wifiConnectionMonitor.register(observer)
|
||||||
|
verify { observer.onWifiConnectionChanged(connected = false) }
|
||||||
|
|
||||||
|
// Notifies observer when network is available or lost
|
||||||
|
slot.captured.onAvailable(mockk())
|
||||||
|
verify { observer.onWifiConnectionChanged(connected = true) }
|
||||||
|
|
||||||
|
slot.captured.onLost(mockk())
|
||||||
|
verify { observer.onWifiConnectionChanged(connected = false) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun captureNetworkCallback(): ConnectivityManager.NetworkCallback {
|
||||||
|
val slot = slot<ConnectivityManager.NetworkCallback>()
|
||||||
|
verify { connectivityManager.registerNetworkCallback(any(), capture(slot)) }
|
||||||
|
return slot.captured
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user