Bug 843638: Uplift Add-on SDK stabilization branch. a=bajaj
authorDave Townsend <dtownsend@oxymoronical.com>
Mon, 25 Feb 2013 16:28:29 -0800
changeset 128452 66736a53ee171fd5db219a17dabb664885ca589a
parent 128451 f1a067a808194f474ff413b5e092f0a6dcf4d2af
child 128453 4fe41db7c3dd9840b7768eac31e39bc360c9894c
push id3415
push userdtownsend@mozilla.com
push dateTue, 26 Feb 2013 00:29:07 +0000
treeherdermozilla-aurora@66736a53ee17 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbajaj
bugs843638
milestone21.0a2
Bug 843638: Uplift Add-on SDK stabilization branch. a=bajaj https://github.com/mozilla/addon-sdk/compare/4e44dd094e8636216e8c9ca5664866a5cf7d0cdd...b563e7dd1c882eccfacdec1171758e03f6e044f5
addon-sdk/source/app-extension/bootstrap.js
addon-sdk/source/app-extension/install.rdf
addon-sdk/source/lib/sdk/addon/runner.js
addon-sdk/source/lib/sdk/context-menu.js
addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
addon-sdk/source/lib/sdk/indexed-db.js
addon-sdk/source/lib/sdk/l10n/html.js
addon-sdk/source/lib/sdk/loader/cuddlefish.js
addon-sdk/source/lib/sdk/selection.js
addon-sdk/source/lib/sdk/test.js
addon-sdk/source/lib/sdk/test/harness.js
addon-sdk/source/lib/sdk/test/runner.js
addon-sdk/source/lib/test.js
addon-sdk/source/lib/toolkit/loader.js
addon-sdk/source/python-lib/cuddlefish/__init__.py
addon-sdk/source/python-lib/cuddlefish/manifest.py
addon-sdk/source/python-lib/cuddlefish/rdf.py
addon-sdk/source/python-lib/cuddlefish/runner.py
addon-sdk/source/python-lib/cuddlefish/tests/test_linker.py
addon-sdk/source/python-lib/cuddlefish/tests/test_xpi.py
addon-sdk/source/python-lib/cuddlefish/xpi.py
addon-sdk/source/test/addons/layout-change/main.js
addon-sdk/source/test/addons/layout-change/package.json
addon-sdk/source/test/addons/packed/main.js
addon-sdk/source/test/addons/packed/package.json
addon-sdk/source/test/addons/unpacked/main.js
addon-sdk/source/test/addons/unpacked/package.json
addon-sdk/source/test/commonjs-test-adapter/asserts.js
addon-sdk/source/test/modules/tiger.js
addon-sdk/source/test/private-browsing/helper.js
addon-sdk/source/test/private-browsing/windows.js
addon-sdk/source/test/tabs/test-firefox-tabs.js
addon-sdk/source/test/test-addon-page.js
addon-sdk/source/test/test-context-menu.js
addon-sdk/source/test/test-indexed-db.js
addon-sdk/source/test/test-layout-change.js
addon-sdk/source/test/test-loader.js
addon-sdk/source/test/test-net-url.js
addon-sdk/source/test/test-page-mod.js
addon-sdk/source/test/test-panel.js
addon-sdk/source/test/test-selection.js
addon-sdk/source/test/test-simple-prefs.js
addon-sdk/source/test/test-tab.js
addon-sdk/source/test/test-url.js
addon-sdk/source/test/test-widget.js
addon-sdk/source/test/windows/test-firefox-windows.js
--- a/addon-sdk/source/app-extension/bootstrap.js
+++ b/addon-sdk/source/app-extension/bootstrap.js
@@ -14,16 +14,23 @@ const { classes: Cc, Constructor: CC, in
         results: Cr, manager: Cm } = Components;
 const ioService = Cc['@mozilla.org/network/io-service;1'].
                   getService(Ci.nsIIOService);
 const resourceHandler = ioService.getProtocolHandler('resource').
                         QueryInterface(Ci.nsIResProtocolHandler);
 const systemPrincipal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')();
 const scriptLoader = Cc['@mozilla.org/moz/jssubscript-loader;1'].
                      getService(Ci.mozIJSSubScriptLoader);
+const prefService = Cc['@mozilla.org/preferences-service;1'].
+                    getService(Ci.nsIPrefService);
+const appInfo = Cc["@mozilla.org/xre/app-info;1"].
+                getService(Ci.nsIXULAppInfo);
+const vc = Cc["@mozilla.org/xpcom/version-comparator;1"].
+           getService(Ci.nsIVersionComparator);
+
 
 const REASON = [ 'unknown', 'startup', 'shutdown', 'enable', 'disable',
                  'install', 'uninstall', 'upgrade', 'downgrade' ];
 
 const bind = Function.call.bind(Function.bind);
 
 let loader = null;
 let unload = null;
@@ -50,39 +57,16 @@ function readURI(uri) {
     data += str.value;
   } while (read != 0);
 
   cstream.close();
 
   return data;
 }
 
