Bug 817881 - Move test plugin to dist/plugins, and touch up tests and test logic to support the change. r=glandium, dtownsend
authorJim Mathies <jmathies@mozilla.com>
Mon, 17 Dec 2012 12:08:00 -0600
changeset 125409 e18421c16c7a14b559638429c5119da3d3d7aed0
parent 125408 2e70b718903a88355c10e2dafa32ca746ba2e9fe
child 125410 6304fff5886683f751843ad95a614b48989f1070
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium, dtownsend
bugs817881
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 817881 - Move test plugin to dist/plugins, and touch up tests and test logic to support the change. r=glandium, dtownsend
config/makefiles/xpcshell.mk
dom/plugins/base/Makefile.in
dom/plugins/test/testplugin/testplugin.mk
dom/plugins/test/unit/head_plugins.js
js/src/config/makefiles/xpcshell.mk
js/xpconnect/shell/xpcshell.cpp
testing/mochitest/Makefile.in
testing/testsuite-targets.mk
testing/xpcshell/runxpcshelltests.py
toolkit/mozapps/extensions/test/xpcshell/test_plugins.js
--- a/config/makefiles/xpcshell.mk
+++ b/config/makefiles/xpcshell.mk
@@ -44,16 +44,17 @@ xpcshell-tests:
       -I$(DEPTH)/_tests/mozbase/mozinfo \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --tests-root-dir=$(testxpcobjdir) \
 	  --testing-modules-dir=$(DEPTH)/_tests/modules \
 	  --xunit-file=$(testxpcobjdir)/$(relativesrcdir)/results.xml \
 	  --xunit-suite-name=xpcshell \
+	  --test-plugin-path=$(DIST)/plugins \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
 xpcshell-tests-remote: DM_TRANS?=adb
 xpcshell-tests-remote:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
 	  -I$(topsrcdir)/build \
@@ -78,31 +79,33 @@ check-interactive:
 	  -I$(topsrcdir)/build \
       -I$(DEPTH)/_tests/mozbase/mozinfo \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --test-path=$(SOLO_FILE) \
 	  --testing-modules-dir=$(DEPTH)/_tests/modules \
 	  --profile-name=$(MOZ_APP_NAME) \
+	  --test-plugin-path=$(DIST)/plugins \
 	  --interactive \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
 # Execute a single test, specified in $(SOLO_FILE)
 check-one:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
 	  -I$(topsrcdir)/build \
       -I$(DEPTH)/_tests/mozbase/mozinfo \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --test-path=$(SOLO_FILE) \
 	  --testing-modules-dir=$(DEPTH)/_tests/modules \
 	  --profile-name=$(MOZ_APP_NAME) \
+	  --test-plugin-path=$(DIST)/plugins \
 	  --verbose \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
 check-one-remote: DM_TRANS?=adb
 check-one-remote:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
--- a/dom/plugins/base/Makefile.in
+++ b/dom/plugins/base/Makefile.in
@@ -114,13 +114,8 @@ LOCAL_INCLUDES += \
   $(NULL)
 
 include $(topsrcdir)/dom/dom-config.mk
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS         += $(TK_CFLAGS)
-
-$(DIST)/bin/plugins:
-	$(NSINSTALL) -D $@
-
-export:: $(DIST)/bin/plugins
--- a/dom/plugins/test/testplugin/testplugin.mk
+++ b/dom/plugins/test/testplugin/testplugin.mk
@@ -56,33 +56,36 @@ RCFILE    = nptest.rc
 RESFILE   = nptest.res
 DEFFILE   = $(win_srcdir)/nptest.def
 OS_LIBS  += $(call EXPAND_LIBNAME,msimg32)
 
 # Windows opt builds without PGO break nptest.dll
 MOZ_OPTIMIZE=
 endif
 
