Bug 753515 - Move json{Load,Save} from services-sync into services-common; r=mconnor
authorGregory Szorc <gps@mozilla.com>
Thu, 10 May 2012 12:21:21 -0700
changeset 98485 2ced009d1831af4978a1471cbee75a3b8e1269c3
parent 98223 02e465c5b1b86c5afc49ac678799ec8c580b2356
child 98486 9081fd136c430ccea66aaa76eccb97670ca6882e
push id173
push userlsblakk@mozilla.com
push dateFri, 24 Aug 2012 15:39:16 +0000
treeherdermozilla-release@bcc45eb1fb41 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconnor
bugs753515
milestone15.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 753515 - Move json{Load,Save} from services-sync into services-common; r=mconnor
services/common/tests/unit/head_helpers.js
services/common/tests/unit/test_utils_json.js
services/common/tests/unit/xpcshell.ini
services/common/utils.js
services/sync/modules/util.js
services/sync/tests/unit/head_helpers.js
services/sync/tests/unit/test_utils_json.js
services/sync/tests/unit/xpcshell.ini
--- a/services/common/tests/unit/head_helpers.js
+++ b/services/common/tests/unit/head_helpers.js
@@ -122,16 +122,29 @@ function readBytesFromInputStream(inputS
       "nsIBinaryInputStream",
       "setInputStream");
   if (!count) {
     count = inputStream.available();
   }
   return new BinaryInputStream(inputStream).readBytes(count);
 }
 
