Bug 1462725 - Add study expiration and testing override pref; r=rhelmer
authorBianca Danforth <bdanforth@mozilla.com>
Mon, 04 Jun 2018 16:22:08 -0700
changeset 421472 21631d8f5133fbef70f1365449c48c8d9c0382ca
parent 421471 109ec8a11ab8c883dc8c5a6b1c5cec9046e6ec3d
child 421473 04b38008d65764f4be8b259f5be45868f583c8e6
push id34095
push usernbeleuzu@mozilla.com
push dateWed, 06 Jun 2018 09:35:33 +0000
treeherdermozilla-central@d51b920aef69 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrhelmer
bugs1462725
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1462725 - Add study expiration and testing override pref; r=rhelmer The study will shutdown on its own after a specified period of time. The testing override pref allows for changing the study duration from the default, which is 4 weeks. MozReview-Commit-ID: 2KbZl5RrL8P
browser/modules/SavantShieldStudy.jsm
--- a/browser/modules/SavantShieldStudy.jsm
+++ b/browser/modules/SavantShieldStudy.jsm
@@ -22,23 +22,26 @@ XPCOMUtils.defineLazyGetter(this, "log",
   return new ConsoleAPI(consoleOptions);
 });
 
 class SavantShieldStudyClass {
   constructor() {
     this.STUDY_PREF = "shield.savant.enabled";
     this.STUDY_TELEMETRY_CATEGORY = "savant";
     this.ALWAYS_PRIVATE_BROWSING_PREF = "browser.privatebrowsing.autostart";
+    this.STUDY_DURATION_OVERRIDE_PREF = "shield.savant.duration_override";
+    this.STUDY_EXPIRATION_DATE_PREF = "shield.savant.expiration_date";
+    // ms = 'x' weeks * 7 days/week * 24 hours/day * 60 minutes/hour
+    // * 60 seconds/minute * 1000 milliseconds/second
+    this.DEFAULT_STUDY_DURATION_MS = 4 * 7 * 24 * 60 * 60 * 1000;
   }
 
   init() {
     this.TelemetryEvents = new TelemetryEvents(this.STUDY_TELEMETRY_CATEGORY);
 
-    // TODO check expiration, add study duration override pref
-
     // check the pref in case Normandy flipped it on before we could add the pref listener
     this.shouldCollect = Services.prefs.getBoolPref(this.STUDY_PREF);
     if (this.shouldCollect) {
       this.startupStudy();
     }
     Services.prefs.addObserver(this.STUDY_PREF, this);
   }
 
@@ -51,53 +54,115 @@ class SavantShieldStudyClass {
       } else {
         // The pref has been turned off
         this.endStudy("study-disabled");
       }
     }
   }
 
   startupStudy() {
+    // enable before any possible calls to endStudy, since it sends an 'end_study' event
+    this.TelemetryEvents.enableCollection();
+
     if (!this.isEligible()) {
       this.endStudy("ineligible");
       return;
     }
 
-    this.TelemetryEvents.enableCollection();
+    this.initStudyDuration();
+
+    if (this.isStudyExpired()) {
+      log.debug("Study expired in between this and the previous session.");
+      this.endStudy("expired");
+    }
   }
 
   isEligible() {
     const isAlwaysPrivateBrowsing = Services.prefs.getBoolPref(this.ALWAYS_PRIVATE_BROWSING_PREF);
     if (isAlwaysPrivateBrowsing) {
       return false;
     }
 
     return true;
   }
 
+  initStudyDuration() {
+    if (Services.prefs.getStringPref(this.STUDY_EXPIRATION_DATE_PREF, "")) {
+      return;
+    }
+    Services.prefs.setStringPref(
+      this.STUDY_EXPIRATION_DATE_PREF,
+      this.getExpirationDateString()
+    );
+  }
+
+  getDurationFromPref() {
+    return Services.prefs.getIntPref(this.STUDY_DURATION_OVERRIDE_PREF, 0);
+  }
+
+  getExpirationDateString() {
+    const now = Date.now();
+    const studyDurationInMs =
+    this.getDurationFromPref()
+      || this.DEFAULT_STUDY_DURATION_MS;
+    const expirationDateInt = now + studyDurationInMs;
+    return new Date(expirationDateInt).toISOString();
+  }
+
+  isStudyExpired() {
+    const expirationDateInt =
+      Date.parse(Services.prefs.getStringPref(
+        this.STUDY_EXPIRATION_DATE_PREF,
+        this.getExpirationDateString()
+      ));
+
+    if (isNaN(expirationDateInt)) {
+      log.error(
+        `The value for the preference ${this.STUDY_EXPIRATION_DATE_PREF} is invalid.`
+      );
+      return false;
+    }
+
+    if (Date.now() > expirationDateInt) {
+      return true;
+    }
+    return false;
+  }
+
 
   sendEvent(method, object, value, extra) {
     this.TelemetryEvents.sendEvent(method, object, value, extra);
   }
 
   endStudy(reason) {
     log.debug(`Ending the study due to reason: ${ reason }`);
-    this.TelemetryEvents.disableCollection();
+    const isStudyEnding = true;
     // Services.telemetry.recordEvent(this.STUDY_TELEMETRY_CATEGORY, "end_study", reason);
-    this.uninit();
-    // Study pref needs to persist between restarts, so only reset on endStudy
+    this.TelemetryEvents.disableCollection();
+    this.uninit(isStudyEnding);
+    // These prefs needs to persist between restarts, so only reset on endStudy
     Services.prefs.clearUserPref(this.STUDY_PREF);
+    Services.prefs.clearUserPref(this.STUDY_EXPIRATION_DATE_PREF);
   }
 
   // Called on every Firefox shutdown and endStudy
-  uninit() {
-    // TODO: clear study expiration override pref and remove its listener
+  uninit(isStudyEnding = false) {
+    // if just shutting down, check for expiration, so the endStudy event can
+    // be sent along with this session's main ping.
+    if (!isStudyEnding && this.isStudyExpired()) {
+      log.debug("Study expired during this session.");
+      this.endStudy("expired");
+      return;
+    }
+
     Services.prefs.removeObserver(this.ALWAYS_PRIVATE_BROWSING_PREF, this);
     Services.prefs.removeObserver(this.STUDY_PREF, this);
+    Services.prefs.removeObserver(this.STUDY_DURATION_OVERRIDE_PREF, this);
     Services.prefs.clearUserPref(PREF_LOG_LEVEL);
+    Services.prefs.clearUserPref(this.STUDY_DURATION_OVERRIDE_PREF);
   }
 }
 
 const SavantShieldStudy = new SavantShieldStudyClass();
 
 // references:
 // - https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/normandy/lib/TelemetryEvents.jsm
 // - https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/normandy/lib/PreferenceExperiments.jsm#l357