Skip to content

Commit

Permalink
Refactor FXIOS-7883 [v122] Move contextual id away from sponsored til…
Browse files Browse the repository at this point in the history
…e telemetry (#17610)
  • Loading branch information
lmarceau authored Dec 5, 2023
1 parent 50778ab commit 451e22b
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 57 deletions.
8 changes: 8 additions & 0 deletions Client.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,8 @@
8A93F87029D3A597004159D9 /* SceneCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A93F86F29D3A597004159D9 /* SceneCoordinator.swift */; };
8A93F87229D3A5AD004159D9 /* BrowserCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A93F87129D3A5AD004159D9 /* BrowserCoordinator.swift */; };
8A93F87429D3A5C1004159D9 /* LaunchCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A93F87329D3A5C1004159D9 /* LaunchCoordinator.swift */; };
8A95FF642B1E969E00AC303D /* TelemetryContextualIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A95FF632B1E969E00AC303D /* TelemetryContextualIdentifier.swift */; };
8A95FF672B1E97A800AC303D /* TelemetryContextualIdentifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A95FF652B1E977E00AC303D /* TelemetryContextualIdentifierTests.swift */; };
8A96C4BB28F9E7B300B75884 /* XCTestCaseRootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A96C4BA28F9E7B300B75884 /* XCTestCaseRootViewController.swift */; };
8A9AC465276CEC4E0047F5B0 /* JumpBackInCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A9AC464276CEC4E0047F5B0 /* JumpBackInCell.swift */; };
8A9AC46B276D11280047F5B0 /* PocketViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A9AC46A276D11280047F5B0 /* PocketViewModel.swift */; };
Expand Down Expand Up @@ -5265,6 +5267,8 @@
8A93F86F29D3A597004159D9 /* SceneCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneCoordinator.swift; sourceTree = "<group>"; };
8A93F87129D3A5AD004159D9 /* BrowserCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserCoordinator.swift; sourceTree = "<group>"; };
8A93F87329D3A5C1004159D9 /* LaunchCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchCoordinator.swift; sourceTree = "<group>"; };
8A95FF632B1E969E00AC303D /* TelemetryContextualIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryContextualIdentifier.swift; sourceTree = "<group>"; };
8A95FF652B1E977E00AC303D /* TelemetryContextualIdentifierTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryContextualIdentifierTests.swift; sourceTree = "<group>"; };
8A96C4B828F9DD8700B75884 /* ThemableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemableTests.swift; sourceTree = "<group>"; };
8A96C4BA28F9E7B300B75884 /* XCTestCaseRootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCaseRootViewController.swift; sourceTree = "<group>"; };
8A99DB9727C6DD3E007EA6BD /* is */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = is; path = "is.lproj/Default Browser.strings"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -10694,6 +10698,7 @@
8AD08D1427E9198E00B8E907 /* TabsQuantityTelemetry.swift */,
EBF47E6F1F7979DF00899189 /* TelemetryWrapper.swift */,
8ADC2A132A33762900543DAA /* ReferringPage.swift */,
8A95FF632B1E969E00AC303D /* TelemetryContextualIdentifier.swift */,
);
path = Telemetry;
sourceTree = "<group>";
Expand Down Expand Up @@ -10942,6 +10947,7 @@
8AA6ADB42742B567004EEE23 /* TelemetryWrapperTests.swift */,
0BA8964A1A250E6500C1010C /* TestBookmarks.swift */,
4A59BF410BBD9B3BE71F4C7C /* TestHistory.swift */,
8A95FF652B1E977E00AC303D /* TelemetryContextualIdentifierTests.swift */,
8A33222027DFE64C008F809E /* TestingHelperClasses */,
E1D8BC7921FF7A0000B100BD /* TPStatsBlocklistsTests.swift */,
8A1E3BE028CBAC1F003388C4 /* Utils */,
Expand Down Expand Up @@ -13268,6 +13274,7 @@
E1442FD1294782D9003680B0 /* UIModalPresentationStyle+Photon.swift in Sources */,
E1ADE23E2B06559500FD17AA /* FakespotAction.swift in Sources */,
5A32C2B62AD8517200A9B5A4 /* MetricKitWrapper.swift in Sources */,
8A95FF642B1E969E00AC303D /* TelemetryContextualIdentifier.swift in Sources */,
D3FEC38D1AC4B42F00494F45 /* AutocompleteTextField.swift in Sources */,
8A19ACAE2A329058001C2147 /* PasswordManagerSetting.swift in Sources */,
AB03032C2AB47AF300DCD8EF /* FakespotOptInCardViewModel.swift in Sources */,
Expand Down Expand Up @@ -13691,6 +13698,7 @@
8A7A26E129D4785900EA76F1 /* MockRouter.swift in Sources */,
965C3C96293431FC006499ED /* MockLaunchSessionProvider.swift in Sources */,
C869915628917803007ACC5C /* WallpaperJSONTestProvider.swift in Sources */,
8A95FF672B1E97A800AC303D /* TelemetryContextualIdentifierTests.swift in Sources */,
965C3C9829343445006499ED /* MockAppSessionManager.swift in Sources */,
8AFCE50929DE136300B1B253 /* MockLaunchFinishedLoadingDelegate.swift in Sources */,
8AE1E1DB27B1C1320024C45E /* SearchBarSettingsViewModelTests.swift in Sources */,
Expand Down
26 changes: 1 addition & 25 deletions Client/Telemetry/SponsoredTileTelemetry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,10 @@ import Glean

