Bug 1381297 - Store the installDate of an extension as a number in the extension-settings.json file, r=aswan
authorBob Silverberg <bsilverberg@mozilla.com>
Thu, 20 Jul 2017 09:02:36 -0400
changeset 422195 2ce634e4577e122b7214b350122f48061396a908
parent 422194 e3dadcaf272679963974179a1334f8c2df1ef57f
child 422196 1f80b3961a73ac1c0368af9e7e39ce582c9ead5a
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1381297
milestone56.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 1381297 - Store the installDate of an extension as a number in the extension-settings.json file, r=aswan MozReview-Commit-ID: 1P7hy23Yyk6
toolkit/components/extensions/ExtensionSettingsStore.jsm
toolkit/components/extensions/test/xpcshell/test_ext_extensionSettingsStore.js
--- a/toolkit/components/extensions/ExtensionSettingsStore.jsm
+++ b/toolkit/components/extensions/ExtensionSettingsStore.jsm
@@ -18,17 +18,17 @@
  *
  * {
  *   type: { // The type of settings being stored in this object, i.e., prefs.
  *     key: { // The unique key for the setting.
  *       initialValue, // The initial value of the setting.
  *       precedenceList: [
  *         {
  *           id, // The id of the extension requesting the setting.
- *           installDate, // The install date of the extension.
+ *           installDate, // The install date of the extension, stored as a number.
  *           value, // The value of the setting requested by the extension.
  *           enabled // Whether the setting is currently enabled.
  *         }
  *       ],
  *     },
  *     key: {
  *       // ...
  *     }
@@ -48,25 +48,52 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "JSONFile",
                                   "resource://gre/modules/JSONFile.jsm");
 
 const JSON_FILE_NAME = "extension-settings.json";
+const JSON_FILE_VERSION = 2;
 const STORE_PATH = OS.Path.join(Services.dirsvc.get("ProfD", Ci.nsIFile).path, JSON_FILE_NAME);
 
 let _store;
 
+// Test-only method to force reloading of the JSON file, by removing the
+// cached file from memory.
+function clearFileFromCache() {
+  let finalizePromise = _store.finalize();
+  _store = null;
+  return finalizePromise;
+}
+
+// Processes the JSON data when read from disk to convert string dates into numbers.
+function dataPostProcessor(json) {
+  if (json.version !== JSON_FILE_VERSION) {
+    for (let storeType in json) {
+      for (let setting in json[storeType]) {
+        for (let extData of json[storeType][setting].precedenceList) {
+          if (typeof extData.installDate != "number") {
+            extData.installDate = new Date(extData.installDate).valueOf();
+          }
+        }
+      }
+    }
+    json.version = JSON_FILE_VERSION;
+  }
+  return json;
+}
+
 // Get the internal settings store, which is persisted in a JSON file.
 function getStore(type) {
   if (!_store) {
     let initStore = new JSONFile({
       path: STORE_PATH,
+      dataPostProcessor,
     });
     initStore.ensureDataReady();
     _store = initStore;
   }
 
   // Ensure a property exists for the given type.
   if (!_store.data[type]) {
     _store.data[type] = {};
@@ -227,17 +254,18 @@ this.ExtensionSettingsStore = {
       };
     }
     let keyInfo = store.data[type][key];
     // Check for this item in the precedenceList.
     let foundIndex = keyInfo.precedenceList.findIndex(item => item.id == id);
     if (foundIndex === -1) {
       // No item for this extension, so add a new one.
       let addon = await AddonManager.getAddonByID(id);
-      keyInfo.precedenceList.push({id, installDate: addon.installDate, value, enabled: true});
+      keyInfo.precedenceList.push(
+        {id, installDate: addon.installDate.valueOf(), value, enabled: true});
     } else {
       // Item already exists or this extension, so update it.
       keyInfo.precedenceList[foundIndex].value = value;
     }
 
     // Sort the list.
     keyInfo.precedenceList.sort(precedenceComparator);
 
@@ -396,13 +424,26 @@ this.ExtensionSettingsStore = {
     }
 
     let topItem = enabledItems[0];
     if (topItem.id == id) {
       return "controlled_by_this_extension";
     }
 
     let addon = await AddonManager.getAddonByID(id);
-    return topItem.installDate > addon.installDate ?
+    return topItem.installDate > addon.installDate.valueOf() ?
       "controlled_by_other_extensions" :
       "controllable_by_this_extension";
   },
+
+  /**
+   * Test-only method to force reloading of the JSON file.
+   *
+   * Note that this method simply clears the local variable that stores the
+   * file, so the next time the file is accessed it will be reloaded.
+   *
+   * @returns {Promise}
+   *          A promise that resolves once the settings store has been cleared.
+   */
+  _reloadFile() {
+    return clearFileFromCache();
+  },
 };
--- a/toolkit/components/extensions/test/xpcshell/test_ext_extensionSettingsStore.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_extensionSettingsStore.js
@@ -118,16 +118,19 @@ add_task(async function test_settings_st
       "getSetting returns correct item with more than one item in the list.");
     let levelOfControl = await ExtensionSettingsStore.getLevelOfControl(extensions[extensionIndex], TEST_TYPE, key);
     equal(
       levelOfControl,
       "controlled_by_other_extensions",
       "getLevelOfControl returns correct levelOfControl when another extension is in control.");
   }
 
+  // Reload the settings store to emulate a browser restart.
+  await ExtensionSettingsStore._reloadFile();
+
   // Add a setting for the newest extension.
   for (let key of KEY_LIST) {
     let extensionIndex = 2;
     let itemToAdd = ITEMS[key][extensionIndex];
     let levelOfControl = await ExtensionSettingsStore.getLevelOfControl(extensions[extensionIndex], TEST_TYPE, key);
     equal(
       levelOfControl,
       "controllable_by_this_extension",