For #6558 - cleanup + added unit tests
parent
f03d65b13d
commit
c4d76dce5a
@ -1,10 +0,0 @@
|
||||
package org.mozilla.fenix.ads
|
||||
|
||||
data class SearchProviderCookie(
|
||||
val extraCodeParam: String,
|
||||
val extraCodePrefixes: List<String>,
|
||||
val host: String,
|
||||
val name: String,
|
||||
val codeParam: String,
|
||||
val codePrefixes: List<String>
|
||||
)
|
@ -1,12 +0,0 @@
|
||||
package org.mozilla.fenix.ext
|
||||
|
||||
import org.json.JSONArray
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> JSONArray.toList(): List<T> {
|
||||
val result = ArrayList<T>()
|
||||
for (i in 0 until length()) {
|
||||
result.add(get(i) as T)
|
||||
}
|
||||
return result
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/* 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.search.telemetry
|
||||
|
||||
data class SearchProviderCookie(
|
||||
val extraCodeParam: String,
|
||||
val extraCodePrefixes: List<String>,
|
||||
val host: String,
|
||||
val name: String,
|
||||
val codeParam: String,
|
||||
val codePrefixes: List<String>
|
||||
)
|
@ -1,4 +1,8 @@
|
||||
package org.mozilla.fenix.ads
|
||||
/* 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.search.telemetry
|
||||
|
||||
data class SearchProviderModel(
|
||||
val name: String,
|
@ -0,0 +1,120 @@
|
||||
/* 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.browser
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.components.metrics.Event
|
||||
import org.mozilla.fenix.components.metrics.MetricController
|
||||
import org.mozilla.fenix.search.telemetry.ads.AdsTelemetry
|
||||
|
||||
class TelemetrySessionObserverTest {
|
||||
|
||||
private val owner: LifecycleOwner = mockk(relaxed = true)
|
||||
private val sessionManager: SessionManager = mockk(relaxed = true)
|
||||
private val metrics: MetricController = mockk(relaxed = true)
|
||||
private val ads: AdsTelemetry = mockk(relaxed = true)
|
||||
|
||||
private lateinit var singleSessionObserver: TelemetrySessionObserver
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
singleSessionObserver =
|
||||
UriOpenedObserver(owner, sessionManager, metrics, ads).singleSessionObserver
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `tracks that a url was loaded`() {
|
||||
val session: Session = mockk(relaxed = true)
|
||||
every { session.url } returns "https://mozilla.com"
|
||||
|
||||
singleSessionObserver.onLoadingStateChanged(session, loading = false)
|
||||
verify(exactly = 0) { metrics.track(Event.UriOpened) }
|
||||
|
||||
singleSessionObserver.onLoadingStateChanged(session, loading = true)
|
||||
singleSessionObserver.onLoadingStateChanged(session, loading = false)
|
||||
verify { metrics.track(Event.UriOpened) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `add originSessionUrl on first link of redirect chain and start chain`() {
|
||||
val session: Session = mockk(relaxed = true)
|
||||
val sessionUrl = "https://www.google.com/search"
|
||||
val url = "www.aaa.com"
|
||||
every { session.url } returns sessionUrl
|
||||
singleSessionObserver.onLoadRequest(
|
||||
session,
|
||||
url,
|
||||
triggeredByRedirect = false,
|
||||
triggeredByWebContent = false
|
||||
)
|
||||
Assert.assertEquals(sessionUrl, singleSessionObserver.originSessionUrl)
|
||||
Assert.assertEquals(url, singleSessionObserver.redirectChain[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `add to redirect chain on subsequent onLoadRequests`() {
|
||||
val session: Session = mockk(relaxed = true)
|
||||
val url = "https://www.google.com/search"
|
||||
val newUrl = "www.aaa.com"
|
||||
every { session.url } returns url
|
||||
singleSessionObserver.originSessionUrl = url
|
||||
singleSessionObserver.redirectChain.add(url)
|
||||
singleSessionObserver.onLoadRequest(
|
||||
session,
|
||||
newUrl,
|
||||
triggeredByRedirect = false,
|
||||
triggeredByWebContent = false
|
||||
)
|
||||
Assert.assertEquals(url, singleSessionObserver.originSessionUrl)
|
||||
Assert.assertEquals(url, singleSessionObserver.redirectChain[0])
|
||||
Assert.assertEquals(newUrl, singleSessionObserver.redirectChain[1])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `do nothing onLoadRequest when it's the first url of the session`() {
|
||||
val session: Session = mockk(relaxed = true)
|
||||
val url = "https://www.google.com/search"
|
||||
every { session.url } returns url
|
||||
singleSessionObserver.onLoadRequest(
|
||||
session,
|
||||
url,
|
||||
triggeredByRedirect = false,
|
||||
triggeredByWebContent = false
|
||||
)
|
||||
Assert.assertNull(singleSessionObserver.originSessionUrl)
|
||||
Assert.assertEquals(0, singleSessionObserver.redirectChain.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `check if metric for ad clicked should be sent`() {
|
||||
val session: Session = mockk(relaxed = true)
|
||||
val sessionUrl = "doesn't matter"
|
||||
val originSessionUrl = "https://www.google.com/search"
|
||||
val url = "www.aaa.com"
|
||||
every { session.url } returns sessionUrl
|
||||
val redirectChain = mutableListOf(url)
|
||||
singleSessionObserver.redirectChain = redirectChain
|
||||
singleSessionObserver.originSessionUrl = originSessionUrl
|
||||
|
||||
singleSessionObserver.onUrlChanged(session, url)
|
||||
|
||||
verify {
|
||||
ads.trackAdClickedMetric(
|
||||
originSessionUrl,
|
||||
redirectChain
|
||||
)
|
||||
}
|
||||
Assert.assertNull(singleSessionObserver.originSessionUrl)
|
||||
Assert.assertEquals(0, singleSessionObserver.redirectChain.size)
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/* 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.ext
|
||||
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.search.telemetry.SearchProviderModel
|
||||
|
||||
class AdsTest {
|
||||
|
||||
private val testSearchProvider =
|
||||
SearchProviderModel(
|
||||
name = "test",
|
||||
regexp = "test",
|
||||
queryParam = "test",
|
||||
codeParam = "test",
|
||||
codePrefixes = listOf(),
|
||||
followOnParams = listOf(),
|
||||
extraAdServersRegexps = listOf(
|
||||
"^https:\\/\\/www\\.bing\\.com\\/acli?c?k",
|
||||
"^https:\\/\\/www\\.bing\\.com\\/fd\\/ls\\/GLinkPingPost\\.aspx.*acli?c?k"
|
||||
)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `test search provider contains ads`() {
|
||||
val ad = "https://www.bing.com/aclick"
|
||||
val nonAd = "https://www.bing.com/notanad"
|
||||
assertTrue(testSearchProvider.containsAds(listOf(ad, nonAd)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test search provider does not contain ads`() {
|
||||
val nonAd1 = "https://www.yahoo.com/notanad"
|
||||
val nonAd2 = "https://www.google.com/"
|
||||
assertFalse(testSearchProvider.containsAds(listOf(nonAd1, nonAd2)))
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
/* 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.search.telemetry.ads
|
||||
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.concept.engine.Engine
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.components.metrics.Event
|
||||
import org.mozilla.fenix.components.metrics.MetricController
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.search.telemetry.ads.AdsTelemetry.Companion.ADS_EXTENSION_ID
|
||||
import org.mozilla.fenix.search.telemetry.ads.AdsTelemetry.Companion.ADS_EXTENSION_RESOURCE_URL
|
||||
import org.mozilla.fenix.search.telemetry.ads.AdsTelemetry.Companion.ADS_MESSAGE_DOCUMENT_URLS_KEY
|
||||
import org.mozilla.fenix.search.telemetry.ads.AdsTelemetry.Companion.ADS_MESSAGE_SESSION_URL_KEY
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class AdsTelemetryTest {
|
||||
|
||||
private val metrics: MetricController = mockk(relaxed = true)
|
||||
private lateinit var ads: AdsTelemetry
|
||||
private lateinit var adsMessageHandler: AdsTelemetry.AdsTelemetryContentMessageHandler
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
ads = spyk(AdsTelemetry(metrics))
|
||||
adsMessageHandler = ads.AdsTelemetryContentMessageHandler()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `don't track with null session url`() {
|
||||
ads.trackAdClickedMetric(null, listOf())
|
||||
|
||||
verify(exactly = 0) { ads.getProviderForUrl(any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `don't track when no ads are in the redirect path`() {
|
||||
val sessionUrl = "https://www.google.com/search?q=aaa"
|
||||
|
||||
ads.trackAdClickedMetric(sessionUrl, listOf("https://www.aaa.com"))
|
||||
|
||||
verify(exactly = 0) { metrics.track(any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `track when ads are in the redirect path`() {
|
||||
val metricEvent = slot<Event.SearchAdClicked>()
|
||||
val sessionUrl = "https://www.google.com/search?q=aaa"
|
||||
|
||||
ads.trackAdClickedMetric(
|
||||
sessionUrl,
|
||||
listOf("https://www.google.com/aclk", "https://www.aaa.com")
|
||||
)
|
||||
|
||||
verify { metrics.track(capture(metricEvent)) }
|
||||
assertEquals(ads.providerList[0].name, metricEvent.captured.label)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun install() {
|
||||
val engine = mockk<Engine>(relaxed = true)
|
||||
val store = mockk<BrowserStore>(relaxed = true)
|
||||
|
||||
ads.install(engine, store)
|
||||
|
||||
verify {
|
||||
engine.installWebExtension(
|
||||
id = ADS_EXTENSION_ID,
|
||||
url = ADS_EXTENSION_RESOURCE_URL,
|
||||
allowContentMessaging = true,
|
||||
onSuccess = any(),
|
||||
onError = any()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `message handler processes the document urls and reports an ad`() {
|
||||
val metricEvent = slot<Event.SearchWithAds>()
|
||||
val first = "https://www.google.com/aclk"
|
||||
val second = "https://www.google.com/aaa"
|
||||
val array = JSONArray()
|
||||
array.put(first)
|
||||
array.put(second)
|
||||
val message = JSONObject()
|
||||
message.put(ADS_MESSAGE_DOCUMENT_URLS_KEY, array)
|
||||
message.put(ADS_MESSAGE_SESSION_URL_KEY, "https://www.google.com/search?q=aaa")
|
||||
|
||||
assertEquals("", adsMessageHandler.onMessage(message, mockk()))
|
||||
|
||||
verify { metrics.track(capture(metricEvent)) }
|
||||
assertEquals(ads.providerList[0].name, metricEvent.captured.label)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `message handler processes the document urls and doesn't find ads`() {
|
||||
val first = "https://www.google.com/aaaaaa"
|
||||
val second = "https://www.google.com/aaa"
|
||||
val array = JSONArray()
|
||||
array.put(first)
|
||||
array.put(second)
|
||||
val message = JSONObject()
|
||||
message.put(ADS_MESSAGE_DOCUMENT_URLS_KEY, array)
|
||||
message.put(ADS_MESSAGE_SESSION_URL_KEY, "https://www.google.com/search?q=aaa")
|
||||
|
||||
assertEquals("", adsMessageHandler.onMessage(message, mockk()))
|
||||
|
||||
verify(exactly = 0) { metrics.track(any()) }
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun `message handler finds no json object`() {
|
||||
val message = "message"
|
||||
|
||||
adsMessageHandler.onMessage(message, mockk())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue