Bug 1249642 - Implement remote modes in aboutNewTabService.js r?oyiptong draft
authorRicky Rosario <rickyrosario@gmail.com>
Mon, 29 Feb 2016 16:40:33 -0500
changeset 335575 0311185e9e5469cbbd68173a9430b0dafbc63ded
parent 335376 7882aa8df614f30d441d924afcc93c1539cc3118
child 515164 3079fc1f8ff99c261f6e9cf347a73808ce542000
push id11818
push userrrosario@mozilla.com
push dateMon, 29 Feb 2016 21:40:41 +0000
reviewersoyiptong
bugs1249642
milestone47.0a1
Bug 1249642 - Implement remote modes in aboutNewTabService.js r?oyiptong MozReview-Commit-ID: 7DiwSSVMJf2
browser/app/profile/firefox.js
browser/components/newtab/NewTabPrefsProvider.jsm
browser/components/newtab/NewTabRemoteResources.jsm
browser/components/newtab/aboutNewTabService.js
browser/components/newtab/moz.build
browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1378,16 +1378,19 @@ pref("browser.newtabpage.columns", 5);
 pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%");
 
 // endpoint to send newtab click and view pings
 pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v3/links/");
 
 // activates the remote-hosted newtab page
 pref("browser.newtabpage.remote", false);
 
+// Toggles endpoints allowed for remote newtab communications
+pref("browser.newtabpage.remote.mode", "production");
+
 // Enable the DOM fullscreen API.
 pref("full-screen-api.enabled", true);
 
 // Startup Crash Tracking
 // number of startup crashes that can occur before starting into safe mode automatically
 // (this pref has no effect if more than 6 hours have passed since the last crash)
 pref("toolkit.startup.max_resumed_crashes", 3);
 
--- a/browser/components/newtab/NewTabPrefsProvider.jsm
+++ b/browser/components/newtab/NewTabPrefsProvider.jsm
@@ -13,16 +13,17 @@ Cu.import("resource://gre/modules/XPCOMU
 XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
   const {EventEmitter} = Cu.import("resource://devtools/shared/event-emitter.js", {});
   return EventEmitter;
 });
 
 // Supported prefs and data type
 const gPrefsMap = new Map([
   ["browser.newtabpage.remote", "bool"],
+  ["browser.newtabpage.remote.mode", "str"],
   ["browser.newtabpage.enabled", "bool"],
   ["browser.newtabpage.enhanced", "bool"],
   ["browser.newtabpage.pinned", "str"],
   ["intl.locale.matchOS", "bool"],
   ["general.useragent.locale", "localized"],
 ]);
 
 let PrefsProvider = function PrefsProvider() {
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/NewTabRemoteResources.jsm
@@ -0,0 +1,13 @@
+/* exported MODE_CHANNEL_MAP */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["MODE_CHANNEL_MAP"];
+
+const MODE_CHANNEL_MAP = {
+  "production": {origin: "https://content.cdn.mozilla.net"},
+  "staging": {origin: "https://content-cdn.stage.mozaws.net"},
+  "test": {origin: "https://example.com"},
+  "test2": {origin: "http://mochi.test:8888"},
+  "dev": {origin: "http://localhost:8888"}
+};
--- a/browser/components/newtab/aboutNewTabService.js
+++ b/browser/components/newtab/aboutNewTabService.js
@@ -1,54 +1,60 @@
 /*
  * 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/.
 */
 
 /* globals XPCOMUtils, NewTabPrefsProvider, Services,
-  Locale, UpdateUtils
+  Locale, UpdateUtils, MODE_CHANNEL_MAP
 */
 "use strict";
 
 const {utils: Cu, interfaces: Ci} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
                                   "resource://gre/modules/UpdateUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
                                   "resource:///modules/NewTabPrefsProvider.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Locale",
                                   "resource://gre/modules/Locale.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "MODE_CHANNEL_MAP",
+                                  "resource:///modules/NewTabRemoteResources.jsm");
 
 const LOCAL_NEWTAB_URL = "chrome://browser/content/newtab/newTab.xhtml";
 
-const REMOTE_NEWTAB_URL = "https://newtab.cdn.mozilla.net/" +
-                              "v%VERSION%/%CHANNEL%/%LOCALE%/index.html";
+const REMOTE_NEWTAB_PATH = "/v%VERSION%/%CHANNEL%/%LOCALE%/index.html";
 
 const ABOUT_URL = "about:newtab";
 
 // Pref that tells if remote newtab is enabled
 const PREF_REMOTE_ENABLED = "browser.newtabpage.remote";
 
 // The preference that tells whether to match the OS locale
 const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
 
 // The preference that tells what locale the user selected
 const PREF_SELECTED_LOCALE = "general.useragent.locale";
 
