For #27549 - Collect shim data about the Pocket sponsored stories.

With the new telemetry will immediately report when a certain Pocket sponsored
story is shown (visible more than 50%) or clicked by the user.
The reasons for the new ping help easily identify the probe being sent and the
type of shim data.
pull/543/head
Mugurell 2 years ago committed by mergify[bot]
parent 573e320708
commit 18d51d9ce2

@ -5890,6 +5890,28 @@ pocket:
metadata: metadata:
tags: tags:
- PocketIntegration - PocketIntegration
spoc_shim:
type: text
description: |
Shim data of the Pocket sponsored story the user just
interacted with.
The shim is a unique base64 string identifying each story and
type of user interaction: story impression or click.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/27549
- https://mozilla-hub.atlassian.net/browse/FNXV2-21791
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/27550#issuecomment-1295027631
data_sensitivity:
- web_activity
notification_emails:
- android-probes@mozilla.com
expires: never
send_in_pings:
- spoc
metadata:
tags:
- PocketIntegration
home_recs_spoc_shown: home_recs_spoc_shown:
type: event type: event
description: | description: |

@ -43,3 +43,22 @@ topsites-impression:
- https://github.com/mozilla-mobile/fenix/pull/23945 - https://github.com/mozilla-mobile/fenix/pull/23945
notification_emails: notification_emails:
- android-probes@mozilla.com - android-probes@mozilla.com
spoc:
description: |
Contains data identifying with which Pocket sponsored story the user
interacted with and the type of interaction: story impression or click.
include_client_id: false
reasons:
impression: |
A sponsored story had more than 50% of it's content visible
on the screen.
click: |
A sponsored story was clicked by the user.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/27549
- https://mozilla-hub.atlassian.net/browse/FNXV2-21791
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/27550#issuecomment-1295027631
notification_emails:
- android-probes@mozilla.com

@ -12,6 +12,7 @@ import mozilla.components.service.pocket.PocketStory.PocketRecommendedStory
import mozilla.components.service.pocket.PocketStory.PocketSponsoredStory import mozilla.components.service.pocket.PocketStory.PocketSponsoredStory
import mozilla.components.service.pocket.ext.getCurrentFlightImpressions import mozilla.components.service.pocket.ext.getCurrentFlightImpressions
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.Pocket import org.mozilla.fenix.GleanMetrics.Pocket
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -93,6 +94,8 @@ internal class DefaultPocketStoriesController(
timesShown = storyShown.getCurrentFlightImpressions().size.inc().toString(), timesShown = storyShown.getCurrentFlightImpressions().size.inc().toString(),
), ),
) )
Pocket.spocShim.set(storyShown.shim.impression)
Pings.spoc.submit(Pings.spocReasonCodes.impression)
} }
else -> { else -> {
// no-op // no-op
@ -169,6 +172,8 @@ internal class DefaultPocketStoriesController(
timesShown = storyClicked.getCurrentFlightImpressions().size.inc().toString(), timesShown = storyClicked.getCurrentFlightImpressions().size.inc().toString(),
), ),
) )
Pocket.spocShim.set(storyClicked.shim.click)
Pings.spoc.submit(Pings.spocReasonCodes.click)
} }
} }
} }

