Bug 828201 - Replace DEBUG constant by a preference across OS.File and add a File.GET_DEBUG method used for testing. r=dteller
authorYura Zenevich <yura.zenevich@gmail.com>
Tue, 29 Jan 2013 10:50:04 -0500
changeset 130105 d8d79ba17527141923665d79843b7b9fd1dc87a3
parent 130104 42c786efb5d67768f348462234a235d6b808b1e4
child 130106 009b00bcce30d2bed015aa8af34ecae378fcb34c
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdteller
bugs828201
milestone21.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 828201 - Replace DEBUG constant by a preference across OS.File and add a File.GET_DEBUG method used for testing. r=dteller
modules/libpref/src/init/all.js
toolkit/components/osfile/osfile_async_front.jsm
toolkit/components/osfile/osfile_async_worker.js
toolkit/components/osfile/osfile_shared_allthreads.jsm
toolkit/components/osfile/tests/mochi/main_test_osfile_async.js
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -337,16 +337,19 @@ pref("accessibility.typeaheadfind.prefil
 pref("gfx.use_text_smoothing_setting", false);
 
 // loading and rendering of framesets and iframes
 pref("browser.frames.enabled", true);
 
 // Number of characters to consider emphasizing for rich autocomplete results
 pref("toolkit.autocomplete.richBoundaryCutoff", 200);
 
+// Variable controlling logging for osfile.
+pref("toolkit.osfile.log", false);
+
 pref("toolkit.scrollbox.smoothScroll", true);
 pref("toolkit.scrollbox.scrollIncrement", 20);
 pref("toolkit.scrollbox.verticalScrollDistance", 3);
 pref("toolkit.scrollbox.horizontalScrollDistance", 5);
 pref("toolkit.scrollbox.clickToScroll.scrollDelay", 150);
 
 // Telemetry
 #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
--- a/toolkit/components/osfile/osfile_async_front.jsm
+++ b/toolkit/components/osfile/osfile_async_front.jsm
@@ -22,19 +22,17 @@
 this.EXPORTED_SYMBOLS = ["OS"];
 
 Components.utils.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", this);
 
 let LOG = OS.Shared.LOG.bind(OS.Shared, "Controller");
 let isTypedArray = OS.Shared.isTypedArray;
 
 // A simple flag used to control debugging messages.
-// FIXME: Once this library has been battle-tested, this flag will
-// either be removed or replaced with a preference.
-const DEBUG = false;
+let DEBUG = OS.Shared.DEBUG;
 
 // The constructor for file errors.
 let OSError;
 if (OS.Constants.Win) {
   Components.utils.import("resource://gre/modules/osfile/osfile_win_allthreads.jsm", this);
   Components.utils.import("resource://gre/modules/osfile/ospath_win_back.jsm", this);
   OSError = OS.Shared.Win.Error;
 } else if (OS.Constants.libc) {
@@ -105,16 +103,32 @@ let Scheduler = {
         } else {
           throw error;
         }
       }
     );
   }
 };
 
+// Update worker's DEBUG flag.
+Scheduler.post("SET_DEBUG", [DEBUG]);
+
+// Define a new getter and setter for OS.Shared.DEBUG to be able to watch
+// for changes to it and update worker's DEBUG accordingly.
+Object.defineProperty(OS.Shared, "DEBUG", {
+    configurable: true,
+    get: function () {
+        return DEBUG;
+    },
+    set: function (newVal) {
+        Scheduler.post("SET_DEBUG", [newVal]);
+        DEBUG = newVal;
+    }
+});
+
 /**
  * Representation of a file, with asynchronous methods.
  *
  * @param {*} fdmsg The _message_ representing the platform-specific file
  * handle.
  *
  * @constructor
  */