+TEST_PLUGIN_FILES = $(SHARED_LIBRARY)
+
+ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
+MAC_PLIST_FILES += $(srcdir)/Info.plist
+MAC_PLIST_DEST   = $(DIST)/plugins/$(COCOA_NAME).plugin/Contents
+TEST_PLUGIN_DEST = $(DIST)/plugins/$(COCOA_NAME).plugin/Contents/MacOS
+INSTALL_TARGETS += \
+	TEST_PLUGIN \
+	MAC_PLIST \
+	$(NULL)
+else
+TEST_PLUGIN_DEST = $(DIST)/plugins
+INSTALL_TARGETS += TEST_PLUGIN
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 ifndef __LP64__
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 EXTRA_DSO_LDOPTS += -framework Carbon
 endif
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 CXXFLAGS        += $(MOZ_GTK2_CFLAGS)
 CFLAGS          += $(MOZ_GTK2_CFLAGS)
 EXTRA_DSO_LDOPTS += $(MOZ_GTK2_LIBS) $(XLDFLAGS) $(XLIBS) $(XEXT_LIBS)
 endif
-
-install-plugin: $(SHARED_LIBRARY)
-ifdef SHARED_LIBRARY
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-	$(INSTALL) $(srcdir)/Info.plist $(DIST)/bin/plugins/$(COCOA_NAME).plugin/Contents
-	$(INSTALL) $(SHARED_LIBRARY) $(DIST)/bin/plugins/$(COCOA_NAME).plugin/Contents/MacOS
-else
-	$(INSTALL) $(SHARED_LIBRARY) $(DIST)/bin/plugins
-endif
-endif
-
-libs:: install-plugin
--- a/dom/plugins/test/unit/head_plugins.js
+++ b/dom/plugins/test/unit/head_plugins.js
@@ -1,33 +1,34 @@
 /* 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/.
  */
 
 // Finds the test plugin library
 function get_test_plugin() {
-  var plugins = gDirSvc.get("GreD", Ci.nsILocalFile);
-  plugins.append("plugins");
-  do_check_true(plugins.exists());
-  var plugin = plugins.clone();
-  // OSX plugin
-  plugin.append("Test.plugin");
-  if (plugin.exists()) {
-    plugin.normalize();
-    return plugin;
-  }
-  plugin = plugins.clone();
-  // *nix plugin
-  plugin.append("libnptest.so");
-  if (plugin.exists()) {
-    plugin.normalize();
-    return plugin;
-  }
-  // Windows plugin
-  plugin = plugins.clone();
-  plugin.append("nptest.dll");
-  if (plugin.exists()) {
-    plugin.normalize();
-    return plugin;
+  var pluginEnum = gDirSvc.get("APluginsDL", Ci.nsISimpleEnumerator);
+  while (pluginEnum.hasMoreElements()) {
+    let dir = pluginEnum.getNext().QueryInterface(Ci.nsILocalFile);
+    let plugin = dir.clone();
+    // OSX plugin
+    plugin.append("Test.plugin");
+    if (plugin.exists()) {
+      plugin.normalize();
+      return plugin;
+    }
+    plugin = dir.clone();
+    // *nix plugin
+    plugin.append("libnptest.so");
+    if (plugin.exists()) {
+      plugin.normalize();
+      return plugin;
+    }
+    // Windows plugin
+    plugin = dir.clone();
+    plugin.append("nptest.dll");
+    if (plugin.exists()) {
+      plugin.normalize();
+      return plugin;
+    }
   }
   return null;
 }
--- a/js/src/config/makefiles/xpcshell.mk
+++ b/js/src/config/makefiles/xpcshell.mk
@@ -44,16 +44,17 @@ xpcshell-tests:
       -I$(DEPTH)/_tests/mozbase/mozinfo \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --tests-root-dir=$(testxpcobjdir) \
 	  --testing-modules-dir=$(DEPTH)/_tests/modules \
 	  --xunit-file=$(testxpcobjdir)/$(relativesrcdir)/results.xml \
 	  --xunit-suite-name=xpcshell \
+	  --test-plugin-path=$(DIST)/plugins \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
 xpcshell-tests-remote: DM_TRANS?=adb
 xpcshell-tests-remote:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
 	  -I$(topsrcdir)/build \
@@ -78,31 +79,33 @@ check-interactive:
 	  -I$(topsrcdir)/build \
       -I$(DEPTH)/_tests/mozbase/mozinfo \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --test-path=$(SOLO_FILE) \
 	  --testing-modules-dir=$(DEPTH)/_tests/modules \
 	  --profile-name=$(MOZ_APP_NAME) \
+	  --test-plugin-path=$(DIST)/plugins \
 	  --interactive \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
 # Execute a single test, specified in $(SOLO_FILE)
 check-one:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
 	  -I$(topsrcdir)/build \
       -I$(DEPTH)/_tests/mozbase/mozinfo \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --test-path=$(SOLO_FILE) \
 	  --testing-modules-dir=$(DEPTH)/_tests/modules \
 	  --profile-name=$(MOZ_APP_NAME) \
+	  --test-plugin-path=$(DIST)/plugins \
 	  --verbose \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
 check-one-remote: DM_TRANS?=adb
 check-one-remote:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -99,20 +99,24 @@ public:
     bool SetGREDir(const char *dir);
     void ClearGREDir() { mGREDir = nullptr; }
     // The application resource folder
     void SetAppDir(nsIFile *appFile);
     void ClearAppDir() { mAppDir = nullptr; }
     // The app executable
     void SetAppFile(nsIFile *appFile);
     void ClearAppFile() { mAppFile = nullptr; }
+    // An additional custom plugin dir if specified
+    void SetPluginDir(nsIFile* pluginDir);
+    void ClearPluginDir() { mPluginDir = nullptr; }
 
 private:
     nsCOMPtr<nsIFile> mGREDir;
     nsCOMPtr<nsIFile> mAppDir;
+    nsCOMPtr<nsIFile> mPluginDir;
     nsCOMPtr<nsIFile> mAppFile;
 };
 
 /***************************************************************************/
 
 #ifdef JS_THREADSAFE
 #define DoBeginRequest(cx) JS_BeginRequest((cx))
 #define DoEndRequest(cx)   JS_EndRequest((cx))
