Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Feature/#6557 Organic search telemetry #10167

Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
For #6557 - added unit tests
BranescuMihai committed Apr 24, 2020
commit 2fcb2c843053182fdb91c82e2251cdcde819b5df
Original file line number Diff line number Diff line change
@@ -91,7 +91,7 @@ abstract class BaseSearchTelemetry {
return null
}

protected fun installWebExtension(
internal fun installWebExtension(
engine: Engine,
store: BrowserStore,
extensionInfo: ExtensionInfo
@@ -138,8 +138,10 @@ abstract class BaseSearchTelemetry {
/**
* This method is used to process any valid json message coming from a web-extension
*/
protected abstract fun processMessage(message: JSONObject)
@VisibleForTesting
internal abstract fun processMessage(message: JSONObject)

@VisibleForTesting
internal inner class SearchTelemetryMessageHandler : MessageHandler {

override fun onMessage(message: Any, source: EngineSession?): Any? {
Original file line number Diff line number Diff line change
@@ -59,6 +59,7 @@ class AdsTelemetry(private val metrics: MetricController) : BaseSearchTelemetry(
internal const val ADS_MESSAGE_SESSION_URL_KEY = "url"
@VisibleForTesting
internal const val ADS_MESSAGE_DOCUMENT_URLS_KEY = "urls"
private const val ADS_MESSAGE_ID = "MozacBrowserAds"
@VisibleForTesting
internal const val ADS_MESSAGE_ID = "MozacBrowserAds"
}
}
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ class InContentTelemetry(private val metrics: MetricController) : BaseSearchTele
override fun processMessage(message: JSONObject) {
val cookies = getMessageList<JSONObject>(
message,
COOKIES_MESSAGE_DOCUMENT_URLS_KEY
COOKIES_MESSAGE_LIST_KEY
)
trackPartnerUrlTypeMetric(message.getString(COOKIES_MESSAGE_SESSION_URL_KEY), cookies)
}
@@ -138,8 +138,9 @@ class InContentTelemetry(private val metrics: MetricController) : BaseSearchTele
@VisibleForTesting
internal const val COOKIES_MESSAGE_SESSION_URL_KEY = "url"
@VisibleForTesting
internal const val COOKIES_MESSAGE_DOCUMENT_URLS_KEY = "cookies"
private const val COOKIES_MESSAGE_ID = "BrowserCookiesMessage"
internal const val COOKIES_MESSAGE_LIST_KEY = "cookies"
@VisibleForTesting
internal const val COOKIES_MESSAGE_ID = "BrowserCookiesMessage"

private const val SEARCH_TYPE_ORGANIC = "organic"
private const val SEARCH_TYPE_SAP = "sap"
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package org.mozilla.fenix.search.telemetry

import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.Engine
import org.json.JSONObject
import org.junit.Assert.assertEquals
import org.junit.Test

class BaseSearchTelemetryTest {

private lateinit var baseTelemetry: BaseSearchTelemetry
private lateinit var handler: BaseSearchTelemetry.SearchTelemetryMessageHandler

@org.junit.Before
fun setUp() {
baseTelemetry = spyk(object : BaseSearchTelemetry() {

override fun install(engine: Engine, store: BrowserStore) {
// mock, do nothing
}

override fun processMessage(message: JSONObject) {
// mock, do nothing
}
})
handler = baseTelemetry.SearchTelemetryMessageHandler()
}

@Test
fun install() {
val engine = mockk<Engine>(relaxed = true)
val store = mockk<BrowserStore>(relaxed = true)
val id = "id"
val resourceUrl = "resourceUrl"
val messageId = "messageId"
val extensionInfo = ExtensionInfo(id, resourceUrl, messageId)

baseTelemetry.installWebExtension(engine, store, extensionInfo)

verify {
engine.installWebExtension(
id = id,
url = resourceUrl,
allowContentMessaging = true,
onSuccess = any(),
onError = any()
)
}
}

@Test
fun `get provider for google url`() {
val url = "https://www.google.com/search?q=computers"

assertEquals("google", baseTelemetry.getProviderForUrl(url)?.name)
}

@Test
fun `message handler finds a valid json object`() {
val message = JSONObject()

handler.onMessage(message, mockk())

verify { baseTelemetry.processMessage(message) }
}

@Test(expected = IllegalStateException::class)
fun `message handler finds no json object`() {
val message = "message"

handler.onMessage(message, mockk())
}
}
Original file line number Diff line number Diff line change
@@ -19,22 +19,22 @@ 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.ExtensionInfo
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_ID
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
@@ -71,22 +71,18 @@ class AdsTelemetryTest {
fun install() {
val engine = mockk<Engine>(relaxed = true)
val store = mockk<BrowserStore>(relaxed = true)
val extensionInfo = slot<ExtensionInfo>()

ads.install(engine, store)

verify {
engine.installWebExtension(
id = ADS_EXTENSION_ID,
url = ADS_EXTENSION_RESOURCE_URL,
allowContentMessaging = true,
onSuccess = any(),
onError = any()
)
}
verify { ads.installWebExtension(engine, store, capture(extensionInfo)) }
assertEquals(ADS_EXTENSION_ID, extensionInfo.captured.id)
assertEquals(ADS_EXTENSION_RESOURCE_URL, extensionInfo.captured.resourceUrl)
assertEquals(ADS_MESSAGE_ID, extensionInfo.captured.messageId)
}

@Test
fun `message handler processes the document urls and reports an ad`() {
fun `process 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"
@@ -97,14 +93,14 @@ class AdsTelemetryTest {
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()))
ads.processMessage(message)

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`() {
fun `process the document urls and don't find ads`() {
val first = "https://www.google.com/aaaaaa"
val second = "https://www.google.com/aaa"
val array = JSONArray()
@@ -114,15 +110,8 @@ class AdsTelemetryTest {
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()))
ads.processMessage(message)

verify(exactly = 0) { metrics.track(any()) }
}

@Test(expected = IllegalStateException::class)
fun `message handler finds no json object`() {
val message = "message"

adsMessageHandler.onMessage(message, mockk())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package org.mozilla.fenix.search.telemetry.incontent

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
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.ExtensionInfo
import org.mozilla.fenix.search.telemetry.incontent.InContentTelemetry.Companion.COOKIES_EXTENSION_ID
import org.mozilla.fenix.search.telemetry.incontent.InContentTelemetry.Companion.COOKIES_EXTENSION_RESOURCE_URL
import org.mozilla.fenix.search.telemetry.incontent.InContentTelemetry.Companion.COOKIES_MESSAGE_ID
import org.mozilla.fenix.search.telemetry.incontent.InContentTelemetry.Companion.COOKIES_MESSAGE_LIST_KEY
import org.mozilla.fenix.search.telemetry.incontent.InContentTelemetry.Companion.COOKIES_MESSAGE_SESSION_URL_KEY

@RunWith(FenixRobolectricTestRunner::class)
class InContentTelemetryTest {

private val metrics: MetricController = mockk(relaxed = true)
private lateinit var telemetry: InContentTelemetry

@Before
fun setUp() {
telemetry = spyk(InContentTelemetry(metrics))
}

@Test
fun install() {
val engine = mockk<Engine>(relaxed = true)
val store = mockk<BrowserStore>(relaxed = true)
val extensionInfo = slot<ExtensionInfo>()

telemetry.install(engine, store)

verify { telemetry.installWebExtension(engine, store, capture(extensionInfo)) }
Assert.assertEquals(COOKIES_EXTENSION_ID, extensionInfo.captured.id)
Assert.assertEquals(COOKIES_EXTENSION_RESOURCE_URL, extensionInfo.captured.resourceUrl)
Assert.assertEquals(COOKIES_MESSAGE_ID, extensionInfo.captured.messageId)
}

@Test
fun processMessage() {
val first = JSONObject()
val second = JSONObject()
val array = JSONArray()
array.put(first)
array.put(second)
val message = JSONObject()
val url = "https://www.google.com/search?q=aaa"
message.put(COOKIES_MESSAGE_LIST_KEY, array)
message.put(COOKIES_MESSAGE_SESSION_URL_KEY, url)

telemetry.processMessage(message)

verify { telemetry.trackPartnerUrlTypeMetric(url, any()) }
}

@Test
fun `track google sap metric`() {
val url = "https://www.google.com/search?q=aaa&client=firefox-b-m"

telemetry.trackPartnerUrlTypeMetric(url, listOf())

verify { metrics.track(Event.SearchInContent("google.in-content.sap.firefox-b-m")) }
}

@Test
fun `track duckduckgo sap metric`() {
val url = "https://duckduckgo.com/?q=aaa&t=fpas"

telemetry.trackPartnerUrlTypeMetric(url, listOf())

verify { metrics.track(Event.SearchInContent("duckduckgo.in-content.sap.fpas")) }
}

@Test
fun `track baidu sap metric`() {
val url = "https://www.baidu.com/from=844b/s?wd=aaa&tn=34046034_firefox"

telemetry.trackPartnerUrlTypeMetric(url, listOf())

verify { metrics.track(Event.SearchInContent("baidu.in-content.sap.34046034_firefox")) }
}

@Test
fun `track bing sap metric`() {
val url = "https://www.bing.com/search?q=aaa&pc=MOZMBA"

telemetry.trackPartnerUrlTypeMetric(url, listOf())

verify { metrics.track(Event.SearchInContent("bing.in-content.sap.mozmba")) }
}

@Test
fun `track google sap-follow-on metric`() {
val url = "https://www.google.com/search?q=aaa&client=firefox-b-m&oq=random"

telemetry.trackPartnerUrlTypeMetric(url, listOf())

verify { metrics.track(Event.SearchInContent("google.in-content.sap-follow-on.firefox-b-m")) }
}

@Test
fun `track baidu sap-follow-on metric`() {
val url = "https://www.baidu.com/from=844b/s?wd=aaa&tn=34046034_firefox&oq=random"

telemetry.trackPartnerUrlTypeMetric(url, listOf())

verify { metrics.track(Event.SearchInContent("baidu.in-content.sap-follow-on.34046034_firefox")) }
}

@Test
fun `track bing sap-follow-on metric by cookies`() {
val url = "https://www.bing.com/search?q=aaa&pc=MOZMBA&form=QBRERANDOM"

telemetry.trackPartnerUrlTypeMetric(url, createCookieList())

verify { metrics.track(Event.SearchInContent("bing.in-content.sap-follow-on.mozmba")) }
}

@Test
fun `track google organic metric`() {
val url = "https://www.google.com/search?q=aaa"

telemetry.trackPartnerUrlTypeMetric(url, listOf())

verify { metrics.track(Event.SearchInContent("google.in-content.organic.none")) }
}

@Test
fun `track duckduckgo organic metric`() {
val url = "https://duckduckgo.com/?q=aaa"

telemetry.trackPartnerUrlTypeMetric(url, listOf())

verify { metrics.track(Event.SearchInContent("duckduckgo.in-content.organic.none")) }
}

@Test
fun `track bing organic metric`() {
val url = "https://www.bing.com/search?q=aaa"

telemetry.trackPartnerUrlTypeMetric(url, listOf())

verify { metrics.track(Event.SearchInContent("bing.in-content.organic.none")) }
}

@Test
fun `track baidu organic metric`() {
val url = "https://www.baidu.com/from=844b/s?wd=aaa"

telemetry.trackPartnerUrlTypeMetric(url, listOf())

verify { metrics.track(Event.SearchInContent("baidu.in-content.organic.none")) }
}

private fun createCookieList(): List<JSONObject> {
val first = JSONObject()
first.put("name", "SRCHS")
first.put("value", "PC=MOZMBA")
val second = JSONObject()
second.put("name", "RANDOM")
second.put("value", "RANDOM")
return listOf(first, second)
}
}