@@ -531,16 +545,24 @@ if (OS.Constants.Win) {
   throw new Error("I am neither under Windows nor under a Posix system");
 }
 
 File.Info.fromMsg = function fromMsg(value) {
   return new File.Info(value);
 };
 
 /**
+ * Get worker's current DEBUG flag.
+ * Note: This is used for testing purposes.
+ */
+File.GET_DEBUG = function GET_DEBUG() {
+  return Scheduler.post("GET_DEBUG");
+};
+
+/**
  * Iterate asynchronously through a directory
  *
  * @constructor
  */
 let DirectoryIterator = function DirectoryIterator(path, options) {
   /**
    * Open the iterator on the worker thread
    *
--- a/toolkit/components/osfile/osfile_async_worker.js
+++ b/toolkit/components/osfile/osfile_async_worker.js
@@ -7,25 +7,22 @@ if (this.Components) {
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 // Worker thread for osfile asynchronous front-end
 
 (function(exports) {
   "use strict";
 
-  // A simple flag used to control debugging messages.
-  // FIXME: Once this library has been battle-tested, this flag will
-  // either be removed or replaced with a pref.
-  const DEBUG = false;
-
    try {
      importScripts("resource://gre/modules/osfile.jsm");
 
      let LOG = exports.OS.Shared.LOG.bind(exports.OS.Shared.LOG, "Agent");
+     // A simple flag used to control debugging messages.
+     let DEBUG = exports.OS.Shared.DEBUG;
 
      /**
       * Communications with the controller.
       *
       * Accepts messages:
       * {fun:function_name, args:array_of_arguments_or_null, id:id}
       *
       * Sends messages:
@@ -196,16 +193,25 @@ if (this.Components) {
      /**
       * The agent.
       *
       * It is in charge of performing method-specific deserialization
       * of messages, calling the function/method of OS.File and serializing
       * back the results.
       */
      let Agent = {
+       // Update DEBUG flag message from controller.
+       SET_DEBUG: function SET_DEBUG (aDEBUG) {
+         DEBUG = aDEBUG;
+       },
+       // Return current DEBUG value to controller.
+       // Note: This is used for testing purposes.
+       GET_DEBUG: function GET_DEBUG () {
+         return DEBUG;
+       },
        // Functions of OS.File
        stat: function stat(path) {
          return exports.OS.File.Info.toMsg(
            exports.OS.File.stat(Type.path.fromMsg(path)));
        },
        getCurrentDirectory: function getCurrentDirectory() {
          return exports.OS.Shared.Type.path.toMsg(File.getCurrentDirectory());
        },
--- a/toolkit/components/osfile/osfile_shared_allthreads.jsm
+++ b/toolkit/components/osfile/osfile_shared_allthreads.jsm
@@ -21,19 +21,61 @@
      }
      if (exports.OS.Shared.Type) {
        return; // Avoid double-initialization
      }
 
      // Import components after having initialized |exports.OS|, to ensure
      // that everybody uses the same definition of |OS|.
      if (typeof Components != "undefined") {
-       Components.utils.import("resource://gre/modules/ctypes.jsm");
+       const Cu = Components.utils;
+       Cu.import("resource://gre/modules/ctypes.jsm");
        Components.classes["@mozilla.org/net/osfileconstantsservice;1"].
          getService(Components.interfaces.nsIOSFileConstantsService).init();
+
+       if (typeof exports.OS.Shared.DEBUG !== "undefined") {
+         return; // Avoid reading and attaching an observer more than once.
+       }
+
+       Cu.import("resource://gre/modules/Services.jsm");
+
+       const PREF_OSFILE_LOG = "toolkit.osfile.log";
+
+       /**
+        * Safely read a PREF_OSFILE_LOG preference.
+        * Returns a value read or, in case of an error, oldPref or false.
+        *
+        * @param bool oldPref
+        *        An optional value that the DEBUG flag was set to previously.
+        */
+       let readDebugPref = function readDebugPref(oldPref) {
+         let pref;
+         try {
+           pref = Services.prefs.getBoolPref(PREF_OSFILE_LOG);
+         } catch (x) {
+           // In case of an error when reading a pref keep it as is.
+           pref = oldPref;
+         }
+         // If neither pref nor oldPref were set, default it to false.
+         return pref || false;
+       };
+
+       /**
+        * A variable controlling if osfile logs should be printed.
+        */
+       exports.OS.Shared.DEBUG = readDebugPref(exports.OS.Shared.DEBUG);
+
+       /**
+        * Listen to PREF_OSFILE_LOG changes and update the shared DEBUG flag
+        * appropriately.
+        */
+       Services.prefs.addObserver(PREF_OSFILE_LOG,
+         function prefObserver(aSubject, aTopic, aData) {
+           exports.OS.Shared.DEBUG = readDebugPref(exports.OS.Shared.DEBUG);
+         }, false);
      }
 
      // Define a lazy getter for a property
      let defineLazyGetter = function defineLazyGetter(object, name, getter) {
        Object.defineProperty(object, name, {
          configurable: true,
          get: function lazy() {
            delete this[name];
@@ -42,20 +84,16 @@
              value: value
            });
            return value;
          }
        });
      };
      exports.OS.Shared.defineLazyGetter = defineLazyGetter;
 
-     /**
-      * A variable controlling whether we should printout logs.
-      */
-     exports.OS.Shared.DEBUG = false;
      let LOG;
      if (typeof console != "undefined" && console.log) {
        LOG = console.log.bind(console, "OS");
      } else {
        LOG = function() {
          let text = "OS";
          for (let i = 0; i < arguments.length; ++i) {
            text += (" " + arguments[i]);
--- a/toolkit/components/osfile/tests/mochi/main_test_osfile_async.js
+++ b/toolkit/components/osfile/tests/mochi/main_test_osfile_async.js
@@ -126,16 +126,17 @@ let reference_compare_files = function r
 
 let test = maketest("Main", function main(test) {
   return Task.spawn(function() {
     SimpleTest.waitForExplicitFinish();
     yield test_constants();
     yield test_path();
     yield test_open();
     yield test_stat();
+    yield test_debug();
     yield test_info_features_detect();
     yield test_read_write();
     yield test_read_write_all();
     yield test_position();
     yield test_copy();
     yield test_mkdir();
     yield test_iter();
     yield test_exists();
@@ -618,8 +619,32 @@ let test_iter = maketest("iter", functio
 let test_exists = maketest("exists", function exists(test) {
   return Task.spawn(function() {
     let fileExists = yield OS.File.exists(EXISTING_FILE);
     test.ok(fileExists, "file exists");
     fileExists = yield OS.File.exists(EXISTING_FILE + ".tmp");
     test.ok(!fileExists, "file does not exists");
   });
 });
+
+/**
+ * Test changes to OS.Shared.DEBUG flag.
+ */
+let test_debug = maketest("debug", function debug(test) {
+  return Task.spawn(function() {
+    function testSetDebugPref (pref) {
+      try {
+        Services.prefs.setBoolPref("toolkit.osfile.log", pref);
+      } catch (x) {
+        test.fail("Setting OS.Shared.DEBUG to " + pref +
+          " should not cause error.");
+      } finally {
+        test.is(OS.Shared.DEBUG, pref, "OS.Shared.DEBUG is set correctly.");
+      }
+    }
+    testSetDebugPref(true);
+    let workerDEBUG = yield OS.File.GET_DEBUG();
+    test.is(workerDEBUG, true, "Worker's DEBUG is set.");
+    testSetDebugPref(false);
+    workerDEBUG = yield OS.File.GET_DEBUG();
+    test.is(workerDEBUG, false, "Worker's DEBUG is unset.");
+  });
+});
\ No newline at end of file