@@ -1168,17 +1172,17 @@ ProcessArgsForCompartment(JSContext *cx,
         case 'n':
             JS_ToggleOptions(cx, JSOPTION_TYPE_INFERENCE);
             break;
         }
     }
 }
 
 static int
-ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
+ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc, XPCShellDirProvider* aDirProvider)
 {
     const char rcfilename[] = "xpcshell.js";
     FILE *rcfile;
     int i;
     JSObject *argsObj;
     char *filename = NULL;
     JSBool isInteractive = true;
     JSBool forceTTY = false;
@@ -1292,16 +1296,28 @@ ProcessArgs(JSContext *cx, JSObject *obj
             break;
         case 'S':
         case 's':
         case 'm':
         case 'I':
         case 'n':
             // These options are processed in ProcessArgsForCompartment.
             break;
+        case 'p':
+        {
+          // plugins path
+          char *pluginPath = argv[++i];
+          nsCOMPtr<nsIFile> pluginsDir;
+          if (NS_FAILED(XRE_GetFileFromPath(pluginPath, getter_AddRefs(pluginsDir)))) {
+              fprintf(gErrFile, "Couldn't use given plugins dir.\n");
+              return usage();
+          }
+          aDirProvider->SetPluginDir(pluginsDir);
+          break;
+        }
         default:
             return usage();
         }
     }
 
     if (filename || isInteractive)
         Process(cx, obj, filename, forceTTY);
     return gExitCode;
@@ -1924,17 +1940,17 @@ main(int argc, char **argv, char **envp)
 
             nsAutoString workingDirectory;
             if (GetCurrentWorkingDirectory(workingDirectory))
                 gWorkingDirectory = &workingDirectory;
 
             JS_DefineProperty(cx, glob, "__LOCATION__", JSVAL_VOID,
                               GetLocationProperty, NULL, 0);
 