+/*
+ * Ensure exceptions from inside callbacks leads to test failures.
+ */
+function ensureThrows(func) {
+  return function() {
+    try {
+      func.apply(this, arguments);
+    } catch (ex) {
+      do_throw(ex);
+    }
+  };
+}
+
 /**
  * Proxy auth helpers.
  */
 
 /**
  * Fake a PAC to prompt a channel replacement.
  */
 let PACSystemSettings = {
rename from services/sync/tests/unit/test_utils_json.js
rename to services/common/tests/unit/test_utils_json.js
--- a/services/sync/tests/unit/test_utils_json.js
+++ b/services/common/tests/unit/test_utils_json.js
@@ -1,94 +1,104 @@
-_("Make sure json saves and loads from disk");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://services-sync/constants.js");
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
 Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://services-common/utils.js");
 
 function run_test() {
+  initTestLogging();
   run_next_test();
 }
 
 add_test(function test_roundtrip() {
   _("Do a simple write of an array to json and read");
-  Utils.jsonSave("foo", {}, ["v1", "v2"], ensureThrows(function() {
-    Utils.jsonLoad("foo", {}, ensureThrows(function(val) {
+  CommonUtils.jsonSave("foo", {}, ["v1", "v2"], ensureThrows(function() {
+    CommonUtils.jsonLoad("foo", {}, ensureThrows(function(val) {
       let foo = val;
       do_check_eq(typeof foo, "object");
       do_check_eq(foo.length, 2);
       do_check_eq(foo[0], "v1");
       do_check_eq(foo[1], "v2");
       run_next_test();
     }));
   }));
 });
 
 add_test(function test_string() {
   _("Try saving simple strings");
-  Utils.jsonSave("str", {}, "hi", ensureThrows(function() {
-    Utils.jsonLoad("str", {}, ensureThrows(function(val) {
+  CommonUtils.jsonSave("str", {}, "hi", ensureThrows(function() {
+    CommonUtils.jsonLoad("str", {}, ensureThrows(function(val) {
       let str = val;
       do_check_eq(typeof str, "string");
       do_check_eq(str.length, 2);
       do_check_eq(str[0], "h");
       do_check_eq(str[1], "i");
       run_next_test();
     }));
   }));
 });
 
 add_test(function test_number() {
   _("Try saving a number");
-  Utils.jsonSave("num", {}, 42, ensureThrows(function() {
-    Utils.jsonLoad("num", {}, ensureThrows(function(val) {
+  CommonUtils.jsonSave("num", {}, 42, ensureThrows(function() {
+    CommonUtils.jsonLoad("num", {}, ensureThrows(function(val) {
       let num = val;
       do_check_eq(typeof num, "number");
       do_check_eq(num, 42);
       run_next_test();
     }));
   }));
 });
 
 add_test(function test_nonexistent_file() {
   _("Try loading a non-existent file.");
-  Utils.jsonLoad("non-existent", {}, ensureThrows(function(val) {
+  CommonUtils.jsonLoad("non-existent", {}, ensureThrows(function(val) {
     do_check_eq(val, undefined);
     run_next_test();
-  }));    
+  }));
 });
 
 add_test(function test_save_logging() {
   _("Verify that writes are logged.");
   let trace;
-  Utils.jsonSave("log", {_log: {trace: function(msg) { trace = msg; }}},
-                 "hi", ensureThrows(function () {
+  CommonUtils.jsonSave("log", {_log: {trace: function(msg) { trace = msg; }}},
+                       "hi", ensureThrows(function () {
     do_check_true(!!trace);
     run_next_test();
   }));
 });
 
 add_test(function test_load_logging() {
   _("Verify that reads and read errors are logged.");
 
   // Write a file with some invalid JSON
-  let filePath = "weave/log.json";
+  let filePath = "log.json";
   let file = FileUtils.getFile("ProfD", filePath.split("/"), true);
   let fos = Cc["@mozilla.org/network/file-output-stream;1"]
               .createInstance(Ci.nsIFileOutputStream);
   let flags = FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE
               | FileUtils.MODE_TRUNCATE;
   fos.init(file, flags, FileUtils.PERMS_FILE, fos.DEFER_OPEN);
   let stream = Cc["@mozilla.org/intl/converter-output-stream;1"]
                  .createInstance(Ci.nsIConverterOutputStream);
   stream.init(fos, "UTF-8", 4096, 0x0000);
   stream.writeString("invalid json!");
   stream.close();
 
   let trace, debug;
-  Utils.jsonLoad("log",
-                 {_log: {trace: function(msg) { trace = msg; },
-                         debug: function(msg) { debug = msg; }}},
-                 ensureThrows(function(val) {
+  let obj = {
+    _log: {
+      trace: function(msg) {
+        trace = msg;
+      },
+      debug: function(msg) {
+        debug = msg;
+      }
+    }
+  };
+  CommonUtils.jsonLoad("log", obj, ensureThrows(function(val) {
+    do_check_true(!val);
     do_check_true(!!trace);
     do_check_true(!!debug);
     run_next_test();
   }));
 });
--- a/services/common/tests/unit/xpcshell.ini
+++ b/services/common/tests/unit/xpcshell.ini
@@ -2,16 +2,17 @@
 head = head_global.js head_helpers.js
 tail =
 
 # Test load modules first so syntax failures are caught early.
 [test_load_modules.js]
 
 [test_utils_atob.js]
 [test_utils_encodeBase32.js]
+[test_utils_json.js]
 [test_utils_makeURI.js]
 [test_utils_namedTimer.js]
 [test_utils_stackTrace.js]
 [test_utils_utf8.js]
 
 [test_async_chain.js]
 [test_async_querySpinningly.js]
 [test_log4moz.js]
--- a/services/common/utils.js
+++ b/services/common/utils.js
@@ -1,16 +1,18 @@
 /* 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/. */
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 const EXPORTED_SYMBOLS = ["CommonUtils"];
 
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://services-common/log4moz.js");
 
 let CommonUtils = {
   exceptionStr: function exceptionStr(e) {
     let message = e.message ? e.message : e;
     return message + " " + CommonUtils.stackTrace(e);
@@ -295,16 +297,97 @@ let CommonUtils = {
    *
    * See bug 562431 comment 4.
    */
   safeAtoB: function safeAtoB(b64) {
     let len = b64.length;
     let over = len % 4;
     return over ? atob(b64.substr(0, len - over)) : atob(b64);
   },
+
+  /**
+   * Load a JSON file from disk in the profile directory.
+   *
+   * @param filePath
+   *        JSON file path load from profile. Loaded file will be
+   *        <profile>/<filePath>.json. i.e. Do not specify the ".json"
+   *        extension.
+   * @param that
+   *        Object to use for logging and "this" for callback.
+   * @param callback
+   *        Function to process json object as its first argument. If the file
+   *        could not be loaded, the first argument will be undefined.
+   */
+  jsonLoad: function jsonLoad(filePath, that, callback) {
+    let path = filePath + ".json";
+
+    if (that._log) {
+      that._log.trace("Loading json from disk: " + filePath);
+    }
+
+    let file = FileUtils.getFile("ProfD", path.split("/"), true);
+    if (!file.exists()) {
+      callback.call(that);
+      return;
+    }
+
+    let channel = NetUtil.newChannel(file);
+    channel.contentType = "application/json";
+
+    NetUtil.asyncFetch(channel, function (is, result) {
+      if (!Components.isSuccessCode(result)) {
+        callback.call(that);
+        return;
+      }
+      let string = NetUtil.readInputStreamToString(is, is.available());
+      is.close();
+      let json;
+      try {
+        json = JSON.parse(string);
+      } catch (ex) {
+        if (that._log) {
+          that._log.debug("Failed to load json: " +
+                          CommonUtils.exceptionStr(ex));
+        }
+      }
+      callback.call(that, json);
+    });
+  },
+
+  /**
+   * Save a json-able object to disk in the profile directory.
+   *
+   * @param filePath
+   *        JSON file path save to <filePath>.json
+   * @param that
+   *        Object to use for logging and "this" for callback
+   * @param obj
+   *        Function to provide json-able object to save. If this isn't a
+   *        function, it'll be used as the object to make a json string.
+   * @param callback
+   *        Function called when the write has been performed. Optional.
+   */
+  jsonSave: function jsonSave(filePath, that, obj, callback) {
+    let path = filePath + ".json";
+    if (that._log) {
+      that._log.trace("Saving json to disk: " + path);
+    }
+
+    let file = FileUtils.getFile("ProfD", path.split("/"), true);
+    let json = typeof obj == "function" ? obj.call(that) : obj;
+    let out = JSON.stringify(json);
+
+    let fos = FileUtils.openSafeFileOutputStream(file);
+    let is = this._utf8Converter.convertToInputStream(out);
+    NetUtil.asyncCopy(is, fos, function (result) {
+      if (typeof callback == "function") {
+        callback.call(that);
+      }
+    });
+  },
 };
 
 XPCOMUtils.defineLazyGetter(CommonUtils, "_utf8Converter", function() {
   let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
                     .createInstance(Ci.nsIScriptableUnicodeConverter);
   converter.charset = "UTF-8";
   return converter;
 });
--- a/services/sync/modules/util.js
+++ b/services/sync/modules/util.js
@@ -352,87 +352,22 @@ let Utils = {
    * Take a base64-encoded 128-bit AES key, returning it as five groups of five
    * uppercase alphanumeric characters, separated by hyphens.
    * A.K.A. base64-to-base32 encoding.
    */
   presentEncodedKeyAsSyncKey : function presentEncodedKeyAsSyncKey(encodedKey) {
     return Utils.encodeKeyBase32(atob(encodedKey));
   },
 
-  /**
-   * Load a json object from disk
-   *
-   * @param filePath
-   *        Json file path load from weave/[filePath].json
-   * @param that
-   *        Object to use for logging and "this" for callback
-   * @param callback
-   *        Function to process json object as its first parameter
-   */
-  jsonLoad: function Utils_jsonLoad(filePath, that, callback) {
-    filePath = "weave/" + filePath + ".json";
-    if (that._log)
-      that._log.trace("Loading json from disk: " + filePath);
-
-    let file = FileUtils.getFile("ProfD", filePath.split("/"), true);
-    if (!file.exists()) {
-      callback.call(that);
-      return;
-    }
-
-    let channel = NetUtil.newChannel(file);
-    channel.contentType = "application/json";
-
-    NetUtil.asyncFetch(channel, function (is, result) {
-      if (!Components.isSuccessCode(result)) {
-        callback.call(that);
-        return;
-      }
-      let string = NetUtil.readInputStreamToString(is, is.available());
-      is.close();
-      let json;
-      try {
-        json = JSON.parse(string);
-      } catch (ex) {
-        if (that._log)
-          that._log.debug("Failed to load json: " + Utils.exceptionStr(ex));
-      }
-      callback.call(that, json);
-    });
+  jsonLoad: function jsonLoad(path, that, callback) {
+    CommonUtils.jsonLoad("weave/" + path, that, callback);
   },
 
-  /**
-   * Save a json-able object to disk
-   *
-   * @param filePath
-   *        Json file path save to weave/[filePath].json
-   * @param that
-   *        Object to use for logging and "this" for callback
-   * @param obj
-   *        Function to provide json-able object to save. If this isn't a
-   *        function, it'll be used as the object to make a json string.
-   * @param callback
-   *        Function called when the write has been performed. Optional.
-   */
-  jsonSave: function Utils_jsonSave(filePath, that, obj, callback) {
-    filePath = "weave/" + filePath + ".json";
-    if (that._log)
-      that._log.trace("Saving json to disk: " + filePath);
-
-    let file = FileUtils.getFile("ProfD", filePath.split("/"), true);
-    let json = typeof obj == "function" ? obj.call(that) : obj;
-    let out = JSON.stringify(json);
-
-    let fos = FileUtils.openSafeFileOutputStream(file);
-    let is = this._utf8Converter.convertToInputStream(out);
-    NetUtil.asyncCopy(is, fos, function (result) {
-      if (typeof callback == "function") {
-        callback.call(that);        
-      }
-    });
+  jsonSave: function jsonSave(path, that, obj, callback) {
+    CommonUtils.jsonSave("weave/" + path, that, obj, callback);
   },
 
   getIcon: function(iconUri, defaultIcon) {
     try {
       let iconURI = Utils.makeURI(iconUri);
       return PlacesUtils.favicons.getFaviconLinkForIcon(iconURI).spec;
     }
     catch(ex) {}
--- a/services/sync/tests/unit/head_helpers.js
+++ b/services/sync/tests/unit/head_helpers.js
@@ -246,30 +246,16 @@ function SyncTestingInfrastructure(usern
   Service.clusterURL = TEST_CLUSTER_URL;
 
   this.logStats = initTestLogging();
   this.fakeFilesystem = new FakeFilesystemService({});
   this.fakeGUIDService = new FakeGUIDService();
   this.fakeCryptoService = new FakeCryptoService();
 }
 
-/*
- * Ensure exceptions from inside callbacks leads to test failures.
- */
-function ensureThrows(func) {
-  return function() {
-    try {
-      func.apply(this, arguments);
-    } catch (ex) {
-      do_throw(ex);
-    }
-  };
-}
-
-
 _("Setting the identity for passphrase");
 Cu.import("resource://services-sync/identity.js");
 
 /*
  * Test setup helpers.
  */
 
 // Turn WBO cleartext into fake "encrypted" payload as it goes over the wire.
--- a/services/sync/tests/unit/xpcshell.ini
+++ b/services/sync/tests/unit/xpcshell.ini
@@ -13,17 +13,16 @@ tail =
 [test_utils_catch.js]
 [test_utils_deepCopy.js]
 [test_utils_deepEquals.js]
 [test_utils_deferGetSet.js]
 [test_utils_deriveKey.js]
 [test_utils_keyEncoding.js]
 [test_utils_getErrorString.js]
 [test_utils_getIcon.js]
-[test_utils_json.js]
 [test_utils_lazyStrings.js]
 [test_utils_lock.js]
 [test_utils_makeGUID.js]
 [test_utils_notify.js]
 [test_utils_passphrase.js]
 
 # We have a number of other libraries that are pretty much standalone.
 [test_httpd_sync_server.js]