@ -7,12 +7,14 @@ package org.mozilla.fenix.home.pocket
import androidx.navigation.NavController import androidx.navigation.NavController
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.spyk import io.mockk.spyk
import io.mockk.verify import io.mockk.verify
import io.mockk.verifyOrder import io.mockk.verifyOrder
import mozilla.components.service.pocket.PocketStory import mozilla.components.service.pocket.PocketStory
import mozilla.components.service.pocket.PocketStory.PocketRecommendedStory import mozilla.components.service.pocket.PocketStory.PocketRecommendedStory
import mozilla.components.service.pocket.PocketStory.PocketSponsoredStory import mozilla.components.service.pocket.PocketStory.PocketSponsoredStory
import mozilla.components.service.pocket.ext.getCurrentFlightImpressions
import mozilla.components.support.test.robolectric.testContext import mozilla.components.support.test.robolectric.testContext
import mozilla.telemetry.glean.testing.GleanTestRule import mozilla.telemetry.glean.testing.GleanTestRule
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@ -23,6 +25,7 @@ import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.Pocket import org.mozilla.fenix.GleanMetrics.Pocket
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -173,13 +176,31 @@ class DefaultPocketStoriesControllerTest {
fun `WHEN a new sponsored story is shown THEN update the State and record telemetry`() { fun `WHEN a new sponsored story is shown THEN update the State and record telemetry`() {
val store = spyk(AppStore()) val store = spyk(AppStore())
val controller = DefaultPocketStoriesController(mockk(), store, mockk()) val controller = DefaultPocketStoriesController(mockk(), store, mockk())
val storyShown: PocketSponsoredStory = mockk(relaxed = true) val storyShown: PocketSponsoredStory = mockk {
val storyGridLocation = 1 to 2 every { shim.click } returns "testClickShim"
every { shim.impression } returns "testImpressionShim"
controller.handleStoryShown(storyShown, storyGridLocation) }
var wasPingSent = false
verify { store.dispatch(AppAction.PocketStoriesShown(listOf(storyShown))) } mockkStatic("mozilla.components.service.pocket.ext.PocketStoryKt") {
assertNotNull(Pocket.homeRecsSpocShown.testGetValue()) // Simulate that the story was already shown 3 times.
every { storyShown.getCurrentFlightImpressions() } returns listOf(2L, 3L, 7L)
// Test that the spoc ping is immediately sent with the needed data.
Pings.spoc.testBeforeNextSubmit { reason ->
assertEquals(storyShown.shim.impression, Pocket.spocShim.testGetValue())
assertEquals(Pings.spocReasonCodes.impression.name, reason?.name)
wasPingSent = true
}
controller.handleStoryShown(storyShown, 1 to 2)
verify { store.dispatch(AppAction.PocketStoriesShown(listOf(storyShown))) }
assertNotNull(Pocket.homeRecsSpocShown.testGetValue())
assertEquals(1, Pocket.homeRecsSpocShown.testGetValue()!!.size)
val data = Pocket.homeRecsSpocShown.testGetValue()!!.single().extra
assertEquals("1x2", data?.entries?.first { it.key == "position" }?.value)
assertEquals("4", data?.entries?.first { it.key == "times_shown" }?.value)
assertTrue(wasPingSent)
}
} }
@Test @Test
@ -227,24 +248,43 @@ class DefaultPocketStoriesControllerTest {
@Test @Test
fun `WHEN a sponsored story is clicked THEN open that story's url using HomeActivity and record telemetry`() { fun `WHEN a sponsored story is clicked THEN open that story's url using HomeActivity and record telemetry`() {
val story = PocketSponsoredStory( val storyClicked = PocketSponsoredStory(
id = 7, id = 7,
title = "", title = "",
url = "testLink", url = "testLink",
imageUrl = "", imageUrl = "",
sponsor = "", sponsor = "",
shim = mockk(), shim = mockk {
every { click } returns "testClickShim"
every { impression } returns "testImpressionShim"
},
priority = 3, priority = 3,
caps = mockk(relaxed = true), caps = mockk(relaxed = true),
) )
val homeActivity: HomeActivity = mockk(relaxed = true) val homeActivity: HomeActivity = mockk(relaxed = true)
val controller = DefaultPocketStoriesController(homeActivity, mockk(), mockk(relaxed = true)) val controller = DefaultPocketStoriesController(homeActivity, mockk(), mockk(relaxed = true))
var wasPingSent = false
assertNull(Pocket.homeRecsSpocClicked.testGetValue()) assertNull(Pocket.homeRecsSpocClicked.testGetValue())
mockkStatic("mozilla.components.service.pocket.ext.PocketStoryKt") {
controller.handleStoryClicked(story, 1 to 2) // Simulate that the story was already shown 2 times.
every { storyClicked.getCurrentFlightImpressions() } returns listOf(2L, 3L)
verify { homeActivity.openToBrowserAndLoad(story.url, true, BrowserDirection.FromHome) } // Test that the spoc ping is immediately sent with the needed data.
assertNull(Pocket.homeRecsStoryClicked.testGetValue()) Pings.spoc.testBeforeNextSubmit { reason ->
assertEquals(storyClicked.shim.click, Pocket.spocShim.testGetValue())
assertEquals(Pings.spocReasonCodes.click.name, reason?.name)
wasPingSent = true
}
controller.handleStoryClicked(storyClicked, 2 to 3)
verify { homeActivity.openToBrowserAndLoad(storyClicked.url, true, BrowserDirection.FromHome) }
assertNotNull(Pocket.homeRecsSpocClicked.testGetValue())
assertEquals(1, Pocket.homeRecsSpocClicked.testGetValue()!!.size)
val data = Pocket.homeRecsSpocClicked.testGetValue()!!.single().extra
assertEquals("2x3", data?.entries?.first { it.key == "position" }?.value)
assertEquals("3", data?.entries?.first { it.key == "times_shown" }?.value)
assertTrue(wasPingSent)
}
} }
@Test @Test

Loading…
Cancel
Save