-            result = ProcessArgs(cx, glob, argv, argc);
+            result = ProcessArgs(cx, glob, argv, argc, &dirprovider);
 
 
 //#define TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN 1
 
 #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN
             // test of late call and release (see below)
             nsCOMPtr<nsIJSContextStack> bogus;
             xpc->WrapJS(cx, glob, NS_GET_IID(nsIJSContextStack),
@@ -1973,16 +1989,17 @@ main(int argc, char **argv, char **envp)
     bogus->Peek(&bogusCX);
     bogus = nullptr;
 #endif
 
     appDir = nullptr;
     appFile = nullptr;
     dirprovider.ClearGREDir();
     dirprovider.ClearAppDir();
+    dirprovider.ClearPluginDir();
     dirprovider.ClearAppFile();
 
 #ifdef MOZ_CRASHREPORTER
     // Shut down the crashreporter service to prevent leaking some strings it holds.
     if (crashReporter) {
         crashReporter->SetEnabled(false);
         crashReporter = nullptr;
     }
@@ -2011,16 +2028,22 @@ XPCShellDirProvider::SetAppFile(nsIFile*
 }
 
 void
 XPCShellDirProvider::SetAppDir(nsIFile* appDir)
 {
     mAppDir = appDir;
 }
 
+void
+XPCShellDirProvider::SetPluginDir(nsIFile* pluginDir)
+{
+    mPluginDir = pluginDir;
+}
+
 NS_IMETHODIMP_(nsrefcnt)
 XPCShellDirProvider::AddRef()
 {
     return 2;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
 XPCShellDirProvider::Release()
@@ -2121,18 +2144,32 @@ XPCShellDirProvider::GetFiles(const char
             NS_SUCCEEDED(mAppDir->Clone(getter_AddRefs(appDir))) &&
             NS_SUCCEEDED(appDir->AppendNative(NS_LITERAL_CSTRING("defaults"))) &&
             NS_SUCCEEDED(appDir->AppendNative(NS_LITERAL_CSTRING("preferences"))) &&
             NS_SUCCEEDED(appDir->Exists(&exists)) && exists) {
             dirs.AppendObject(appDir);
             return NS_NewArrayEnumerator(result, dirs);
         }
         return NS_ERROR_FAILURE;
-    } else if (mGREDir && !strcmp(prop, NS_APP_PLUGINS_DIR_LIST)) {
+    } else if (!strcmp(prop, NS_APP_PLUGINS_DIR_LIST)) {
         nsCOMPtr<nsIFile> file;
-        mGREDir->Clone(getter_AddRefs(file));
-        file->AppendNative(NS_LITERAL_CSTRING("plugins"));
         nsCOMArray<nsIFile> dirs;
-        dirs.AppendObject(file);
+        bool exists;
+        // We have to add this path, buildbot copies the test plugin directory
+        // to (app)/bin when unpacking test zips.
+        if (mGREDir) {
+            mGREDir->Clone(getter_AddRefs(file));
+            if (NS_SUCCEEDED(mGREDir->Clone(getter_AddRefs(file)))) {
+                file->AppendNative(NS_LITERAL_CSTRING("plugins"));
+                if (NS_SUCCEEDED(file->Exists(&exists)) && exists) {
+                    dirs.AppendObject(file);
+                }
+            }
+        }
+        // Add the test plugin location passed in by the caller or through
+        // runxpcshelltests.
+        if (mPluginDir) {
+            dirs.AppendObject(mPluginDir);
+        }
         return NS_NewArrayEnumerator(result, dirs);
     }
     return NS_ERROR_FAILURE;
 }
--- a/testing/mochitest/Makefile.in
+++ b/testing/mochitest/Makefile.in
@@ -195,14 +195,14 @@ endif
 
 stage-package: stage-chromejar
 endif
 
 $(_DEST_DIR):
 	$(NSINSTALL) -D $@
 
 stage-package:
