Skip to content

Commit

Permalink
Add FXIOS-10757 [Homepage] [Top Site] Unified Ads API for Sponsored T…
Browse files Browse the repository at this point in the history
…iles (#23977)

* Add FXIOS-10978 [Homepage] [Top Site] Unified Ads API for Sponsored Tiles

* add back code; uncomment only for testing purposes
  • Loading branch information
cyndichin authored Dec 31, 2024
1 parent c28c15e commit 6586187
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,22 @@ protocol TopSitesManagerInterface {
}

/// Manager to fetch the top sites data, the data gets updated from notifications on specific user actions
class TopSitesManager: TopSitesManagerInterface {
class TopSitesManager: TopSitesManagerInterface, FeatureFlaggable {
private var logger: Logger
private let prefs: Prefs
private let contileProvider: ContileProviderInterface
private let googleTopSiteManager: GoogleTopSiteManagerProvider
private let topSiteHistoryManager: TopSiteHistoryManagerProvider
private let searchEnginesManager: SearchEnginesManagerProvider
private let unifiedAdsProvider: UnifiedAdsProviderInterface

private let maxTopSites: Int
private let maxNumberOfSponsoredTile: Int = 2

init(
prefs: Prefs,
contileProvider: ContileProviderInterface = ContileProvider(),
unifiedAdsProvider: UnifiedAdsProviderInterface = UnifiedAdsProvider(),
googleTopSiteManager: GoogleTopSiteManagerProvider,
topSiteHistoryManager: TopSiteHistoryManagerProvider,
searchEnginesManager: SearchEnginesManagerProvider,
Expand All @@ -50,6 +52,7 @@ class TopSitesManager: TopSitesManagerInterface {
) {
self.prefs = prefs
self.contileProvider = contileProvider
self.unifiedAdsProvider = unifiedAdsProvider
self.googleTopSiteManager = googleTopSiteManager
self.topSiteHistoryManager = topSiteHistoryManager
self.searchEnginesManager = searchEnginesManager
Expand Down Expand Up @@ -83,16 +86,32 @@ class TopSitesManager: TopSitesManagerInterface {
// MARK: Sponsored tiles (Contiles)
func fetchSponsoredSites() async -> [SponsoredTile] {
let contiles = await withCheckedContinuation { continuation in
contileProvider.fetchContiles { [weak self] result in
if case .success(let contiles) = result {
continuation.resume(returning: contiles)
} else {
self?.logger.log(
"Contile provider did not return any sponsored tiles when requested",
level: .warning,
category: .homepage
)
continuation.resume(returning: [])
if featureFlags.isFeatureEnabled(.unifiedAds, checking: .buildOnly) {
unifiedAdsProvider.fetchTiles { [weak self] result in
if case .success(let unifiedTiles) = result {
let sponsoredTiles = UnifiedAdsConverter.convert(unifiedTiles: unifiedTiles)
continuation.resume(returning: sponsoredTiles)
} else {
self?.logger.log(
"Unified ads provider did not return any sponsored tiles when requested",
level: .warning,
category: .homepage
)
continuation.resume(returning: [])
}
}
} else {
contileProvider.fetchContiles { [weak self] result in
if case .success(let contiles) = result {
continuation.resume(returning: contiles)
} else {
self?.logger.log(
"Contile provider did not return any sponsored tiles when requested",
level: .warning,
category: .homepage
)
continuation.resume(returning: [])
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Shared

@testable import Client

class MockContileProvider: ContileProviderInterface {
class MockSponsoredProvider: ContileProviderInterface, UnifiedAdsProviderInterface {
enum MockError: Error {
case testError
}
Expand Down Expand Up @@ -51,4 +51,25 @@ class MockContileProvider: ContileProviderInterface {
func fetchContiles(timestamp: Timestamp = Date.now(), completion: @escaping (ContileResult) -> Void) {
completion(result)
}

func fetchTiles(timestamp: Timestamp, completion: @escaping (UnifiedTileResult) -> Void) {
switch result {
case .success(let contiles):
let unifiedTiles = self.convert(contiles: contiles)
completion(.success(unifiedTiles))
case .failure(let error):
completion(.failure(error))
}
}

func convert(contiles: [Contile]) -> [UnifiedTile] {
return contiles.enumerated().map { (index, contile) in
UnifiedTile(format: "tile",
url: contile.url,
callbacks: UnifiedTileCallback(click: contile.clickUrl, impression: contile.impressionUrl),
imageUrl: contile.imageUrl,
name: contile.name,
blockKey: "Block_key_\(index)")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ final class MockTopSitesManager: TopSitesManagerInterface {
func fetchSponsoredSites() async -> [SponsoredTile] {
fetchSponsoredSitesCalledCount += 1

let contiles = MockContileProvider.defaultSuccessData
let contiles = MockSponsoredProvider.defaultSuccessData
return contiles.compactMap { SponsoredTile(contile: $0) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ final class TopSitesManagerTests: XCTestCase {
override func setUp() {
super.setUp()
profile = MockProfile()
LegacyFeatureFlagsManager.shared.initializeDeveloperFeatures(with: MockProfile())
}

override func tearDown() {
Expand Down Expand Up @@ -68,9 +69,10 @@ final class TopSitesManagerTests: XCTestCase {

// MARK: Sponsored Top Site
func test_fetchSponsoredSites_withSuccessData_returnSponsoredSites() async throws {
setupNimbusUnifiedAdsTesting(isEnabled: false)
let subject = try createSubject(
contileProvider: MockContileProvider(
result: .success(MockContileProvider.defaultSuccessData)
contileProvider: MockSponsoredProvider(
result: .success(MockSponsoredProvider.defaultSuccessData)
)
)

Expand All @@ -81,9 +83,10 @@ final class TopSitesManagerTests: XCTestCase {
}

func test_fetchSponsoredSites_withEmptySuccess_returnSponsoredSites() async throws {
setupNimbusUnifiedAdsTesting(isEnabled: false)
let subject = try createSubject(
contileProvider: MockContileProvider(
result: .success(MockContileProvider.emptySuccessData)
contileProvider: MockSponsoredProvider(
result: .success(MockSponsoredProvider.emptySuccessData)
)
)

Expand All @@ -92,9 +95,48 @@ final class TopSitesManagerTests: XCTestCase {
}

func test_fetchSponsoredSites_withFailure_returnNoSponsoredSites() async throws {
setupNimbusUnifiedAdsTesting(isEnabled: false)
let subject = try createSubject(
contileProvider: MockContileProvider(
result: .failure(MockContileProvider.MockError.testError)
contileProvider: MockSponsoredProvider(
result: .failure(MockSponsoredProvider.MockError.testError)
)
)

let topSites = await subject.fetchSponsoredSites()
XCTAssertEqual(topSites.count, 0)
}

func test_fetchSponsoredSites_forUnifiedAds_withSuccessData_returnSponsoredSites() async throws {
setupNimbusUnifiedAdsTesting(isEnabled: true)
let subject = try createSubject(
unifiedAdsProvider: MockSponsoredProvider(
result: .success(MockSponsoredProvider.defaultSuccessData)
)
)

let topSites = await subject.fetchSponsoredSites()
XCTAssertEqual(topSites.count, 3)
let expectedTitles = ["Firefox Sponsored Tile", "Mozilla Sponsored Tile", "Focus Sponsored Tile"]
XCTAssertEqual(topSites.compactMap { $0.title }, expectedTitles)
}

func test_fetchSponsoredSites_forUnifiedAds_withEmptySuccess_returnSponsoredSites() async throws {
setupNimbusUnifiedAdsTesting(isEnabled: true)
let subject = try createSubject(
unifiedAdsProvider: MockSponsoredProvider(
result: .success(MockSponsoredProvider.emptySuccessData)
)
)

let topSites = await subject.fetchSponsoredSites()
XCTAssertEqual(topSites.count, 0)
}

func test_fetchSponsoredSites_forUnifiedAds_withFailure_returnNoSponsoredSites() async throws {
setupNimbusUnifiedAdsTesting(isEnabled: true)
let subject = try createSubject(
unifiedAdsProvider: MockSponsoredProvider(
result: .failure(MockSponsoredProvider.MockError.testError)
)
)

Expand Down Expand Up @@ -203,7 +245,7 @@ final class TopSitesManagerTests: XCTestCase {

let topSites = await subject.recalculateTopSites(
otherSites: MockTopSiteHistoryManager.duplicateTile.compactMap { TopSiteState(site: $0) },
sponsoredSites: MockContileProvider.defaultSuccessData.compactMap { SponsoredTile(contile: $0) }
sponsoredSites: MockSponsoredProvider.defaultSuccessData.compactMap { SponsoredTile(contile: $0) }
)

XCTAssertEqual(topSites.count, 2)
Expand All @@ -217,7 +259,7 @@ final class TopSitesManagerTests: XCTestCase {
let subject = try createSubject(googleTopSiteManager: MockGoogleTopSiteManager(), maxCount: 2)
let topSites = await subject.recalculateTopSites(
otherSites: MockTopSiteHistoryManager.noPinnedData.compactMap { TopSiteState(site: $0) },
sponsoredSites: MockContileProvider.defaultSuccessData.compactMap { SponsoredTile(contile: $0) }
sponsoredSites: MockSponsoredProvider.defaultSuccessData.compactMap { SponsoredTile(contile: $0) }
)

XCTAssertEqual(topSites.count, 2)
Expand All @@ -232,7 +274,7 @@ final class TopSitesManagerTests: XCTestCase {

let topSites = await subject.recalculateTopSites(
otherSites: MockTopSiteHistoryManager.defaultSuccessData.compactMap { TopSiteState(site: $0) },
sponsoredSites: MockContileProvider.defaultSuccessData.compactMap { SponsoredTile(contile: $0) }
sponsoredSites: MockSponsoredProvider.defaultSuccessData.compactMap { SponsoredTile(contile: $0) }
)
XCTAssertEqual(topSites.count, 6)
let expectedTitles = [
Expand Down Expand Up @@ -260,7 +302,7 @@ final class TopSitesManagerTests: XCTestCase {

let topSites = await subject.recalculateTopSites(
otherSites: MockTopSiteHistoryManager.noPinnedData.compactMap { TopSiteState(site: $0) },
sponsoredSites: MockContileProvider.defaultSuccessData.compactMap { SponsoredTile(contile: $0) }
sponsoredSites: MockSponsoredProvider.defaultSuccessData.compactMap { SponsoredTile(contile: $0) }
)
XCTAssertEqual(topSites.count, 3)
let expectedTitles = [
Expand Down Expand Up @@ -292,7 +334,7 @@ final class TopSitesManagerTests: XCTestCase {

let topSites = await subject.recalculateTopSites(
otherSites: [],
sponsoredSites: MockContileProvider.defaultSuccessData.compactMap { SponsoredTile(contile: $0) }
sponsoredSites: MockSponsoredProvider.defaultSuccessData.compactMap { SponsoredTile(contile: $0) }
)

XCTAssertEqual(topSites.compactMap { $0.title }, ["Google Test", "Mozilla Sponsored Tile"])
Expand All @@ -301,8 +343,11 @@ final class TopSitesManagerTests: XCTestCase {

private func createSubject(
googleTopSiteManager: GoogleTopSiteManagerProvider = MockGoogleTopSiteManager(mockSiteData: nil),
contileProvider: ContileProviderInterface = MockContileProvider(
result: .success(MockContileProvider.emptySuccessData)
contileProvider: ContileProviderInterface = MockSponsoredProvider(
result: .success(MockSponsoredProvider.emptySuccessData)
),
unifiedAdsProvider: UnifiedAdsProviderInterface = MockSponsoredProvider(
result: .success(MockSponsoredProvider.emptySuccessData)
),
topSiteHistoryManager: TopSiteHistoryManagerProvider = MockTopSiteHistoryManager(sites: []),
searchEngineManager: SearchEnginesManagerProvider = MockSearchEnginesManager(),
Expand All @@ -314,6 +359,7 @@ final class TopSitesManagerTests: XCTestCase {
let subject = TopSitesManager(
prefs: mockProfile.prefs,
contileProvider: contileProvider,
unifiedAdsProvider: unifiedAdsProvider,
googleTopSiteManager: googleTopSiteManager,
topSiteHistoryManager: topSiteHistoryManager,
searchEnginesManager: searchEngineManager,
Expand Down Expand Up @@ -348,4 +394,10 @@ final class TopSitesManagerTests: XCTestCase {
}
return tiles
}

private func setupNimbusUnifiedAdsTesting(isEnabled: Bool) {
FxNimbus.shared.features.unifiedAds.with { _, _ in
return UnifiedAds(enabled: isEnabled)
}
}
}

0 comments on commit 6586187

Please sign in to comment.