+// The preference that tells what remote mode is enabled.
+const PREF_REMOTE_MODE = "browser.newtabpage.remote.mode";
+
 const VALID_CHANNELS = new Set(["esr", "release", "beta", "aurora", "nightly"]);
 
 const REMOTE_NEWTAB_VERSION = "0";
 
 function AboutNewTabService() {
   NewTabPrefsProvider.prefs.on(PREF_REMOTE_ENABLED, this._handleToggleEvent.bind(this));
 
+  this._updateRemoteMaybe = this._updateRemoteMaybe.bind(this);
+
   // trigger remote change if needed, according to pref
   this.toggleRemote(Services.prefs.getBoolPref(PREF_REMOTE_ENABLED));
 }
 
 /*
  * A service that allows for the overriding, at runtime, of the newtab page's url.
  * Additionally, the service manages pref state between a remote and local newtab page.
  *
@@ -119,40 +125,48 @@ AboutNewTabService.prototype = {
       // exit there is no change of state
       return false;
     }
 
     if (stateEnabled) {
       this._remoteURL = this.generateRemoteURL();
       NewTabPrefsProvider.prefs.on(
         PREF_SELECTED_LOCALE,
-        this._updateRemoteMaybe.bind(this));
+        this._updateRemoteMaybe);
       NewTabPrefsProvider.prefs.on(
         PREF_MATCH_OS_LOCALE,
-        this._updateRemoteMaybe.bind(this));
+        this._updateRemoteMaybe);
+      NewTabPrefsProvider.prefs.on(
+        PREF_REMOTE_MODE,
+        this._updateRemoteMaybe);
       this._remoteEnabled = true;
     } else {
       NewTabPrefsProvider.prefs.off(PREF_SELECTED_LOCALE, this._updateRemoteMaybe);
       NewTabPrefsProvider.prefs.off(PREF_MATCH_OS_LOCALE, this._updateRemoteMaybe);
+      NewTabPrefsProvider.prefs.off(PREF_REMOTE_MODE, this._updateRemoteMaybe);
       this._remoteEnabled = false;
     }
     this._newTabURL = ABOUT_URL;
     return true;
   },
 
   /*
-   * Generate a default url based on locale and update channel
+   * Generate a default url based on remote mode, version, locale and update channel
    */
   generateRemoteURL() {
     let releaseName = this.releaseFromUpdateChannel(UpdateUtils.UpdateChannel);
-    let url = REMOTE_NEWTAB_URL
+    let path = REMOTE_NEWTAB_PATH
       .replace("%VERSION%", REMOTE_NEWTAB_VERSION)
       .replace("%LOCALE%", Locale.getLocale())
       .replace("%CHANNEL%", releaseName);
-    return url;
+    let mode = Services.prefs.getCharPref(PREF_REMOTE_MODE, "production");
+    if (!(mode in MODE_CHANNEL_MAP)) {
+      mode = "production";
+    }
+    return MODE_CHANNEL_MAP[mode].origin + path;
   },
 
   /*
    * Returns the default URL.
    *
    * This URL only depends on the browser.newtabpage.remote pref. Overriding
    * the newtab page has no effect on the result of this function.
    *
--- a/browser/components/newtab/moz.build
+++ b/browser/components/newtab/moz.build
@@ -7,16 +7,17 @@
 BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
 
 XPCSHELL_TESTS_MANIFESTS += [
     'tests/xpcshell/xpcshell.ini',
 ]
 
 EXTRA_JS_MODULES += [
     'NewTabPrefsProvider.jsm',
+    'NewTabRemoteResources.jsm',
     'NewTabURL.jsm',
     'PlacesProvider.jsm'
 ]
 
 XPIDL_SOURCES += [
     'nsIAboutNewTabService.idl',
 ]
 
--- a/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js
+++ b/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js
@@ -100,35 +100,50 @@ add_task(function* test_override_remote_
 add_task(function* test_updates() {
   /*
    * Simulates a "cold-boot" situation, with some pref already set before testing a series
    * of changes.
    */
   Preferences.set("browser.newtabpage.remote", true);
   aboutNewTabService.resetNewTabURL(); // need to set manually because pref notifs are off
   let notificationPromise;
-  let expectedHref = "https://newtab.cdn.mozilla.net" +
-                     `/v${aboutNewTabService.remoteVersion}` +
+  let productionModeBaseUrl = "https://content.cdn.mozilla.net";
+  let testModeBaseUrl = "https://example.com";
+  let expectedPath = `/v${aboutNewTabService.remoteVersion}` +
                      `/${aboutNewTabService.remoteReleaseName}` +
                      "/en-GB" +
                      "/index.html";
+  let expectedHref = productionModeBaseUrl + expectedPath;
   Preferences.set("intl.locale.matchOS", true);
   Preferences.set("general.useragent.locale", "en-GB");
+  Preferences.set("browser.newtabpage.remote.mode", "production");
   NewTabPrefsProvider.prefs.init();
 
   // test update checks for prefs
   notificationPromise = nextChangeNotificationPromise(
     expectedHref, "Remote href should be updated");
   Preferences.set("intl.locale.matchOS", false);
   yield notificationPromise;
 
   notificationPromise = nextChangeNotificationPromise(
     DEFAULT_HREF, "Remote href changes back to default");
   Preferences.set("general.useragent.locale", "en-US");
+  yield notificationPromise;
 
+  // test update fires when mode is changed
+  expectedPath = expectedPath.replace("/en-GB/", "/en-US/");
+  notificationPromise = nextChangeNotificationPromise(
+    testModeBaseUrl + expectedPath, "Remote href changes back to origin of test mode");
+  Preferences.set("browser.newtabpage.remote.mode", "test");
+  yield notificationPromise;
+
+  // test invalid mode ends up pointing to production url
+  notificationPromise = nextChangeNotificationPromise(
+    DEFAULT_HREF, "Remote href changes back to production default");
+  Preferences.set("browser.newtabpage.remote.mode", "invalid");
   yield notificationPromise;
 
   // test update fires on override and reset
   let testURL = "https://example.com/";
   notificationPromise = nextChangeNotificationPromise(
     testURL, "a notification occurs on override");
   aboutNewTabService.newTabURL = testURL;
   yield notificationPromise;