-	$(NSINSTALL) -D $(PKG_STAGE)/mochitest && $(NSINSTALL) -D $(PKG_STAGE)/bin/plugins
+	$(NSINSTALL) -D $(PKG_STAGE)/mochitest && $(NSINSTALL) -D $(PKG_STAGE)/bin/plugins && $(NSINSTALL) -D $(DIST)/plugins
 	(cd $(DEPTH)/_tests/testing/mochitest/ && tar $(TAR_CREATE_FLAGS_QUIET) - *) | (cd $(PKG_STAGE)/mochitest && tar -xf -)
 	@(cd $(DIST_BIN) && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_BINS)) | (cd $(PKG_STAGE)/bin && tar -xf -)
 	@(cd $(DIST_BIN)/components && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_COMPONENTS)) | (cd $(PKG_STAGE)/bin/components && tar -xf -)
 	(cd $(topsrcdir)/build/pgo/certs && tar $(TAR_CREATE_FLAGS_QUIET) - *) | (cd $(PKG_STAGE)/certs && tar -xf -)
-	@(cd $(DIST_BIN)/plugins && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_PLUGINS)) | (cd $(PKG_STAGE)/bin/plugins && tar -xf -)
+	@(cd $(DIST)/plugins && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_PLUGINS)) | (cd $(PKG_STAGE)/bin/plugins && tar -xf -)
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -28,24 +28,26 @@ TEST_PACKAGE_NAME := $(ANDROID_PACKAGE_N
 endif
 
 RUN_MOCHITEST = \
   rm -f ./$@.log && \
   $(PYTHON) _tests/testing/mochitest/runtests.py --autorun --close-when-done \
     --console-level=INFO --log-file=./$@.log --file-level=INFO \
     --failure-file=$(call core_abspath,_tests/testing/mochitest/makefailures.json) \
     --testing-modules-dir=$(call core_abspath,_tests/modules) \
+    --extra-profile-file=$(DIST)/plugins \
     $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
 
 RERUN_MOCHITEST = \
   rm -f ./$@.log && \
   $(PYTHON) _tests/testing/mochitest/runtests.py --autorun --close-when-done \
     --console-level=INFO --log-file=./$@.log --file-level=INFO \
     --run-only-tests=makefailures.json \
     --testing-modules-dir=$(call core_abspath,_tests/modules) \
+    --extra-profile-file=$(DIST)/plugins \
     $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
 
 RUN_MOCHITEST_REMOTE = \
   rm -f ./$@.log && \
   $(PYTHON) _tests/testing/mochitest/runtestsremote.py --autorun --close-when-done \
     --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=$(DM_TRANS) \
     --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \
     --testing-modules-dir=$(call core_abspath,_tests/modules) \
@@ -148,16 +150,17 @@ webapprt-test-content:
 	$(CHECK_TEST_ERROR)
 webapprt-test-chrome:
 	$(RUN_MOCHITEST) --webapprt-chrome --appname $(webapprt_stub_path) --browser-arg -test-mode
 	$(CHECK_TEST_ERROR)
 endif
 
 # Usage: |make [EXTRA_TEST_ARGS=...] *test|.
 RUN_REFTEST = rm -f ./$@.log && $(PYTHON) _tests/reftest/runreftest.py \
+  --extra-profile-file=$(DIST)/plugins \
   $(SYMBOLS_PATH) $(EXTRA_TEST_ARGS) $(1) | tee ./$@.log
 
 REMOTE_REFTEST = rm -f ./$@.log && $(PYTHON) _tests/reftest/remotereftest.py \
   --dm_trans=$(DM_TRANS) --ignore-window-size \
   --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \
   $(SYMBOLS_PATH) $(EXTRA_TEST_ARGS) $(1) | tee ./$@.log
 
 RUN_REFTEST_B2G = rm -f ./$@.log && $(PYTHON) _tests/reftest/runreftestb2g.py \
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -216,16 +216,19 @@ class XPCShellTests(object):
             'const _TESTING_MODULES_DIR = "%s";' % sanitized
         ])
 
     self.xpcsCmd.extend(['-f', os.path.join(self.testharnessdir, 'head.js')])
 
     if self.debuggerInfo:
       self.xpcsCmd = [self.debuggerInfo["path"]] + self.debuggerInfo["args"] + self.xpcsCmd
 