// Telemetry for the Sponsored tiles located in the Top sites on the Firefox home page
// Using Pings to send the telemetry events
class SponsoredTileTelemetry {
struct SponsoredTileTelemetry {
// Source is only new tab at the moment, more source could be added later
static let source = "newtab"

enum UserDefaultsKey: String {
case keyContextId = "com.moz.contextId.key"
}

static var contextId: String? {
get { UserDefaults.standard.object(forKey: UserDefaultsKey.keyContextId.rawValue) as? String }
set { UserDefaults.standard.set(newValue, forKey: UserDefaultsKey.keyContextId.rawValue) }
}

static func clearUserDefaults() {
SponsoredTileTelemetry.contextId = nil
}

static func setupContextId() {
// Use existing client UUID, if doesn't exists create a new one
if let stringContextId = contextId, let clientUUID = UUID(uuidString: stringContextId) {
GleanMetrics.TopSites.contextId.set(clientUUID)
} else {
let newUUID = UUID()
GleanMetrics.TopSites.contextId.set(newUUID)
contextId = newUUID.uuidString
}
}

static func sendImpressionTelemetry(tile: SponsoredTile, position: Int) {
let extra = GleanMetrics.TopSites.ContileImpressionExtra(position: Int32(position), source: SponsoredTileTelemetry.source)
GleanMetrics.TopSites.contileImpression.record(extra)
Expand Down
33 changes: 33 additions & 0 deletions Client/Telemetry/TelemetryContextualIdentifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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/

import Foundation
import Glean

// Contextual identifier used for the sponsored tiles in top sites and the suggestions in the search view
struct TelemetryContextualIdentifier {
enum UserDefaultsKey: String {
case keyContextId = "com.moz.contextId.key"
}

static var contextId: String? {
get { UserDefaults.standard.object(forKey: UserDefaultsKey.keyContextId.rawValue) as? String }
set { UserDefaults.standard.set(newValue, forKey: UserDefaultsKey.keyContextId.rawValue) }
}

static func clearUserDefaults() {
TelemetryContextualIdentifier.contextId = nil
}

static func setupContextId() {
// Use existing client UUID, if doesn't exists create a new one
if let stringContextId = contextId, let clientUUID = UUID(uuidString: stringContextId) {
GleanMetrics.TopSites.contextId.set(clientUUID)
} else {
let newUUID = UUID()
GleanMetrics.TopSites.contextId.set(newUUID)
contextId = newUUID.uuidString
}
}
}
2 changes: 1 addition & 1 deletion Client/Telemetry/TelemetryWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class TelemetryWrapper: TelemetryWrapperProtocol, FeatureFlaggable {
// Save the profile so we can record settings from it when the notification below fires.
self.profile = profile

SponsoredTileTelemetry.setupContextId()
TelemetryContextualIdentifier.setupContextId()

// Register an observer to record settings and other metrics that are more appropriate to
// record on going to background rather than during initialization.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,10 @@ class SponsoredTileTelemetryTests: XCTestCase {
clearTest()
}

// MARK: Context id

func testContextId_isNilByDefault() {
XCTAssertNil(SponsoredTileTelemetry.contextId)
}

func testContextId_isCreated() {
SponsoredTileTelemetry.setupContextId()
XCTAssertNotNil(SponsoredTileTelemetry.contextId)
}

func testContextId_isReusedAfterCreation() {
SponsoredTileTelemetry.setupContextId()
let contextId = SponsoredTileTelemetry.contextId
SponsoredTileTelemetry.setupContextId()
XCTAssertEqual(contextId, SponsoredTileTelemetry.contextId)
}

func testTelemetryWrapper_setsContextId() {
TelemetryWrapper.shared.setup(profile: MockProfile())
XCTAssertNotNil(SponsoredTileTelemetry.contextId)
}

// MARK: Impression

func testImpressionTopSite() {
SponsoredTileTelemetry.setupContextId()
TelemetryContextualIdentifier.setupContextId()
let contile = ContileProviderMock.defaultSuccessData[0]
let topSite = SponsoredTile(contile: contile)

Expand Down Expand Up @@ -75,7 +52,7 @@ class SponsoredTileTelemetryTests: XCTestCase {
// MARK: Click

func testClickTopSite() {
SponsoredTileTelemetry.setupContextId()
TelemetryContextualIdentifier.setupContextId()
let contile = ContileProviderMock.defaultSuccessData[1]
let topSite = SponsoredTile(contile: contile)

Expand Down Expand Up @@ -104,13 +81,13 @@ class SponsoredTileTelemetryTests: XCTestCase {

// MARK: ContexId
func testContextIdImpressionTopSite() {
SponsoredTileTelemetry.setupContextId()
TelemetryContextualIdentifier.setupContextId()
let contile = ContileProviderMock.defaultSuccessData[0]
let topSite = SponsoredTile(contile: contile)

let expectation = expectation(description: "The top sites ping was sent")
GleanMetrics.Pings.shared.topsitesImpression.testBeforeNextSubmit { _ in
guard let contextId = SponsoredTileTelemetry.contextId,
guard let contextId = TelemetryContextualIdentifier.contextId,
let uuid = UUID(uuidString: contextId) else {
XCTFail("Expected contextId to be configured")
return
Expand All @@ -125,13 +102,12 @@ class SponsoredTileTelemetryTests: XCTestCase {
SponsoredTileTelemetry.sendImpressionTelemetry(tile: topSite, position: 2)
waitForExpectations(timeout: 5.0)
}
}

// MARK: Helper methods
extension SponsoredTileTelemetryTests {
// MARK: Helper methods

func clearTest() {
Glean.shared.resetGlean(clearStores: true)
Glean.shared.enableTestingMode()
SponsoredTileTelemetry.clearUserDefaults()
TelemetryContextualIdentifier.clearUserDefaults()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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/

@testable import Client

import Glean
import XCTest

class TelemetryContextualIdentifierTests: XCTestCase {
override func setUp() {
super.setUp()
clearTest()
}

override func tearDown() {
super.tearDown()
clearTest()
}

// MARK: Context id

func testContextId_isNilByDefault() {
XCTAssertNil(TelemetryContextualIdentifier.contextId)
}

func testContextId_isCreated() {
TelemetryContextualIdentifier.setupContextId()
XCTAssertNotNil(TelemetryContextualIdentifier.contextId)
}

func testContextId_isReusedAfterCreation() {
TelemetryContextualIdentifier.setupContextId()
let contextId = TelemetryContextualIdentifier.contextId
TelemetryContextualIdentifier.setupContextId()
XCTAssertEqual(contextId, TelemetryContextualIdentifier.contextId)
}

func testTelemetryWrapper_setsContextId() {
TelemetryWrapper.shared.setup(profile: MockProfile())
XCTAssertNotNil(TelemetryContextualIdentifier.contextId)
}

// MARK: Helper methods
func clearTest() {
Glean.shared.resetGlean(clearStores: true)
TelemetryContextualIdentifier.clearUserDefaults()
}
}

0 comments on commit 451e22b

Please sign in to comment.