Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DuckPlayer] Experiment Fix - Update Test Variables and pixel names #3363

Merged
merged 3 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 5 additions & 5 deletions Core/PixelEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1619,11 +1619,11 @@ extension Pixel.Event {
case .pproFeedbackSubmitScreenFAQClick: return "m_ppro_feedback_submit-screen-faq_click"

// MARK: Duckplayer experiment
case .duckplayerExperimentCohortAssign: return "duckplayer_experiment_cohort_assign"
case .duckplayerExperimentSearch: return "duckplayer_experiment_search"
case .duckplayerExperimentDailySearch: return "duckplayer_experiment_daily_search"
case .duckplayerExperimentWeeklySearch: return "duckplayer_experiment_weekly_search"
case .duckplayerExperimentYoutubePageView: return "duckplayer_experiment_youtube_page_view"
case .duckplayerExperimentCohortAssign: return "duckplayer_experiment_cohort_assign_v2"
case .duckplayerExperimentSearch: return "duckplayer_experiment_search_v2"
case .duckplayerExperimentDailySearch: return "duckplayer_experiment_daily_search_v2"
case .duckplayerExperimentWeeklySearch: return "duckplayer_experiment_weekly_search_v2"
case .duckplayerExperimentYoutubePageView: return "duckplayer_experiment_youtube_page_view_v2"

}
}
Expand Down
66 changes: 33 additions & 33 deletions DuckDuckGo/DuckPlayer/DuckPlayerLaunchExperiment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,19 @@ final class DuckPlayerLaunchExperiment: DuckPlayerLaunchExperimentHandling {
private let dateProvider: DuckPlayerExperimentDateProvider

@UserDefaultsWrapper(key: .duckPlayerPixelExperimentLastWeekPixelFired, defaultValue: nil)
private var lastWeekPixelFired: Int?
private var lastWeekPixelFiredV2: Int?

@UserDefaultsWrapper(key: .duckPlayerPixelExperimentLastDayPixelFired, defaultValue: nil)
private var lastDayPixelFired: Int?
private var lastDayPixelFiredV2: Int?

@UserDefaultsWrapper(key: .duckPlayerPixelExperimentLastVideoIDRendered, defaultValue: nil)
private var lastVideoIDReported: String?
private var lastVideoIDReportedV2: String?

@UserDefaultsWrapper(key: .duckPlayerPixelExperimentEnrollmentDate, defaultValue: nil)
var enrollmentDate: Date?
var enrollmentDateV2: Date?

@UserDefaultsWrapper(key: .duckPlayerPixelExperimentCohort, defaultValue: nil)
var experimentCohort: String?
var experimentCohortV2: String?

private var isInternalUser: Bool

Expand All @@ -113,7 +113,7 @@ final class DuckPlayerLaunchExperiment: DuckPlayerLaunchExperimentHandling {

private var dates: (day: Int, week: Int)? {
guard isEnrolled,
let enrollmentDate = enrollmentDate else { return nil }
let enrollmentDate = enrollmentDateV2 else { return nil }
let currentDate = dateProvider.currentDate
let calendar = Calendar.current
let dayDifference = calendar.dateComponents([.day], from: enrollmentDate, to: currentDate).day ?? 0
Expand All @@ -123,7 +123,7 @@ final class DuckPlayerLaunchExperiment: DuckPlayerLaunchExperimentHandling {

private var formattedEnrollmentDate: String? {
guard isEnrolled,
let enrollmentDate = enrollmentDate else { return nil }
let enrollmentDate = enrollmentDateV2 else { return nil }
return Self.formattedDate(enrollmentDate)
}

Expand All @@ -135,11 +135,11 @@ final class DuckPlayerLaunchExperiment: DuckPlayerLaunchExperimentHandling {
}

var isEnrolled: Bool {
return enrollmentDate != nil && experimentCohort != nil
return enrollmentDateV2 != nil && experimentCohortV2 != nil
}

var isExperimentCohort: Bool {
return experimentCohort == "experiment"
return experimentCohortV2 == "experiment"
}

func assignUserToCohort() {
Expand All @@ -149,32 +149,32 @@ final class DuckPlayerLaunchExperiment: DuckPlayerLaunchExperimentHandling {
if isInternalUser {
cohort = .experiment
}
experimentCohort = cohort.rawValue
enrollmentDate = dateProvider.currentDate
experimentCohortV2 = cohort.rawValue
enrollmentDateV2 = dateProvider.currentDate
fireEnrollmentPixel()
}
}

private func fireEnrollmentPixel() {
guard isEnrolled,
let experimentCohort = experimentCohort,
let experimentCohortV2 = experimentCohortV2,
let formattedEnrollmentDate else { return }

let params = [Constants.variantKey: experimentCohort, Constants.enrollmentKey: formattedEnrollmentDate]
let params = [Constants.variantKey: experimentCohortV2, Constants.enrollmentKey: formattedEnrollmentDate]
pixel.fireDuckPlayerExperimentPixel(pixel: .duckplayerExperimentCohortAssign, withAdditionalParameters: params)
}

func fireSearchPixels() {
if isEnrolled {
guard isEnrolled,
let experimentCohort = experimentCohort,
let experimentCohortV2 = experimentCohortV2,
let dates,
let formattedEnrollmentDate else {
return
}

var params = [
Constants.variantKey: experimentCohort,
Constants.variantKey: experimentCohortV2,
Constants.dayKey: "\(dates.day)",
Constants.enrollmentKey: formattedEnrollmentDate
]
Expand All @@ -183,56 +183,56 @@ final class DuckPlayerLaunchExperiment: DuckPlayerLaunchExperimentHandling {
pixel.fireDuckPlayerExperimentPixel(pixel: .duckplayerExperimentSearch, withAdditionalParameters: params)

// Fire a daily pixel
if dates.day != lastDayPixelFired {
if dates.day != lastDayPixelFiredV2 {
pixel.fireDuckPlayerExperimentPixel(pixel: .duckplayerExperimentDailySearch, withAdditionalParameters: params)
lastDayPixelFired = dates.day
lastDayPixelFiredV2 = dates.day
}

// Fire a weekly pixel
if dates.week != lastWeekPixelFired && dates.day > 0 {
if dates.week != lastWeekPixelFiredV2 && dates.day > 0 {
params.removeValue(forKey: Constants.dayKey)
params[Constants.weekKey] = "\(dates.week)"
pixel.fireDuckPlayerExperimentPixel(pixel: .duckplayerExperimentWeeklySearch, withAdditionalParameters: params)
lastWeekPixelFired = dates.week
lastWeekPixelFiredV2 = dates.week
}
}
}

func fireYoutubePixel(videoID: String) {
guard isEnrolled,
let experimentCohort = experimentCohort,
let experimentCohortV2 = experimentCohortV2,
let dates,
let formattedEnrollmentDate else {
return
}

let params = [
Constants.variantKey: experimentCohort,
Constants.variantKey: experimentCohortV2,
Constants.dayKey: "\(dates.day)",
Constants.stateKey: duckPlayerMode?.stringValue ?? "",
Constants.referrerKey: referrer?.stringValue ?? "",
Constants.enrollmentKey: formattedEnrollmentDate
]
if lastVideoIDReported != videoID {
if lastVideoIDReportedV2 != videoID {
pixel.fireDuckPlayerExperimentPixel(pixel: .duckplayerExperimentYoutubePageView, withAdditionalParameters: params)
lastVideoIDReported = videoID
lastVideoIDReportedV2 = videoID
}
}

func cleanup() {
enrollmentDate = nil
experimentCohort = nil
lastDayPixelFired = nil
lastWeekPixelFired = nil
lastVideoIDReported = nil
enrollmentDateV2 = nil
experimentCohortV2 = nil
lastDayPixelFiredV2 = nil
lastWeekPixelFiredV2 = nil
lastVideoIDReportedV2 = nil
}

func override() {
enrollmentDate = Date()
experimentCohort = "experiment"
lastDayPixelFired = nil
lastWeekPixelFired = nil
lastVideoIDReported = nil
enrollmentDateV2 = Date()
experimentCohortV2 = "experiment"
lastDayPixelFiredV2 = nil
lastWeekPixelFiredV2 = nil
lastVideoIDReportedV2 = nil

}

Expand Down
43 changes: 24 additions & 19 deletions DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ final class DuckPlayerNavigationHandler {
var featureFlagger: FeatureFlagger
var appSettings: AppSettings
var experiment: DuckPlayerLaunchExperimentHandling
private lazy var internalUserDecider = AppDependencyProvider.shared.internalUserDecider

private struct Constants {
static let SERPURL = "duckduckgo.com/"
Expand Down Expand Up @@ -216,26 +217,30 @@ final class DuckPlayerNavigationHandler {
if let navigationAction, isSERPLink(navigationAction: navigationAction) {
referrer = .serp
}


// DuckPlayer Experiment run
let experiment = DuckPlayerLaunchExperiment(duckPlayerMode: duckPlayerMode, referrer: referrer)

// Enroll user if not enrolled
if !experiment.isEnrolled {
experiment.assignUserToCohort()
}

// DuckPlayer is disabled before user enrolls,
// So trigger a settings change notification
// to let the FE know about the 'actual' setting
// and update Experiment value
if experiment.isExperimentCohort {
duckPlayer.settings.triggerNotification()
experiment.duckPlayerMode = duckPlayer.settings.mode

if featureFlagger.isFeatureOn(.duckPlayer) || internalUserDecider.isInternalUser {

// DuckPlayer Experiment run
let experiment = DuckPlayerLaunchExperiment(duckPlayerMode: duckPlayerMode,
referrer: referrer,
isInternalUser: internalUserDecider.isInternalUser)

// Enroll user if not enrolled
if !experiment.isEnrolled {
experiment.assignUserToCohort()
}

// DuckPlayer is disabled before user enrolls,
// So trigger a settings change notification
// to let the FE know about the 'actual' setting
// and update Experiment value
if experiment.isExperimentCohort {
duckPlayer.settings.triggerNotification()
experiment.duckPlayerMode = duckPlayer.settings.mode
}

experiment.fireYoutubePixel(videoID: videoID)
}

experiment.fireYoutubePixel(videoID: videoID)

}

Expand Down
8 changes: 4 additions & 4 deletions DuckDuckGoTests/DuckPlayerExperimentTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ final class DuckPlayerLaunchExperimentTests: XCTestCase {
sut.assignUserToCohort()

XCTAssertTrue(sut.isEnrolled, "User should be enrolled after assigning to cohort.")
XCTAssertNotNil(sut.experimentCohort, "Experiment cohort should be assigned.")
XCTAssertNotNil(sut.enrollmentDate, "Enrollment date should be set.")
XCTAssertEqual(DuckPlayerLaunchExperiment.formattedDate(sut.enrollmentDate ?? Date()), "20240910", "The assigned date should match.")
XCTAssertNotNil(sut.experimentCohortV2, "Experiment cohort should be assigned.")
XCTAssertNotNil(sut.enrollmentDateV2, "Enrollment date should be set.")
XCTAssertEqual(DuckPlayerLaunchExperiment.formattedDate(sut.enrollmentDateV2 ?? Date()), "20240910", "The assigned date should match.")

// Check the pixel event history
let history = DuckPlayerExperimentPixelFireMock.capturedPixelEventHistory
Expand Down Expand Up @@ -142,7 +142,7 @@ final class DuckPlayerLaunchExperimentTests: XCTestCase {
sut.assignUserToCohort()
XCTAssertEqual(DuckPlayerExperimentPixelFireMock.capturedPixelEventHistory.count, 0, "Enrollment pixel should not have fired again")
XCTAssertEqual(sut.isEnrolled, true, "The assigned date should not change.")
XCTAssertEqual(DuckPlayerLaunchExperiment.formattedDate(sut.enrollmentDate ?? Date()), "20240910", "The assigned date should not change.")
XCTAssertEqual(DuckPlayerLaunchExperiment.formattedDate(sut.enrollmentDateV2 ?? Date()), "20240910", "The assigned date should not change.")
}

func testIfUserIsEnrolled_SearchDailyPixelsFire() {
Expand Down
Loading