+    if self.pluginsPath:
+      self.xpcsCmd.extend(['-p', os.path.abspath(self.pluginsPath)])
+
   def buildTestPath(self):
     """
       If we specifiy a testpath, set the self.testPath variable to be the given directory or file.
 
       |testPath| will be the optional path only, or |None|.
       |singleFile| will be the optional test only, or |None|.
     """
     self.singleFile = None
@@ -604,29 +607,32 @@ class XPCShellTests(object):
 
   def runTests(self, xpcshell, xrePath=None, appPath=None, symbolsPath=None,
                manifest=None, testdirs=None, testPath=None,
                interactive=False, verbose=False, keepGoing=False, logfiles=True,
                thisChunk=1, totalChunks=1, debugger=None,
                debuggerArgs=None, debuggerInteractive=False,
                profileName=None, mozInfo=None, shuffle=False,
                testsRootDir=None, xunitFilename=None, xunitName=None,
-               testingModulesDir=None, autolog=False, **otherOptions):
+               testingModulesDir=None, autolog=False, pluginsPath=None,
+               **otherOptions):
     """Run xpcshell tests.
 
     |xpcshell|, is the xpcshell executable to use to run the tests.
     |xrePath|, if provided, is the path to the XRE to use.
     |appPath|, if provided, is the path to an application directory.
     |symbolsPath|, if provided is the path to a directory containing
       breakpad symbols for processing crashes in tests.
     |manifest|, if provided, is a file containing a list of
       test directories to run.
     |testdirs|, if provided, is a list of absolute paths of test directories.
       No-manifest only option.
     |testPath|, if provided, indicates a single path and/or test to run.
+    |pluginsPath|, if provided, custom plugins directory to be returned from
+      the xpcshell dir svc provider for NS_APP_PLUGINS_DIR_LIST.
     |interactive|, if set to True, indicates to provide an xpcshell prompt
       instead of automatically executing the test.
     |verbose|, if set to True, will cause stdout/stderr from tests to
       be printed always
     |logfiles|, if set to False, indicates not to save output to log files.
       Non-interactive only option.
     |debuggerInfo|, if set, specifies the debugger and debugger arguments
       that will be used to launch xpcshell.
@@ -697,16 +703,17 @@ class XPCShellTests(object):
     self.keepGoing = keepGoing
     self.logfiles = logfiles
     self.totalChunks = totalChunks
     self.thisChunk = thisChunk
     self.debuggerInfo = getDebuggerInfo(self.oldcwd, debugger, debuggerArgs, debuggerInteractive)
     self.profileName = profileName or "xpcshell"
     self.mozInfo = mozInfo
     self.testingModulesDir = testingModulesDir
+    self.pluginsPath = pluginsPath
 
     # If we have an interactive debugger, disable ctrl-c.
     if self.debuggerInfo and self.debuggerInfo["interactive"]:
         signal.signal(signal.SIGINT, lambda signum, frame: None)
 
     if not testdirs and not manifest:
       # nothing to test!
       self.log.error("Error: No test dirs or test manifest specified!")
@@ -1028,16 +1035,21 @@ class XPCShellOptions(OptionParser):
                     type="string", dest="testPath", default=None,
                     help="single path and/or test filename to test")
     self.add_option("--tests-root-dir",
                     type="string", dest="testsRootDir", default=None,
                     help="absolute path to directory where all tests are located. this is typically $(objdir)/_tests")
     self.add_option("--testing-modules-dir",
                     dest="testingModulesDir", default=None,
                     help="Directory where testing modules are located.")
+    self.add_option("--test-plugin-path",
+                    type="string", dest="pluginsPath", default=None,
+                    help="Path to the location of a plugins directory containing the test plugin or plugins required for tests. "
+                         "By default xpcshell's dir svc provider returns gre/plugins. Use test-plugin-path to add a directory "
+                         "to return for NS_APP_PLUGINS_DIR_LIST when queried.")
     self.add_option("--total-chunks",
                     type = "int", dest = "totalChunks", default=1,
                     help = "how many chunks to split the tests up into")
     self.add_option("--this-chunk",
                     type = "int", dest = "thisChunk", default=1,
                     help = "which chunk to run between 1 and --total-chunks")
     self.add_option("--profile-name",
                     type = "string", dest="profileName", default=None,
--- a/toolkit/mozapps/extensions/test/xpcshell/test_plugins.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_plugins.js
@@ -13,38 +13,41 @@ function run_test() {
   AddonManager.addAddonListener(AddonListener);
   AddonManager.addInstallListener(InstallListener);
 
   run_test_1();
 }
 
 // Finds the test plugin library
 function get_test_plugin() {
-  var plugins = Services.dirsvc.get("GreD", AM_Ci.nsIFile);
-  plugins.append("plugins");
-  do_check_true(plugins.exists());
-
-  var plugin = plugins.clone();
-  // OSX plugin
-  plugin.append("Test.plugin");
-  if (plugin.exists())
-    return plugin;
-
-  plugin = plugins.clone();
-  // *nix plugin
-  plugin.append("libnptest.so");
-  if (plugin.exists())
-    return plugin;
-
-  // Windows plugin
-  plugin = plugins.clone();
-  plugin.append("nptest.dll");
-  if (plugin.exists())
-    return plugin;
-
+  var pluginEnum = Services.dirsvc.get("APluginsDL", AM_Ci.nsISimpleEnumerator);
+  while (pluginEnum.hasMoreElements()) {
+    let dir = pluginEnum.getNext().QueryInterface(AM_Ci.nsILocalFile);
+    let plugin = dir.clone();
+    // OSX plugin
+    plugin.append("Test.plugin");
+    if (plugin.exists()) {
+      plugin.normalize();
+      return plugin;
+    }
+    plugin = dir.clone();
+    // *nix plugin
+    plugin.append("libnptest.so");
+    if (plugin.exists()) {
+      plugin.normalize();
+      return plugin;
+    }
+    // Windows plugin
+    plugin = dir.clone();
+    plugin.append("nptest.dll");
+    if (plugin.exists()) {
+      plugin.normalize();
+      return plugin;
+    }
+  }
   return null;
 }
 
 function getFileSize(aFile) {
   if (!aFile.isDirectory())
     return aFile.fileSize;
 
   let size = 0;
@@ -90,30 +93,16 @@ function run_test_1() {
       do_check_eq(p.blocklistState, 0);
       do_check_eq(p.permissions, AddonManager.PERM_CAN_DISABLE);
       do_check_eq(p.pendingOperations, 0);
       do_check_true(p.size > 0);
       do_check_eq(p.size, getFileSize(testPlugin));
       do_check_true(p.updateDate > 0);
       do_check_eq(p.updateDate.getTime(), testPlugin.lastModifiedTime);
       do_check_eq(p.installDate.getTime(), testPlugin.lastModifiedTime);
-
-      // Work around the fact that on Linux source builds, if we're using
-      // symlinks (i.e. objdir), then Linux will see these as a different scope
-      // to non-symlinks.
-      // See Bug 562886 and Bug 568027.
-      if (testPlugin.isSymlink()) {
-        do_check_neq(p.scope, AddonManager.SCOPE_APPLICATION);
-        do_check_neq(p.scope, AddonManager.SCOPE_PROFILE);
-      } else {
-        // XXX Prior to landing bug 755724 on mc this will be application,
-        // afterward it will be system.
-        do_check_true(p.scope == AddonManager.SCOPE_APPLICATION ||
-                      p.scope == AddonManager.SCOPE_SYSTEM);
-      }
       do_check_true("isCompatibleWith" in p);
       do_check_true("findUpdates" in p);
 
       run_test_2(p);
     });
   });
 }