-// Utility function that converts cfx-py generated paths to a
-// module ids.
-function path2id(path) {
-  // Strips out `/lib` and `.js` from package/lib/path.js
-  return path.replace(/([^\/]*)\/lib/, '$1').replace(/.js$/, '');
-}
-// Utility function that takes old manifest format and creates a manifest
-// in a new format: https://github.com/mozilla/addon-sdk/wiki/JEP-Linker
-function manifestV2(manifest) {
-  return Object.keys(manifest).reduce(function(result, path) {
-    let entry = manifest[path];
-    let id = path2id(path);
-    let requirements = entry.requirements || {};
-    result[id] = {
-      requirements: Object.keys(requirements).reduce(function(result, path) {
-        result[path] = path2id(requirements[path].path);
-        return result;
-      }, {})
-    };
-    return result
-  }, {});
-}
-
 // We don't do anything on install & uninstall yet, but in a future
 // we should allow add-ons to cleanup after uninstall.
 function install(data, reason) {}
 function uninstall(data, reason) {}
 
 function startup(data, reasonCode) {
   try {
     let reason = REASON[reasonCode];
@@ -110,38 +94,89 @@ function startup(data, reasonCode) {
       replace(/\./g, '-dot-').
       replace(uuidRe, '$1');
 
     let prefixURI = 'resource://' + domain + '/';
     let resourcesURI = ioService.newURI(rootURI + '/resources/', null, null);
     resourceHandler.setSubstitution(domain, resourcesURI);
 
     // Create path to URLs mapping supported by loader.
-    let paths = Object.keys(options.metadata).reduce(function(result, name) {
-      result[name + '/'] = prefixURI + name + '/lib/'
-      result[name + '/tests/'] = prefixURI + name + '/tests/'
-      return result
-    }, {
+    let paths = {
       // Relative modules resolve to add-on package lib
       './': prefixURI + name + '/lib/',
-      'toolkit/': 'resource://gre/modules/toolkit/',
-      '': 'resources:///modules/'
-    });
+      './tests/': prefixURI + name + '/tests/',
+      '': 'resource://gre/modules/commonjs/'
+    };
+
+    // Maps addon lib and tests ressource folders for each package
+    paths = Object.keys(options.metadata).reduce(function(result, name) {
+      result[name + '/'] = prefixURI + name + '/lib/'
+      result[name + '/tests/'] = prefixURI + name + '/tests/'
+      return result;
+    }, paths);
+
+    // We need to map tests folder when we run sdk tests whose package name
+    // is stripped
+    if (name == 'addon-sdk')
+      paths['tests/'] = prefixURI + name + '/tests/';
+
+    // Starting with Firefox 21.0a1, we start using modules shipped into firefox
+    // Still allow using modules from the xpi if the manifest tell us to do so.
+    // And only try to look for sdk modules in xpi if the xpi actually ship them
+    if (options['is-sdk-bundled'] &&
+        (vc.compare(appInfo.version, '21.0a1') < 0 ||
+         options['force-use-bundled-sdk'])) {
+      // Maps sdk module folders to their resource folder
+      paths[''] = prefixURI + 'addon-sdk/lib/';
+      // test.js is usually found in root commonjs or SDK_ROOT/lib/ folder,
+      // so that it isn't shipped in the xpi. Keep a copy of it in sdk/ folder
+      // until we no longer support SDK modules in XPI:
+      paths['test'] = prefixURI + 'addon-sdk/lib/sdk/test.js';
+    }
+
+    // Retrieve list of module folder overloads based on preferences in order to
+    // eventually used a local modules instead of files shipped into Firefox.
+    let branch = prefService.getBranch('extensions.modules.' + id + '.path');
+    paths = branch.getChildList('', {}).reduce(function (result, name) {
+      // Allows overloading of any sub folder by replacing . by / in pref name
+      let path = name.substr(1).split('.').join('/');
+      // Only accept overloading folder by ensuring always ending with `/`
+      if (path) path += '/';
+      let fileURI = branch.getCharPref(name);
+
+      // Maps the given file:// URI to a resource:// in order to avoid various
+      // failure that happens with file:// URI and be close to production env
+      let resourcesURI = ioService.newURI(fileURI, null, null);
+      let resName = 'extensions.modules.' + domain + '.commonjs.path' + name;
+      resourceHandler.setSubstitution(resName, resourcesURI);
+
+      result[path] = 'resource://' + resName + '/';
+      return result;
+    }, paths);
 
     // Make version 2 of the manifest
-    let manifest = manifestV2(options.manifest);
+    let manifest = options.manifest;
 
     // Import `cuddlefish.js` module using a Sandbox and bootstrap loader.
-    let cuddlefishURI = prefixURI + options.loader;
+    let cuddlefishPath = 'loader/cuddlefish.js';
+    let cuddlefishURI = 'resource://gre/modules/commonjs/sdk/' + cuddlefishPath;
+    if (paths['sdk/']) { // sdk folder has been overloaded
+                         // (from pref, or cuddlefish is still in the xpi)
+      cuddlefishURI = paths['sdk/'] + cuddlefishPath;
+    }
+    else if (paths['']) { // root modules folder has been overloaded
+      cuddlefishURI = paths[''] + 'sdk/' + cuddlefishPath;
+    }
+
     cuddlefishSandbox = loadSandbox(cuddlefishURI);
     let cuddlefish = cuddlefishSandbox.exports;
 
     // Normalize `options.mainPath` so that it looks like one that will come
     // in a new version of linker.
-    let main = path2id(options.mainPath);
+    let main = options.mainPath;
 
     unload = cuddlefish.unload;
     loader = cuddlefish.Loader({
       paths: paths,
       // modules manifest.
       manifest: manifest,
 
       // Add-on ID used by different APIs as a unique identifier.
@@ -175,17 +210,17 @@ function startup(data, reasonCode) {
           profileMemory: options.profileMemory,
           stopOnError: options.stopOnError,
           verbose: options.verbose,
           parseable: options.parseable,
         }
       }
     });
 
-    let module = cuddlefish.Module('addon-sdk/sdk/loader/cuddlefish', cuddlefishURI);
+    let module = cuddlefish.Module('sdk/loader/cuddlefish', cuddlefishURI);
     let require = cuddlefish.Require(loader, module);
 
     require('sdk/addon/runner').startup(reason, {
       loader: loader,
       main: main,
       prefsURI: rootURI + 'defaults/preferences/prefs.js'
     });
   } catch (error) {
@@ -231,22 +266,26 @@ function setTimeout(callback, delay) {
   return timer;
 }
 
 function shutdown(data, reasonCode) {
   let reason = REASON[reasonCode];
   if (loader) {
     unload(loader, reason);
     unload = null;
-    // Avoid leaking all modules when something goes wrong with one particular
-    // module. Do not clean it up immediatly in order to allow executing some
-    // actions on addon disabling.
-    // We need to keep a reference to the timer, otherwise it is collected
-    // and won't ever fire.
-    nukeTimer = setTimeout(nukeModules, 1000);
+
+    // Don't waste time cleaning up if the application is shutting down
+    if (reason != "shutdown") {
+      // Avoid leaking all modules when something goes wrong with one particular
+      // module. Do not clean it up immediatly in order to allow executing some
+      // actions on addon disabling.
+      // We need to keep a reference to the timer, otherwise it is collected
+      // and won't ever fire.
+      nukeTimer = setTimeout(nukeModules, 1000);
+    }
   }
 };
 
 function nukeModules() {
   nukeTimer = null;
   // module objects store `exports` which comes from sandboxes
   // We should avoid keeping link to these object to avoid leaking sandboxes
   for (let key in loader.modules) {
--- a/addon-sdk/source/app-extension/install.rdf
+++ b/addon-sdk/source/app-extension/install.rdf
@@ -12,17 +12,17 @@
     <em:type>2</em:type>
     <em:bootstrap>true</em:bootstrap>
     <em:unpack>false</em:unpack>
 
     <!-- Firefox -->
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
-        <em:minVersion>18.0</em:minVersion>
+        <em:minVersion>19.0</em:minVersion>
         <em:maxVersion>20.*</em:maxVersion>
       </Description>
     </em:targetApplication>
 
     <!-- Front End MetaData -->
     <em:name>Test App</em:name>
     <em:description>Harness for tests.</em:description>
     <em:creator>Mozilla Corporation</em:creator>
--- a/addon-sdk/source/lib/sdk/addon/runner.js
+++ b/addon-sdk/source/lib/sdk/addon/runner.js
@@ -81,18 +81,17 @@ function startup(reason, options) {
   require('../l10n/loader').
     load(rootURI).
     then(null, function failure(error) {
       console.info("Error while loading localization: " + error.message);
     }).
     then(function onLocalizationReady(data) {
       // Exports data to a pseudo module so that api-utils/l10n/core
       // can get access to it
-      if (data)
-        definePseudo(options.loader, '@l10n/data', data);
+      definePseudo(options.loader, '@l10n/data', data ? data : null);
       run(options);
     });
 }
 
 function run(options) {
   try {
     // Try initializing HTML localization before running main module. Just print
     // an exception in case of error, instead of preventing addon to be run.
--- a/addon-sdk/source/lib/sdk/context-menu.js
+++ b/addon-sdk/source/lib/sdk/context-menu.js
@@ -199,16 +199,19 @@ let URLContext = Class({
   }
 });
 exports.URLContext = URLContext;
 
 function removeItemFromArray(array, item) {
   return array.filter(function(i) i !== item);
 }
 
+// Converts anything that isn't false, null or undefined into a string
+function stringOrNull(val) val ? String(val) : val;
+
 // Shared option validation rules for Item and Menu
 let baseItemRules = {
   parentMenu: {
     is: ["object", "undefined"],
     ok: function (v) {
       if (!v)
         return true;
       return (v instanceof ItemContainer) || (v instanceof Menu);
@@ -249,32 +252,32 @@ let baseItemRules = {
   },
   onMessage: {
     is: ["function", "undefined"]
   }
 };
 
 let labelledItemRules =  mix(baseItemRules, {
   label: {
-    map: String,
+    map: stringOrNull,
     is: ["string"],
     ok: function (v) !!v,
     msg: "The item must have a non-empty string label."
   },
   image: {
-    map: String,
+    map: stringOrNull,
     is: ["string", "undefined", "null"]
   }
 });
 
 // Additional validation rules for Item
 let itemRules = mix(labelledItemRules, {
   data: {
-    map: String,
-    is: ["string", "undefined"]
+    map: stringOrNull,
+    is: ["string", "undefined", "null"]
   }
 });
 
 // Additional validation rules for Menu
 let menuRules = mix(labelledItemRules, {
   items: {
     is: ["array", "undefined"],
     ok: function (v) {
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
@@ -6,17 +6,18 @@
 
 module.metadata = {
   "stability": "deprecated"
 };
 
 const file = require("../io/file");
 const memory = require('./memory');
 const suites = require('@test/options').allTestModules;
-
+const { Loader } = require("sdk/test/loader");
+const cuddlefish = require("sdk/loader/cuddlefish");
 
 const NOT_TESTS = ['setup', 'teardown'];
 
 var TestFinder = exports.TestFinder = function TestFinder(options) {
   memory.track(this);
   this.filter = options.filter;
   this.testInProcess = options.testInProcess === false ? false : true;
   this.testOutOfProcess = options.testOutOfProcess === true ? true : false;
@@ -47,17 +48,21 @@ TestFinder.prototype = {
                ((testname && filterNameRegex) ? filterNameRegex.test(testname)
                                               : true);
       };
     } else
       filter = function() {return true};
 
     suites.forEach(
       function(suite) {
-        var module = require(suite);
+        // Load each test file as a main module in its own loader instance
+        // `suite` is defined by cuddlefish/manifest.py:ManifestBuilder.build
+        var loader = Loader(module);
+        var module = cuddlefish.main(loader, suite);
+
         if (self.testInProcess)
           for each (let name in Object.keys(module).sort()) {
             if(NOT_TESTS.indexOf(name) === -1 && filter(suite, name)) {
               tests.push({
                            setup: module.setup,
                            teardown: module.teardown,
                            testFunction: module[name],
                            name: suite + "." + name
--- a/addon-sdk/source/lib/sdk/indexed-db.js
+++ b/addon-sdk/source/lib/sdk/indexed-db.js
@@ -5,17 +5,17 @@
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
 };
 
 const { Cc, Ci } = require("chrome");
 const { extend } = require("./core/heritage");
-const { id } = require("self");
+const { id } = require("./self");
 
 // placeholder, copied from bootstrap.js
 let sanitizeId = function(id){
   let uuidRe =
     /^\{([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\}$/;
 
   let domain = id.
     toLowerCase().
--- a/addon-sdk/source/lib/sdk/l10n/html.js
+++ b/addon-sdk/source/lib/sdk/l10n/html.js
@@ -87,9 +87,9 @@ exports.enable = enable;
 function disable() {
   if (enabled) {
     events.off(ON_CONTENT, onContentWindow);
     enabled = false;
   }
 }
 exports.disable = disable;
 
-require("api-utils/unload").when(disable);
+require("sdk/system/unload").when(disable);
--- a/addon-sdk/source/lib/sdk/loader/cuddlefish.js
+++ b/addon-sdk/source/lib/sdk/loader/cuddlefish.js
@@ -83,40 +83,39 @@ function incompatibility(module) {
 function CuddlefishLoader(options) {
   let { manifest } = options;
 
   options = override(options, {
     // Put `api-utils/loader` and `api-utils/cuddlefish` loaded as JSM to module
     // cache to avoid subsequent loads via `require`.
     modules: override({
       'toolkit/loader': loaderModule,
-      'addon-sdk/sdk/loader/cuddlefish': exports,
-      'addon-sdk/sdk/system/xul-app': xulappModule
+      'sdk/loader/cuddlefish': exports,
+      'sdk/system/xul-app': xulappModule
     }, options.modules),
     resolve: function resolve(id, requirer) {
       let entry = requirer && requirer in manifest && manifest[requirer];
       let uri = null;
 
       // If manifest entry for this requirement is present we follow manifest.
       // Note: Standard library modules like 'panel' will be present in
       // manifest unless they were moved to platform.
       if (entry) {
         let requirement = entry.requirements[id];
         // If requirer entry is in manifest and it's requirement is not, than
         // it has no authority to load since linker was not able to find it.
         if (!requirement)
-          throw Error('Module: ' + requirer.id + ' located at ' + requirer.uri
-                      + ' has no authority to load: ' + id, requirer.uri);
+          throw Error('Module: ' + requirer + ' has no authority to load: '
+                      + id, requirer);
 
         uri = requirement;
-      }
-      // If requirer is off manifest than it's a system module and we allow it
-      // to go off manifest.
-      else {
-        uri = id;
+      } else {
+        // If requirer is off manifest than it's a system module and we allow it
+        // to go off manifest by resolving a relative path.
+        uri = loaderModule.resolve(id, requirer);
       }
       return uri;
     },
     load: function(loader, module) {
       let result;
       let error;
 
       // In order to get the module's metadata, we need to load the module.
--- a/addon-sdk/source/lib/sdk/selection.js
+++ b/addon-sdk/source/lib/sdk/selection.js
@@ -15,17 +15,17 @@ const { Ci, Cc } = require("chrome"),
     { setTimeout } = require("./timers"),
     { emit, off } = require("./event/core"),
     { Class, obscure } = require("./core/heritage"),
     { EventTarget } = require("./event/target"),
     { ns } = require("./core/namespace"),
     { when: unload } = require("./system/unload"),
     { getTabs, getTabContentWindow, getTabForContentWindow,
       getAllTabContentWindows } = require('./tabs/utils'),
-    { getInnerId, getMostRecentBrowserWindow,
+    { getMostRecentBrowserWindow,
       windows, getFocusedWindow, getFocusedElement } = require("./window/utils"),
     events = require("./system/events");
 
 // The selection types
 const HTML = 0x01,
       TEXT = 0x02,
       DOM  = 0x03; // internal use only
 
@@ -316,27 +316,16 @@ function addSelectionListener(window) {
   // a selection is in a text field, therefore we need to add a listener to
   // window.onselect, that is fired only for text fields.
   // For consistency, we add it only when the nsISelectionListener is added.
   //
   // https://developer.mozilla.org/en/DOM/window.onselect
   window.addEventListener("select", selectionListener.onSelect, true);
 
   selections(window).selection = selection;
-
-  let innerId = getInnerId(window);
-
-  events.on("inner-window-destroyed", function destroyed (event) {
-    let destroyedId = event.subject.QueryInterface(Ci.nsISupportsPRUint64).data;
-
-    if (destroyedId === innerId) {
-      removeSelectionListener(window);
-      events.off("inner-window-destroyed", destroyed);
-    }
-  });
 };
 
 /**
  * Removes the Selection Listener to the content's window given
  */
 function removeSelectionListener(window) {
   // Don't remove the selection's listener to a window that wasn't handled.
   if (!("selection" in selections(window)))
@@ -377,17 +366,17 @@ getAllTabContentWindows().forEach(addSel
 // a new selection object is created when it becomes visible again.
 // That makes the previous selection's listeners added previously totally
 // useless – the listeners are not notified anymore.
 // To fix that we're listening for `document-shown` event in order to add
 // the listeners to the new selection object created.
 //
 // See bug 665386 for further details.
 
-events.on("document-shown", function (event) {
+function onShown(event) {
   let window = event.subject.defaultView;
 
   // We are not interested in documents without valid defaultView.
   // For example XML documents don't have windows and we don't yet support them.
   if (!window)
     return;
 
   // We want to handle only the windows where we added selection's listeners
@@ -403,27 +392,31 @@ events.on("document-shown", function (ev
     // because is detached. An attempt to remove the listener, will raise an
     // error (see http://mxr.mozilla.org/mozilla-central/source/layout/generic/nsSelection.cpp#5343 )
     //
     // We ensure that the current selection is an instance of
     // `nsISelectionPrivate` before working on it, in case is `null`.
     if (currentSelection instanceof Ci.nsISelectionPrivate &&
       currentSelection !== selection) {
 
+      window.addEventListener("select", selectionListener.onSelect, true);
       currentSelection.addSelectionListener(selectionListener);
       selections(window).selection = currentSelection;
     }
   }
-});
+}
+
+events.on("document-shown", onShown, true);
 
 // Removes Selection listeners when the add-on is unloaded
 unload(function(){
   getAllTabContentWindows().forEach(removeSelectionListener);
 
   events.off("document-element-inserted", onContent);
+  events.off("document-shown", onShown);
 
   off(exports);
 });
 
 const selection = Class({
   extends: EventTarget,
   implements: [ Selection, selectionIterator ]
 })();
--- a/addon-sdk/source/lib/sdk/test.js
+++ b/addon-sdk/source/lib/sdk/test.js
@@ -4,18 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
 
-const BaseAssert = require("./test/assert").Assert;
-const { isFunction, isObject } = require("./lang/type");
+const BaseAssert = require("sdk/test/assert").Assert;
+const { isFunction, isObject } = require("sdk/lang/type");
 
 function extend(target) {
   let descriptor = {}
   Array.slice(arguments, 1).forEach(function(source) {
     Object.getOwnPropertyNames(source).forEach(function onEach(name) {
       descriptor[name] = Object.getOwnPropertyDescriptor(source, name);
     });
   });
--- a/addon-sdk/source/lib/sdk/test/harness.js
+++ b/addon-sdk/source/lib/sdk/test/harness.js
@@ -15,17 +15,17 @@ const { setTimeout } = require('../timer
 const memory = require('../deprecated/memory');
 const { PlainTextConsole } = require("../console/plain-text");
 const { when: unload } = require("../system/unload");
 const { format, fromException }  = require("../console/traceback");
 const system = require("../system");
 
 // Trick manifest builder to make it think we need these modules ?
 const unit = require("../deprecated/unit-test");
-const test = require("../test");
+const test = require("../../test");
 const url = require("../url");
 
 var cService = Cc['@mozilla.org/consoleservice;1'].getService()
                .QueryInterface(Ci.nsIConsoleService);
 
 // The console used to log messages
 var testConsole;
 
--- a/addon-sdk/source/lib/sdk/test/runner.js
+++ b/addon-sdk/source/lib/sdk/test/runner.js
@@ -100,17 +100,17 @@ exports.runTestsFromModule = function ru
   // Make a copy of exports as it may already be frozen by module loader
   let exports = {};
   Object.keys(module.exports).forEach(function(key) {
     exports[key] = module.exports[key];
   });
 
   runTests(function findAndRunTests(loader, nextIteration) {
     // Consider that all these tests are CommonJS ones
-    loader.require('../test').run(exports);
+    loader.require('../../test').run(exports);
 
     // Reproduce what is done in unit-test-finder.findTests()
     let tests = [];
     for each (let name in Object.keys(exports).sort()) {
       tests.push({
         setup: exports.setup,
         teardown: exports.teardown,
         testFunction: exports[name],
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/lib/test.js
@@ -0,0 +1,112 @@
+/* vim:ts=2:sts=2:sw=2:
+ * 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/. */
+
+"use strict";
+
+module.metadata = {
+  "stability": "unstable"
+};
+
+const BaseAssert = require("sdk/test/assert").Assert;
+const { isFunction, isObject } = require("sdk/lang/type");
+
+function extend(target) {
+  let descriptor = {}
+  Array.slice(arguments, 1).forEach(function(source) {
+    Object.getOwnPropertyNames(source).forEach(function onEach(name) {
+      descriptor[name] = Object.getOwnPropertyDescriptor(source, name);
+    });
+  });
+  return Object.create(target, descriptor);
+}
+
+/**
+ * Function takes test `suite` object in CommonJS format and defines all of the
+ * tests from that suite and nested suites in a jetpack format on a given
+ * `target` object. Optionally third argument `prefix` can be passed to prefix
+ * all the test names.
+ */
+function defineTestSuite(target, suite, prefix) {
+  prefix = prefix || "";
+  // If suite defines `Assert` that's what `assert` object have to be created
+  // from and passed to a test function (This allows custom assertion functions)
+  // See for details: http://wiki.commonjs.org/wiki/Unit_Testing/1.1
+  let Assert = suite.Assert || BaseAssert;
+  // Going through each item in the test suite and wrapping it into a
+  // Jetpack test format.
+  Object.keys(suite).forEach(function(key) {
+     // If name starts with test then it's a test function or suite.
+    if (key.indexOf("test") === 0) {
+      let test = suite[key];
+
+      // For each test function so we create a wrapper test function in a
+      // jetpack format and copy that to a `target` exports.
+      if (isFunction(test)) {
+
+        // Since names of the test may match across suites we use full object
+        // path as a name to avoid overriding same function.
+        target[prefix + key] = function(options) {
+
+          // Creating `assert` functions for this test.
+          let assert = Assert(options);
+
+          // If CommonJS test function expects more than one argument
+          // it means that test is async and second argument is a callback
+          // to notify that test is finished.
+          if (1 < test.length) {
+
+            // Letting test runner know that test is executed async and
+            // creating a callback function that CommonJS tests will call
+            // once it's done.
+            options.waitUntilDone();
+            test(assert, function() {
+              options.done();
+            });
+          }
+
+          // Otherwise CommonJS test is synchronous so we call it only with
+          // one argument.
+          else {
+            test(assert);
+          }
+        }
+      }
+
+      // If it's an object then it's a test suite containing test function
+      // and / or nested test suites. In that case we just extend prefix used
+      // and call this function to copy and wrap tests from nested suite.
+      else if (isObject(test)) {
+        // We need to clone `tests` instead of modifying it, since it's very
+        // likely that it is frozen (usually test suites imported modules).
+        test = extend(Object.prototype, test, {
+          Assert: test.Assert || Assert
+        });
+        defineTestSuite(target, test, prefix + key + ".");
+      }
+    }
+  });
+}
+
+/**
+ * This function is a CommonJS test runner function, but since Jetpack test
+ * runner and test format is different from CommonJS this function shims given
+ * `exports` with all its tests into a Jetpack test format so that the built-in
+ * test runner will be able to run CommonJS test without manual changes.
+ */
+exports.run = function run(exports) {
+
+  // We can't leave old properties on exports since those are test in a CommonJS
+  // format that why we move everything to a new `suite` object.
+  let suite = {};
+  Object.keys(exports).forEach(function(key) {
+    suite[key] = exports[key];
+    delete exports[key];
+  });
+
+  // Now we wrap all the CommonJS tests to a Jetpack format and define
+  // those to a given `exports` object since that where jetpack test runner
+  // will look for them.
+  defineTestSuite(exports, suite);
+};
--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -201,17 +201,16 @@ exports.Sandbox = Sandbox;
 const evaluate = iced(function evaluate(sandbox, uri, options) {
   let { source, line, version, encoding } = override({
     encoding: 'UTF-8',
     line: 1,
     version: '1.8',
     source: null
   }, options);
 
-
   return source ? Cu.evalInSandbox(source, sandbox, version, uri, line)
                 : loadSubScript(uri, sandbox, encoding);
 });
 exports.evaluate = evaluate;
 
 // Populates `exports` of the given CommonJS `module` object, in the context
 // of the given `loader` by evaluating code associated with it.
 const load = iced(function load(loader, module) {
@@ -276,16 +275,17 @@ exports.load = load;
 // Utility function to check if id is relative.
 function isRelative(id) { return id[0] === '.'; }
 // Utility function to normalize module `uri`s so they have `.js` extension.
 function normalize(uri) { return uri.substr(-3) === '.js' ? uri : uri + '.js'; }
 // Utility function to join paths. In common case `base` is a
 // `requirer.uri` but in some cases it may be `baseURI`. In order to
 // avoid complexity we require `baseURI` with a trailing `/`.
 const resolve = iced(function resolve(id, base) {
+  if (!isRelative(id)) return id;
   let paths = id.split('/');
   let result = base.split('/');
   result.pop();
   while (paths.length) {
     let path = paths.shift();
     if (path === '..')
       result.pop();
     else if (path !== '.')
@@ -315,17 +315,16 @@ const Require = iced(function Require(lo
   function require(id) {
     if (!id) // Throw if `id` is not passed.
       throw Error('you must provide a module name when calling require() from '
                   + requirer.id, requirer.uri);
 
     // Resolve `id` to its requirer if it's relative.
     let requirement = requirer ? resolve(id, requirer.id) : id;
 
-
     // Resolves `uri` of module using loaders resolve function.
     let uri = resolveURI(requirement, mapping);
 
     if (!uri) // Throw if `uri` can not be resolved.
       throw Error('Module: Can not resolve "' + id + '" module required by ' +
                   requirer.id + ' located at ' + requirer.uri, requirer.uri);
 
     let module = null;
--- a/addon-sdk/source/python-lib/cuddlefish/__init__.py
+++ b/addon-sdk/source/python-lib/cuddlefish/__init__.py
@@ -156,16 +156,38 @@ parser_groups = (
                                 metavar=None,
                                 type="choice",
                                 choices=["firefox", "fennec",
                                          "fennec-on-device", "thunderbird",
                                          "xulrunner"],
                                 default="firefox",
                                 cmds=['test', 'run', 'testex', 'testpkgs',
                                       'testall'])),
+        (("-o", "--overload-modules",), dict(dest="overload_modules",
+                                     help=("Overload JS modules integrated into"
+                                           " Firefox with the one from your SDK"
+                                           " repository"),
+                                     action="store_true",
+                                     default=False,
+                                     cmds=['run', 'test', 'testex', 'testpkgs',
+                                           'testall'])),
+        (("", "--strip-sdk",), dict(dest="bundle_sdk",
+                                    help=("Do not ship SDK modules in the xpi"),
+                                    action="store_false",
+                                    default=True,
+                                    cmds=['run', 'test', 'testex', 'testpkgs',
+                                          'testall', 'xpi'])),
+        (("", "--force-use-bundled-sdk",), dict(dest="force_use_bundled_sdk",
+                                    help=("When --strip-sdk isn't passed, "
+                                          "force using sdk modules shipped in "
+                                          "the xpi instead of firefox ones"),
+                                    action="store_true",
+                                    default=False,
+                                    cmds=['run', 'test', 'testex', 'testpkgs',
+                                          'testall', 'xpi'])),
         (("", "--no-run",), dict(dest="no_run",
                                      help=("Instead of launching the "
                                            "application, just show the command "
                                            "for doing so.  Use this to launch "
                                            "the application in a debugger like "
                                            "gdb."),
                                      action="store_true",
                                      default=False,
@@ -759,22 +781,30 @@ def run(arguments=sys.argv[1:], target_c
     harness_options = {
         'jetpackID': jid,
         'staticArgs': options.static_args,
         'name': target,
         }
 
     harness_options.update(build)
 
+    # When cfx is run from sdk root directory, we will strip sdk modules and
+    # override them with local modules.
+    # So that integration tools will continue to work and use local modules
+    if os.getcwd() == env_root:
+        options.bundle_sdk = True
+        options.force_use_bundled_sdk = False
+        options.overload_modules = True
+
     extra_environment = {}
     if command == "test":
         # This should be contained in the test runner package.
         # maybe just do: target_cfg.main = 'test-harness/run-tests'
         harness_options['main'] = 'sdk/test/runner'
-        harness_options['mainPath'] = manifest.get_manifest_entry("addon-sdk", "lib", "sdk/test/runner").get_path()
+        harness_options['mainPath'] = 'sdk/test/runner'
     else:
         harness_options['main'] = target_cfg.get('main')
         harness_options['mainPath'] = manifest.top_path
     extra_environment["CFX_COMMAND"] = command
 
     for option in inherited_options:
         harness_options[option] = getattr(options, option)
 
@@ -787,24 +817,42 @@ def run(arguments=sys.argv[1:], target_c
     retval = 0
 
     if options.templatedir:
         app_extension_dir = os.path.abspath(options.templatedir)
     else:
         mydir = os.path.dirname(os.path.abspath(__file__))
         app_extension_dir = os.path.join(mydir, "../../app-extension")
 
-
     if target_cfg.get('preferences'):
         harness_options['preferences'] = target_cfg.get('preferences')
 
-    harness_options['manifest'] = manifest.get_harness_options_manifest()
-    harness_options['allTestModules'] = manifest.get_all_test_modules()
-    if len(harness_options['allTestModules']) == 0 and command == "test":
-        sys.exit(0)
+    harness_options['manifest'] = \
+        manifest.get_harness_options_manifest(options.bundle_sdk)
+
+    # Gives an hint to tell if sdk modules are bundled or not
+    harness_options['is-sdk-bundled'] = options.bundle_sdk
+
+    if options.force_use_bundled_sdk:
+        if not options.bundle_sdk:
+            print >>sys.stderr, ("--force-use-bundled-sdk and --strip-sdk "
+                                 "can't be used at the same time.")
+            sys.exit(1)
+        if options.overload_modules:
+            print >>sys.stderr, ("--force-use-bundled-sdk and --overload-modules "
+                                 "can't be used at the same time.")
+            sys.exit(1)
+        # Pass a flag in order to force using sdk modules shipped in the xpi
+        harness_options['force-use-bundled-sdk'] = True
+
+    # Pass the list of absolute path for all test modules
+    if command == "test":
+        harness_options['allTestModules'] = manifest.get_all_test_modules()
+        if len(harness_options['allTestModules']) == 0:
+            sys.exit(0)
 
     from cuddlefish.rdf import gen_manifest, RDFUpdate
 
     manifest_rdf = gen_manifest(template_root_dir=app_extension_dir,
                                 target_cfg=target_cfg,
                                 jid=jid,
                                 update_url=options.update_url,
                                 bootstrap=True,
@@ -820,17 +868,17 @@ def run(arguments=sys.argv[1:], target_c
         open(rdf_name, "w").write(str(update))
 
     # ask the manifest what files were used, so we can construct an XPI
     # without the rest. This will include the loader (and everything it
     # uses) because of the "loader_modules" starting points we passed to
     # build_manifest earlier
     used_files = None
     if command == "xpi":
-      used_files = set(manifest.get_used_files())
+        used_files = set(manifest.get_used_files(options.bundle_sdk))
 
     if options.no_strip_xpi:
         used_files = None # disables the filter, includes all files
 
     if command == 'xpi':
         from cuddlefish.xpi import build_xpi
         extra_harness_options = {}
         for kv in options.extra_harness_option_args:
@@ -865,17 +913,21 @@ def run(arguments=sys.argv[1:], target_c
                              enforce_timeouts=enforce_timeouts,
                              logfile=options.logfile,
                              addons=options.addons,
                              args=options.cmdargs,
                              extra_environment=extra_environment,
                              norun=options.no_run,
                              used_files=used_files,
                              enable_mobile=options.enable_mobile,
-                             mobile_app_name=options.mobile_app_name)
+                             mobile_app_name=options.mobile_app_name,
+                             env_root=env_root,
+                             is_running_tests=(command == "test"),
+                             overload_modules=options.overload_modules,
+                             bundle_sdk=options.bundle_sdk)
         except ValueError, e:
             print ""
             print "A given cfx option has an inappropriate value:"
             print >>sys.stderr, "  " + "  \n  ".join(str(e).split("\n"))
             retval = -1
         except Exception, e:
             if str(e).startswith(MOZRUNNER_BIN_NOT_FOUND):
                 print >>sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip()
--- a/addon-sdk/source/python-lib/cuddlefish/manifest.py
+++ b/addon-sdk/source/python-lib/cuddlefish/manifest.py
@@ -53,40 +53,51 @@ class UnreachablePrefixError(Exception):
 class ManifestEntry:
     def __init__(self):
         self.docs_filename = None
         self.docs_hash = None
         self.requirements = {}
         self.datamap = None
 
     def get_path(self):
-        path = "%s/%s/%s" % \
-               (self.packageName, self.sectionName, self.moduleName)
-        if not path.endswith(".js"):
-          path += ".js"
-        return path
+        name = self.moduleName
+
+        if name.endswith(".js"):
+            name = name[:-3]
+        items = []
+        # Only add package name for addons, so that system module paths match
+        # the path from the commonjs root directory and also match the loader
+        # mappings.
+        if self.packageName != "addon-sdk":
+            items.append(self.packageName)
+        # And for the same reason, do not append `lib/`.
+        if self.sectionName == "tests":
+            items.append(self.sectionName)
+        items.append(name)
+
+        return "/".join(items)
 
     def get_entry_for_manifest(self):
         entry = { "packageName": self.packageName,
                   "sectionName": self.sectionName,
                   "moduleName": self.moduleName,
                   "jsSHA256": self.js_hash,
                   "docsSHA256": self.docs_hash,
                   "requirements": {},
                   }
         for req in self.requirements:
             if isinstance(self.requirements[req], ManifestEntry):
                 them = self.requirements[req] # this is another ManifestEntry
-                them_path = them.get_path()
-                entry["requirements"][req] = {"path": them_path}
+                entry["requirements"][req] = them.get_path()
             else:
                 # something magic. The manifest entry indicates that they're
                 # allowed to require() it
                 entry["requirements"][req] = self.requirements[req]
-            assert isinstance(entry["requirements"][req], dict)
+            assert isinstance(entry["requirements"][req], unicode) or \
+                   isinstance(entry["requirements"][req], str)
         return entry
 
     def add_js(self, js_filename):
         self.js_filename = js_filename
         self.js_hash = hash_file(js_filename)
     def add_docs(self, docs_filename):
         self.docs_filename = docs_filename
         self.docs_hash = hash_file(docs_filename)
@@ -221,17 +232,18 @@ class ManifestBuilder:
             test_finder = self.get_manifest_entry("addon-sdk", "lib",
                                                   "sdk/deprecated/unit-test-finder")
             for (testname,tme) in test_modules:
                 test_finder.add_requirement(testname, tme)
                 # finally, tell the runtime about it, so they won't have to
                 # search for all tests. self.test_modules will be passed
                 # through the harness-options.json file in the
                 # .allTestModules property.
-                self.test_modules.append(testname)
+                # Pass the absolute module path.
+                self.test_modules.append(tme.get_path())
 
         # include files used by the loader
         for em in self.extra_modules:
             (pkgname, section, modname, js) = em
             mi = ModuleInfo(self.pkg_cfg.packages[pkgname], section, modname,
                             js, None)
             self.process_module(mi)
 
@@ -243,35 +255,41 @@ class ManifestBuilder:
 
     def get_used_packages(self):
         used = set()
         for index in self.manifest:
             (package, section, module) = index
             used.add(package)
         return sorted(used)
 
-    def get_used_files(self):
+    def get_used_files(self, bundle_sdk_modules):
         # returns all .js files that we reference, plus data/ files. You will
         # need to add the loader, off-manifest files that it needs, and
         # generated metadata.
         for datamap in self.datamaps.values():
             for (zipname, absname) in datamap.files_to_copy:
                 yield absname
 
         for me in self.get_module_entries():
-            yield me.js_filename
+            # Do not add manifest entries for system modules,
+            # so that we won't ship SDK files.
+            if me.packageName != "addon-sdk" or bundle_sdk_modules:
+                yield me.js_filename
 
     def get_all_test_modules(self):
         return self.test_modules
 
-    def get_harness_options_manifest(self):
+    def get_harness_options_manifest(self, bundle_sdk_modules):
         manifest = {}
         for me in self.get_module_entries():
             path = me.get_path()
-            manifest[path] = me.get_entry_for_manifest()
+            # Do not add manifest entries for system modules,
+            # so that we won't ship SDK files.
+            if me.packageName != "addon-sdk" or bundle_sdk_modules:
+                manifest[path] = me.get_entry_for_manifest()
         return manifest
 
     def get_manifest_entry(self, package, section, module):
         index = (package, section, module)
         if index not in self.manifest:
             m = self.manifest[index] = ManifestEntry()
             m.packageName = package
             m.sectionName = section
@@ -373,17 +391,17 @@ class ManifestBuilder:
 
         # We update our requirements on the way out of the depth-first
         # traversal of the module graph
 
         for reqname in sorted(requires.keys()):
             # If requirement is chrome or a pseudo-module (starts with @) make
             # path a requirement name.
             if reqname == "chrome" or reqname.startswith("@"):
-                me.add_requirement(reqname, {"path": reqname})
+                me.add_requirement(reqname, reqname)
             else:
                 # when two modules require() the same name, do they get a
                 # shared instance? This is a deep question. For now say yes.
 
                 # find_req_for() returns an entry to put in our
                 # 'requirements' dict, and will recursively process
                 # everything transitively required from here. It will also
                 # populate the self.modules[] cache. Note that we must
--- a/addon-sdk/source/python-lib/cuddlefish/rdf.py
+++ b/addon-sdk/source/python-lib/cuddlefish/rdf.py
@@ -160,17 +160,17 @@ def gen_manifest(template_root_dir, targ
         ta_desc = dom.createElement("Description")
         target_app.appendChild(ta_desc)
 
         elem = dom.createElement("em:id")
         elem.appendChild(dom.createTextNode("{aa3c5121-dab2-40e2-81ca-7ea25febc110}"))
         ta_desc.appendChild(elem)
 
         elem = dom.createElement("em:minVersion")
-        elem.appendChild(dom.createTextNode("18.0"))
+        elem.appendChild(dom.createTextNode("19.0"))
         ta_desc.appendChild(elem)
 
         elem = dom.createElement("em:maxVersion")
         elem.appendChild(dom.createTextNode("20.*"))
         ta_desc.appendChild(elem)
 
     if target_cfg.get("homepage"):
         manifest.set("em:homepageURL", target_cfg.get("homepage"))
--- a/addon-sdk/source/python-lib/cuddlefish/runner.py
+++ b/addon-sdk/source/python-lib/cuddlefish/runner.py
@@ -375,28 +375,48 @@ class XulrunnerAppRunner(mozrunner.Runne
         return self.__real_binary
 
 def run_app(harness_root_dir, manifest_rdf, harness_options,
             app_type, binary=None, profiledir=None, verbose=False,
             enforce_timeouts=False,
             logfile=None, addons=None, args=None, extra_environment={},
             norun=None,
             used_files=None, enable_mobile=False,
-            mobile_app_name=None):
+            mobile_app_name=None,
+            env_root=None,
+            is_running_tests=False,
+            overload_modules=False,
+            bundle_sdk=True):
     if binary:
         binary = os.path.expanduser(binary)
 
     if addons is None:
         addons = []
     else:
         addons = list(addons)
 
     cmdargs = []
     preferences = dict(DEFAULT_COMMON_PREFS)
 
+    # Overload global commonjs path with lib/ folders
+    file_scheme = "file://"
+    # win32 file scheme needs 3 slashes
+    if not env_root.startswith("/"):
+      file_scheme = file_scheme + "/"
+    addon_id = harness_options["jetpackID"]
+    pref_prefix = "extensions.modules." + addon_id + ".path"
+    if overload_modules:
+        preferences[pref_prefix] = file_scheme + \
+            os.path.join(env_root, "lib").replace("\\", "/") + "/"
+
+    # Overload tests/ mapping with test/ folder, only when running test
+    if is_running_tests:
+        preferences[pref_prefix + ".tests"] = file_scheme + \
+            os.path.join(env_root, "test").replace("\\", "/") + "/"
+
     # For now, only allow running on Mobile with --force-mobile argument
     if app_type in ["fennec", "fennec-on-device"] and not enable_mobile:
         print """
   WARNING: Firefox Mobile support is still experimental.
   If you would like to run an addon on this platform, use --force-mobile flag:
 
     cfx --force-mobile"""
         return 0
@@ -478,17 +498,18 @@ def run_app(harness_root_dir, manifest_r
     # Create the addon XPI so mozrunner will copy it to the profile it creates.
     # We delete it below after getting mozrunner to create the profile.
     from cuddlefish.xpi import build_xpi
     xpi_path = tempfile.mktemp(suffix='cfx-tmp.xpi')
     build_xpi(template_root_dir=harness_root_dir,
               manifest=manifest_rdf,
               xpi_path=xpi_path,
               harness_options=harness_options,
-              limit_to=used_files)
+              limit_to=used_files,
+              bundle_sdk=bundle_sdk)
     addons.append(xpi_path)
 
     starttime = last_output_time = time.time()
 
     # Redirect runner output to a file so we can catch output not generated
     # by us.
     # In theory, we could do this using simple redirection on all platforms
     # other than Windows, but this way we only have a single codepath to
--- a/addon-sdk/source/python-lib/cuddlefish/tests/test_linker.py
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_linker.py
@@ -38,28 +38,28 @@ class Basic(unittest.TestCase):
         target_cfg = self.get_pkg("one")
         pkg_cfg = packaging.build_config(ROOT, target_cfg)
         deps = packaging.get_deps_for_targets(pkg_cfg,
                                               [target_cfg.name, "addon-sdk"])
         self.failUnlessEqual(deps, ["addon-sdk", "one"])
         # target_cfg.dependencies is not provided, so we'll search through
         # all known packages (everything in 'deps').
         m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False)
-        m = m.get_harness_options_manifest()
+        m = m.get_harness_options_manifest(False)
 
         def assertReqIs(modname, reqname, path):
-            reqs = m["one/lib/%s.js" % modname]["requirements"]
-            self.failUnlessEqual(reqs[reqname]["path"], path)
-        assertReqIs("main", "panel", "addon-sdk/lib/sdk/panel.js")
-        assertReqIs("main", "two.js", "one/lib/two.js")
-        assertReqIs("main", "./two", "one/lib/two.js")
-        assertReqIs("main", "sdk/tabs.js", "addon-sdk/lib/sdk/tabs.js")
-        assertReqIs("main", "./subdir/three", "one/lib/subdir/three.js")
-        assertReqIs("two", "main", "one/lib/main.js")
-        assertReqIs("subdir/three", "../main", "one/lib/main.js")
+            reqs = m["one/%s" % modname]["requirements"]
+            self.failUnlessEqual(reqs[reqname], path)
+        assertReqIs("main", "panel", "sdk/panel")
+        assertReqIs("main", "two.js", "one/two")
+        assertReqIs("main", "./two", "one/two")
+        assertReqIs("main", "sdk/tabs.js", "sdk/tabs")
+        assertReqIs("main", "./subdir/three", "one/subdir/three")
+        assertReqIs("two", "main", "one/main")
+        assertReqIs("subdir/three", "../main", "one/main")
 
         target_cfg.dependencies = []
         # now, because .dependencies *is* provided, we won't search 'deps',
         # so we'll get a link error
         self.assertRaises(manifest.ModuleNotFoundError,
                           manifest.build_manifest,
                           target_cfg, pkg_cfg, deps, scan_tests=False)
 
@@ -67,36 +67,36 @@ class Basic(unittest.TestCase):
         target_cfg = self.get_pkg("three")
         package_path = [get_linker_files_dir("three-deps")]
         pkg_cfg = packaging.build_config(ROOT, target_cfg,
                                          packagepath=package_path)
         deps = packaging.get_deps_for_targets(pkg_cfg,
                                               [target_cfg.name, "addon-sdk"])
         self.failUnlessEqual(deps, ["addon-sdk", "three"])
         m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False)
-        m = m.get_harness_options_manifest()
+        m = m.get_harness_options_manifest(False)
         def assertReqIs(modname, reqname, path):
-            reqs = m["three/lib/%s.js" % modname]["requirements"]
-            self.failUnlessEqual(reqs[reqname]["path"], path)
-        assertReqIs("main", "three-a", "three-a/lib/main.js")
-        assertReqIs("main", "three-b", "three-b/lib/main.js")
-        assertReqIs("main", "three-c", "three-c/lib/main.js")
+            reqs = m["three/%s" % modname]["requirements"]
+            self.failUnlessEqual(reqs[reqname], path)
+        assertReqIs("main", "three-a", "three-a/main")
+        assertReqIs("main", "three-b", "three-b/main")
+        assertReqIs("main", "three-c", "three-c/main")
 
     def test_relative_main_in_top(self):
         target_cfg = self.get_pkg("five")
         package_path = []
         pkg_cfg = packaging.build_config(ROOT, target_cfg,
                                          packagepath=package_path)
         deps = packaging.get_deps_for_targets(pkg_cfg,
                                               [target_cfg.name, "addon-sdk"])
         self.failUnlessEqual(deps, ["addon-sdk", "five"])
         # all we care about is that this next call doesn't raise an exception
         m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False)
-        m = m.get_harness_options_manifest()
-        reqs = m["five/lib/main.js"]["requirements"]
+        m = m.get_harness_options_manifest(False)
+        reqs = m["five/main"]["requirements"]
         self.failUnlessEqual(reqs, {});
 
     def test_unreachable_relative_main_in_top(self):
         target_cfg = self.get_pkg("six")
         package_path = []
         pkg_cfg = packaging.build_config(ROOT, target_cfg,
                                          packagepath=package_path)
         deps = packaging.get_deps_for_targets(pkg_cfg,
--- a/addon-sdk/source/python-lib/cuddlefish/tests/test_xpi.py
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_xpi.py
@@ -197,17 +197,17 @@ class SmallXPI(unittest.TestCase):
         target_cfg = self.get_pkg("three")
         package_path = [self.get_linker_files_dir("three-deps")]
         pkg_cfg = packaging.build_config(self.root, target_cfg,
                                          packagepath=package_path)
         deps = packaging.get_deps_for_targets(pkg_cfg,
                                               [target_cfg.name, "addon-sdk"])
         addon_sdk_dir = pkg_cfg.packages["addon-sdk"].lib[0]
         m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False)
-        used_files = list(m.get_used_files())
+        used_files = list(m.get_used_files(True))
         here = up(os.path.abspath(__file__))
         def absify(*parts):
             fn = os.path.join(here, "linker-files", *parts)
             return os.path.abspath(fn)
         expected = [absify(*parts) for parts in
                     [("three", "lib", "main.js"),
                      ("three-deps", "three-a", "lib", "main.js"),
                      ("three-deps", "three-a", "lib", "subdir", "subfile.js"),
@@ -323,17 +323,17 @@ class SmallXPI(unittest.TestCase):
         package_path = [self.get_linker_files_dir("three-deps")]
         pkg_cfg = packaging.build_config(self.root, target_cfg,
                                          packagepath=package_path)
 
         deps = packaging.get_deps_for_targets(pkg_cfg,
                                               [target_cfg.name, "addon-sdk"])
         m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=True)
         self.failUnlessEqual(sorted(m.get_all_test_modules()),
-                             sorted(["test-one", "test-two"]))
+                             sorted(["three/tests/test-one", "three/tests/test-two"]))
         # the current __init__.py code omits limit_to=used_files for 'cfx
         # test', so all test files are included in the XPI. But the test
         # runner will only execute the tests that m.get_all_test_modules()
         # tells us about (which are put into the .allTestModules property of
         # harness-options.json).
         used_deps = m.get_used_packages()
 
         build = packaging.generate_build_for_target(pkg_cfg, target_cfg.name,
@@ -366,17 +366,17 @@ class SmallXPI(unittest.TestCase):
         pkg_cfg = packaging.build_config(self.root, target_cfg,
                                          packagepath=package_path)
         deps = packaging.get_deps_for_targets(pkg_cfg,
                                               [target_cfg.name, "addon-sdk"])
         FILTER = ".*one.*"
         m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=True,
                                     test_filter_re=FILTER)
         self.failUnlessEqual(sorted(m.get_all_test_modules()),
-                             sorted(["test-one"]))
+                             sorted(["three/tests/test-one"]))
         # the current __init__.py code omits limit_to=used_files for 'cfx
         # test', so all test files are included in the XPI. But the test
         # runner will only execute the tests that m.get_all_test_modules()
         # tells us about (which are put into the .allTestModules property of
         # harness-options.json).
         used_deps = m.get_used_packages()
 
         build = packaging.generate_build_for_target(pkg_cfg, target_cfg.name,
--- a/addon-sdk/source/python-lib/cuddlefish/xpi.py
+++ b/addon-sdk/source/python-lib/cuddlefish/xpi.py
@@ -17,17 +17,18 @@ def make_zipfile_path(localroot, localpa
     return ZIPSEP.join(localpath[len(localroot)+1:].split(os.sep))
 
 def mkzipdir(zf, path):
     dirinfo = zipfile.ZipInfo(path)
     dirinfo.external_attr = int("040755", 8) << 16L
     zf.writestr(dirinfo, "")
 
 def build_xpi(template_root_dir, manifest, xpi_path,
-              harness_options, limit_to=None, extra_harness_options={}):
+              harness_options, limit_to=None, extra_harness_options={},
+              bundle_sdk=True):
     zf = zipfile.ZipFile(xpi_path, "w", zipfile.ZIP_DEFLATED)
 
     open('.install.rdf', 'w').write(str(manifest))
     zf.write('.install.rdf', 'install.rdf')
     os.remove('.install.rdf')
 
     if 'icon' in harness_options:
         zf.write(str(harness_options['icon']), 'icon.png')
@@ -77,16 +78,20 @@ def build_xpi(template_root_dir, manifes
             abspath = os.path.join(dirpath, filename)
             arcpath = make_zipfile_path(template_root_dir, abspath)
             files_to_copy[arcpath] = abspath
 
     # `packages` attribute contains a dictionnary of dictionnary
     # of all packages sections directories
     for packageName in harness_options['packages']:
       base_arcpath = ZIPSEP.join(['resources', packageName])
+      # Eventually strip sdk files. We need to do that in addition to the
+      # whilelist as the whitelist is only used for `cfx xpi`:
+      if not bundle_sdk and packageName == 'addon-sdk':
+          continue
       # Always write the top directory, even if it contains no files, since
       # the harness will try to access it.
       dirs_to_create.add(base_arcpath)
       for sectionName in harness_options['packages'][packageName]:
         abs_dirname = harness_options['packages'][packageName][sectionName]
         base_arcpath = ZIPSEP.join(['resources', packageName, sectionName])
         # Always write the top directory, even if it contains no files, since
         # the harness will try to access it.
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/layout-change/main.js
@@ -0,0 +1,187 @@
+/* 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/. */
+
+"use strict";
+
+// This test makes sure that require statements used by all AMO hosted
+// add-ons will be able to use old require statements.
+// Tests are based on following usage data:
+// https://docs.google.com/spreadsheet/ccc?key=0ApEBy-GRnGxzdHlRMHJ5RXN1aWJ4RGhINkxSd0FCQXc#gid=0
+
+exports["test compatibility"] = function(assert) {
+  assert.equal(require("self"),
+               require("sdk/self"), "sdk/self -> self");
+
+  assert.equal(require("tabs"),
+               require("sdk/tabs"), "sdk/tabs -> tabs");
+
+  assert.equal(require("widget"),
+               require("sdk/widget"), "sdk/widget -> widget");
+
+  assert.equal(require("page-mod"),
+               require("sdk/page-mod"), "sdk/page-mod -> page-mod");
+
+  assert.equal(require("panel"),
+               require("sdk/panel"), "sdk/panel -> panel");
+
+  assert.equal(require("request"),
+               require("sdk/request"), "sdk/request -> request");
+
+  assert.equal(require("chrome"),
+               require("chrome"), "chrome -> chrome");
+
+  assert.equal(require("simple-storage"),
+               require("sdk/simple-storage"), "sdk/simple-storage -> simple-storage");
+
+  assert.equal(require("context-menu"),
+               require("sdk/context-menu"), "sdk/context-menu -> context-menu");
+
+  assert.equal(require("notifications"),
+               require("sdk/notifications"), "sdk/notifications -> notifications");
+
+  assert.equal(require("preferences-service"),
+               require("sdk/preferences/service"), "sdk/preferences/service -> preferences-service");
+
+  assert.equal(require("window-utils"),
+               require("sdk/deprecated/window-utils"), "sdk/deprecated/window-utils -> window-utils");
+
+  assert.equal(require("url"),
+               require("sdk/url"), "sdk/url -> url");
+
+  assert.equal(require("selection"),
+               require("sdk/selection"), "sdk/selection -> selection");
+
+  assert.equal(require("timers"),
+               require("sdk/timers"), "sdk/timers -> timers");
+
+  assert.equal(require("simple-prefs"),
+               require("sdk/simple-prefs"), "sdk/simple-prefs -> simple-prefs");
+
+  assert.equal(require("traceback"),
+               require("sdk/console/traceback"), "sdk/console/traceback -> traceback");
+
+  assert.equal(require("unload"),
+               require("sdk/system/unload"), "sdk/system/unload -> unload");
+
+  assert.equal(require("hotkeys"),
+               require("sdk/hotkeys"), "sdk/hotkeys -> hotkeys");
+
+  assert.equal(require("clipboard"),
+               require("sdk/clipboard"), "sdk/clipboard -> clipboard");
+
+  assert.equal(require("windows"),
+               require("sdk/windows"), "sdk/windows -> windows");
+
+  assert.equal(require("page-worker"),
+               require("sdk/page-worker"), "sdk/page-worker -> page-worker");
+
+  assert.equal(require("timer"),
+               require("sdk/timers"), "sdk/timers -> timer");
+
+  assert.equal(require("xhr"),
+               require("sdk/net/xhr"), "sdk/io/xhr -> xhr");
+
+  assert.equal(require("observer-service"),
+               require("sdk/deprecated/observer-service"), "sdk/deprecated/observer-service -> observer-service");
+
+  assert.equal(require("private-browsing"),
+               require("sdk/private-browsing"), "sdk/private-browsing -> private-browsing");
+
+  assert.equal(require("passwords"),
+               require("sdk/passwords"), "sdk/passwords -> passwords");
+
+  assert.equal(require("events"),
+               require("sdk/deprecated/events"), "sdk/deprecated/events -> events");
+
+  assert.equal(require("match-pattern"),
+               require("sdk/page-mod/match-pattern"), "sdk/page-mod/match-pattern -> match-pattern");
+
+  assert.equal(require("tab-browser"),
+               require("sdk/deprecated/tab-browser"), "sdk/deprecated/tab-browser -> tab-browser");
+
+  assert.equal(require("file"),
+               require("sdk/io/file"), "sdk/io/file -> file");
+
+  assert.equal(require("xul-app"),
+               require("sdk/system/xul-app"), "sdk/system/xul-app -> xul-app");
+
+  assert.equal(require("api-utils"),
+               require("sdk/deprecated/api-utils"), "sdk/deprecated/api-utils -> api-utils");
+
+  assert.equal(require("runtime"),
+               require("sdk/system/runtime"), "sdk/system/runtime -> runtime");
+
+  assert.equal(require("base64"),
+               require("sdk/base64"), "sdk/base64 -> base64");
+
+  assert.equal(require("xpcom"),
+               require("sdk/platform/xpcom"), "sdk/platform/xpcom -> xpcom");
+
+  assert.equal(require("traits"),
+               require("sdk/deprecated/traits"), "sdk/deprecated/traits -> traits");
+
+  assert.equal(require("keyboard/utils"),
+               require("sdk/keyboard/utils"), "sdk/keyboard/utils -> keyboard/utils");
+
+  assert.equal(require("system"),
+               require("sdk/system"), "sdk/system -> system");
+
+  assert.equal(require("querystring"),
+               require("sdk/querystring"), "sdk/querystring -> querystring");
+
+  assert.equal(require("addon-page"),
+               require("sdk/addon-page"), "sdk/addon-page -> addon-page");
+
+  assert.equal(require("tabs/utils"),
+               require("sdk/tabs/utils"), "sdk/tabs/utils -> tabs/utils");
+
+  assert.equal(require("app-strings"),
+               require("sdk/deprecated/app-strings"), "sdk/deprecated/app-strings -> app-strings");
+
+  assert.equal(require("dom/events"),
+               require("sdk/dom/events"), "sdk/dom/events -> dom/events");
+
+  assert.equal(require("tabs/tab.js"),
+               require("sdk/tabs/tab"), "sdk/tabs/tab -> tabs/tab.js");
+
+  assert.equal(require("memory"),
+               require("sdk/deprecated/memory"), "sdk/deprecated/memory -> memory");
+
+  assert.equal(require("light-traits"),
+               require("sdk/deprecated/light-traits"), "sdk/deprecated/light-traits -> light-traits");
+
+  assert.equal(require("environment"),
+               require("sdk/system/environment"), "sdk/system/environment -> environment");
+
+  assert.equal(require("utils/data"),
+               require("sdk/io/data"), "sdk/io/data -> utils/data");
+
+  assert.equal(require("test/assert"),
+               require("sdk/test/assert"), "sdk/test/assert -> test/assert");
+
+  assert.equal(require("hidden-frame"),
+               require("sdk/frame/hidden-frame"), "sdk/frame/hidden-frame -> hidden-frame");
+
+  assert.equal(require("collection"),
+               require("sdk/util/collection"), "sdk/util/collection -> collection");
+
+  assert.equal(require("array"),
+               require("sdk/util/array"), "sdk/util/array -> array");
+
+  assert.equal(require("api-utils/cortex"),
+               require("sdk/deprecated/cortex"),
+               "api-utils/cortex -> sdk/deprecated/cortex");
+};
+
+if (require("sdk/system/xul-app").is("Fennec")) {
+  module.exports = {
+    "test Unsupported Test": function UnsupportedTest (assert) {
+        assert.pass(
+          "Skipping this test until Fennec support is implemented." +
+          "See bug 809352");
+    }
+  }
+}
+
+require("sdk/test/runner").runTestsFromModule(module);
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/layout-change/package.json
@@ -0,0 +1,3 @@
+{
+  "id": "test-layout-change"
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/packed/main.js
@@ -0,0 +1,20 @@
+/* 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/. */
+"use strict";
+
+const { packed } = require("sdk/self");
+const url = require("sdk/url");
+
+exports["test self.packed"] = function (assert) {
+  assert.ok(packed, "require('sdk/self').packed is correct");
+}
+
+exports["test url.toFilename"] = function (assert) {
+  assert.throws(
+      function() { url.toFilename(module.uri); },
+      /cannot map to filename: /,
+      "url.toFilename() can fail for packed XPIs");
+}
+
+require("sdk/test/runner").runTestsFromModule(module);
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/packed/package.json
@@ -0,0 +1,4 @@
+{
+  "id": "test-url",
+  "unpack": false
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/unpacked/main.js
@@ -0,0 +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/. */
+"use strict";
+
+const { packed } = require("sdk/self");
+const url = require("sdk/url");
+
+exports["test self.packed"] = function (assert) {
+  assert.ok(!packed, "require('sdk/self').packed is correct");
+}
+
+exports["test url.toFilename"] = function (assert) {
+  assert.ok(/.*main\.js$/.test(url.toFilename(module.uri)),
+            "url.toFilename() on resource: URIs should work");
+}
+
+require("sdk/test/runner").runTestsFromModule(module);
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/unpacked/package.json
@@ -0,0 +1,4 @@
+{
+  "id": "test-url",
+  "unpack": true
+}
\ No newline at end of file
--- a/addon-sdk/source/test/commonjs-test-adapter/asserts.js
+++ b/addon-sdk/source/test/commonjs-test-adapter/asserts.js
@@ -1,15 +1,15 @@
 /* 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/. */
 
 "use strict";
 
-const AssertBase = require("test/assert").Assert;
+const AssertBase = require("sdk/test/assert").Assert;
 
 /**
  * Generates custom assertion constructors that may be bundled with a test
  * suite.
  * @params {String}
  *    names of assertion function to be added to the generated Assert.
  */
 function Assert() {
--- a/addon-sdk/source/test/modules/tiger.js
+++ b/addon-sdk/source/test/modules/tiger.js
@@ -1,8 +1,8 @@
 /* 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/. */
 
 define(function (require, exports) {
   exports.name = 'tiger';
-  exports.type = require('modules/types/cat').type;
+  exports.type = require('./types/cat').type;
 });
--- a/addon-sdk/source/test/private-browsing/helper.js
+++ b/addon-sdk/source/test/private-browsing/helper.js
@@ -2,17 +2,17 @@
  * 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/. */
 'use strict';
 
 let { Cc,Ci } = require('chrome');
 const unload = require("sdk/system/unload");
 const { Loader } = require('sdk/test/loader');
 const { windows: windowsIterator } = require("sdk/window/utils");
-const windows = require("windows").browserWindows;
+const windows = require("sdk/windows").browserWindows;
 
 let { loader } = LoaderWithHookedConsole();
 const pb = loader.require('sdk/private-browsing');
 const pbUtils = loader.require('sdk/private-browsing/utils');
 
 function LoaderWithHookedConsole() {
   let errors = [];
   let loader = Loader(module, {
--- a/addon-sdk/source/test/private-browsing/windows.js
+++ b/addon-sdk/source/test/private-browsing/windows.js
@@ -1,15 +1,15 @@
 /* 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/. */
 'use strict';
 
 const { pb, pbUtils } = require('./helper');
-const { openDialog } = require('window/utils');
+const { openDialog } = require('sdk/window/utils');
 
 exports["test Per Window Private Browsing getter"] = function(assert, done) {
   let win = openDialog({
     private: true
   });
 
   win.addEventListener('DOMContentLoaded', function onload() {
     win.removeEventListener('DOMContentLoaded', onload, false);
--- a/addon-sdk/source/test/tabs/test-firefox-tabs.js
+++ b/addon-sdk/source/test/tabs/test-firefox-tabs.js
@@ -913,17 +913,17 @@ exports['test ready event on new window 
   });
 
   let window = openBrowserWindow(function(){}, uri);
 };
 
 exports['test unique tab ids'] = function(test) {
   test.waitUntilDone();
 
-  var windows = require('windows').browserWindows,
+  var windows = require('sdk/windows').browserWindows,
     tabIds = {}, win1, win2;
 
   let steps = [
     function (index) {
       win1 = windows.open({
           url: "data:text/html;charset=utf-8,foo",
           onOpen: function(window) {
             tabIds['tab1'] = window.tabs.activeTab.id;
--- a/addon-sdk/source/test/test-addon-page.js
+++ b/addon-sdk/source/test/test-addon-page.js
@@ -16,17 +16,17 @@ let uri = require('sdk/self').data.url('
 
 function isChromeVisible(window) {
   let x = window.document.documentElement.getAttribute('disablechrome')
   return x !== 'true';
 }
 
 exports['test that add-on page has no chrome'] = function(assert, done) {
   let loader = Loader(module);
-  loader.require('addon-kit/addon-page');
+  loader.require('sdk/addon-page');
 
   let window = windows.activeBrowserWindow;
   let tab = openTab(window, uri);
 
   assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
 
   // need to do this in another turn to make sure event listener
   // that sets property has time to do that.
@@ -39,17 +39,17 @@ exports['test that add-on page has no ch
     assert.ok(isChromeVisible(window), 'chrome is visible again');
     loader.unload();
     done();
   });
 };
 
 exports['test that add-on page with hash has no chrome'] = function(assert, done) {
   let loader = Loader(module);
-  loader.require('addon-kit/addon-page');
+  loader.require('sdk/addon-page');
 
   let window = windows.activeBrowserWindow;
   let tab = openTab(window, uri + "#foo");
 
   assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
 
   // need to do this in another turn to make sure event listener
   // that sets property has time to do that.
@@ -62,17 +62,17 @@ exports['test that add-on page with hash
     assert.ok(isChromeVisible(window), 'chrome is visible again');
     loader.unload();
     done();
   });
 };
 
 exports['test that add-on page with querystring has no chrome'] = function(assert, done) {
   let loader = Loader(module);
-  loader.require('addon-kit/addon-page');
+  loader.require('sdk/addon-page');
 
   let window = windows.activeBrowserWindow;
   let tab = openTab(window, uri + '?foo=bar');
 
   assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
 
   // need to do this in another turn to make sure event listener
   // that sets property has time to do that.
@@ -85,17 +85,17 @@ exports['test that add-on page with quer
     assert.ok(isChromeVisible(window), 'chrome is visible again');
     loader.unload();
     done();
   });
 };
 
 exports['test that add-on page with hash and querystring has no chrome'] = function(assert, done) {
   let loader = Loader(module);
-  loader.require('addon-kit/addon-page');
+  loader.require('sdk/addon-page');
 
   let window = windows.activeBrowserWindow;
   let tab = openTab(window, uri + '#foo?foo=bar');
 
   assert.ok(isChromeVisible(window), 'chrome is visible for non addon page');
 
   // need to do this in another turn to make sure event listener
   // that sets property has time to do that.
@@ -108,17 +108,17 @@ exports['test that add-on page with hash
     assert.ok(isChromeVisible(window), 'chrome is visible again');
     loader.unload();
     done();
   });
 };
 
 exports['test that malformed uri is not an addon-page'] = function(assert, done) {
   let loader = Loader(module);
-  loader.require('addon-kit/addon-page');
+  loader.require('sdk/addon-page');
 
   let window = windows.activeBrowserWindow;
   let tab = openTab(window, uri + 'anguage');
 
   // need to do this in another turn to make sure event listener
   // that sets property has time to do that.
   setTimeout(function() {
     activateTab(tab);
@@ -141,9 +141,9 @@ exports['test that add-on pages are clos
       loader.unload();
       assert.ok(!isTabOpen(tab), 'add-on page tabs are closed on unload');
 
       done();
     }
   });
 };
 
-require('sdk/test').run(exports);
+require('test').run(exports);
--- a/addon-sdk/source/test/test-context-menu.js
+++ b/addon-sdk/source/test/test-context-menu.js
@@ -1355,17 +1355,17 @@ exports.testMultipleModulesOrder = funct
 // Checks that the order of menu items is correct when adding/removing across
 // multiple modules when overflowing. All items from a single module should
 // remain in a group
 exports.testMultipleModulesOrderOverflow = function (test) {
   test = new TestHelper(test);
   let loader0 = test.newLoader();
   let loader1 = test.newLoader();
 
-  let prefs = loader0.loader.require("preferences-service");
+  let prefs = loader0.loader.require("sdk/preferences/service");
   prefs.set(OVERFLOW_THRESH_PREF, 0);
 
   // Use each module to add an item, then unload each module in turn.
   let item0 = new loader0.cm.Item({ label: "item 0" });
   let item1 = new loader1.cm.Item({ label: "item 1" });
 
   test.showMenu(null, function (popup) {
 
@@ -1396,17 +1396,17 @@ exports.testMultipleModulesOrderOverflow
 
 // Checks that if a module's items are all hidden then the overflow menu doesn't
 // get hidden
 exports.testMultipleModulesOverflowHidden = function (test) {
   test = new TestHelper(test);
   let loader0 = test.newLoader();
   let loader1 = test.newLoader();
 
-  let prefs = loader0.loader.require("preferences-service");
+  let prefs = loader0.loader.require("sdk/preferences/service");
   prefs.set(OVERFLOW_THRESH_PREF, 0);
 
   // Use each module to add an item, then unload each module in turn.
   let item0 = new loader0.cm.Item({ label: "item 0" });
   let item1 = new loader1.cm.Item({
     label: "item 1",
     context: loader1.cm.SelectorContext("a")
   });
@@ -1421,17 +1421,17 @@ exports.testMultipleModulesOverflowHidde
 
 // Checks that if a module's items are all hidden then the overflow menu doesn't
 // get hidden (reverse order to above)
 exports.testMultipleModulesOverflowHidden2 = function (test) {
   test = new TestHelper(test);
   let loader0 = test.newLoader();
   let loader1 = test.newLoader();
 
-  let prefs = loader0.loader.require("preferences-service");
+  let prefs = loader0.loader.require("sdk/preferences/service");
   prefs.set(OVERFLOW_THRESH_PREF, 0);
 
   // Use each module to add an item, then unload each module in turn.
   let item0 = new loader0.cm.Item({
     label: "item 0",
     context: loader0.cm.SelectorContext("a")
   });
   let item1 = new loader1.cm.Item({ label: "item 1" });
@@ -1445,17 +1445,17 @@ exports.testMultipleModulesOverflowHidde
 
 
 // Checks that we don't overflow if there are more items than the overflow
 // threshold but not all of them are visible
 exports.testOverflowIgnoresHidden = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
-  let prefs = loader.loader.require("preferences-service");
+  let prefs = loader.loader.require("sdk/preferences/service");
   prefs.set(OVERFLOW_THRESH_PREF, 2);
 
   let allItems = [
     new loader.cm.Item({
       label: "item 0"
     }),
     new loader.cm.Item({
       label: "item 1"
@@ -1476,17 +1476,17 @@ exports.testOverflowIgnoresHidden = func
 
 // Checks that we don't overflow if there are more items than the overflow
 // threshold but not all of them are visible
 exports.testOverflowIgnoresHiddenMultipleModules1 = function (test) {
   test = new TestHelper(test);
   let loader0 = test.newLoader();
   let loader1 = test.newLoader();
 
-  let prefs = loader0.loader.require("preferences-service");
+  let prefs = loader0.loader.require("sdk/preferences/service");
   prefs.set(OVERFLOW_THRESH_PREF, 2);
 
   let allItems = [
     new loader0.cm.Item({
       label: "item 0"
     }),
     new loader0.cm.Item({
       label: "item 1"
@@ -1511,17 +1511,17 @@ exports.testOverflowIgnoresHiddenMultipl
 
 // Checks that we don't overflow if there are more items than the overflow
 // threshold but not all of them are visible
 exports.testOverflowIgnoresHiddenMultipleModules2 = function (test) {
   test = new TestHelper(test);
   let loader0 = test.newLoader();
   let loader1 = test.newLoader();
 
-  let prefs = loader0.loader.require("preferences-service");
+  let prefs = loader0.loader.require("sdk/preferences/service");
   prefs.set(OVERFLOW_THRESH_PREF, 2);
 
   let allItems = [
     new loader0.cm.Item({
       label: "item 0"
     }),
     new loader0.cm.Item({
       label: "item 1",
@@ -1546,17 +1546,17 @@ exports.testOverflowIgnoresHiddenMultipl
 
 // Checks that we don't overflow if there are more items than the overflow
 // threshold but not all of them are visible
 exports.testOverflowIgnoresHiddenMultipleModules3 = function (test) {
   test = new TestHelper(test);
   let loader0 = test.newLoader();
   let loader1 = test.newLoader();
 
-  let prefs = loader0.loader.require("preferences-service");
+  let prefs = loader0.loader.require("sdk/preferences/service");
   prefs.set(OVERFLOW_THRESH_PREF, 2);
 
   let allItems = [
     new loader0.cm.Item({
       label: "item 0",
       context: loader0.cm.SelectorContext("a")
     }),
     new loader0.cm.Item({
@@ -1580,17 +1580,17 @@ exports.testOverflowIgnoresHiddenMultipl
 
 
 // Tests that we transition between overflowing to non-overflowing to no items
 // and back again
 exports.testOverflowTransition = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
-  let prefs = loader.loader.require("preferences-service");
+  let prefs = loader.loader.require("sdk/preferences/service");
   prefs.set(OVERFLOW_THRESH_PREF, 2);
 
   let pItems = [
     new loader.cm.Item({
       label: "item 0",
       context: loader.cm.SelectorContext("p")
     }),
     new loader.cm.Item({
@@ -2475,37 +2475,161 @@ exports.testAlreadyOpenIframe = function
     test.showMenu(doc.getElementById("iframe"), function (popup) {
       test.checkMenu([item], [], []);
       test.done();
     });
   });
 };
 
 
+// Tests that a missing label throws an exception
+exports.testItemNoLabel = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  try {
+    new loader.cm.Item({});
+    test.assert(false, "Should have seen exception");
+  }
+  catch (e) {
+    test.assert(true, "Should have seen exception");
+  }
+
+  try {
+    new loader.cm.Item({ label: null });
+    test.assert(false, "Should have seen exception");
+  }
+  catch (e) {
+    test.assert(true, "Should have seen exception");
+  }
+
+  try {
+    new loader.cm.Item({ label: undefined });
+    test.assert(false, "Should have seen exception");
+  }
+  catch (e) {
+    test.assert(true, "Should have seen exception");
+  }
+
+  try {
+    new loader.cm.Item({ label: "" });
+    test.assert(false, "Should have seen exception");
+  }
+  catch (e) {
+    test.assert(true, "Should have seen exception");
+  }
+
+  test.done();
+}
+
+
+// Tests that items can have an empty data property
+exports.testItemNoData = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  function checkData(data) {
+    test.assertEqual(data, undefined, "Data should be undefined");
+  }
+
+  let item1 = new loader.cm.Item({
+    label: "item 1",
+    contentScript: 'self.on("click", function(node, data) self.postMessage(data))',
+    onMessage: checkData
+  });
+  let item2 = new loader.cm.Item({
+    label: "item 2",
+    data: null,
+    contentScript: 'self.on("click", function(node, data) self.postMessage(data))',
+    onMessage: checkData
+  });
+  let item3 = new loader.cm.Item({
+    label: "item 3",
+    data: undefined,
+    contentScript: 'self.on("click", function(node, data) self.postMessage(data))',
+    onMessage: checkData
+  });
+
+  test.assertEqual(item1.data, undefined, "Should be no defined data");
+  test.assertEqual(item2.data, null, "Should be no defined data");
+  test.assertEqual(item3.data, undefined, "Should be no defined data");
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item1, item2, item3], [], []);
+
+    let itemElt = test.getItemElt(popup, item1);
+    itemElt.click();
+
+    test.hideMenu(function() {
+      test.showMenu(null, function (popup) {
+        let itemElt = test.getItemElt(popup, item2);
+        itemElt.click();
+
+        test.hideMenu(function() {
+          test.showMenu(null, function (popup) {
+            let itemElt = test.getItemElt(popup, item3);
+            itemElt.click();
+
+            test.done();
+          });
+        });
+      });
+    });
+  });
+}
+
+
+// Tests that items without an image don't attempt to show one
+exports.testItemNoImage = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item1 = new loader.cm.Item({ label: "item 1" });
+  let item2 = new loader.cm.Item({ label: "item 2", image: null });
+  let item3 = new loader.cm.Item({ label: "item 3", image: undefined });
+
+  test.assertEqual(item1.image, undefined, "Should be no defined image");
+  test.assertEqual(item2.image, null, "Should be no defined image");
+  test.assertEqual(item3.image, undefined, "Should be no defined image");
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item1, item2, item3], [], []);
+
+    test.done();
+  });
+}
+
+
 // Test image support.
 exports.testItemImage = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
   let imageURL = require("sdk/self").data.url("moz_favicon.ico");
   let item = new loader.cm.Item({ label: "item", image: imageURL });
   let menu = new loader.cm.Menu({ label: "menu", image: imageURL, items: [
     loader.cm.Item({ label: "subitem" })
   ]});
+  test.assertEqual(item.image, imageURL, "Should have set the image correctly");
+  test.assertEqual(menu.image, imageURL, "Should have set the image correctly");
 
   test.showMenu(null, function (popup) {
     test.checkMenu([item, menu], [], []);
 
     let imageURL2 = require("sdk/self").data.url("dummy.ico");
     item.image = imageURL2;
     menu.image = imageURL2;
+    test.assertEqual(item.image, imageURL2, "Should have set the image correctly");
+    test.assertEqual(menu.image, imageURL2, "Should have set the image correctly");
     test.checkMenu([item, menu], [], []);
 
     item.image = null;
     menu.image = null;
+    test.assertEqual(item.image, null, "Should have set the image correctly");
+    test.assertEqual(menu.image, null, "Should have set the image correctly");
     test.checkMenu([item, menu], [], []);
 
     test.done();
   });
 };
 
 
 // Menu.destroy should destroy the item tree rooted at that menu.
--- a/addon-sdk/source/test/test-indexed-db.js
+++ b/addon-sdk/source/test/test-indexed-db.js
@@ -1,22 +1,22 @@
 /* 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/. */
 
 "use strict";
 
-let xulApp = require("api-utils/xul-app");
+let xulApp = require("sdk/system/xul-app");
 if (xulApp.versionInRange(xulApp.platformVersion, "16.0a1", "*")) {
 new function tests() {
 
 const { indexedDB, IDBKeyRange, DOMException, IDBCursor, IDBTransaction,
         IDBOpenDBRequest, IDBVersionChangeEvent, IDBDatabase, IDBFactory,
         IDBIndex, IDBObjectStore, IDBRequest
-      } = require("indexed-db");
+      } = require("sdk/indexed-db");
 
 exports["test indexedDB is frozen"] = function(assert){
   let original = indexedDB.open;
   let f = function(){};
   assert.throws(function(){indexedDB.open = f});
   assert.equal(indexedDB.open,original);
   assert.notEqual(indexedDB.open,f);
 
deleted file mode 100644
--- a/addon-sdk/source/test/test-layout-change.js
+++ /dev/null
@@ -1,187 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-// This test makes sure that require statements used by all AMO hosted
-// add-ons will be able to use old require statements.
-// Tests are based on following usage data:
-// https://docs.google.com/spreadsheet/ccc?key=0ApEBy-GRnGxzdHlRMHJ5RXN1aWJ4RGhINkxSd0FCQXc#gid=0
-
-exports["test compatibility"] = function(assert) {
-  assert.equal(require("self"),
-               require("sdk/self"), "sdk/self -> self");
-
-  assert.equal(require("tabs"),
-               require("sdk/tabs"), "sdk/tabs -> tabs");
-
-  assert.equal(require("widget"),
-               require("sdk/widget"), "sdk/widget -> widget");
-
-  assert.equal(require("page-mod"),
-               require("sdk/page-mod"), "sdk/page-mod -> page-mod");
-
-  assert.equal(require("panel"),
-               require("sdk/panel"), "sdk/panel -> panel");
-
-  assert.equal(require("request"),
-               require("sdk/request"), "sdk/request -> request");
-
-  assert.equal(require("chrome"),
-               require("chrome"), "chrome -> chrome");
-
-  assert.equal(require("simple-storage"),
-               require("sdk/simple-storage"), "sdk/simple-storage -> simple-storage");
-
-  assert.equal(require("context-menu"),
-               require("sdk/context-menu"), "sdk/context-menu -> context-menu");
-
-  assert.equal(require("notifications"),
-               require("sdk/notifications"), "sdk/notifications -> notifications");
-
-  assert.equal(require("preferences-service"),
-               require("sdk/preferences/service"), "sdk/preferences/service -> preferences-service");
-
-  assert.equal(require("window-utils"),
-               require("sdk/deprecated/window-utils"), "sdk/deprecated/window-utils -> window-utils");
-
-  assert.equal(require("url"),
-               require("sdk/url"), "sdk/url -> url");
-
-  assert.equal(require("selection"),
-               require("sdk/selection"), "sdk/selection -> selection");
-
-  assert.equal(require("timers"),
-               require("sdk/timers"), "sdk/timers -> timers");
-
-  assert.equal(require("simple-prefs"),
-               require("sdk/simple-prefs"), "sdk/simple-prefs -> simple-prefs");
-
-  assert.equal(require("traceback"),
-               require("sdk/console/traceback"), "sdk/console/traceback -> traceback");
-
-  assert.equal(require("unload"),
-               require("sdk/system/unload"), "sdk/system/unload -> unload");
-
-  assert.equal(require("hotkeys"),
-               require("sdk/hotkeys"), "sdk/hotkeys -> hotkeys");
-
-  assert.equal(require("clipboard"),
-               require("sdk/clipboard"), "sdk/clipboard -> clipboard");
-
-  assert.equal(require("windows"),
-               require("sdk/windows"), "sdk/windows -> windows");
-
-  assert.equal(require("page-worker"),
-               require("sdk/page-worker"), "sdk/page-worker -> page-worker");
-
-  assert.equal(require("timer"),
-               require("sdk/timers"), "sdk/timers -> timer");
-
-  assert.equal(require("xhr"),
-               require("sdk/net/xhr"), "sdk/io/xhr -> xhr");
-
-  assert.equal(require("observer-service"),
-               require("sdk/deprecated/observer-service"), "sdk/deprecated/observer-service -> observer-service");
-
-  assert.equal(require("private-browsing"),
-               require("sdk/private-browsing"), "sdk/private-browsing -> private-browsing");
-
-  assert.equal(require("passwords"),
-               require("sdk/passwords"), "sdk/passwords -> passwords");
-
-  assert.equal(require("events"),
-               require("sdk/deprecated/events"), "sdk/deprecated/events -> events");
-
-  assert.equal(require("match-pattern"),
-               require("sdk/page-mod/match-pattern"), "sdk/page-mod/match-pattern -> match-pattern");
-
-  assert.equal(require("tab-browser"),
-               require("sdk/deprecated/tab-browser"), "sdk/deprecated/tab-browser -> tab-browser");
-
-  assert.equal(require("file"),
-               require("sdk/io/file"), "sdk/io/file -> file");
-
-  assert.equal(require("xul-app"),
-               require("sdk/system/xul-app"), "sdk/system/xul-app -> xul-app");
-
-  assert.equal(require("api-utils"),
-               require("sdk/deprecated/api-utils"), "sdk/deprecated/api-utils -> api-utils");
-
-  assert.equal(require("runtime"),
-               require("sdk/system/runtime"), "sdk/system/runtime -> runtime");
-
-  assert.equal(require("base64"),
-               require("sdk/base64"), "sdk/base64 -> base64");
-
-  assert.equal(require("xpcom"),
-               require("sdk/platform/xpcom"), "sdk/platform/xpcom -> xpcom");
-
-  assert.equal(require("traits"),
-               require("sdk/deprecated/traits"), "sdk/deprecated/traits -> traits");
-
-  assert.equal(require("keyboard/utils"),
-               require("sdk/keyboard/utils"), "sdk/keyboard/utils -> keyboard/utils");
-
-  assert.equal(require("system"),
-               require("sdk/system"), "sdk/system -> system");
-
-  assert.equal(require("querystring"),
-               require("sdk/querystring"), "sdk/querystring -> querystring");
-
-  assert.equal(require("addon-page"),
-               require("sdk/addon-page"), "sdk/addon-page -> addon-page");
-
-  assert.equal(require("tabs/utils"),
-               require("sdk/tabs/utils"), "sdk/tabs/utils -> tabs/utils");
-
-  assert.equal(require("app-strings"),
-               require("sdk/deprecated/app-strings"), "sdk/deprecated/app-strings -> app-strings");
-
-  assert.equal(require("dom/events"),
-               require("sdk/dom/events"), "sdk/dom/events -> dom/events");
-
-  assert.equal(require("tabs/tab.js"),
-               require("sdk/tabs/tab"), "sdk/tabs/tab -> tabs/tab.js");
-
-  assert.equal(require("memory"),
-               require("sdk/deprecated/memory"), "sdk/deprecated/memory -> memory");
-
-  assert.equal(require("light-traits"),
-               require("sdk/deprecated/light-traits"), "sdk/deprecated/light-traits -> light-traits");
-
-  assert.equal(require("environment"),
-               require("sdk/system/environment"), "sdk/system/environment -> environment");
-
-  assert.equal(require("utils/data"),
-               require("sdk/io/data"), "sdk/io/data -> utils/data");
-
-  assert.equal(require("test/assert"),
-               require("sdk/test/assert"), "sdk/test/assert -> test/assert");
-
-  assert.equal(require("hidden-frame"),
-               require("sdk/frame/hidden-frame"), "sdk/frame/hidden-frame -> hidden-frame");
-
-  assert.equal(require("collection"),
-               require("sdk/util/collection"), "sdk/util/collection -> collection");
-
-  assert.equal(require("array"),
-               require("sdk/util/array"), "sdk/util/array -> array");
-
-  assert.equal(require("api-utils/cortex"),
-               require("sdk/deprecated/cortex"),
-               "api-utils/cortex -> sdk/deprecated/cortex");
-};
-
-if (require("sdk/system/xul-app").is("Fennec")) {
-  module.exports = {
-    "test Unsupported Test": function UnsupportedTest (assert) {
-        assert.pass(
-          "Skipping this test until Fennec support is implemented." +
-          "See bug 809352");
-    }
-  }
-}
-
-require("test").run(exports);
--- a/addon-sdk/source/test/test-loader.js
+++ b/addon-sdk/source/test/test-loader.js
@@ -1,35 +1,33 @@
 /* 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/. */
 
 'use strict';
 
 let { Loader, main, unload, parseStack } = require('toolkit/loader');
 
+let root = module.uri.substr(0, module.uri.lastIndexOf('/'))
+
 exports['test dependency cycles'] = function(assert) {
-  let uri = module.uri.substr(0, module.uri.lastIndexOf('/')) +
-            '/fixtures/loader/cycles/'
-
+  let uri = root + '/fixtures/loader/cycles/';
   let loader = Loader({ paths: { '': uri } });
 
   let program = main(loader, 'main');
 
   assert.equal(program.a.b, program.b, 'module `a` gets correct `b`');
   assert.equal(program.b.a, program.a, 'module `b` gets correct `a`');
   assert.equal(program.c.main, program, 'module `c` gets correct `main`');
 
   unload(loader);
-};
+}
 
 exports['test syntax errors'] = function(assert) {
-  let uri = module.uri.substr(0, module.uri.lastIndexOf('/')) +
-            '/fixtures/loader/syntax-error/';
-
+  let uri = root + '/fixtures/loader/syntax-error/';
   let loader = Loader({ paths: { '': uri } });
 
   try {
     let program = main(loader, 'main');
   } catch (error) {
     assert.equal(error.name, "SyntaxError", "throws syntax error");
     assert.equal(error.fileName.split("/").pop(), "error.js",
               "Error contains filename");
@@ -38,22 +36,20 @@ exports['test syntax errors'] = function
     assert.equal(stack.pop().fileName, uri + "main.js",
                  "loader stack is omitted");
     assert.equal(stack.pop().fileName, module.uri,
                  "previous in the stack is test module");
 
   } finally {
     unload(loader);
   }
-};
+}
 
 exports['test missing module'] = function(assert) {
-  let uri = module.uri.substr(0, module.uri.lastIndexOf('/')) +
-            '/fixtures/loader/missing/'
-
+  let uri = root + '/fixtures/loader/missing/'
   let loader = Loader({ paths: { '': uri } });
 
   try {
     let program = main(loader, 'main')
   } catch (error) {
     assert.equal(error.message, "Module `not-found` is not found at " +
                 uri + "not-found.js", "throws if error not found");
 
@@ -70,18 +66,17 @@ exports['test missing module'] = functio
     assert.equal(stack.pop().fileName, module.uri,
                  "previous in the stack is test module");
   } finally {
     unload(loader);
   }
 }
 
 exports['test exceptions in modules'] = function(assert) {
-  let uri = module.uri.substr(0, module.uri.lastIndexOf('/')) +
-            '/fixtures/loader/exceptions/'
+  let uri = root + '/fixtures/loader/exceptions/'
 
   let loader = Loader({ paths: { '': uri } });
 
   try {
     let program = main(loader, 'main')
   } catch (error) {
     assert.equal(error.message, "Boom!", "thrown errors propagate");
 
@@ -107,19 +102,17 @@ exports['test exceptions in modules'] = 
     assert.equal(stack.pop().fileName, module.uri,
                  "this test module is next in the stack");
   } finally {
     unload(loader);
   }
 }
 
 exports['test early errors in module'] = function(assert) {
-  let uri = module.uri.substr(0, module.uri.lastIndexOf('/')) +
-            '/fixtures/loader/errors/'
-
+  let uri = root + '/fixtures/loader/errors/';
   let loader = Loader({ paths: { '': uri } });
 
   try {
     let program = main(loader, 'main')
   } catch (error) {
     assert.equal(String(error),
                  "Error: opening input stream (invalid filename?)",
                  "thrown errors propagate");
--- a/addon-sdk/source/test/test-net-url.js
+++ b/addon-sdk/source/test/test-net-url.js
@@ -1,16 +1,16 @@
 /* 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/. */
 
 "use strict";
 
 const { readURI, readURISync } = require("sdk/net/url");
-const { data } = require("self");
+const { data } = require("sdk/self");
 
 const utf8text = "Hello, ゼロ!";
 const latin1text = "Hello, ゼロ!";
 
 const dataURIutf8 = "data:text/plain;charset=utf-8," + encodeURIComponent(utf8text);
 const dataURIlatin1 = "data:text/plain;charset=ISO-8859-1," + escape(latin1text);
 const chromeURI = "chrome://global-platform/locale/accessible.properties";
 
--- a/addon-sdk/source/test/test-page-mod.js
+++ b/addon-sdk/source/test/test-page-mod.js
@@ -7,17 +7,17 @@ var pageMod = require("sdk/page-mod");
 var testPageMod = require("./pagemod-test-helpers").testPageMod;
 const { Loader } = require('sdk/test/loader');
 const tabs = require("sdk/tabs");
 const timer = require("sdk/timers");
 const { Cc, Ci } = require("chrome");
 const { open, getFrames, getMostRecentBrowserWindow } = require('sdk/window/utils');
 const windowUtils = require('sdk/deprecated/window-utils');
 const { getTabContentWindow, getActiveTab, openTab, closeTab } = require('sdk/tabs/utils');
-const { data } = require('self');
+const { data } = require('sdk/self');
 
 /* XXX This can be used to delay closing the test Firefox instance for interactive
  * testing or visual inspection. This test is registered first so that it runs
  * the last. */
 exports.delay = function(test) {
   if (false) {
     test.waitUntilDone(60000);
     timer.setTimeout(function() {test.done();}, 4000);
@@ -628,17 +628,17 @@ exports['test111 attachTo [frame]'] = fu
       test.pass("worker on first frame");
     else if (href == subFrameURL)
       test.pass("worker on second frame");
     else
       test.fail("worker on unexpected document: " + href);
     this.destroy();
     if (++messageCount == 2) {
       mod.destroy();
-      require('tabs').activeTab.close(function() {
+      require('sdk/tabs').activeTab.close(function() {
         test.done();
       });
     }
   }
   let mod = PageMod({
     include: 'data:text/html*',
     contentScriptWhen: 'start',
     contentScript: 'self.postMessage(document.location.href);',
@@ -787,17 +787,17 @@ exports.testPageModCssDestroy = function
     }
   );
 };
 
 exports.testPageModCssAutomaticDestroy = function(test) {
   test.waitUntilDone();
   let loader = Loader(module);
 
-  let pageMod = loader.require("page-mod").PageMod({
+  let pageMod = loader.require("sdk/page-mod").PageMod({
     include: "data:*",
     contentStyle: "div { width: 100px!important; }"
   });
 
   tabs.open({
     url: "data:text/html;charset=utf-8,<div style='width:200px'>css test</div>",
 
     onReady: function onReady(tab) {
@@ -827,17 +827,17 @@ exports.testPageModCssAutomaticDestroy =
   });
 };
 
 
 exports.testPageModTimeout = function(test) {
   test.waitUntilDone();
   let tab = null
   let loader = Loader(module);
-  let { PageMod } = loader.require("page-mod");
+  let { PageMod } = loader.require("sdk/page-mod");
 
   let mod = PageMod({
     include: "data:*",
     contentScript: Isolate(function() {
       var id = setTimeout(function() {
         self.port.emit("fired", id)
       }, 10)
       self.port.emit("scheduled", id);
@@ -862,17 +862,17 @@ exports.testPageModTimeout = function(te
   })
 }
 
 
 exports.testPageModcancelTimeout = function(test) {
   test.waitUntilDone();
   let tab = null
   let loader = Loader(module);
-  let { PageMod } = loader.require("page-mod");
+  let { PageMod } = loader.require("sdk/page-mod");
 
   let mod = PageMod({
     include: "data:*",
     contentScript: Isolate(function() {
       var id1 = setTimeout(function() {
         self.port.emit("failed")
       }, 10)
       var id2 = setTimeout(function() {
--- a/addon-sdk/source/test/test-panel.js
+++ b/addon-sdk/source/test/test-panel.js
@@ -1,16 +1,16 @@
 /* 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/. */
 
 let { Cc, Ci } = require("chrome");
 const { Loader } = require('sdk/test/loader');
 const timer = require("sdk/timers");
-const self = require('self');
+const self = require('sdk/self');
 
 exports["test Panel"] = function(assert, done) {
   const { Panel } = require('sdk/panel');
 
   let panel = Panel({
     contentURL: "about:buildconfig",
     contentScript: "self.postMessage(1); self.on('message', function() self.postMessage(2));",
     onMessage: function (message) {
--- a/addon-sdk/source/test/test-selection.js
+++ b/addon-sdk/source/test/test-selection.js
@@ -9,22 +9,26 @@ const HTML = "<html>\
     <div>foo</div>\
     <div>and</div>\
     <textarea>noodles</textarea>\
   </body>\
 </html>";
 
 const URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
 
+const FRAME_HTML = "<iframe src='" + URL + "'><iframe>";
+const FRAME_URL = "data:text/html;charset=utf-8," + encodeURIComponent(FRAME_HTML);
+
 const { defer } = require("sdk/core/promise");
 const tabs = require("sdk/tabs");
 const { getActiveTab, getTabContentWindow, closeTab } = require("sdk/tabs/utils")
 const { getMostRecentBrowserWindow } = require("sdk/window/utils");
 const { Loader } = require("sdk/test/loader");
 const { setTimeout } = require("sdk/timers");
+const { Cu } = require("chrome");
 
 // General purpose utility functions
 
 /**
  * Opens the url given and return a promise, that will be resolved with the
  * content window when the document is ready.
  *
  * I believe this approach could be useful in most of our unit test, that
@@ -78,16 +82,65 @@ function reload(window) {
   window.location.reload(true);
 
   return promise;
 }
 
 // Selection's unit test utility function
 
 /**
+ * Returns the frame's window once the document is loaded
+ */
+function getFrameWindow(window) {
+  let { promise, resolve } = defer();
+
+  let frame = window.frames[0];
+  let { document } = frame;
+
+  frame.focus();
+
+  if (document.readyState === "complete")
+    return frame;
+
+  document.addEventListener("readystatechange", function readystate() {
+    if (this.readyState === "complete") {
+      this.removeEventListener("readystatechange", readystate);
+      frame.focus();
+      resolve(frame);
+    }
+  });
+
+  return promise;
+}
+
+/**
+ * Hide the frame in order to destroy the selection object, and show it again
+ * after ~500 msec, to give time to attach the code on `document-shown`
+ * notification.
+ * In the process, call `Cu.forgeGC` to ensure that the `document-shown` code
+ * is not garbaged.
+ */
+function hideAndShowFrame(window) {
+  let { promise, resolve } = defer();
+  let iframe = window.document.querySelector("iframe");
+
+  iframe.style.display = "none";
+
+  Cu.forceGC();
+
+  setTimeout(function(){
+    iframe.style.display = "";
+
+    setTimeout(resolve, 500, window);
+  }, 0)
+
+  return promise;
+}
+
+/**
  * Select the first div in the page, adding the range to the selection.
  */
 function selectFirstDiv(window) {
   let div = window.document.querySelector("div");
   let selection = window.getSelection();
   let range = window.document.createRange();
 
   if (selection.rangeCount > 0)
@@ -169,17 +222,17 @@ function dispatchSelectionEvent(window) 
  */
 function dispatchOnSelectEvent(window) {
   let { document } = window;
   let textarea = document.querySelector("textarea");
   let event = document.createEvent("UIEvents");
 
   event.initUIEvent("select", true, true, window, 1);
 
-  textarea.dispatchEvent(event)
+  textarea.dispatchEvent(event);
 }
 
 /**
  * Creates empty ranges and add them to selections
  */
 function createEmptySelections(window) {
   selectAllDivs(window);
 
@@ -725,16 +778,52 @@ exports["test Textarea OnSelect Listener
   open(URL).
     then(reload).
     then(selectTextarea).
     then(dispatchOnSelectEvent).
     then(close).
     then(loader.unload);
 };
 
+exports["test Selection Listener on frame"] = function(assert, done) {
+  let loader = Loader(module);
+  let selection = loader.require("sdk/selection");
+
+  selection.once("select", function() {
+    assert.equal(selection.text, "fo");
+    done();
+  });
+
+  open(FRAME_URL).
+    then(hideAndShowFrame).
+    then(getFrameWindow).
+    then(selectContentFirstDiv).
+    then(dispatchSelectionEvent).
+    then(close).
+    then(loader.unload)
+};
+
+exports["test Textarea onSelect Listener on frame"] = function(assert, done) {
+  let loader = Loader(module);
+  let selection = loader.require("sdk/selection");
+
+  selection.once("select", function() {
+    assert.equal(selection.text, "noodles");
+    done();
+  });
+
+  open(FRAME_URL).
+    then(hideAndShowFrame).
+    then(getFrameWindow).
+    then(selectTextarea).
+    then(dispatchOnSelectEvent).
+    then(close).
+    then(loader.unload)
+};
+
 // TODO: test Selection Listener on long-held connection (Bug 661884)
 //
 //  I didn't find a way to do so with httpd, using `processAsync` I'm able to
 //  Keep the connection but not to flush the buffer to the client in two steps,
 //  that is what I need for this test (e.g. flush "Hello" to the client, makes
 //  selection when the connection is still hold, and check that the listener
 //  is executed before the server send "World" and close the connection).
 //
--- a/addon-sdk/source/test/test-simple-prefs.js
+++ b/addon-sdk/source/test/test-simple-prefs.js
@@ -194,28 +194,28 @@ exports.testPrefUnloadListener = functio
 };
 
 
 // Bug 710117: Test that simple-pref listeners are removed on unload
 exports.testPrefUnloadWildcardListener = function(test) {
   test.waitUntilDone();
   let testpref = "test-wildcard-unload-listener";
   let loader = Loader(module);
-  let sp = loader.require("simple-prefs");
+  let sp = loader.require("sdk/simple-prefs");
   let counter = 0;
 
   let listener = function() {
     test.assertEqual(++counter, 1, "This listener should only be called once");
 
     loader.unload();
 
     // this may not execute after unload, but definitely shouldn't fire listener
     sp.prefs[testpref] = false;
     // this should execute, but also definitely shouldn't fire listener
-    require("simple-prefs").prefs[testpref] = false;
+    require("sdk/simple-prefs").prefs[testpref] = false;
 
     test.done();
   };
 
   sp.on("", listener);
   // emit change
   sp.prefs[testpref] = true;
 };
--- a/addon-sdk/source/test/test-tab.js
+++ b/addon-sdk/source/test/test-tab.js
@@ -110,17 +110,18 @@ function step3(assert, done) {
 }
 
 exports["test behavior on close"] = function(assert, done) {
 
   tabs.open({
     url: "about:mozilla",
     onReady: function(tab) {
       assert.equal(tab.url, "about:mozilla", "Tab has the expected url");
-      assert.equal(tab.index, 1, "Tab has the expected index");
+      // if another test ends before closing a tab then index != 1 here
+      assert.ok(tab.index >= 1, "Tab has the expected index, a value greater than 0");
       tab.close(function () {
         assert.equal(tab.url, undefined,
                      "After being closed, tab attributes are undefined (url)");
         assert.equal(tab.index, undefined,
                      "After being closed, tab attributes are undefined (index)");
         // Ensure that we can call destroy multiple times without throwing
         tab.destroy();
         tab.destroy();
--- a/addon-sdk/source/test/test-url.js
+++ b/addon-sdk/source/test/test-url.js
@@ -1,14 +1,13 @@
 /* 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/. */
 
 var url = require("sdk/url");
-var { packed } = require("sdk/self");
 
 exports.testResolve = function(test) {
   test.assertEqual(url.URL("bar", "http://www.foo.com/").toString(),
                    "http://www.foo.com/bar");
 
   test.assertEqual(url.URL("bar", "http://www.foo.com"),
                    "http://www.foo.com/bar");
 
@@ -81,26 +80,16 @@ exports.testParseFTPWithUserPass = funct
 
 exports.testToFilename = function(test) {
   test.assertRaises(
     function() { url.toFilename("resource://nonexistent"); },
     "resource does not exist: resource://nonexistent/",
     "url.toFilename() on nonexistent resources should throw"
   );
 
-  if (!packed)
-    test.assertMatches(url.toFilename(module.uri),
-                       /.*test-url\.js$/,
-                       "url.toFilename() on resource: URIs should work");
-  else
-    test.assertRaises(
-      function() { url.toFilename(module.uri); },
-      "cannot map to filename: "+module.uri,
-      "url.toFilename() can fail for packed XPIs");
-
   test.assertRaises(
     function() { url.toFilename("http://foo.com/"); },
     "cannot map to filename: http://foo.com/",
     "url.toFilename() on http: URIs should raise error"
   );
 
   try {
     test.assertMatches(
--- a/addon-sdk/source/test/test-widget.js
+++ b/addon-sdk/source/test/test-widget.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Cc, Ci } = require("chrome");
 const { Loader } = require('sdk/test/loader');
 const url = require("sdk/url");
 const timer = require("sdk/timers");
-const self = require("self");
+const self = require("sdk/self");
 const windowUtils = require("sdk/deprecated/window-utils");
 
 exports.testConstructor = function(test) {
   test.waitUntilDone();
 
   let browserWindow = windowUtils.activeBrowserWindow;
   let doc = browserWindow.document;
   let AddonsMgrListener = browserWindow.AddonsMgrListener;
@@ -1024,17 +1024,17 @@ exports.testPostMessageOnLocationChange 
 };
 
 exports.testSVGWidget = function(test) {
   test.waitUntilDone();
 
   // use of capital SVG here is intended, that was failing..
   let SVG_URL = self.data.url("mofo_logo.SVG");
 
-  let widget = require("widget").Widget({
+  let widget = require("sdk/widget").Widget({
     id: "mozilla-svg-logo",
     label: "moz foundation logo",
     contentURL: SVG_URL,
     contentScript: "self.postMessage({count: window.document.images.length, src: window.document.images[0].src});",
     onMessage: function(data) {
       widget.destroy();
       test.assertEqual(data.count, 1, 'only one image');
       test.assertEqual(data.src, SVG_URL, 'only one image');
--- a/addon-sdk/source/test/windows/test-firefox-windows.js
+++ b/addon-sdk/source/test/windows/test-firefox-windows.js
@@ -5,17 +5,18 @@
 
 const { Cc, Ci } = require('chrome');
 const { setTimeout } = require('sdk/timers');
 const { Loader } = require('sdk/test/loader');
 const wm = Cc['@mozilla.org/appshell/window-mediator;1'].
            getService(Ci.nsIWindowMediator);
 
 const { browserWindows } = require("sdk/windows");
-const tabs = require("tabs");
+const tabs = require("sdk/tabs");
+const { WindowTracker } = require("sdk/deprecated/window-utils");
 
 // TEST: open & close window
 exports.testOpenAndCloseWindow = function(test) {
   test.waitUntilDone();
 
   test.assertEqual(browserWindows.length, 1, "Only one window open");
 
   browserWindows.open({
@@ -198,65 +199,74 @@ exports.testActiveWindow = function(test
   let testSteps = [
     function() {
       test.assertEqual(windows.length, 3, "Correct number of browser windows");
       let count = 0;
       for (let window in windows)
         count++;
       test.assertEqual(count, 3, "Correct number of windows returned by iterator");
 
+      test.assertEqual(windows.activeWindow.title, window3.title, "Correct active window - 3");
+
+      continueAfterFocus(rawWindow2);
       rawWindow2.focus();
-      continueAfterFocus(rawWindow2);
     },
     function() {
       nextStep();
     },
     function() {
-      /**
-       * Bug 614079: This test fails intermittently on some specific linux
-       *             environnements, without being able to reproduce it in same
-       *             distribution with same window manager.
-       *             Disable it until being able to reproduce it easily.
+      test.assertEqual(windows.activeWindow.title, window2.title, "Correct active window - 2");
 
-      // On linux, focus is not consistent, so we can't be sure
-      // what window will be on top.
-      // Here when we focus "non-browser" window,
-      // Any Browser window may be selected as "active".
-      test.assert(windows.activeWindow == window2 || windows.activeWindow == window3,
-        "Non-browser windows aren't handled by this module");
-      */
+      continueAfterFocus(rawWindow2);
       window2.activate();
-      continueAfterFocus(rawWindow2);
     },
     function() {
       test.assertEqual(windows.activeWindow.title, window2.title, "Correct active window - 2");
+      continueAfterFocus(rawWindow3);
       window3.activate();
-      continueAfterFocus(rawWindow3);
     },
     function() {
       test.assertEqual(windows.activeWindow.title, window3.title, "Correct active window - 3");
       finishTest();
     }
   ];
 
+  let newWindow = null;
+  let tracker = new WindowTracker({
+    onTrack: function(window) {
+      newWindow = window;
+    }
+  });
+
   windows.open({
     url: "data:text/html;charset=utf-8,<title>window 2</title>",
     onOpen: function(window) {
-      window2 = window;
-      rawWindow2 = wm.getMostRecentWindow("navigator:browser");
+      window.tabs.activeTab.on('ready', function() {
+        window2 = window;
+        test.assert(newWindow, "A new window was opened");
+        rawWindow2 = newWindow;
+        newWindow = null;
+        test.assertEqual(rawWindow2.content.document.title, "window 2", "Got correct raw window 2");
+        test.assertEqual(rawWindow2.document.title, window2.title, "Saw correct title on window 2");
 
-      windows.open({
-        url: "data:text/html;charset=utf-8,<title>window 3</title>",
-        onOpen: function(window) {
-          window.tabs.activeTab.on('ready', function onReady() {
-            window3 = window;
-            rawWindow3 = wm.getMostRecentWindow("navigator:browser");
-            nextStep()
-          });
-        }
+        windows.open({
+          url: "data:text/html;charset=utf-8,<title>window 3</title>",
+          onOpen: function(window) {
+            window.tabs.activeTab.on('ready', function onReady() {
+              window3 = window;
+              test.assert(newWindow, "A new window was opened");
+              rawWindow3 = newWindow;
+              tracker.unload();
+              test.assertEqual(rawWindow3.content.document.title, "window 3", "Got correct raw window 3");
+              test.assertEqual(rawWindow3.document.title, window3.title, "Saw correct title on window 3");
+              continueAfterFocus(rawWindow3);
+              rawWindow3.focus();
+            });
+          }
+        });
       });
     }
   });
 
   function nextStep() {
     if (testSteps.length > 0)
       testSteps.shift()();
   }
@@ -273,21 +283,21 @@ exports.testActiveWindow = function(test
     var focusedChildWindow = {};
     if (fm.activeWindow) {
       fm.getFocusedElementForWindow(fm.activeWindow, true, focusedChildWindow);
       focusedChildWindow = focusedChildWindow.value;
     }
 
     var focused = (focusedChildWindow == childTargetWindow);
     if (focused) {
-      nextStep();
+      setTimeout(nextStep, 0);
     } else {
       childTargetWindow.addEventListener("focus", function focusListener() {
         childTargetWindow.removeEventListener("focus", focusListener, true);
-        nextStep();
+        setTimeout(nextStep, 0);
       }, true);
     }
 
   }
 
   function finishTest() {
     window3.close(function() {
       window2.close(function() {