summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2018-02-09 11:10:00 -0500
committerMatt A. Tobin <email@mattatobin.com>2018-02-09 11:10:00 -0500
commitf164d9124708b50789dbb6959e1de96cc5697c48 (patch)
tree6dffd12e08c5383130df0252fb69cd6d6330794f /toolkit/components/extensions/test/xpcshell
parent30de4018913f0cdaea19d1dd12ecd8209e2ed08e (diff)
downloadUXP-f164d9124708b50789dbb6959e1de96cc5697c48.tar
UXP-f164d9124708b50789dbb6959e1de96cc5697c48.tar.gz
UXP-f164d9124708b50789dbb6959e1de96cc5697c48.tar.lz
UXP-f164d9124708b50789dbb6959e1de96cc5697c48.tar.xz
UXP-f164d9124708b50789dbb6959e1de96cc5697c48.zip
Rename Toolkit's webextensions component directory to better reflect what it is.
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell')
-rw-r--r--toolkit/components/extensions/test/xpcshell/.eslintrc.js9
-rw-r--r--toolkit/components/extensions/test/xpcshell/data/file_download.html12
-rw-r--r--toolkit/components/extensions/test/xpcshell/data/file_download.txt1
-rw-r--r--toolkit/components/extensions/test/xpcshell/head.js111
-rw-r--r--toolkit/components/extensions/test/xpcshell/head_native_messaging.js131
-rw-r--r--toolkit/components/extensions/test/xpcshell/head_sync.js67
-rw-r--r--toolkit/components/extensions/test/xpcshell/native_messaging.ini13
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_csp_custom_policies.js38
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_csp_validator.js85
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_alarms.js210
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_alarms_does_not_fire.js33
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_alarms_periodic.js44
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_alarms_replaces.js44
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_api_permissions.js64
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_apimanager.js91
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_background_generated_load_events.js23
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_background_generated_reload.js24
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_background_global_history.js22
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_background_private_browsing.js40
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js72
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_background_sub_windows.js45
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_background_window_properties.js34
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_contexts.js190
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_downloads.js76
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js354
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js862
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_downloads_search.js402
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_experiments.js175
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_extension.js55
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_idle.js202
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_json_parser.js37
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_context.js168
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_embedding.js188
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_localStorage.js50
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_management.js20
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_management_uninstall_self.js135
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_manifest_content_security_policy.js30
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_manifest_incognito.js27
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_manifest_minimum_chrome_version.js13
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js514
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_perf.js128
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_unresponsive.js82
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js30
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js23
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_runtime_getBrowserInfo.js26
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js25
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js337
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js79
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_errors.js59
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js54
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_self.js51
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_schemas.js1427
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_schemas_allowed_contexts.js147
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_schemas_api_injection.js102
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_schemas_async.js232
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_simple.js69
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_storage.js334
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_topSites.js85
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_getAPILevelForWindow.js55
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_locale_converter.js133
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_locale_data.js130
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_native_messaging.js302
-rw-r--r--toolkit/components/extensions/test/xpcshell/xpcshell.ini69
63 files changed, 0 insertions, 8690 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/.eslintrc.js b/toolkit/components/extensions/test/xpcshell/.eslintrc.js
deleted file mode 100644
index 3758537ef..000000000
--- a/toolkit/components/extensions/test/xpcshell/.eslintrc.js
+++ /dev/null
@@ -1,9 +0,0 @@
-"use strict";
-
-module.exports = { // eslint-disable-line no-undef
- "extends": "../../../../../testing/xpcshell/xpcshell.eslintrc.js",
-
- "globals": {
- "browser": false,
- },
-};
diff --git a/toolkit/components/extensions/test/xpcshell/data/file_download.html b/toolkit/components/extensions/test/xpcshell/data/file_download.html
deleted file mode 100644
index d970c6325..000000000
--- a/toolkit/components/extensions/test/xpcshell/data/file_download.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE HTML>
-
-<html>
-<head>
-<meta charset="utf-8">
-</head>
-<body>
-
-<div>Download HTML File</div>
-
-</body>
-</html>
diff --git a/toolkit/components/extensions/test/xpcshell/data/file_download.txt b/toolkit/components/extensions/test/xpcshell/data/file_download.txt
deleted file mode 100644
index 6293c7af7..000000000
--- a/toolkit/components/extensions/test/xpcshell/data/file_download.txt
+++ /dev/null
@@ -1 +0,0 @@
-This is a sample file used in download tests.
diff --git a/toolkit/components/extensions/test/xpcshell/head.js b/toolkit/components/extensions/test/xpcshell/head.js
deleted file mode 100644
index 9e22be6da..000000000
--- a/toolkit/components/extensions/test/xpcshell/head.js
+++ /dev/null
@@ -1,111 +0,0 @@
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-/* exported createHttpServer, promiseConsoleOutput, cleanupDir */
-
-Components.utils.import("resource://gre/modules/Task.jsm");
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-Components.utils.import("resource://gre/modules/Timer.jsm");
-Components.utils.import("resource://testing-common/AddonTestUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
- "resource://gre/modules/AppConstants.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Extension",
- "resource://gre/modules/Extension.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData",
- "resource://gre/modules/Extension.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
- "resource://gre/modules/ExtensionManagement.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils",
- "resource://testing-common/ExtensionXPCShellUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
- "resource://gre/modules/FileUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
- "resource://testing-common/httpd.js");
-XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
- "resource://gre/modules/NetUtil.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
- "resource://gre/modules/Schemas.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
- "resource://gre/modules/Services.jsm");
-
-ExtensionTestUtils.init(this);
-
-/**
- * Creates a new HttpServer for testing, and begins listening on the
- * specified port. Automatically shuts down the server when the test
- * unit ends.
- *
- * @param {integer} [port]
- * The port to listen on. If omitted, listen on a random
- * port. The latter is the preferred behavior.
- *
- * @returns {HttpServer}
- */
-function createHttpServer(port = -1) {
- let server = new HttpServer();
- server.start(port);
-
- do_register_cleanup(() => {
- return new Promise(resolve => {
- server.stop(resolve);
- });
- });
-
- return server;
-}
-
-var promiseConsoleOutput = Task.async(function* (task) {
- const DONE = `=== console listener ${Math.random()} done ===`;
-
- let listener;
- let messages = [];
- let awaitListener = new Promise(resolve => {
- listener = msg => {
- if (msg == DONE) {
- resolve();
- } else {
- void (msg instanceof Ci.nsIConsoleMessage);
- messages.push(msg);
- }
- };
- });
-
- Services.console.registerListener(listener);
- try {
- let result = yield task();
-
- Services.console.logStringMessage(DONE);
- yield awaitListener;
-
- return {messages, result};
- } finally {
- Services.console.unregisterListener(listener);
- }
-});
-
-// Attempt to remove a directory. If the Windows OS is still using the
-// file sometimes remove() will fail. So try repeatedly until we can
-// remove it or we give up.
-function cleanupDir(dir) {
- let count = 0;
- return new Promise((resolve, reject) => {
- function tryToRemoveDir() {
- count += 1;
- try {
- dir.remove(true);
- } catch (e) {
- // ignore
- }
- if (!dir.exists()) {
- return resolve();
- }
- if (count >= 25) {
- return reject(`Failed to cleanup directory: ${dir}`);
- }
- setTimeout(tryToRemoveDir, 100);
- }
- tryToRemoveDir();
- });
-}
diff --git a/toolkit/components/extensions/test/xpcshell/head_native_messaging.js b/toolkit/components/extensions/test/xpcshell/head_native_messaging.js
deleted file mode 100644
index f7c619b76..000000000
--- a/toolkit/components/extensions/test/xpcshell/head_native_messaging.js
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-/* globals AppConstants, FileUtils */
-/* exported getSubprocessCount, setupHosts, waitForSubprocessExit */
-
-XPCOMUtils.defineLazyModuleGetter(this, "MockRegistry",
- "resource://testing-common/MockRegistry.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
- "resource://gre/modules/Timer.jsm");
-
-let {Subprocess, SubprocessImpl} = Cu.import("resource://gre/modules/Subprocess.jsm");
-
-
-// It's important that we use a space in this directory name to make sure we
-// correctly handle executing batch files with spaces in their path.
-let tmpDir = FileUtils.getDir("TmpD", ["Native Messaging"]);
-tmpDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
-
-do_register_cleanup(() => {
- tmpDir.remove(true);
-});
-
-function getPath(filename) {
- return OS.Path.join(tmpDir.path, filename);
-}
-
-const ID = "native@tests.mozilla.org";
-
-
-function* setupHosts(scripts) {
- const PERMS = {unixMode: 0o755};
-
- const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
- const pythonPath = yield Subprocess.pathSearch(env.get("PYTHON"));
-
- function* writeManifest(script, scriptPath, path) {
- let body = `#!${pythonPath} -u\n${script.script}`;
-
- yield OS.File.writeAtomic(scriptPath, body);
- yield OS.File.setPermissions(scriptPath, PERMS);
-
- let manifest = {
- name: script.name,
- description: script.description,
- path,
- type: "stdio",
- allowed_extensions: [ID],
- };
-
- let manifestPath = getPath(`${script.name}.json`);
- yield OS.File.writeAtomic(manifestPath, JSON.stringify(manifest));
-
- return manifestPath;
- }
-
- switch (AppConstants.platform) {
- case "macosx":
- case "linux":
- let dirProvider = {
- getFile(property) {
- if (property == "XREUserNativeMessaging") {
- return tmpDir.clone();
- } else if (property == "XRESysNativeMessaging") {
- return tmpDir.clone();
- }
- return null;
- },
- };
-
- Services.dirsvc.registerProvider(dirProvider);
- do_register_cleanup(() => {
- Services.dirsvc.unregisterProvider(dirProvider);
- });
-
- for (let script of scripts) {
- let path = getPath(`${script.name}.py`);
-
- yield writeManifest(script, path, path);
- }
- break;
-
- case "win":
- const REGKEY = String.raw`Software\Mozilla\NativeMessagingHosts`;
-
- let registry = new MockRegistry();
- do_register_cleanup(() => {
- registry.shutdown();
- });
-
- for (let script of scripts) {
- // It's important that we use a space in this filename. See directory
- // name comment above.
- let batPath = getPath(`batch ${script.name}.bat`);
- let scriptPath = getPath(`${script.name}.py`);
-
- let batBody = `@ECHO OFF\n${pythonPath} -u "${scriptPath}" %*\n`;
- yield OS.File.writeAtomic(batPath, batBody);
-
- // Create absolute and relative path versions of the entry.
- for (let [name, path] of [[script.name, batPath],
- [`relative.${script.name}`, OS.Path.basename(batPath)]]) {
- script.name = name;
- let manifestPath = yield writeManifest(script, scriptPath, path);
-
- registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
- `${REGKEY}\\${script.name}`, "", manifestPath);
- }
- }
- break;
-
- default:
- ok(false, `Native messaging is not supported on ${AppConstants.platform}`);
- }
-}
-
-
-function getSubprocessCount() {
- return SubprocessImpl.Process.getWorker().call("getProcesses", [])
- .then(result => result.size);
-}
-function waitForSubprocessExit() {
- return SubprocessImpl.Process.getWorker().call("waitForNoProcesses", []).then(() => {
- // Return to the main event loop to give IO handlers enough time to consume
- // their remaining buffered input.
- return new Promise(resolve => setTimeout(resolve, 0));
- });
-}
diff --git a/toolkit/components/extensions/test/xpcshell/head_sync.js b/toolkit/components/extensions/test/xpcshell/head_sync.js
deleted file mode 100644
index 9b66b78e7..000000000
--- a/toolkit/components/extensions/test/xpcshell/head_sync.js
+++ /dev/null
@@ -1,67 +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";
-
-/* exported withSyncContext */
-
-Components.utils.import("resource://gre/modules/Services.jsm", this);
-Components.utils.import("resource://gre/modules/ExtensionCommon.jsm", this);
-
-var {
- BaseContext,
-} = ExtensionCommon;
-
-class Context extends BaseContext {
- constructor(principal) {
- super();
- Object.defineProperty(this, "principal", {
- value: principal,
- configurable: true,
- });
- this.sandbox = Components.utils.Sandbox(principal, {wantXrays: false});
- this.extension = {id: "test@web.extension"};
- }
-
- get cloneScope() {
- return this.sandbox;
- }
-}
-
-/**
- * Call the given function with a newly-constructed context.
- * Unload the context on the way out.
- *
- * @param {function} f the function to call
- */
-function* withContext(f) {
- const ssm = Services.scriptSecurityManager;
- const PRINCIPAL1 = ssm.createCodebasePrincipalFromOrigin("http://www.example.org");
- const context = new Context(PRINCIPAL1);
- try {
- yield* f(context);
- } finally {
- yield context.unload();
- }
-}
-
-/**
- * Like withContext(), but also turn on the "storage.sync" pref for
- * the duration of the function.
- * Calls to this function can be replaced with calls to withContext
- * once the pref becomes on by default.
- *
- * @param {function} f the function to call
- */
-function* withSyncContext(f) {
- const STORAGE_SYNC_PREF = "webextensions.storage.sync.enabled";
- let prefs = Services.prefs;
-
- try {
- prefs.setBoolPref(STORAGE_SYNC_PREF, true);
- yield* withContext(f);
- } finally {
- prefs.clearUserPref(STORAGE_SYNC_PREF);
- }
-}
diff --git a/toolkit/components/extensions/test/xpcshell/native_messaging.ini b/toolkit/components/extensions/test/xpcshell/native_messaging.ini
deleted file mode 100644
index d0e1da163..000000000
--- a/toolkit/components/extensions/test/xpcshell/native_messaging.ini
+++ /dev/null
@@ -1,13 +0,0 @@
-[DEFAULT]
-head = head.js head_native_messaging.js
-tail =
-firefox-appdir = browser
-skip-if = appname == "thunderbird" || os == "android"
-subprocess = true
-support-files =
- data/**
-tags = webextensions
-
-[test_ext_native_messaging.js]
-[test_ext_native_messaging_perf.js]
-[test_ext_native_messaging_unresponsive.js]
diff --git a/toolkit/components/extensions/test/xpcshell/test_csp_custom_policies.js b/toolkit/components/extensions/test/xpcshell/test_csp_custom_policies.js
deleted file mode 100644
index b6213baac..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_csp_custom_policies.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-Cu.import("resource://gre/modules/Preferences.jsm");
-
-const ADDON_ID = "test@web.extension";
-
-const aps = Cc["@mozilla.org/addons/policy-service;1"]
- .getService(Ci.nsIAddonPolicyService).wrappedJSObject;
-
-do_register_cleanup(() => {
- aps.setAddonCSP(ADDON_ID, null);
-});
-
-add_task(function* test_addon_csp() {
- equal(aps.baseCSP, Preferences.get("extensions.webextensions.base-content-security-policy"),
- "Expected base CSP value");
-
- equal(aps.defaultCSP, Preferences.get("extensions.webextensions.default-content-security-policy"),
- "Expected default CSP value");
-
- equal(aps.getAddonCSP(ADDON_ID), aps.defaultCSP,
- "CSP for unknown add-on ID should be the default CSP");
-
-
- const CUSTOM_POLICY = "script-src: 'self' https://xpcshell.test.custom.csp; object-src: 'none'";
-
- aps.setAddonCSP(ADDON_ID, CUSTOM_POLICY);
-
- equal(aps.getAddonCSP(ADDON_ID), CUSTOM_POLICY, "CSP should point to add-on's custom policy");
-
-
- aps.setAddonCSP(ADDON_ID, null);
-
- equal(aps.getAddonCSP(ADDON_ID), aps.defaultCSP,
- "CSP should revert to default when set to null");
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_csp_validator.js b/toolkit/components/extensions/test/xpcshell/test_csp_validator.js
deleted file mode 100644
index 59a7322bc..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_csp_validator.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-const cps = Cc["@mozilla.org/addons/content-policy;1"].getService(Ci.nsIAddonContentPolicy);
-
-add_task(function* test_csp_validator() {
- let checkPolicy = (policy, expectedResult, message = null) => {
- do_print(`Checking policy: ${policy}`);
-
- let result = cps.validateAddonCSP(policy);
- equal(result, expectedResult);
- };
-
- checkPolicy("script-src 'self'; object-src 'self';",
- null);
-
- let hash = "'sha256-NjZhMDQ1YjQ1MjEwMmM1OWQ4NDBlYzA5N2Q1OWQ5NDY3ZTEzYTNmMzRmNjQ5NGU1MzlmZmQzMmMxYmIzNWYxOCAgLQo='";
-
- checkPolicy(`script-src 'self' https://com https://*.example.com moz-extension://09abcdef blob: filesystem: ${hash} 'unsafe-eval'; ` +
- `object-src 'self' https://com https://*.example.com moz-extension://09abcdef blob: filesystem: ${hash}`,
- null);
-
- checkPolicy("",
- "Policy is missing a required \u2018script-src\u2019 directive");
-
- checkPolicy("object-src 'none';",
- "Policy is missing a required \u2018script-src\u2019 directive");
-
-
- checkPolicy("default-src 'self'", null,
- "A valid default-src should count as a valid script-src or object-src");
-
- checkPolicy("default-src 'self'; script-src 'self'", null,
- "A valid default-src should count as a valid script-src or object-src");
-
- checkPolicy("default-src 'self'; object-src 'self'", null,
- "A valid default-src should count as a valid script-src or object-src");
-
-
- checkPolicy("default-src 'self'; script-src http://example.com",
- "\u2018script-src\u2019 directive contains a forbidden http: protocol source",
- "A valid default-src should not allow an invalid script-src directive");
-
- checkPolicy("default-src 'self'; object-src http://example.com",
- "\u2018object-src\u2019 directive contains a forbidden http: protocol source",
- "A valid default-src should not allow an invalid object-src directive");
-
-
- checkPolicy("script-src 'self';",
- "Policy is missing a required \u2018object-src\u2019 directive");
-
- checkPolicy("script-src 'none'; object-src 'none'",
- "\u2018script-src\u2019 must include the source 'self'");
-
- checkPolicy("script-src 'self'; object-src 'none';",
- null);
-
- checkPolicy("script-src 'self' 'unsafe-inline'; object-src 'self';",
- "\u2018script-src\u2019 directive contains a forbidden 'unsafe-inline' keyword");
-
-
- let directives = ["script-src", "object-src"];
-
- for (let [directive, other] of [directives, directives.slice().reverse()]) {
- for (let src of ["https://*", "https://*.blogspot.com", "https://*"]) {
- checkPolicy(`${directive} 'self' ${src}; ${other} 'self';`,
- `https: wildcard sources in \u2018${directive}\u2019 directives must include at least one non-generic sub-domain (e.g., *.example.com rather than *.com)`);
- }
-
- checkPolicy(`${directive} 'self' https:; ${other} 'self';`,
- `https: protocol requires a host in \u2018${directive}\u2019 directives`);
-
- checkPolicy(`${directive} 'self' http://example.com; ${other} 'self';`,
- `\u2018${directive}\u2019 directive contains a forbidden http: protocol source`);
-
- for (let protocol of ["http", "ftp", "meh"]) {
- checkPolicy(`${directive} 'self' ${protocol}:; ${other} 'self';`,
- `\u2018${directive}\u2019 directive contains a forbidden ${protocol}: protocol source`);
- }
-
- checkPolicy(`${directive} 'self' 'nonce-01234'; ${other} 'self';`,
- `\u2018${directive}\u2019 directive contains a forbidden 'nonce-*' keyword`);
- }
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_alarms.js b/toolkit/components/extensions/test/xpcshell/test_ext_alarms.js
deleted file mode 100644
index 936c984c6..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_alarms.js
+++ /dev/null
@@ -1,210 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_alarm_without_permissions() {
- function backgroundScript() {
- browser.test.assertTrue(!browser.alarms,
- "alarm API is not available when the alarm permission is not required");
- browser.test.notifyPass("alarms_permission");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background: `(${backgroundScript})()`,
- manifest: {
- permissions: [],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("alarms_permission");
- yield extension.unload();
-});
-
-
-add_task(function* test_alarm_fires() {
- function backgroundScript() {
- let ALARM_NAME = "test_ext_alarms";
- let timer;
-
- browser.alarms.onAlarm.addListener(alarm => {
- browser.test.assertEq(ALARM_NAME, alarm.name, "alarm has the correct name");
- clearTimeout(timer);
- browser.test.notifyPass("alarm-fires");
- });
-
- browser.alarms.create(ALARM_NAME, {delayInMinutes: 0.02});
-
- timer = setTimeout(async () => {
- browser.test.fail("alarm fired within expected time");
- let wasCleared = await browser.alarms.clear(ALARM_NAME);
- browser.test.assertTrue(wasCleared, "alarm was cleared");
- browser.test.notifyFail("alarm-fires");
- }, 10000);
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background: `(${backgroundScript})()`,
- manifest: {
- permissions: ["alarms"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("alarm-fires");
- yield extension.unload();
-});
-
-
-add_task(function* test_alarm_fires_with_when() {
- function backgroundScript() {
- let ALARM_NAME = "test_ext_alarms";
- let timer;
-
- browser.alarms.onAlarm.addListener(alarm => {
- browser.test.assertEq(ALARM_NAME, alarm.name, "alarm has the expected name");
- clearTimeout(timer);
- browser.test.notifyPass("alarm-when");
- });
-
- browser.alarms.create(ALARM_NAME, {when: Date.now() + 1000});
-
- timer = setTimeout(async () => {
- browser.test.fail("alarm fired within expected time");
- let wasCleared = await browser.alarms.clear(ALARM_NAME);
- browser.test.assertTrue(wasCleared, "alarm was cleared");
- browser.test.notifyFail("alarm-when");
- }, 10000);
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background: `(${backgroundScript})()`,
- manifest: {
- permissions: ["alarms"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("alarm-when");
- yield extension.unload();
-});
-
-
-add_task(function* test_alarm_clear_non_matching_name() {
- async function backgroundScript() {
- let ALARM_NAME = "test_ext_alarms";
-
- browser.alarms.create(ALARM_NAME, {when: Date.now() + 2000});
-
- let wasCleared = await browser.alarms.clear(ALARM_NAME + "1");
- browser.test.assertFalse(wasCleared, "alarm was not cleared");
-
- let alarms = await browser.alarms.getAll();
- browser.test.assertEq(1, alarms.length, "alarm was not removed");
- browser.test.notifyPass("alarm-clear");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background: `(${backgroundScript})()`,
- manifest: {
- permissions: ["alarms"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("alarm-clear");
- yield extension.unload();
-});
-
-
-add_task(function* test_alarm_get_and_clear_single_argument() {
- async function backgroundScript() {
- browser.alarms.create({when: Date.now() + 2000});
-
- let alarm = await browser.alarms.get();
- browser.test.assertEq("", alarm.name, "expected alarm returned");
-
- let wasCleared = await browser.alarms.clear();
- browser.test.assertTrue(wasCleared, "alarm was cleared");
-
- let alarms = await browser.alarms.getAll();
- browser.test.assertEq(0, alarms.length, "alarm was removed");
-
- browser.test.notifyPass("alarm-single-arg");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background: `(${backgroundScript})()`,
- manifest: {
- permissions: ["alarms"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("alarm-single-arg");
- yield extension.unload();
-});
-
-
-add_task(function* test_get_get_all_clear_all_alarms() {
- async function backgroundScript() {
- const ALARM_NAME = "test_alarm";
-
- let suffixes = [0, 1, 2];
-
- for (let suffix of suffixes) {
- browser.alarms.create(ALARM_NAME + suffix, {when: Date.now() + (suffix + 1) * 10000});
- }
-
- let alarms = await browser.alarms.getAll();
- browser.test.assertEq(suffixes.length, alarms.length, "expected number of alarms were found");
- alarms.forEach((alarm, index) => {
- browser.test.assertEq(ALARM_NAME + index, alarm.name, "alarm has the expected name");
- });
-
-
- for (let suffix of suffixes) {
- let alarm = await browser.alarms.get(ALARM_NAME + suffix);
- browser.test.assertEq(ALARM_NAME + suffix, alarm.name, "alarm has the expected name");
- browser.test.sendMessage(`get-${suffix}`);
- }
-
- let wasCleared = await browser.alarms.clear(ALARM_NAME + suffixes[0]);
- browser.test.assertTrue(wasCleared, "alarm was cleared");
-
- alarms = await browser.alarms.getAll();
- browser.test.assertEq(2, alarms.length, "alarm was removed");
-
- let alarm = await browser.alarms.get(ALARM_NAME + suffixes[0]);
- browser.test.assertEq(undefined, alarm, "non-existent alarm is undefined");
- browser.test.sendMessage(`get-invalid`);
-
- wasCleared = await browser.alarms.clearAll();
- browser.test.assertTrue(wasCleared, "alarms were cleared");
-
- alarms = await browser.alarms.getAll();
- browser.test.assertEq(0, alarms.length, "no alarms exist");
- browser.test.sendMessage("clearAll");
- browser.test.sendMessage("clear");
- browser.test.sendMessage("getAll");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background: `(${backgroundScript})()`,
- manifest: {
- permissions: ["alarms"],
- },
- });
-
- yield Promise.all([
- extension.startup(),
- extension.awaitMessage("getAll"),
- extension.awaitMessage("get-0"),
- extension.awaitMessage("get-1"),
- extension.awaitMessage("get-2"),
- extension.awaitMessage("clear"),
- extension.awaitMessage("get-invalid"),
- extension.awaitMessage("clearAll"),
- ]);
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_alarms_does_not_fire.js b/toolkit/components/extensions/test/xpcshell/test_ext_alarms_does_not_fire.js
deleted file mode 100644
index 11407b108..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_alarms_does_not_fire.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_cleared_alarm_does_not_fire() {
- async function backgroundScript() {
- let ALARM_NAME = "test_ext_alarms";
-
- browser.alarms.onAlarm.addListener(alarm => {
- browser.test.fail("cleared alarm does not fire");
- browser.test.notifyFail("alarm-cleared");
- });
- browser.alarms.create(ALARM_NAME, {when: Date.now() + 1000});
-
- let wasCleared = await browser.alarms.clear(ALARM_NAME);
- browser.test.assertTrue(wasCleared, "alarm was cleared");
-
- await new Promise(resolve => setTimeout(resolve, 2000));
-
- browser.test.notifyPass("alarm-cleared");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background: `(${backgroundScript})()`,
- manifest: {
- permissions: ["alarms"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("alarm-cleared");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_alarms_periodic.js b/toolkit/components/extensions/test/xpcshell/test_ext_alarms_periodic.js
deleted file mode 100644
index 6bcdf4e33..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_alarms_periodic.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_periodic_alarm_fires() {
- function backgroundScript() {
- const ALARM_NAME = "test_ext_alarms";
- let count = 0;
- let timer;
-
- browser.alarms.onAlarm.addListener(async alarm => {
- browser.test.assertEq(alarm.name, ALARM_NAME, "alarm has the expected name");
- if (count++ === 3) {
- clearTimeout(timer);
- let wasCleared = await browser.alarms.clear(ALARM_NAME);
- browser.test.assertTrue(wasCleared, "alarm was cleared");
-
- browser.test.notifyPass("alarm-periodic");
- }
- });
-
- browser.alarms.create(ALARM_NAME, {periodInMinutes: 0.02});
-
- timer = setTimeout(async () => {
- browser.test.fail("alarm fired expected number of times");
-
- let wasCleared = await browser.alarms.clear(ALARM_NAME);
- browser.test.assertTrue(wasCleared, "alarm was cleared");
-
- browser.test.notifyFail("alarm-periodic");
- }, 30000);
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background: `(${backgroundScript})()`,
- manifest: {
- permissions: ["alarms"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("alarm-periodic");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_alarms_replaces.js b/toolkit/components/extensions/test/xpcshell/test_ext_alarms_replaces.js
deleted file mode 100644
index 96f61acb5..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_alarms_replaces.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-
-add_task(function* test_duplicate_alarm_name_replaces_alarm() {
- function backgroundScript() {
- let count = 0;
-
- browser.alarms.onAlarm.addListener(async alarm => {
- if (alarm.name === "master alarm") {
- browser.alarms.create("child alarm", {delayInMinutes: 0.05});
- let results = await browser.alarms.getAll();
-
- browser.test.assertEq(2, results.length, "exactly two alarms exist");
- browser.test.assertEq("master alarm", results[0].name, "first alarm has the expected name");
- browser.test.assertEq("child alarm", results[1].name, "second alarm has the expected name");
-
- if (count++ === 3) {
- await browser.alarms.clear("master alarm");
- await browser.alarms.clear("child alarm");
-
- browser.test.notifyPass("alarm-duplicate");
- }
- } else {
- browser.test.fail("duplicate named alarm replaced existing alarm");
- browser.test.notifyFail("alarm-duplicate");
- }
- });
-
- browser.alarms.create("master alarm", {delayInMinutes: 0.025, periodInMinutes: 0.025});
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background: `(${backgroundScript})()`,
- manifest: {
- permissions: ["alarms"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("alarm-duplicate");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_api_permissions.js b/toolkit/components/extensions/test/xpcshell/test_ext_api_permissions.js
deleted file mode 100644
index d653d0e7a..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_api_permissions.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-let {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
-function getNextContext() {
- return new Promise(resolve => {
- Management.on("proxy-context-load", function listener(type, context) {
- Management.off("proxy-context-load", listener);
- resolve(context);
- });
- });
-}
-
-add_task(function* test_storage_api_without_permissions() {
- let extension = ExtensionTestUtils.loadExtension({
- background() {
- // Force API initialization.
- void browser.storage;
- },
-
- manifest: {
- permissions: [],
- },
- });
-
- let contextPromise = getNextContext();
- yield extension.startup();
-
- let context = yield contextPromise;
-
- // Force API initialization.
- void context.apiObj;
-
- ok(!("storage" in context.apiObj),
- "The storage API should not be initialized");
-
- yield extension.unload();
-});
-
-add_task(function* test_storage_api_with_permissions() {
- let extension = ExtensionTestUtils.loadExtension({
- background() {
- void browser.storage;
- },
-
- manifest: {
- permissions: ["storage"],
- },
- });
-
- let contextPromise = getNextContext();
- yield extension.startup();
-
- let context = yield contextPromise;
-
- // Force API initialization.
- void context.apiObj;
-
- equal(typeof context.apiObj.storage, "object",
- "The storage API should be initialized");
-
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_apimanager.js b/toolkit/components/extensions/test/xpcshell/test_ext_apimanager.js
deleted file mode 100644
index 3f6672a11..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_apimanager.js
+++ /dev/null
@@ -1,91 +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";
-
-Cu.import("resource://gre/modules/ExtensionCommon.jsm");
-
-const {
- SchemaAPIManager,
-} = ExtensionCommon;
-
-this.unknownvar = "Some module-global var";
-
-var gUniqueId = 0;
-
-// SchemaAPIManager's loadScript uses loadSubScript to load a script. This
-// requires a local (resource://) URL. So create such a temporary URL for
-// testing.
-function toLocalURI(code) {
- let dataUrl = `data:charset=utf-8,${encodeURIComponent(code)}`;
- let uniqueResPart = `need-a-local-uri-for-subscript-loading-${++gUniqueId}`;
- Services.io.getProtocolHandler("resource")
- .QueryInterface(Ci.nsIResProtocolHandler)
- .setSubstitution(uniqueResPart, Services.io.newURI(dataUrl, null, null));
- return `resource://${uniqueResPart}`;
-}
-
-add_task(function* test_global_isolation() {
- let manA = new SchemaAPIManager("procA");
- let manB = new SchemaAPIManager("procB");
-
- // The "global" variable should be persistent and shared.
- manA.loadScript(toLocalURI`global.globalVar = 1;`);
- do_check_eq(manA.global.globalVar, 1);
- do_check_eq(manA.global.unknownvar, undefined);
- manA.loadScript(toLocalURI`global.canSeeGlobal = global.globalVar;`);
- do_check_eq(manA.global.canSeeGlobal, 1);
-
- // Each loadScript call should have their own scope, and global is shared.
- manA.loadScript(toLocalURI`this.aVar = 1; global.thisScopeVar = aVar`);
- do_check_eq(manA.global.aVar, undefined);
- do_check_eq(manA.global.thisScopeVar, 1);
- manA.loadScript(toLocalURI`global.differentScopeVar = this.aVar;`);
- do_check_eq(manA.global.differentScopeVar, undefined);
- manA.loadScript(toLocalURI`global.cantSeeOtherScope = typeof aVar;`);
- do_check_eq(manA.global.cantSeeOtherScope, "undefined");
-
- manB.loadScript(toLocalURI`global.tryReadOtherGlobal = global.tryagain;`);
- do_check_eq(manA.global.tryReadOtherGlobal, undefined);
-
- // Cu.import without second argument exports to the caller's global. Let's
- // verify that it does not leak to the SchemaAPIManager's global.
- do_check_eq(typeof ExtensionUtils, "undefined"); // Sanity check #1.
- manA.loadScript(toLocalURI`global.hasExtUtils = typeof ExtensionUtils;`);
- do_check_eq(manA.global.hasExtUtils, "undefined"); // Sanity check #2
-
- Cu.import("resource://gre/modules/ExtensionUtils.jsm");
- do_check_eq(typeof ExtensionUtils, "object"); // Sanity check #3.
-
- manA.loadScript(toLocalURI`global.hasExtUtils = typeof ExtensionUtils;`);
- do_check_eq(manA.global.hasExtUtils, "undefined");
- manB.loadScript(toLocalURI`global.hasExtUtils = typeof ExtensionUtils;`);
- do_check_eq(manB.global.hasExtUtils, "undefined");
-
- // Confirm that Cu.import does not leak between SchemaAPIManager globals.
- manA.loadScript(toLocalURI`
- Cu.import("resource://gre/modules/ExtensionUtils.jsm");
- global.hasExtUtils = typeof ExtensionUtils;
- `);
- do_check_eq(manA.global.hasExtUtils, "object"); // Sanity check.
- manB.loadScript(toLocalURI`global.hasExtUtils = typeof ExtensionUtils;`);
- do_check_eq(manB.global.hasExtUtils, "undefined");
-
- // Prototype modifications should be isolated.
- manA.loadScript(toLocalURI`
- Object.prototype.modifiedByA = "Prrft";
- global.fromA = {};
- `);
- manA.loadScript(toLocalURI`
- global.fromAagain = {};
- `);
- manB.loadScript(toLocalURI`
- global.fromB = {};
- `);
- do_check_eq(manA.global.modifiedByA, "Prrft");
- do_check_eq(manA.global.fromA.modifiedByA, "Prrft");
- do_check_eq(manA.global.fromAagain.modifiedByA, "Prrft");
- do_check_eq(manB.global.modifiedByA, undefined);
- do_check_eq(manB.global.fromB.modifiedByA, undefined);
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_load_events.js b/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_load_events.js
deleted file mode 100644
index 26282fcb9..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_load_events.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-/* eslint-disable mozilla/balanced-listeners */
-
-add_task(function* test_DOMContentLoaded_in_generated_background_page() {
- let extension = ExtensionTestUtils.loadExtension({
- background() {
- function reportListener(event) {
- browser.test.sendMessage("eventname", event.type);
- }
- document.addEventListener("DOMContentLoaded", reportListener);
- window.addEventListener("load", reportListener);
- },
- });
-
- yield extension.startup();
- equal("DOMContentLoaded", yield extension.awaitMessage("eventname"));
- equal("load", yield extension.awaitMessage("eventname"));
-
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_reload.js b/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_reload.js
deleted file mode 100644
index 4bf59b798..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_reload.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_reload_generated_background_page() {
- let extension = ExtensionTestUtils.loadExtension({
- background() {
- if (location.hash !== "#firstrun") {
- browser.test.sendMessage("first run");
- location.hash = "#firstrun";
- browser.test.assertEq("#firstrun", location.hash);
- location.reload();
- } else {
- browser.test.notifyPass("second run");
- }
- },
- });
-
- yield extension.startup();
- yield extension.awaitMessage("first run");
- yield extension.awaitFinish("second run");
-
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_background_global_history.js b/toolkit/components/extensions/test/xpcshell/test_ext_background_global_history.js
deleted file mode 100644
index 092a9f5b3..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_background_global_history.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-Cu.import("resource://testing-common/PlacesTestUtils.jsm");
-
-add_task(function* test_global_history() {
- let extension = ExtensionTestUtils.loadExtension({
- background() {
- browser.test.sendMessage("background-loaded", location.href);
- },
- });
-
- yield extension.startup();
-
- let backgroundURL = yield extension.awaitMessage("background-loaded");
-
- yield extension.unload();
-
- let exists = yield PlacesTestUtils.isPageInDB(backgroundURL);
- ok(!exists, "Background URL should not be in history database");
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_background_private_browsing.js b/toolkit/components/extensions/test/xpcshell/test_ext_background_private_browsing.js
deleted file mode 100644
index 8e8b5e0b0..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_background_private_browsing.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-Cu.import("resource://gre/modules/Preferences.jsm");
-
-function* testBackgroundPage(expected) {
- let extension = ExtensionTestUtils.loadExtension({
- async background() {
- browser.test.assertEq(window, browser.extension.getBackgroundPage(),
- "Caller should be able to access itself as a background page");
- browser.test.assertEq(window, await browser.runtime.getBackgroundPage(),
- "Caller should be able to access itself as a background page");
-
- browser.test.sendMessage("incognito", browser.extension.inIncognitoContext);
- },
- });
-
- yield extension.startup();
-
- let incognito = yield extension.awaitMessage("incognito");
- equal(incognito, expected.incognito, "Expected incognito value");
-
- yield extension.unload();
-}
-
-add_task(function* test_background_incognito() {
- do_print("Test background page incognito value with permanent private browsing disabled");
-
- yield testBackgroundPage({incognito: false});
-
- do_print("Test background page incognito value with permanent private browsing enabled");
-
- Preferences.set("browser.privatebrowsing.autostart", true);
- do_register_cleanup(() => {
- Preferences.reset("browser.privatebrowsing.autostart");
- });
-
- yield testBackgroundPage({incognito: true});
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js b/toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js
deleted file mode 100644
index 426833edd..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-function backgroundScript() {
- let received_ports_number = 0;
-
- const expected_received_ports_number = 1;
-
- function countReceivedPorts(port) {
- received_ports_number++;
-
- if (port.name == "check-results") {
- browser.runtime.onConnect.removeListener(countReceivedPorts);
-
- browser.test.assertEq(expected_received_ports_number, received_ports_number, "invalid connect should not create a port");
-
- browser.test.notifyPass("runtime.connect invalid params");
- }
- }
-
- browser.runtime.onConnect.addListener(countReceivedPorts);
-
- let childFrame = document.createElement("iframe");
- childFrame.src = "extensionpage.html";
- document.body.appendChild(childFrame);
-}
-
-function senderScript() {
- let detected_invalid_connect_params = 0;
-
- const invalid_connect_params = [
- // too many params
- ["fake-extensions-id", {name: "fake-conn-name"}, "unexpected third params"],
- // invalid params format
- [{}, {}],
- ["fake-extensions-id", "invalid-connect-info-format"],
- ];
- const expected_detected_invalid_connect_params = invalid_connect_params.length;
-
- function assertInvalidConnectParamsException(params) {
- try {
- browser.runtime.connect(...params);
- } catch (e) {
- detected_invalid_connect_params++;
- browser.test.assertTrue(e.toString().indexOf("Incorrect argument types for runtime.connect.") >= 0, "exception message is correct");
- }
- }
- for (let params of invalid_connect_params) {
- assertInvalidConnectParamsException(params);
- }
- browser.test.assertEq(expected_detected_invalid_connect_params, detected_invalid_connect_params, "all invalid runtime.connect params detected");
-
- browser.runtime.connect(browser.runtime.id, {name: "check-results"});
-}
-
-let extensionData = {
- background: backgroundScript,
- files: {
- "senderScript.js": senderScript,
- "extensionpage.html": `<!DOCTYPE html><meta charset="utf-8"><script src="senderScript.js"></script>`,
- },
-};
-
-add_task(function* test_backgroundRuntimeConnectParams() {
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
-
- yield extension.awaitFinish("runtime.connect invalid params");
-
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_background_sub_windows.js b/toolkit/components/extensions/test/xpcshell/test_ext_background_sub_windows.js
deleted file mode 100644
index c5f2f1332..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_background_sub_windows.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* testBackgroundWindow() {
- let extension = ExtensionTestUtils.loadExtension({
- background() {
- browser.test.log("background script executed");
-
- browser.test.sendMessage("background-script-load");
-
- let img = document.createElement("img");
- img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
- document.body.appendChild(img);
-
- img.onload = () => {
- browser.test.log("image loaded");
-
- let iframe = document.createElement("iframe");
- iframe.src = "about:blank?1";
-
- iframe.onload = () => {
- browser.test.log("iframe loaded");
- setTimeout(() => {
- browser.test.notifyPass("background sub-window test done");
- }, 0);
- };
- document.body.appendChild(iframe);
- };
- },
- });
-
- let loadCount = 0;
- extension.onMessage("background-script-load", () => {
- loadCount++;
- });
-
- yield extension.startup();
-
- yield extension.awaitFinish("background sub-window test done");
-
- equal(loadCount, 1, "background script loaded only once");
-
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_background_window_properties.js b/toolkit/components/extensions/test/xpcshell/test_ext_background_window_properties.js
deleted file mode 100644
index 948e2913e..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_background_window_properties.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* testBackgroundWindowProperties() {
- let extension = ExtensionTestUtils.loadExtension({
- background() {
- let expectedValues = {
- screenX: 0,
- screenY: 0,
- outerWidth: 0,
- outerHeight: 0,
- };
-
- for (let k in window) {
- try {
- if (k in expectedValues) {
- browser.test.assertEq(expectedValues[k], window[k],
- `should return the expected value for window property: ${k}`);
- } else {
- void window[k];
- }
- } catch (e) {
- browser.test.assertEq(null, e, `unexpected exception accessing window property: ${k}`);
- }
- }
-
- browser.test.notifyPass("background.testWindowProperties.done");
- },
- });
- yield extension.startup();
- yield extension.awaitFinish("background.testWindowProperties.done");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_contexts.js b/toolkit/components/extensions/test/xpcshell/test_ext_contexts.js
deleted file mode 100644
index 56a14e189..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_contexts.js
+++ /dev/null
@@ -1,190 +0,0 @@
-"use strict";
-
-const global = this;
-
-Cu.import("resource://gre/modules/Timer.jsm");
-
-Cu.import("resource://gre/modules/ExtensionCommon.jsm");
-Cu.import("resource://gre/modules/ExtensionUtils.jsm");
-
-var {
- BaseContext,
-} = ExtensionCommon;
-
-var {
- EventManager,
- SingletonEventManager,
-} = ExtensionUtils;
-
-class StubContext extends BaseContext {
- constructor() {
- let fakeExtension = {id: "test@web.extension"};
- super("testEnv", fakeExtension);
- this.sandbox = Cu.Sandbox(global);
- }
-
- get cloneScope() {
- return this.sandbox;
- }
-}
-
-
-add_task(function* test_post_unload_promises() {
- let context = new StubContext();
-
- let fail = result => {
- ok(false, `Unexpected callback: ${result}`);
- };
-
- // Make sure promises resolve normally prior to unload.
- let promises = [
- context.wrapPromise(Promise.resolve()),
- context.wrapPromise(Promise.reject({message: ""})).catch(() => {}),
- ];
-
- yield Promise.all(promises);
-
- // Make sure promises that resolve after unload do not trigger
- // resolution handlers.
-
- context.wrapPromise(Promise.resolve("resolved"))
- .then(fail);
-
- context.wrapPromise(Promise.reject({message: "rejected"}))
- .then(fail, fail);
-
- context.unload();
-
- // The `setTimeout` ensures that we return to the event loop after
- // promise resolution, which means we're guaranteed to return after
- // any micro-tasks that get enqueued by the resolution handlers above.
- yield new Promise(resolve => setTimeout(resolve, 0));
-});
-
-
-add_task(function* test_post_unload_listeners() {
- let context = new StubContext();
-
- let fireEvent;
- let onEvent = new EventManager(context, "onEvent", fire => {
- fireEvent = fire;
- return () => {};
- });
-
- let fireSingleton;
- let onSingleton = new SingletonEventManager(context, "onSingleton", callback => {
- fireSingleton = () => {
- Promise.resolve().then(callback);
- };
- return () => {};
- });
-
- let fail = event => {
- ok(false, `Unexpected event: ${event}`);
- };
-
- // Check that event listeners aren't called after they've been removed.
- onEvent.addListener(fail);
- onSingleton.addListener(fail);
-
- let promises = [
- new Promise(resolve => onEvent.addListener(resolve)),
- new Promise(resolve => onSingleton.addListener(resolve)),
- ];
-
- fireEvent("onEvent");
- fireSingleton("onSingleton");
-
- // Both `fireEvent` calls are dispatched asynchronously, so they won't
- // have fired by this point. The `fail` listeners that we remove now
- // should not be called, even though the events have already been
- // enqueued.
- onEvent.removeListener(fail);
- onSingleton.removeListener(fail);
-
- // Wait for the remaining listeners to be called, which should always
- // happen after the `fail` listeners would normally be called.
- yield Promise.all(promises);
-
- // Check that event listeners aren't called after the context has
- // unloaded.
- onEvent.addListener(fail);
- onSingleton.addListener(fail);
-
- // The EventManager `fire` callback always dispatches events
- // asynchronously, so we need to test that any pending event callbacks
- // aren't fired after the context unloads. We also need to test that
- // any `fire` calls that happen *after* the context is unloaded also
- // do not trigger callbacks.
- fireEvent("onEvent");
- Promise.resolve("onEvent").then(fireEvent);
-
- fireSingleton("onSingleton");
- Promise.resolve("onSingleton").then(fireSingleton);
-
- context.unload();
-
- // The `setTimeout` ensures that we return to the event loop after
- // promise resolution, which means we're guaranteed to return after
- // any micro-tasks that get enqueued by the resolution handlers above.
- yield new Promise(resolve => setTimeout(resolve, 0));
-});
-
-class Context extends BaseContext {
- constructor(principal) {
- let fakeExtension = {id: "test@web.extension"};
- super("testEnv", fakeExtension);
- Object.defineProperty(this, "principal", {
- value: principal,
- configurable: true,
- });
- this.sandbox = Cu.Sandbox(principal, {wantXrays: false});
- }
-
- get cloneScope() {
- return this.sandbox;
- }
-}
-
-let ssm = Services.scriptSecurityManager;
-const PRINCIPAL1 = ssm.createCodebasePrincipalFromOrigin("http://www.example.org");
-const PRINCIPAL2 = ssm.createCodebasePrincipalFromOrigin("http://www.somethingelse.org");
-
-// Test that toJSON() works in the json sandbox
-add_task(function* test_stringify_toJSON() {
- let context = new Context(PRINCIPAL1);
- let obj = Cu.evalInSandbox("({hidden: true, toJSON() { return {visible: true}; } })", context.sandbox);
-
- let stringified = context.jsonStringify(obj);
- let expected = JSON.stringify({visible: true});
- equal(stringified, expected, "Stringified object with toJSON() method is as expected");
-});
-
-// Test that stringifying in inaccessible property throws
-add_task(function* test_stringify_inaccessible() {
- let context = new Context(PRINCIPAL1);
- let sandbox = context.sandbox;
- let sandbox2 = Cu.Sandbox(PRINCIPAL2);
-
- Cu.waiveXrays(sandbox).subobj = Cu.evalInSandbox("({ subobject: true })", sandbox2);
- let obj = Cu.evalInSandbox("({ local: true, nested: subobj })", sandbox);
- Assert.throws(() => {
- context.jsonStringify(obj);
- });
-});
-
-add_task(function* test_stringify_accessible() {
- // Test that an accessible property from another global is included
- let principal = Cu.getObjectPrincipal(Cu.Sandbox([PRINCIPAL1, PRINCIPAL2]));
- let context = new Context(principal);
- let sandbox = context.sandbox;
- let sandbox2 = Cu.Sandbox(PRINCIPAL2);
-
- Cu.waiveXrays(sandbox).subobj = Cu.evalInSandbox("({ subobject: true })", sandbox2);
- let obj = Cu.evalInSandbox("({ local: true, nested: subobj })", sandbox);
- let stringified = context.jsonStringify(obj);
-
- let expected = JSON.stringify({local: true, nested: {subobject: true}});
- equal(stringified, expected, "Stringified object with accessible property is as expected");
-});
-
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_downloads.js b/toolkit/components/extensions/test/xpcshell/test_ext_downloads.js
deleted file mode 100644
index 058b9b18c..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_downloads.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_downloads_api_namespace_and_permissions() {
- function backgroundScript() {
- browser.test.assertTrue(!!browser.downloads, "`downloads` API is present.");
- browser.test.assertTrue(!!browser.downloads.FilenameConflictAction,
- "`downloads.FilenameConflictAction` enum is present.");
- browser.test.assertTrue(!!browser.downloads.InterruptReason,
- "`downloads.InterruptReason` enum is present.");
- browser.test.assertTrue(!!browser.downloads.DangerType,
- "`downloads.DangerType` enum is present.");
- browser.test.assertTrue(!!browser.downloads.State,
- "`downloads.State` enum is present.");
- browser.test.notifyPass("downloads tests");
- }
-
- let extensionData = {
- background: backgroundScript,
- manifest: {
- permissions: ["downloads", "downloads.open", "downloads.shelf"],
- },
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
- yield extension.awaitFinish("downloads tests");
- yield extension.unload();
-});
-
-add_task(function* test_downloads_open_permission() {
- function backgroundScript() {
- browser.test.assertFalse("open" in browser.downloads,
- "`downloads.open` permission is required.");
- browser.test.notifyPass("downloads tests");
- }
-
- let extensionData = {
- background: backgroundScript,
- manifest: {
- permissions: ["downloads"],
- },
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
- yield extension.awaitFinish("downloads tests");
- yield extension.unload();
-});
-
-add_task(function* test_downloads_open() {
- async function backgroundScript() {
- await browser.test.assertRejects(
- browser.downloads.open(10),
- "Invalid download id 10",
- "The error is informative.");
-
- browser.test.notifyPass("downloads tests");
-
- // TODO: Once downloads.{pause,cancel,resume} lands (bug 1245602) test that this gives a good
- // error when called with an incompleted download.
- }
-
- let extensionData = {
- background: backgroundScript,
- manifest: {
- permissions: ["downloads", "downloads.open"],
- },
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
- yield extension.awaitFinish("downloads tests");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js
deleted file mode 100644
index 37ddd4d7c..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js
+++ /dev/null
@@ -1,354 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-/* global OS */
-
-Cu.import("resource://gre/modules/osfile.jsm");
-Cu.import("resource://gre/modules/Downloads.jsm");
-
-const gServer = createHttpServer();
-gServer.registerDirectory("/data/", do_get_file("data"));
-
-const WINDOWS = AppConstants.platform == "win";
-
-const BASE = `http://localhost:${gServer.identity.primaryPort}/data`;
-const FILE_NAME = "file_download.txt";
-const FILE_URL = BASE + "/" + FILE_NAME;
-const FILE_NAME_UNIQUE = "file_download(1).txt";
-const FILE_LEN = 46;
-
-let downloadDir;
-
-function setup() {
- downloadDir = FileUtils.getDir("TmpD", ["downloads"]);
- downloadDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
- do_print(`Using download directory ${downloadDir.path}`);
-
- Services.prefs.setIntPref("browser.download.folderList", 2);
- Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, downloadDir);
-
- do_register_cleanup(() => {
- Services.prefs.clearUserPref("browser.download.folderList");
- Services.prefs.clearUserPref("browser.download.dir");
-
- let entries = downloadDir.directoryEntries;
- while (entries.hasMoreElements()) {
- let entry = entries.getNext().QueryInterface(Ci.nsIFile);
- ok(false, `Leftover file ${entry.path} in download directory`);
- entry.remove(false);
- }
-
- downloadDir.remove(false);
- });
-}
-
-function backgroundScript() {
- let blobUrl;
- browser.test.onMessage.addListener(async (msg, ...args) => {
- if (msg == "download.request") {
- let options = args[0];
-
- if (options.blobme) {
- let blob = new Blob(options.blobme);
- delete options.blobme;
- blobUrl = options.url = window.URL.createObjectURL(blob);
- }
-
- try {
- let id = await browser.downloads.download(options);
- browser.test.sendMessage("download.done", {status: "success", id});
- } catch (error) {
- browser.test.sendMessage("download.done", {status: "error", errmsg: error.message});
- }
- } else if (msg == "killTheBlob") {
- window.URL.revokeObjectURL(blobUrl);
- blobUrl = null;
- }
- });
-
- browser.test.sendMessage("ready");
-}
-
-// This function is a bit of a sledgehammer, it looks at every download
-// the browser knows about and waits for all active downloads to complete.
-// But we only start one at a time and only do a handful in total, so
-// this lets us test download() without depending on anything else.
-async function waitForDownloads() {
- let list = await Downloads.getList(Downloads.ALL);
- let downloads = await list.getAll();
-
- let inprogress = downloads.filter(dl => !dl.stopped);
- return Promise.all(inprogress.map(dl => dl.whenSucceeded()));
-}
-
-// Create a file in the downloads directory.
-function touch(filename) {
- let file = downloadDir.clone();
- file.append(filename);
- file.create(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
-}
-
-// Remove a file in the downloads directory.
-function remove(filename, recursive = false) {
- let file = downloadDir.clone();
- file.append(filename);
- file.remove(recursive);
-}
-
-add_task(function* test_downloads() {
- setup();
-
- let extension = ExtensionTestUtils.loadExtension({
- background: `(${backgroundScript})()`,
- manifest: {
- permissions: ["downloads"],
- },
- });
-
- function download(options) {
- extension.sendMessage("download.request", options);
- return extension.awaitMessage("download.done");
- }
-
- async function testDownload(options, localFile, expectedSize, description) {
- let msg = await download(options);
- equal(msg.status, "success", `downloads.download() works with ${description}`);
-
- await waitForDownloads();
-
- let localPath = downloadDir.clone();
- let parts = Array.isArray(localFile) ? localFile : [localFile];
-
- parts.map(p => localPath.append(p));
- equal(localPath.fileSize, expectedSize, "Downloaded file has expected size");
- localPath.remove(false);
- }
-
- yield extension.startup();
- yield extension.awaitMessage("ready");
- do_print("extension started");
-
- // Call download() with just the url property.
- yield testDownload({url: FILE_URL}, FILE_NAME, FILE_LEN, "just source");
-
- // Call download() with a filename property.
- yield testDownload({
- url: FILE_URL,
- filename: "newpath.txt",
- }, "newpath.txt", FILE_LEN, "source and filename");
-
- // Call download() with a filename with subdirs.
- yield testDownload({
- url: FILE_URL,
- filename: "sub/dir/file",
- }, ["sub", "dir", "file"], FILE_LEN, "source and filename with subdirs");
-
- // Call download() with a filename with existing subdirs.
- yield testDownload({
- url: FILE_URL,
- filename: "sub/dir/file2",
- }, ["sub", "dir", "file2"], FILE_LEN, "source and filename with existing subdirs");
-
- // Only run Windows path separator test on Windows.
- if (WINDOWS) {
- // Call download() with a filename with Windows path separator.
- yield testDownload({
- url: FILE_URL,
- filename: "sub\\dir\\file3",
- }, ["sub", "dir", "file3"], FILE_LEN, "filename with Windows path separator");
- }
- remove("sub", true);
-
- // Call download(), filename with subdir, skipping parts.
- yield testDownload({
- url: FILE_URL,
- filename: "skip//part",
- }, ["skip", "part"], FILE_LEN, "source, filename, with subdir, skipping parts");
- remove("skip", true);
-
- // Check conflictAction of "uniquify".
- touch(FILE_NAME);
- yield testDownload({
- url: FILE_URL,
- conflictAction: "uniquify",
- }, FILE_NAME_UNIQUE, FILE_LEN, "conflictAction=uniquify");
- // todo check that preexisting file was not modified?
- remove(FILE_NAME);
-
- // Check conflictAction of "overwrite".
- touch(FILE_NAME);
- yield testDownload({
- url: FILE_URL,
- conflictAction: "overwrite",
- }, FILE_NAME, FILE_LEN, "conflictAction=overwrite");
-
- // Try to download in invalid url
- yield download({url: "this is not a valid URL"}).then(msg => {
- equal(msg.status, "error", "downloads.download() fails with invalid url");
- ok(/not a valid URL/.test(msg.errmsg), "error message for invalid url is correct");
- });
-
- // Try to download to an empty path.
- yield download({
- url: FILE_URL,
- filename: "",
- }).then(msg => {
- equal(msg.status, "error", "downloads.download() fails with empty filename");
- equal(msg.errmsg, "filename must not be empty", "error message for empty filename is correct");
- });
-
- // Try to download to an absolute path.
- const absolutePath = OS.Path.join(WINDOWS ? "\\tmp" : "/tmp", "file_download.txt");
- yield download({
- url: FILE_URL,
- filename: absolutePath,
- }).then(msg => {
- equal(msg.status, "error", "downloads.download() fails with absolute filename");
- equal(msg.errmsg, "filename must not be an absolute path", `error message for absolute path (${absolutePath}) is correct`);
- });
-
- if (WINDOWS) {
- yield download({
- url: FILE_URL,
- filename: "C:\\file_download.txt",
- }).then(msg => {
- equal(msg.status, "error", "downloads.download() fails with absolute filename");
- equal(msg.errmsg, "filename must not be an absolute path", "error message for absolute path with drive letter is correct");
- });
- }
-
- // Try to download to a relative path containing ..
- yield download({
- url: FILE_URL,
- filename: OS.Path.join("..", "file_download.txt"),
- }).then(msg => {
- equal(msg.status, "error", "downloads.download() fails with back-references");
- equal(msg.errmsg, "filename must not contain back-references (..)", "error message for back-references is correct");
- });
-
- // Try to download to a long relative path containing ..
- yield download({
- url: FILE_URL,
- filename: OS.Path.join("foo", "..", "..", "file_download.txt"),
- }).then(msg => {
- equal(msg.status, "error", "downloads.download() fails with back-references");
- equal(msg.errmsg, "filename must not contain back-references (..)", "error message for back-references is correct");
- });
-
- // Try to download a blob url
- const BLOB_STRING = "Hello, world";
- yield testDownload({
- blobme: [BLOB_STRING],
- filename: FILE_NAME,
- }, FILE_NAME, BLOB_STRING.length, "blob url");
- extension.sendMessage("killTheBlob");
-
- // Try to download a blob url without a given filename
- yield testDownload({
- blobme: [BLOB_STRING],
- }, "download", BLOB_STRING.length, "blob url with no filename");
- extension.sendMessage("killTheBlob");
-
- yield extension.unload();
-});
-
-add_task(function* test_download_post() {
- const server = createHttpServer();
- const url = `http://localhost:${server.identity.primaryPort}/post-log`;
-
- let received;
- server.registerPathHandler("/post-log", request => {
- received = request;
- });
-
- // Confirm received vs. expected values.
- function confirm(method, headers = {}, body) {
- equal(received.method, method, "method is correct");
-
- for (let name in headers) {
- ok(received.hasHeader(name), `header ${name} received`);
- equal(received.getHeader(name), headers[name], `header ${name} is correct`);
- }
-
- if (body) {
- const str = NetUtil.readInputStreamToString(received.bodyInputStream,
- received.bodyInputStream.available());
- equal(str, body, "body is correct");
- }
- }
-
- function background() {
- browser.test.onMessage.addListener(async options => {
- try {
- await browser.downloads.download(options);
- } catch (err) {
- browser.test.sendMessage("done", {err: err.message});
- }
- });
- browser.downloads.onChanged.addListener(({state}) => {
- if (state && state.current === "complete") {
- browser.test.sendMessage("done", {ok: true});
- }
- });
- }
-
- const manifest = {permissions: ["downloads"]};
- const extension = ExtensionTestUtils.loadExtension({background, manifest});
- yield extension.startup();
-
- function download(options) {
- options.url = url;
- options.conflictAction = "overwrite";
-
- extension.sendMessage(options);
- return extension.awaitMessage("done");
- }
-
- // Test method option.
- let result = yield download({});
- ok(result.ok, "download works without the method option, defaults to GET");
- confirm("GET");
-
- result = yield download({method: "PUT"});
- ok(!result.ok, "download rejected with PUT method");
- ok(/method: Invalid enumeration/.test(result.err), "descriptive error message");
-
- result = yield download({method: "POST"});
- ok(result.ok, "download works with POST method");
- confirm("POST");
-
- // Test body option values.
- result = yield download({body: []});
- ok(!result.ok, "download rejected because of non-string body");
- ok(/body: Expected string/.test(result.err), "descriptive error message");
-
- result = yield download({method: "POST", body: "of work"});
- ok(result.ok, "download works with POST method and body");
- confirm("POST", {"Content-Length": 7}, "of work");
-
- // Test custom headers.
- result = yield download({headers: [{name: "X-Custom"}]});
- ok(!result.ok, "download rejected because of missing header value");
- ok(/"value" is required/.test(result.err), "descriptive error message");
-
- result = yield download({headers: [{name: "X-Custom", value: "13"}]});
- ok(result.ok, "download works with a custom header");
- confirm("GET", {"X-Custom": "13"});
-
- // Test forbidden headers.
- result = yield download({headers: [{name: "DNT", value: "1"}]});
- ok(!result.ok, "download rejected because of forbidden header name DNT");
- ok(/Forbidden request header/.test(result.err), "descriptive error message");
-
- result = yield download({headers: [{name: "Proxy-Connection", value: "keep"}]});
- ok(!result.ok, "download rejected because of forbidden header name prefix Proxy-");
- ok(/Forbidden request header/.test(result.err), "descriptive error message");
-
- result = yield download({headers: [{name: "Sec-ret", value: "13"}]});
- ok(!result.ok, "download rejected because of forbidden header name prefix Sec-");
- ok(/Forbidden request header/.test(result.err), "descriptive error message");
-
- remove("post-log");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js
deleted file mode 100644
index d08aab666..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js
+++ /dev/null
@@ -1,862 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-Cu.import("resource://gre/modules/Downloads.jsm");
-
-const server = createHttpServer();
-server.registerDirectory("/data/", do_get_file("data"));
-
-const ROOT = `http://localhost:${server.identity.primaryPort}`;
-const BASE = `${ROOT}/data`;
-const TXT_FILE = "file_download.txt";
-const TXT_URL = BASE + "/" + TXT_FILE;
-
-// Keep these in sync with code in interruptible.sjs
-const INT_PARTIAL_LEN = 15;
-const INT_TOTAL_LEN = 31;
-
-const TEST_DATA = "This is 31 bytes of sample data";
-const TOTAL_LEN = TEST_DATA.length;
-const PARTIAL_LEN = 15;
-
-// A handler to let us systematically test pausing/resuming/canceling
-// of downloads. This target represents a small text file but a simple
-// GET will stall after sending part of the data, to give the test code
-// a chance to pause or do other operations on an in-progress download.
-// A resumed download (ie, a GET with a Range: header) will allow the
-// download to complete.
-function handleRequest(request, response) {
- response.setHeader("Content-Type", "text/plain", false);
-
- if (request.hasHeader("Range")) {
- let start, end;
- let matches = request.getHeader("Range")
- .match(/^\s*bytes=(\d+)?-(\d+)?\s*$/);
- if (matches != null) {
- start = matches[1] ? parseInt(matches[1], 10) : 0;
- end = matches[2] ? parseInt(matches[2], 10) : (TOTAL_LEN - 1);
- }
-
- if (end == undefined || end >= TOTAL_LEN) {
- response.setStatusLine(request.httpVersion, 416, "Requested Range Not Satisfiable");
- response.setHeader("Content-Range", `*/${TOTAL_LEN}`, false);
- response.finish();
- return;
- }
-
- response.setStatusLine(request.httpVersion, 206, "Partial Content");
- response.setHeader("Content-Range", `${start}-${end}/${TOTAL_LEN}`, false);
- response.write(TEST_DATA.slice(start, end + 1));
- } else {
- response.processAsync();
- response.setHeader("Content-Length", `${TOTAL_LEN}`, false);
- response.write(TEST_DATA.slice(0, PARTIAL_LEN));
- }
-
- do_register_cleanup(() => {
- try {
- response.finish();
- } catch (e) {
- // This will throw, but we don't care at this point.
- }
- });
-}
-
-server.registerPathHandler("/interruptible.html", handleRequest);
-
-let interruptibleCount = 0;
-function getInterruptibleUrl() {
- let n = interruptibleCount++;
- return `${ROOT}/interruptible.html?count=${n}`;
-}
-
-function backgroundScript() {
- let events = new Set();
- let eventWaiter = null;
-
- browser.downloads.onCreated.addListener(data => {
- events.add({type: "onCreated", data});
- if (eventWaiter) {
- eventWaiter();
- }
- });
-
- browser.downloads.onChanged.addListener(data => {
- events.add({type: "onChanged", data});
- if (eventWaiter) {
- eventWaiter();
- }
- });
-
- browser.downloads.onErased.addListener(data => {
- events.add({type: "onErased", data});
- if (eventWaiter) {
- eventWaiter();
- }
- });
-
- // Returns a promise that will resolve when the given list of expected
- // events have all been seen. By default, succeeds only if the exact list
- // of expected events is seen in the given order. options.exact can be
- // set to false to allow other events and options.inorder can be set to
- // false to allow the events to arrive in any order.
- function waitForEvents(expected, options = {}) {
- function compare(a, b) {
- if (typeof b == "object" && b != null) {
- if (typeof a != "object") {
- return false;
- }
- return Object.keys(b).every(fld => compare(a[fld], b[fld]));
- }
- return (a == b);
- }
-
- const exact = ("exact" in options) ? options.exact : true;
- const inorder = ("inorder" in options) ? options.inorder : true;
- return new Promise((resolve, reject) => {
- function check() {
- function fail(msg) {
- browser.test.fail(msg);
- reject(new Error(msg));
- }
- if (events.size < expected.length) {
- return;
- }
- if (exact && expected.length < events.size) {
- fail(`Got ${events.size} events but only expected ${expected.length}`);
- return;
- }
-
- let remaining = new Set(events);
- if (inorder) {
- for (let event of events) {
- if (compare(event, expected[0])) {
- expected.shift();
- remaining.delete(event);
- }
- }
- } else {
- expected = expected.filter(val => {
- for (let remainingEvent of remaining) {
- if (compare(remainingEvent, val)) {
- remaining.delete(remainingEvent);
- return false;
- }
- }
- return true;
- });
- }
-
- // Events that did occur have been removed from expected so if
- // expected is empty, we're done. If we didn't see all the
- // expected events and we're not looking for an exact match,
- // then we just may not have seen the event yet, so return without
- // failing and check() will be called again when a new event arrives.
- if (expected.length == 0) {
- events = remaining;
- eventWaiter = null;
- resolve();
- } else if (exact) {
- fail(`Mismatched event: expecting ${JSON.stringify(expected[0])} but got ${JSON.stringify(Array.from(remaining)[0])}`);
- }
- }
- eventWaiter = check;
- check();
- });
- }
-
- browser.test.onMessage.addListener(async (msg, ...args) => {
- let match = msg.match(/(\w+).request$/);
- if (!match) {
- return;
- }
-
- let what = match[1];
- if (what == "waitForEvents") {
- try {
- await waitForEvents(...args);
- browser.test.sendMessage("waitForEvents.done", {status: "success"});
- } catch (error) {
- browser.test.sendMessage("waitForEvents.done", {status: "error", errmsg: error.message});
- }
- } else if (what == "clearEvents") {
- events = new Set();
- browser.test.sendMessage("clearEvents.done", {status: "success"});
- } else {
- try {
- let result = await browser.downloads[what](...args);
- browser.test.sendMessage(`${what}.done`, {status: "success", result});
- } catch (error) {
- browser.test.sendMessage(`${what}.done`, {status: "error", errmsg: error.message});
- }
- }
- });
-
- browser.test.sendMessage("ready");
-}
-
-let downloadDir;
-let extension;
-
-async function clearDownloads(callback) {
- let list = await Downloads.getList(Downloads.ALL);
- let downloads = await list.getAll();
-
- await Promise.all(downloads.map(download => list.remove(download)));
-
- return downloads;
-}
-
-function runInExtension(what, ...args) {
- extension.sendMessage(`${what}.request`, ...args);
- return extension.awaitMessage(`${what}.done`);
-}
-
-// This is pretty simplistic, it looks for a progress update for a
-// download of the given url in which the total bytes are exactly equal
-// to the given value. Unless you know exactly how data will arrive from
-// the server (eg see interruptible.sjs), it probably isn't very useful.
-async function waitForProgress(url, bytes) {
- let list = await Downloads.getList(Downloads.ALL);
-
- return new Promise(resolve => {
- const view = {
- onDownloadChanged(download) {
- if (download.source.url == url && download.currentBytes == bytes) {
- list.removeView(view);
- resolve();
- }
- },
- };
- list.addView(view);
- });
-}
-
-add_task(function* setup() {
- const nsIFile = Ci.nsIFile;
- downloadDir = FileUtils.getDir("TmpD", ["downloads"]);
- downloadDir.createUnique(nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
- do_print(`downloadDir ${downloadDir.path}`);
-
- Services.prefs.setIntPref("browser.download.folderList", 2);
- Services.prefs.setComplexValue("browser.download.dir", nsIFile, downloadDir);
-
- do_register_cleanup(() => {
- Services.prefs.clearUserPref("browser.download.folderList");
- Services.prefs.clearUserPref("browser.download.dir");
- downloadDir.remove(true);
-
- return clearDownloads();
- });
-
- yield clearDownloads().then(downloads => {
- do_print(`removed ${downloads.length} pre-existing downloads from history`);
- });
-
- extension = ExtensionTestUtils.loadExtension({
- background: backgroundScript,
- manifest: {
- permissions: ["downloads"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitMessage("ready");
-});
-
-add_task(function* test_events() {
- let msg = yield runInExtension("download", {url: TXT_URL});
- equal(msg.status, "success", "download() succeeded");
- const id = msg.result;
-
- msg = yield runInExtension("waitForEvents", [
- {type: "onCreated", data: {id, url: TXT_URL}},
- {
- type: "onChanged",
- data: {
- id,
- state: {
- previous: "in_progress",
- current: "complete",
- },
- },
- },
- ]);
- equal(msg.status, "success", "got onCreated and onChanged events");
-});
-
-add_task(function* test_cancel() {
- let url = getInterruptibleUrl();
- do_print(url);
- let msg = yield runInExtension("download", {url});
- equal(msg.status, "success", "download() succeeded");
- const id = msg.result;
-
- let progressPromise = waitForProgress(url, INT_PARTIAL_LEN);
-
- msg = yield runInExtension("waitForEvents", [
- {type: "onCreated", data: {id}},
- ]);
- equal(msg.status, "success", "got created and changed events");
-
- yield progressPromise;
- do_print(`download reached ${INT_PARTIAL_LEN} bytes`);
-
- msg = yield runInExtension("cancel", id);
- equal(msg.status, "success", "cancel() succeeded");
-
- // This sequence of events is bogus (bug 1256243)
- msg = yield runInExtension("waitForEvents", [
- {
- type: "onChanged",
- data: {
- state: {
- previous: "in_progress",
- current: "interrupted",
- },
- paused: {
- previous: false,
- current: true,
- },
- },
- }, {
- type: "onChanged",
- data: {
- id,
- error: {
- previous: null,
- current: "USER_CANCELED",
- },
- },
- }, {
- type: "onChanged",
- data: {
- id,
- paused: {
- previous: true,
- current: false,
- },
- },
- },
- ]);
- equal(msg.status, "success", "got onChanged events corresponding to cancel()");
-
- msg = yield runInExtension("search", {error: "USER_CANCELED"});
- equal(msg.status, "success", "search() succeeded");
- equal(msg.result.length, 1, "search() found 1 download");
- equal(msg.result[0].id, id, "download.id is correct");
- equal(msg.result[0].state, "interrupted", "download.state is correct");
- equal(msg.result[0].paused, false, "download.paused is correct");
- equal(msg.result[0].canResume, false, "download.canResume is correct");
- equal(msg.result[0].error, "USER_CANCELED", "download.error is correct");
- equal(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct");
- equal(msg.result[0].exists, false, "download.exists is correct");
-
- msg = yield runInExtension("pause", id);
- equal(msg.status, "error", "cannot pause a canceled download");
-
- msg = yield runInExtension("resume", id);
- equal(msg.status, "error", "cannot resume a canceled download");
-});
-
-add_task(function* test_pauseresume() {
- let url = getInterruptibleUrl();
- let msg = yield runInExtension("download", {url});
- equal(msg.status, "success", "download() succeeded");
- const id = msg.result;
-
- let progressPromise = waitForProgress(url, INT_PARTIAL_LEN);
-
- msg = yield runInExtension("waitForEvents", [
- {type: "onCreated", data: {id}},
- ]);
- equal(msg.status, "success", "got created and changed events");
-
- yield progressPromise;
- do_print(`download reached ${INT_PARTIAL_LEN} bytes`);
-
- msg = yield runInExtension("pause", id);
- equal(msg.status, "success", "pause() succeeded");
-
- msg = yield runInExtension("waitForEvents", [
- {
- type: "onChanged",
- data: {
- id,
- state: {
- previous: "in_progress",
- current: "interrupted",
- },
- paused: {
- previous: false,
- current: true,
- },
- canResume: {
- previous: false,
- current: true,
- },
- },
- }, {
- type: "onChanged",
- data: {
- id,
- error: {
- previous: null,
- current: "USER_CANCELED",
- },
- },
- }]);
- equal(msg.status, "success", "got onChanged event corresponding to pause");
-
- msg = yield runInExtension("search", {paused: true});
- equal(msg.status, "success", "search() succeeded");
- equal(msg.result.length, 1, "search() found 1 download");
- equal(msg.result[0].id, id, "download.id is correct");
- equal(msg.result[0].state, "interrupted", "download.state is correct");
- equal(msg.result[0].paused, true, "download.paused is correct");
- equal(msg.result[0].canResume, true, "download.canResume is correct");
- equal(msg.result[0].error, "USER_CANCELED", "download.error is correct");
- equal(msg.result[0].bytesReceived, INT_PARTIAL_LEN, "download.bytesReceived is correct");
- equal(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct");
- equal(msg.result[0].exists, false, "download.exists is correct");
-
- msg = yield runInExtension("search", {error: "USER_CANCELED"});
- equal(msg.status, "success", "search() succeeded");
- let found = msg.result.filter(item => item.id == id);
- equal(found.length, 1, "search() by error found the paused download");
-
- msg = yield runInExtension("pause", id);
- equal(msg.status, "error", "cannot pause an already paused download");
-
- msg = yield runInExtension("resume", id);
- equal(msg.status, "success", "resume() succeeded");
-
- msg = yield runInExtension("waitForEvents", [
- {
- type: "onChanged",
- data: {
- id,
- state: {
- previous: "interrupted",
- current: "in_progress",
- },
- paused: {
- previous: true,
- current: false,
- },
- canResume: {
- previous: true,
- current: false,
- },
- error: {
- previous: "USER_CANCELED",
- current: null,
- },
- },
- },
- {
- type: "onChanged",
- data: {
- id,
- state: {
- previous: "in_progress",
- current: "complete",
- },
- },
- },
- ]);
- equal(msg.status, "success", "got onChanged events for resume and complete");
-
- msg = yield runInExtension("search", {id});
- equal(msg.status, "success", "search() succeeded");
- equal(msg.result.length, 1, "search() found 1 download");
- equal(msg.result[0].state, "complete", "download.state is correct");
- equal(msg.result[0].paused, false, "download.paused is correct");
- equal(msg.result[0].canResume, false, "download.canResume is correct");
- equal(msg.result[0].error, null, "download.error is correct");
- equal(msg.result[0].bytesReceived, INT_TOTAL_LEN, "download.bytesReceived is correct");
- equal(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct");
- equal(msg.result[0].exists, true, "download.exists is correct");
-
- msg = yield runInExtension("pause", id);
- equal(msg.status, "error", "cannot pause a completed download");
-
- msg = yield runInExtension("resume", id);
- equal(msg.status, "error", "cannot resume a completed download");
-});
-
-add_task(function* test_pausecancel() {
- let url = getInterruptibleUrl();
- let msg = yield runInExtension("download", {url});
- equal(msg.status, "success", "download() succeeded");
- const id = msg.result;
-
- let progressPromise = waitForProgress(url, INT_PARTIAL_LEN);
-
- msg = yield runInExtension("waitForEvents", [
- {type: "onCreated", data: {id}},
- ]);
- equal(msg.status, "success", "got created and changed events");
-
- yield progressPromise;
- do_print(`download reached ${INT_PARTIAL_LEN} bytes`);
-
- msg = yield runInExtension("pause", id);
- equal(msg.status, "success", "pause() succeeded");
-
- msg = yield runInExtension("waitForEvents", [
- {
- type: "onChanged",
- data: {
- id,
- state: {
- previous: "in_progress",
- current: "interrupted",
- },
- paused: {
- previous: false,
- current: true,
- },
- canResume: {
- previous: false,
- current: true,
- },
- },
- }, {
- type: "onChanged",
- data: {
- id,
- error: {
- previous: null,
- current: "USER_CANCELED",
- },
- },
- }]);
- equal(msg.status, "success", "got onChanged event corresponding to pause");
-
- msg = yield runInExtension("search", {paused: true});
- equal(msg.status, "success", "search() succeeded");
- equal(msg.result.length, 1, "search() found 1 download");
- equal(msg.result[0].id, id, "download.id is correct");
- equal(msg.result[0].state, "interrupted", "download.state is correct");
- equal(msg.result[0].paused, true, "download.paused is correct");
- equal(msg.result[0].canResume, true, "download.canResume is correct");
- equal(msg.result[0].error, "USER_CANCELED", "download.error is correct");
- equal(msg.result[0].bytesReceived, INT_PARTIAL_LEN, "download.bytesReceived is correct");
- equal(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct");
- equal(msg.result[0].exists, false, "download.exists is correct");
-
- msg = yield runInExtension("search", {error: "USER_CANCELED"});
- equal(msg.status, "success", "search() succeeded");
- let found = msg.result.filter(item => item.id == id);
- equal(found.length, 1, "search() by error found the paused download");
-
- msg = yield runInExtension("cancel", id);
- equal(msg.status, "success", "cancel() succeeded");
-
- msg = yield runInExtension("waitForEvents", [
- {
- type: "onChanged",
- data: {
- id,
- paused: {
- previous: true,
- current: false,
- },
- canResume: {
- previous: true,
- current: false,
- },
- },
- },
- ]);
- equal(msg.status, "success", "got onChanged event for cancel");
-
- msg = yield runInExtension("search", {id});
- equal(msg.status, "success", "search() succeeded");
- equal(msg.result.length, 1, "search() found 1 download");
- equal(msg.result[0].state, "interrupted", "download.state is correct");
- equal(msg.result[0].paused, false, "download.paused is correct");
- equal(msg.result[0].canResume, false, "download.canResume is correct");
- equal(msg.result[0].error, "USER_CANCELED", "download.error is correct");
- equal(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct");
- equal(msg.result[0].exists, false, "download.exists is correct");
-});
-
-add_task(function* test_pause_resume_cancel_badargs() {
- let BAD_ID = 1000;
-
- let msg = yield runInExtension("pause", BAD_ID);
- equal(msg.status, "error", "pause() failed with a bad download id");
- ok(/Invalid download id/.test(msg.errmsg), "error message is descriptive");
-
- msg = yield runInExtension("resume", BAD_ID);
- equal(msg.status, "error", "resume() failed with a bad download id");
- ok(/Invalid download id/.test(msg.errmsg), "error message is descriptive");
-
- msg = yield runInExtension("cancel", BAD_ID);
- equal(msg.status, "error", "cancel() failed with a bad download id");
- ok(/Invalid download id/.test(msg.errmsg), "error message is descriptive");
-});
-
-add_task(function* test_file_removal() {
- let msg = yield runInExtension("download", {url: TXT_URL});
- equal(msg.status, "success", "download() succeeded");
- const id = msg.result;
-
- msg = yield runInExtension("waitForEvents", [
- {type: "onCreated", data: {id, url: TXT_URL}},
- {
- type: "onChanged",
- data: {
- id,
- state: {
- previous: "in_progress",
- current: "complete",
- },
- },
- },
- ]);
-
- equal(msg.status, "success", "got onCreated and onChanged events");
-
- msg = yield runInExtension("removeFile", id);
- equal(msg.status, "success", "removeFile() succeeded");
-
- msg = yield runInExtension("removeFile", id);
- equal(msg.status, "error", "removeFile() fails since the file was already removed.");
- ok(/file doesn't exist/.test(msg.errmsg), "removeFile() failed on removed file.");
-
- msg = yield runInExtension("removeFile", 1000);
- ok(/Invalid download id/.test(msg.errmsg), "removeFile() failed due to non-existent id");
-});
-
-add_task(function* test_removal_of_incomplete_download() {
- let url = getInterruptibleUrl();
- let msg = yield runInExtension("download", {url});
- equal(msg.status, "success", "download() succeeded");
- const id = msg.result;
-
- let progressPromise = waitForProgress(url, INT_PARTIAL_LEN);
-
- msg = yield runInExtension("waitForEvents", [
- {type: "onCreated", data: {id}},
- ]);
- equal(msg.status, "success", "got created and changed events");
-
- yield progressPromise;
- do_print(`download reached ${INT_PARTIAL_LEN} bytes`);
-
- msg = yield runInExtension("pause", id);
- equal(msg.status, "success", "pause() succeeded");
-
- msg = yield runInExtension("waitForEvents", [
- {
- type: "onChanged",
- data: {
- id,
- state: {
- previous: "in_progress",
- current: "interrupted",
- },
- paused: {
- previous: false,
- current: true,
- },
- canResume: {
- previous: false,
- current: true,
- },
- },
- }, {
- type: "onChanged",
- data: {
- id,
- error: {
- previous: null,
- current: "USER_CANCELED",
- },
- },
- }]);
- equal(msg.status, "success", "got onChanged event corresponding to pause");
-
- msg = yield runInExtension("removeFile", id);
- equal(msg.status, "error", "removeFile() on paused download failed");
-
- ok(/Cannot remove incomplete download/.test(msg.errmsg), "removeFile() failed due to download being incomplete");
-
- msg = yield runInExtension("resume", id);
- equal(msg.status, "success", "resume() succeeded");
-
- msg = yield runInExtension("waitForEvents", [
- {
- type: "onChanged",
- data: {
- id,
- state: {
- previous: "interrupted",
- current: "in_progress",
- },
- paused: {
- previous: true,
- current: false,
- },
- canResume: {
- previous: true,
- current: false,
- },
- error: {
- previous: "USER_CANCELED",
- current: null,
- },
- },
- },
- {
- type: "onChanged",
- data: {
- id,
- state: {
- previous: "in_progress",
- current: "complete",
- },
- },
- },
- ]);
- equal(msg.status, "success", "got onChanged events for resume and complete");
-
- msg = yield runInExtension("removeFile", id);
- equal(msg.status, "success", "removeFile() succeeded following completion of resumed download.");
-});
-
-// Test erase(). We don't do elaborate testing of the query handling
-// since it uses the exact same engine as search() which is tested
-// more thoroughly in test_chrome_ext_downloads_search.html
-add_task(function* test_erase() {
- yield clearDownloads();
-
- yield runInExtension("clearEvents");
-
- function* download() {
- let msg = yield runInExtension("download", {url: TXT_URL});
- equal(msg.status, "success", "download succeeded");
- let id = msg.result;
-
- msg = yield runInExtension("waitForEvents", [{
- type: "onChanged", data: {id, state: {current: "complete"}},
- }], {exact: false});
- equal(msg.status, "success", "download finished");
-
- return id;
- }
-
- let ids = {};
- ids.dl1 = yield download();
- ids.dl2 = yield download();
- ids.dl3 = yield download();
-
- let msg = yield runInExtension("search", {});
- equal(msg.status, "success", "search succeded");
- equal(msg.result.length, 3, "search found 3 downloads");
-
- msg = yield runInExtension("clearEvents");
-
- msg = yield runInExtension("erase", {id: ids.dl1});
- equal(msg.status, "success", "erase by id succeeded");
-
- msg = yield runInExtension("waitForEvents", [
- {type: "onErased", data: ids.dl1},
- ]);
- equal(msg.status, "success", "received onErased event");
-
- msg = yield runInExtension("search", {});
- equal(msg.status, "success", "search succeded");
- equal(msg.result.length, 2, "search found 2 downloads");
-
- msg = yield runInExtension("erase", {});
- equal(msg.status, "success", "erase everything succeeded");
-
- msg = yield runInExtension("waitForEvents", [
- {type: "onErased", data: ids.dl2},
- {type: "onErased", data: ids.dl3},
- ], {inorder: false});
- equal(msg.status, "success", "received 2 onErased events");
-
- msg = yield runInExtension("search", {});
- equal(msg.status, "success", "search succeded");
- equal(msg.result.length, 0, "search found 0 downloads");
-});
-
-function loadImage(img, data) {
- return new Promise((resolve) => {
- img.src = data;
- img.onload = resolve;
- });
-}
-
-add_task(function* test_getFileIcon() {
- let webNav = Services.appShell.createWindowlessBrowser(false);
- let docShell = webNav.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDocShell);
-
- let system = Services.scriptSecurityManager.getSystemPrincipal();
- docShell.createAboutBlankContentViewer(system);
-
- let img = webNav.document.createElement("img");
-
- let msg = yield runInExtension("download", {url: TXT_URL});
- equal(msg.status, "success", "download() succeeded");
- const id = msg.result;
-
- msg = yield runInExtension("getFileIcon", id);
- equal(msg.status, "success", "getFileIcon() succeeded");
- yield loadImage(img, msg.result);
- equal(img.height, 32, "returns an icon with the right height");
- equal(img.width, 32, "returns an icon with the right width");
-
- msg = yield runInExtension("waitForEvents", [
- {type: "onCreated", data: {id, url: TXT_URL}},
- {type: "onChanged"},
- ]);
- equal(msg.status, "success", "got events");
-
- msg = yield runInExtension("getFileIcon", id);
- equal(msg.status, "success", "getFileIcon() succeeded");
- yield loadImage(img, msg.result);
- equal(img.height, 32, "returns an icon with the right height after download");
- equal(img.width, 32, "returns an icon with the right width after download");
-
- msg = yield runInExtension("getFileIcon", id + 100);
- equal(msg.status, "error", "getFileIcon() failed");
- ok(msg.errmsg.includes("Invalid download id"), "download id is invalid");
-
- msg = yield runInExtension("getFileIcon", id, {size: 127});
- equal(msg.status, "success", "getFileIcon() succeeded");
- yield loadImage(img, msg.result);
- equal(img.height, 127, "returns an icon with the right custom height");
- equal(img.width, 127, "returns an icon with the right custom width");
-
- msg = yield runInExtension("getFileIcon", id, {size: 1});
- equal(msg.status, "success", "getFileIcon() succeeded");
- yield loadImage(img, msg.result);
- equal(img.height, 1, "returns an icon with the right custom height");
- equal(img.width, 1, "returns an icon with the right custom width");
-
- msg = yield runInExtension("getFileIcon", id, {size: "foo"});
- equal(msg.status, "error", "getFileIcon() fails");
- ok(msg.errmsg.includes("Error processing size"), "size is not a number");
-
- msg = yield runInExtension("getFileIcon", id, {size: 0});
- equal(msg.status, "error", "getFileIcon() fails");
- ok(msg.errmsg.includes("Error processing size"), "size is too small");
-
- msg = yield runInExtension("getFileIcon", id, {size: 128});
- equal(msg.status, "error", "getFileIcon() fails");
- ok(msg.errmsg.includes("Error processing size"), "size is too big");
-
- webNav.close();
-});
-
-add_task(function* cleanup() {
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_downloads_search.js b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_search.js
deleted file mode 100644
index 4caa82456..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_downloads_search.js
+++ /dev/null
@@ -1,402 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-Cu.import("resource://gre/modules/Downloads.jsm");
-
-const server = createHttpServer();
-server.registerDirectory("/data/", do_get_file("data"));
-
-const BASE = `http://localhost:${server.identity.primaryPort}/data`;
-const TXT_FILE = "file_download.txt";
-const TXT_URL = BASE + "/" + TXT_FILE;
-const TXT_LEN = 46;
-const HTML_FILE = "file_download.html";
-const HTML_URL = BASE + "/" + HTML_FILE;
-const HTML_LEN = 117;
-const BIG_LEN = 1000; // something bigger both TXT_LEN and HTML_LEN
-
-function backgroundScript() {
- let complete = new Map();
-
- function waitForComplete(id) {
- if (complete.has(id)) {
- return complete.get(id).promise;
- }
-
- let promise = new Promise(resolve => {
- complete.set(id, {resolve});
- });
- complete.get(id).promise = promise;
- return promise;
- }
-
- browser.downloads.onChanged.addListener(change => {
- if (change.state && change.state.current == "complete") {
- // Make sure we have a promise.
- waitForComplete(change.id);
- complete.get(change.id).resolve();
- }
- });
-
- browser.test.onMessage.addListener(async (msg, ...args) => {
- if (msg == "download.request") {
- try {
- let id = await browser.downloads.download(args[0]);
- browser.test.sendMessage("download.done", {status: "success", id});
- } catch (error) {
- browser.test.sendMessage("download.done", {status: "error", errmsg: error.message});
- }
- } else if (msg == "search.request") {
- try {
- let downloads = await browser.downloads.search(args[0]);
- browser.test.sendMessage("search.done", {status: "success", downloads});
- } catch (error) {
- browser.test.sendMessage("search.done", {status: "error", errmsg: error.message});
- }
- } else if (msg == "waitForComplete.request") {
- await waitForComplete(args[0]);
- browser.test.sendMessage("waitForComplete.done");
- }
- });
-
- browser.test.sendMessage("ready");
-}
-
-async function clearDownloads(callback) {
- let list = await Downloads.getList(Downloads.ALL);
- let downloads = await list.getAll();
-
- await Promise.all(downloads.map(download => list.remove(download)));
-
- return downloads;
-}
-
-add_task(function* test_search() {
- const nsIFile = Ci.nsIFile;
- let downloadDir = FileUtils.getDir("TmpD", ["downloads"]);
- downloadDir.createUnique(nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
- do_print(`downloadDir ${downloadDir.path}`);
-
- function downloadPath(filename) {
- let path = downloadDir.clone();
- path.append(filename);
- return path.path;
- }
-
- Services.prefs.setIntPref("browser.download.folderList", 2);
- Services.prefs.setComplexValue("browser.download.dir", nsIFile, downloadDir);
-
- do_register_cleanup(async () => {
- Services.prefs.clearUserPref("browser.download.folderList");
- Services.prefs.clearUserPref("browser.download.dir");
- await cleanupDir(downloadDir);
- await clearDownloads();
- });
-
- yield clearDownloads().then(downloads => {
- do_print(`removed ${downloads.length} pre-existing downloads from history`);
- });
-
- let extension = ExtensionTestUtils.loadExtension({
- background: backgroundScript,
- manifest: {
- permissions: ["downloads"],
- },
- });
-
- async function download(options) {
- extension.sendMessage("download.request", options);
- let result = await extension.awaitMessage("download.done");
-
- if (result.status == "success") {
- do_print(`wait for onChanged event to indicate ${result.id} is complete`);
- extension.sendMessage("waitForComplete.request", result.id);
-
- await extension.awaitMessage("waitForComplete.done");
- }
-
- return result;
- }
-
- function search(query) {
- extension.sendMessage("search.request", query);
- return extension.awaitMessage("search.done");
- }
-
- yield extension.startup();
- yield extension.awaitMessage("ready");
-
- // Do some downloads...
- const time1 = new Date();
-
- let downloadIds = {};
- let msg = yield download({url: TXT_URL});
- equal(msg.status, "success", "download() succeeded");
- downloadIds.txt1 = msg.id;
-
- const TXT_FILE2 = "NewFile.txt";
- msg = yield download({url: TXT_URL, filename: TXT_FILE2});
- equal(msg.status, "success", "download() succeeded");
- downloadIds.txt2 = msg.id;
-
- const time2 = new Date();
-
- msg = yield download({url: HTML_URL});
- equal(msg.status, "success", "download() succeeded");
- downloadIds.html1 = msg.id;
-
- const HTML_FILE2 = "renamed.html";
- msg = yield download({url: HTML_URL, filename: HTML_FILE2});
- equal(msg.status, "success", "download() succeeded");
- downloadIds.html2 = msg.id;
-
- const time3 = new Date();
-
- // Search for each individual download and check
- // the corresponding DownloadItem.
- function* checkDownloadItem(id, expect) {
- let item = yield search({id});
- equal(item.status, "success", "search() succeeded");
- equal(item.downloads.length, 1, "search() found exactly 1 download");
-
- Object.keys(expect).forEach(function(field) {
- equal(item.downloads[0][field], expect[field], `DownloadItem.${field} is correct"`);
- });
- }
- yield checkDownloadItem(downloadIds.txt1, {
- url: TXT_URL,
- filename: downloadPath(TXT_FILE),
- mime: "text/plain",
- state: "complete",
- bytesReceived: TXT_LEN,
- totalBytes: TXT_LEN,
- fileSize: TXT_LEN,
- exists: true,
- });
-
- yield checkDownloadItem(downloadIds.txt2, {
- url: TXT_URL,
- filename: downloadPath(TXT_FILE2),
- mime: "text/plain",
- state: "complete",
- bytesReceived: TXT_LEN,
- totalBytes: TXT_LEN,
- fileSize: TXT_LEN,
- exists: true,
- });
-
- yield checkDownloadItem(downloadIds.html1, {
- url: HTML_URL,
- filename: downloadPath(HTML_FILE),
- mime: "text/html",
- state: "complete",
- bytesReceived: HTML_LEN,
- totalBytes: HTML_LEN,
- fileSize: HTML_LEN,
- exists: true,
- });
-
- yield checkDownloadItem(downloadIds.html2, {
- url: HTML_URL,
- filename: downloadPath(HTML_FILE2),
- mime: "text/html",
- state: "complete",
- bytesReceived: HTML_LEN,
- totalBytes: HTML_LEN,
- fileSize: HTML_LEN,
- exists: true,
- });
-
- function* checkSearch(query, expected, description, exact) {
- let item = yield search(query);
- equal(item.status, "success", "search() succeeded");
- equal(item.downloads.length, expected.length, `search() for ${description} found exactly ${expected.length} downloads`);
-
- let receivedIds = item.downloads.map(i => i.id);
- if (exact) {
- receivedIds.forEach((id, idx) => {
- equal(id, downloadIds[expected[idx]], `search() for ${description} returned ${expected[idx]} in position ${idx}`);
- });
- } else {
- Object.keys(downloadIds).forEach(key => {
- const id = downloadIds[key];
- const thisExpected = expected.includes(key);
- equal(receivedIds.includes(id), thisExpected,
- `search() for ${description} ${thisExpected ? "includes" : "does not include"} ${key}`);
- });
- }
- }
-
- // Check that search with an invalid id returns nothing.
- // NB: for now ids are not persistent and we start numbering them at 1
- // so a sufficiently large number will be unused.
- const INVALID_ID = 1000;
- yield checkSearch({id: INVALID_ID}, [], "invalid id");
-
- // Check that search on url works.
- yield checkSearch({url: TXT_URL}, ["txt1", "txt2"], "url");
-
- // Check that regexp on url works.
- const HTML_REGEX = "[downlad]{8}\.html+$";
- yield checkSearch({urlRegex: HTML_REGEX}, ["html1", "html2"], "url regexp");
-
- // Check that compatible url+regexp works
- yield checkSearch({url: HTML_URL, urlRegex: HTML_REGEX}, ["html1", "html2"], "compatible url+urlRegex");
-
- // Check that incompatible url+regexp works
- yield checkSearch({url: TXT_URL, urlRegex: HTML_REGEX}, [], "incompatible url+urlRegex");
-
- // Check that search on filename works.
- yield checkSearch({filename: downloadPath(TXT_FILE)}, ["txt1"], "filename");
-
- // Check that regexp on filename works.
- yield checkSearch({filenameRegex: HTML_REGEX}, ["html1"], "filename regex");
-
- // Check that compatible filename+regexp works
- yield checkSearch({filename: downloadPath(HTML_FILE), filenameRegex: HTML_REGEX}, ["html1"], "compatible filename+filename regex");
-
- // Check that incompatible filename+regexp works
- yield checkSearch({filename: downloadPath(TXT_FILE), filenameRegex: HTML_REGEX}, [], "incompatible filename+filename regex");
-
- // Check that simple positive search terms work.
- yield checkSearch({query: ["file_download"]}, ["txt1", "txt2", "html1", "html2"],
- "term file_download");
- yield checkSearch({query: ["NewFile"]}, ["txt2"], "term NewFile");
-
- // Check that positive search terms work case-insensitive.
- yield checkSearch({query: ["nEwfILe"]}, ["txt2"], "term nEwfiLe");
-
- // Check that negative search terms work.
- yield checkSearch({query: ["-txt"]}, ["html1", "html2"], "term -txt");
-
- // Check that positive and negative search terms together work.
- yield checkSearch({query: ["html", "-renamed"]}, ["html1"], "postive and negative terms");
-
- function* checkSearchWithDate(query, expected, description) {
- const fields = Object.keys(query);
- if (fields.length != 1 || !(query[fields[0]] instanceof Date)) {
- throw new Error("checkSearchWithDate expects exactly one Date field");
- }
- const field = fields[0];
- const date = query[field];
-
- let newquery = {};
-
- // Check as a Date
- newquery[field] = date;
- yield checkSearch(newquery, expected, `${description} as Date`);
-
- // Check as numeric milliseconds
- newquery[field] = date.valueOf();
- yield checkSearch(newquery, expected, `${description} as numeric ms`);
-
- // Check as stringified milliseconds
- newquery[field] = date.valueOf().toString();
- yield checkSearch(newquery, expected, `${description} as string ms`);
-
- // Check as ISO string
- newquery[field] = date.toISOString();
- yield checkSearch(newquery, expected, `${description} as iso string`);
- }
-
- // Check startedBefore
- yield checkSearchWithDate({startedBefore: time1}, [], "before time1");
- yield checkSearchWithDate({startedBefore: time2}, ["txt1", "txt2"], "before time2");
- yield checkSearchWithDate({startedBefore: time3}, ["txt1", "txt2", "html1", "html2"], "before time3");
-
- // Check startedAfter
- yield checkSearchWithDate({startedAfter: time1}, ["txt1", "txt2", "html1", "html2"], "after time1");
- yield checkSearchWithDate({startedAfter: time2}, ["html1", "html2"], "after time2");
- yield checkSearchWithDate({startedAfter: time3}, [], "after time3");
-
- // Check simple search on totalBytes
- yield checkSearch({totalBytes: TXT_LEN}, ["txt1", "txt2"], "totalBytes");
- yield checkSearch({totalBytes: HTML_LEN}, ["html1", "html2"], "totalBytes");
-
- // Check simple test on totalBytes{Greater,Less}
- // (NB: TXT_LEN < HTML_LEN < BIG_LEN)
- yield checkSearch({totalBytesGreater: 0}, ["txt1", "txt2", "html1", "html2"], "totalBytesGreater than 0");
- yield checkSearch({totalBytesGreater: TXT_LEN}, ["html1", "html2"], `totalBytesGreater than ${TXT_LEN}`);
- yield checkSearch({totalBytesGreater: HTML_LEN}, [], `totalBytesGreater than ${HTML_LEN}`);
- yield checkSearch({totalBytesLess: TXT_LEN}, [], `totalBytesLess than ${TXT_LEN}`);
- yield checkSearch({totalBytesLess: HTML_LEN}, ["txt1", "txt2"], `totalBytesLess than ${HTML_LEN}`);
- yield checkSearch({totalBytesLess: BIG_LEN}, ["txt1", "txt2", "html1", "html2"], `totalBytesLess than ${BIG_LEN}`);
-
- // Check good combinations of totalBytes*.
- yield checkSearch({totalBytes: HTML_LEN, totalBytesGreater: TXT_LEN}, ["html1", "html2"], "totalBytes and totalBytesGreater");
- yield checkSearch({totalBytes: TXT_LEN, totalBytesLess: HTML_LEN}, ["txt1", "txt2"], "totalBytes and totalBytesGreater");
- yield checkSearch({totalBytes: HTML_LEN, totalBytesLess: BIG_LEN, totalBytesGreater: 0}, ["html1", "html2"], "totalBytes and totalBytesLess and totalBytesGreater");
-
- // Check bad combination of totalBytes*.
- yield checkSearch({totalBytesLess: TXT_LEN, totalBytesGreater: HTML_LEN}, [], "bad totalBytesLess, totalBytesGreater combination");
- yield checkSearch({totalBytes: TXT_LEN, totalBytesGreater: HTML_LEN}, [], "bad totalBytes, totalBytesGreater combination");
- yield checkSearch({totalBytes: HTML_LEN, totalBytesLess: TXT_LEN}, [], "bad totalBytes, totalBytesLess combination");
-
- // Check mime.
- yield checkSearch({mime: "text/plain"}, ["txt1", "txt2"], "mime text/plain");
- yield checkSearch({mime: "text/html"}, ["html1", "html2"], "mime text/htmlplain");
- yield checkSearch({mime: "video/webm"}, [], "mime video/webm");
-
- // Check fileSize.
- yield checkSearch({fileSize: TXT_LEN}, ["txt1", "txt2"], "fileSize");
- yield checkSearch({fileSize: HTML_LEN}, ["html1", "html2"], "fileSize");
-
- // Fields like bytesReceived, paused, state, exists are meaningful
- // for downloads that are in progress but have not yet completed.
- // todo: add tests for these when we have better support for in-progress
- // downloads (e.g., after pause(), resume() and cancel() are implemented)
-
- // Check multiple query properties.
- // We could make this testing arbitrarily complicated...
- // We already tested combining fields with obvious interactions above
- // (e.g., filename and filenameRegex or startTime and startedBefore/After)
- // so now just throw as many fields as we can at a single search and
- // make sure a simple case still works.
- yield checkSearch({
- url: TXT_URL,
- urlRegex: "download",
- filename: downloadPath(TXT_FILE),
- filenameRegex: "download",
- query: ["download"],
- startedAfter: time1.valueOf().toString(),
- startedBefore: time2.valueOf().toString(),
- totalBytes: TXT_LEN,
- totalBytesGreater: 0,
- totalBytesLess: BIG_LEN,
- mime: "text/plain",
- fileSize: TXT_LEN,
- }, ["txt1"], "many properties");
-
- // Check simple orderBy (forward and backward).
- yield checkSearch({orderBy: ["startTime"]}, ["txt1", "txt2", "html1", "html2"], "orderBy startTime", true);
- yield checkSearch({orderBy: ["-startTime"]}, ["html2", "html1", "txt2", "txt1"], "orderBy -startTime", true);
-
- // Check orderBy with multiple fields.
- // NB: TXT_URL and HTML_URL differ only in extension and .html precedes .txt
- yield checkSearch({orderBy: ["url", "-startTime"]}, ["html2", "html1", "txt2", "txt1"], "orderBy with multiple fields", true);
-
- // Check orderBy with limit.
- yield checkSearch({orderBy: ["url"], limit: 1}, ["html1"], "orderBy with limit", true);
-
- // Check bad arguments.
- function* checkBadSearch(query, pattern, description) {
- let item = yield search(query);
- equal(item.status, "error", "search() failed");
- ok(pattern.test(item.errmsg), `error message for ${description} was correct (${item.errmsg}).`);
- }
-
- yield checkBadSearch("myquery", /Incorrect argument type/, "query is not an object");
- yield checkBadSearch({bogus: "boo"}, /Unexpected property/, "query contains an unknown field");
- yield checkBadSearch({query: "query string"}, /Expected array/, "query.query is a string");
- yield checkBadSearch({startedBefore: "i am not a time"}, /Type error/, "query.startedBefore is not a valid time");
- yield checkBadSearch({startedAfter: "i am not a time"}, /Type error/, "query.startedAfter is not a valid time");
- yield checkBadSearch({endedBefore: "i am not a time"}, /Type error/, "query.endedBefore is not a valid time");
- yield checkBadSearch({endedAfter: "i am not a time"}, /Type error/, "query.endedAfter is not a valid time");
- yield checkBadSearch({urlRegex: "["}, /Invalid urlRegex/, "query.urlRegexp is not a valid regular expression");
- yield checkBadSearch({filenameRegex: "["}, /Invalid filenameRegex/, "query.filenameRegexp is not a valid regular expression");
- yield checkBadSearch({orderBy: "startTime"}, /Expected array/, "query.orderBy is not an array");
- yield checkBadSearch({orderBy: ["bogus"]}, /Invalid orderBy field/, "query.orderBy references a non-existent field");
-
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_experiments.js b/toolkit/components/extensions/test/xpcshell/test_ext_experiments.js
deleted file mode 100644
index bc6bfcd68..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_experiments.js
+++ /dev/null
@@ -1,175 +0,0 @@
-"use strict";
-
-/* globals browser */
-
-XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
- "resource://gre/modules/AddonManager.jsm");
-
-function promiseAddonStartup() {
- const {Management} = Cu.import("resource://gre/modules/Extension.jsm");
-
- return new Promise(resolve => {
- let listener = (evt, extension) => {
- Management.off("startup", listener);
- resolve(extension);
- };
-
- Management.on("startup", listener);
- });
-}
-
-add_task(function* setup() {
- yield ExtensionTestUtils.startAddonManager();
-});
-
-add_task(function* test_experiments_api() {
- let apiAddonFile = Extension.generateZipFile({
- "install.rdf": `<?xml version="1.0" encoding="UTF-8"?>
- <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:em="http://www.mozilla.org/2004/em-rdf#">
- <Description about="urn:mozilla:install-manifest"
- em:id="meh@experiments.addons.mozilla.org"
- em:name="Meh Experiment"
- em:type="256"
- em:version="0.1"
- em:description="Meh experiment"
- em:creator="Mozilla">
-
- <em:targetApplication>
- <Description
- em:id="xpcshell@tests.mozilla.org"
- em:minVersion="48"
- em:maxVersion="*"/>
- </em:targetApplication>
- </Description>
- </RDF>
- `,
-
- "api.js": String.raw`
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- Services.obs.notifyObservers(null, "webext-api-loaded", "");
-
- class API extends ExtensionAPI {
- getAPI(context) {
- return {
- meh: {
- hello(text) {
- Services.obs.notifyObservers(null, "webext-api-hello", text);
- }
- }
- }
- }
- }
- `,
-
- "schema.json": [
- {
- "namespace": "meh",
- "description": "All full of meh.",
- "permissions": ["experiments.meh"],
- "functions": [
- {
- "name": "hello",
- "type": "function",
- "description": "Hates you. This is all.",
- "parameters": [
- {"type": "string", "name": "text"},
- ],
- },
- ],
- },
- ],
- });
-
- let addonFile = Extension.generateXPI({
- manifest: {
- applications: {gecko: {id: "meh@web.extension"}},
- permissions: ["experiments.meh"],
- },
-
- background() {
- // The test code below checks that hello() is called at the right
- // time with the string "Here I am". Verify that the api schema is
- // being correctly interpreted by calling hello() with bad arguments
- // and only calling hello() with the magic string if the call with
- // bad arguments throws.
- try {
- browser.meh.hello("I should not see this", "since two arguments are bad");
- } catch (err) {
- browser.meh.hello("Here I am");
- }
- },
- });
-
- let boringAddonFile = Extension.generateXPI({
- manifest: {
- applications: {gecko: {id: "boring@web.extension"}},
- },
- background() {
- if (browser.meh) {
- browser.meh.hello("Here I should not be");
- }
- },
- });
-
- do_register_cleanup(() => {
- for (let file of [apiAddonFile, addonFile, boringAddonFile]) {
- Services.obs.notifyObservers(file, "flush-cache-entry", null);
- file.remove(false);
- }
- });
-
-
- let resolveHello;
- let observer = (subject, topic, data) => {
- if (topic == "webext-api-loaded") {
- ok(!!resolveHello, "Should not see API loaded until dependent extension loads");
- } else if (topic == "webext-api-hello") {
- resolveHello(data);
- }
- };
-
- Services.obs.addObserver(observer, "webext-api-loaded", false);
- Services.obs.addObserver(observer, "webext-api-hello", false);
- do_register_cleanup(() => {
- Services.obs.removeObserver(observer, "webext-api-loaded");
- Services.obs.removeObserver(observer, "webext-api-hello");
- });
-
-
- // Install API add-on.
- let apiAddon = yield AddonManager.installTemporaryAddon(apiAddonFile);
-
- let {APIs} = Cu.import("resource://gre/modules/ExtensionManagement.jsm", {});
- ok(APIs.apis.has("meh"), "Should have meh API.");
-
-
- // Install boring WebExtension add-on.
- let boringAddon = yield AddonManager.installTemporaryAddon(boringAddonFile);
- yield promiseAddonStartup();
-
-
- // Install interesting WebExtension add-on.
- let promise = new Promise(resolve => {
- resolveHello = resolve;
- });
-
- let addon = yield AddonManager.installTemporaryAddon(addonFile);
- yield promiseAddonStartup();
-
- let hello = yield promise;
- equal(hello, "Here I am", "Should get hello from add-on");
-
- // Cleanup.
- apiAddon.uninstall();
-
- boringAddon.userDisabled = true;
- yield new Promise(do_execute_soon);
-
- equal(addon.appDisabled, true, "Add-on should be app-disabled after its dependency is removed.");
-
- addon.uninstall();
- boringAddon.uninstall();
-});
-
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_extension.js b/toolkit/components/extensions/test/xpcshell/test_ext_extension.js
deleted file mode 100644
index f18845f6a..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_extension.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_is_allowed_incognito_access() {
- async function background() {
- let allowed = await browser.extension.isAllowedIncognitoAccess();
-
- browser.test.assertEq(true, allowed, "isAllowedIncognitoAccess is true");
- browser.test.notifyPass("isAllowedIncognitoAccess");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {},
- });
-
- yield extension.startup();
- yield extension.awaitFinish("isAllowedIncognitoAccess");
- yield extension.unload();
-});
-
-add_task(function* test_in_incognito_context_false() {
- function background() {
- browser.test.assertEq(false, browser.extension.inIncognitoContext, "inIncognitoContext returned false");
- browser.test.notifyPass("inIncognitoContext");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {},
- });
-
- yield extension.startup();
- yield extension.awaitFinish("inIncognitoContext");
- yield extension.unload();
-});
-
-add_task(function* test_is_allowed_file_scheme_access() {
- async function background() {
- let allowed = await browser.extension.isAllowedFileSchemeAccess();
-
- browser.test.assertEq(false, allowed, "isAllowedFileSchemeAccess is false");
- browser.test.notifyPass("isAllowedFileSchemeAccess");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {},
- });
-
- yield extension.startup();
- yield extension.awaitFinish("isAllowedFileSchemeAccess");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_idle.js b/toolkit/components/extensions/test/xpcshell/test_ext_idle.js
deleted file mode 100644
index 89bcac217..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_idle.js
+++ /dev/null
@@ -1,202 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-Cu.import("resource://testing-common/MockRegistrar.jsm");
-
-let idleService = {
- _observers: new Set(),
- _activity: {
- addCalls: [],
- removeCalls: [],
- observerFires: [],
- },
- _reset: function() {
- this._observers.clear();
- this._activity.addCalls = [];
- this._activity.removeCalls = [];
- this._activity.observerFires = [];
- },
- _fireObservers: function(state) {
- for (let observer of this._observers.values()) {
- observer.observe(observer, state, null);
- this._activity.observerFires.push(state);
- }
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIIdleService]),
- idleTime: 19999,
- addIdleObserver: function(observer, time) {
- this._observers.add(observer);
- this._activity.addCalls.push(time);
- },
- removeIdleObserver: function(observer, time) {
- this._observers.delete(observer);
- this._activity.removeCalls.push(time);
- },
-};
-
-function checkActivity(expectedActivity) {
- let {expectedAdd, expectedRemove, expectedFires} = expectedActivity;
- let {addCalls, removeCalls, observerFires} = idleService._activity;
- equal(expectedAdd.length, addCalls.length, "idleService.addIdleObserver was called the expected number of times");
- equal(expectedRemove.length, removeCalls.length, "idleService.removeIdleObserver was called the expected number of times");
- equal(expectedFires.length, observerFires.length, "idle observer was fired the expected number of times");
- deepEqual(addCalls, expectedAdd, "expected interval passed to idleService.addIdleObserver");
- deepEqual(removeCalls, expectedRemove, "expected interval passed to idleService.removeIdleObserver");
- deepEqual(observerFires, expectedFires, "expected topic passed to idle observer");
-}
-
-add_task(function* setup() {
- let fakeIdleService = MockRegistrar.register("@mozilla.org/widget/idleservice;1", idleService);
- do_register_cleanup(() => {
- MockRegistrar.unregister(fakeIdleService);
- });
-});
-
-add_task(function* testQueryStateActive() {
- function background() {
- browser.idle.queryState(20).then(status => {
- browser.test.assertEq("active", status, "Idle status is active");
- browser.test.notifyPass("idle");
- },
- err => {
- browser.test.fail(`Error: ${err} :: ${err.stack}`);
- browser.test.notifyFail("idle");
- });
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- permissions: ["idle"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("idle");
- yield extension.unload();
-});
-
-add_task(function* testQueryStateIdle() {
- function background() {
- browser.idle.queryState(15).then(status => {
- browser.test.assertEq("idle", status, "Idle status is idle");
- browser.test.notifyPass("idle");
- },
- err => {
- browser.test.fail(`Error: ${err} :: ${err.stack}`);
- browser.test.notifyFail("idle");
- });
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- permissions: ["idle"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("idle");
- yield extension.unload();
-});
-
-add_task(function* testOnlySetDetectionInterval() {
- function background() {
- browser.idle.setDetectionInterval(99);
- browser.test.sendMessage("detectionIntervalSet");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- permissions: ["idle"],
- },
- });
-
- idleService._reset();
- yield extension.startup();
- yield extension.awaitMessage("detectionIntervalSet");
- idleService._fireObservers("idle");
- checkActivity({expectedAdd: [], expectedRemove: [], expectedFires: []});
- yield extension.unload();
-});
-
-add_task(function* testSetDetectionIntervalBeforeAddingListener() {
- function background() {
- browser.idle.setDetectionInterval(99);
- browser.idle.onStateChanged.addListener(newState => {
- browser.test.assertEq("idle", newState, "listener fired with the expected state");
- browser.test.sendMessage("listenerFired");
- });
- browser.test.sendMessage("listenerAdded");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- permissions: ["idle"],
- },
- });
-
- idleService._reset();
- yield extension.startup();
- yield extension.awaitMessage("listenerAdded");
- idleService._fireObservers("idle");
- yield extension.awaitMessage("listenerFired");
- checkActivity({expectedAdd: [99], expectedRemove: [], expectedFires: ["idle"]});
- yield extension.unload();
-});
-
-add_task(function* testSetDetectionIntervalAfterAddingListener() {
- function background() {
- browser.idle.onStateChanged.addListener(newState => {
- browser.test.assertEq("idle", newState, "listener fired with the expected state");
- browser.test.sendMessage("listenerFired");
- });
- browser.idle.setDetectionInterval(99);
- browser.test.sendMessage("detectionIntervalSet");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- permissions: ["idle"],
- },
- });
-
- idleService._reset();
- yield extension.startup();
- yield extension.awaitMessage("detectionIntervalSet");
- idleService._fireObservers("idle");
- yield extension.awaitMessage("listenerFired");
- checkActivity({expectedAdd: [60, 99], expectedRemove: [60], expectedFires: ["idle"]});
- yield extension.unload();
-});
-
-add_task(function* testOnlyAddingListener() {
- function background() {
- browser.idle.onStateChanged.addListener(newState => {
- browser.test.assertEq("active", newState, "listener fired with the expected state");
- browser.test.sendMessage("listenerFired");
- });
- browser.test.sendMessage("listenerAdded");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- permissions: ["idle"],
- },
- });
-
- idleService._reset();
- yield extension.startup();
- yield extension.awaitMessage("listenerAdded");
- idleService._fireObservers("active");
- yield extension.awaitMessage("listenerFired");
- // check that "idle-daily" topic does not cause a listener to fire
- idleService._fireObservers("idle-daily");
- checkActivity({expectedAdd: [60], expectedRemove: [], expectedFires: ["active", "idle-daily"]});
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_json_parser.js b/toolkit/components/extensions/test/xpcshell/test_ext_json_parser.js
deleted file mode 100644
index 652f41315..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_json_parser.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_json_parser() {
- const ID = "json@test.web.extension";
-
- let xpi = Extension.generateXPI({
- files: {
- "manifest.json": String.raw`{
- // This is a manifest.
- "applications": {"gecko": {"id": "${ID}"}},
- "name": "This \" is // not a comment",
- "version": "0.1\\" // , "description": "This is not a description"
- }`,
- },
- });
-
- let expectedManifest = {
- "applications": {"gecko": {"id": ID}},
- "name": "This \" is // not a comment",
- "version": "0.1\\",
- };
-
- let fileURI = Services.io.newFileURI(xpi);
- let uri = NetUtil.newURI(`jar:${fileURI.spec}!/`);
-
- let extension = new ExtensionData(uri);
-
- yield extension.readManifest();
-
- Assert.deepEqual(extension.rawManifest, expectedManifest,
- "Manifest with correctly-filtered comments");
-
- Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
- xpi.remove(false);
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_context.js b/toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_context.js
deleted file mode 100644
index 63d5361a1..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_context.js
+++ /dev/null
@@ -1,168 +0,0 @@
-"use strict";
-
-/* globals browser */
-
-Cu.import("resource://gre/modules/Extension.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-const {LegacyExtensionContext} = Cu.import("resource://gre/modules/LegacyExtensionsUtils.jsm");
-
-/**
- * This test case ensures that LegacyExtensionContext instances:
- * - expose the expected API object and can join the messaging
- * of a webextension given its addon id
- * - the exposed API object can receive a port related to a `runtime.connect`
- * Port created in the webextension's background page
- * - the received Port instance can exchange messages with the background page
- * - the received Port receive a disconnect event when the webextension is
- * shutting down
- */
-add_task(function* test_legacy_extension_context() {
- function background() {
- let bgURL = window.location.href;
-
- let extensionInfo = {
- bgURL,
- // Extract the assigned uuid from the background page url.
- uuid: window.location.hostname,
- };
-
- browser.test.sendMessage("webextension-ready", extensionInfo);
-
- let port;
-
- browser.test.onMessage.addListener(async msg => {
- if (msg == "do-send-message") {
- let reply = await browser.runtime.sendMessage("webextension -> legacy_extension message");
-
- browser.test.assertEq("legacy_extension -> webextension reply", reply,
- "Got the expected message from the LegacyExtensionContext");
- browser.test.sendMessage("got-reply-message");
- } else if (msg == "do-connect") {
- port = browser.runtime.connect();
-
- port.onMessage.addListener(portMsg => {
- browser.test.assertEq("legacy_extension -> webextension port message", portMsg,
- "Got the expected message from the LegacyExtensionContext");
- port.postMessage("webextension -> legacy_extension port message");
- });
- } else if (msg == "do-disconnect") {
- port.disconnect();
- }
- });
- }
-
- let extensionData = {
- background,
- };
-
- let extension = Extension.generate(extensionData);
-
- let waitForExtensionInfo = new Promise((resolve, reject) => {
- extension.on("test-message", function testMessageListener(kind, msg, ...args) {
- if (msg != "webextension-ready") {
- reject(new Error(`Got an unexpected test-message: ${msg}`));
- } else {
- extension.off("test-message", testMessageListener);
- resolve(args[0]);
- }
- });
- });
-
- // Connect to the target extension as an external context
- // using the given custom sender info.
- let legacyContext;
-
- extension.on("startup", function onStartup() {
- extension.off("startup", onStartup);
- legacyContext = new LegacyExtensionContext(extension);
- extension.callOnClose({
- close: () => legacyContext.unload(),
- });
- });
-
- yield extension.startup();
-
- let extensionInfo = yield waitForExtensionInfo;
-
- equal(legacyContext.envType, "legacy_extension",
- "LegacyExtensionContext instance has the expected type");
-
- ok(legacyContext.api, "Got the expected API object");
- ok(legacyContext.api.browser, "Got the expected browser property");
-
- let waitMessage = new Promise(resolve => {
- const {browser} = legacyContext.api;
- browser.runtime.onMessage.addListener((singleMsg, msgSender) => {
- resolve({singleMsg, msgSender});
-
- // Send a reply to the sender.
- return Promise.resolve("legacy_extension -> webextension reply");
- });
- });
-
- extension.testMessage("do-send-message");
-
- let {singleMsg, msgSender} = yield waitMessage;
- equal(singleMsg, "webextension -> legacy_extension message",
- "Got the expected message");
- ok(msgSender, "Got a message sender object");
-
- equal(msgSender.id, extensionInfo.uuid, "The sender has the expected id property");
- equal(msgSender.url, extensionInfo.bgURL, "The sender has the expected url property");
-
- // Wait confirmation that the reply has been received.
- yield new Promise((resolve, reject) => {
- extension.on("test-message", function testMessageListener(kind, msg, ...args) {
- if (msg != "got-reply-message") {
- reject(new Error(`Got an unexpected test-message: ${msg}`));
- } else {
- extension.off("test-message", testMessageListener);
- resolve();
- }
- });
- });
-
- let waitConnectPort = new Promise(resolve => {
- let {browser} = legacyContext.api;
- browser.runtime.onConnect.addListener(port => {
- resolve(port);
- });
- });
-
- extension.testMessage("do-connect");
-
- let port = yield waitConnectPort;
-
- ok(port, "Got the Port API object");
- ok(port.sender, "The port has a sender property");
- equal(port.sender.id, extensionInfo.uuid,
- "The port sender has the expected id property");
- equal(port.sender.url, extensionInfo.bgURL,
- "The port sender has the expected url property");
-
- let waitPortMessage = new Promise(resolve => {
- port.onMessage.addListener((msg) => {
- resolve(msg);
- });
- });
-
- port.postMessage("legacy_extension -> webextension port message");
-
- let msg = yield waitPortMessage;
-
- equal(msg, "webextension -> legacy_extension port message",
- "LegacyExtensionContext received the expected message from the webextension");
-
- let waitForDisconnect = new Promise(resolve => {
- port.onDisconnect.addListener(resolve);
- });
-
- extension.testMessage("do-disconnect");
-
- yield waitForDisconnect;
-
- do_print("Got the disconnect event on unload");
-
- yield extension.shutdown();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_embedding.js b/toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_embedding.js
deleted file mode 100644
index ea5d78524..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_embedding.js
+++ /dev/null
@@ -1,188 +0,0 @@
-"use strict";
-
-/* globals browser */
-
-Cu.import("resource://gre/modules/LegacyExtensionsUtils.jsm");
-
-// Import EmbeddedExtensionManager to be able to check that the
-// tacked instances are cleared after the embedded extension shutdown.
-const {
- EmbeddedExtensionManager,
-} = Cu.import("resource://gre/modules/LegacyExtensionsUtils.jsm", {});
-
-/**
- * This test case ensures that the LegacyExtensionsUtils.EmbeddedExtension:
- * - load the embedded webextension resources from a "/webextension/" dir
- * inside the XPI.
- * - EmbeddedExtension.prototype.api returns an API object which exposes
- * a working `runtime.onConnect` event object (e.g. the API can receive a port
- * when the embedded webextension is started and it can exchange messages
- * with the background page).
- * - EmbeddedExtension.prototype.startup/shutdown methods manage the embedded
- * webextension lifecycle as expected.
- */
-add_task(function* test_embedded_webextension_utils() {
- function backgroundScript() {
- let port = browser.runtime.connect();
-
- port.onMessage.addListener((msg) => {
- if (msg == "legacy_extension -> webextension") {
- port.postMessage("webextension -> legacy_extension");
- port.disconnect();
- }
- });
- }
-
- const id = "@test.embedded.web.extension";
-
- // Extensions.generateXPI is used here (and in the other hybrid addons tests in this same
- // test dir) to be able to generate an xpi with the directory layout that we expect from
- // an hybrid legacy+webextension addon (where all the embedded webextension resources are
- // loaded from a 'webextension/' directory).
- let fakeHybridAddonFile = Extension.generateZipFile({
- "webextension/manifest.json": {
- applications: {gecko: {id}},
- name: "embedded webextension name",
- manifest_version: 2,
- version: "1.0",
- background: {
- scripts: ["bg.js"],
- },
- },
- "webextension/bg.js": `new ${backgroundScript}`,
- });
-
- // Remove the generated xpi file and flush the its jar cache
- // on cleanup.
- do_register_cleanup(() => {
- Services.obs.notifyObservers(fakeHybridAddonFile, "flush-cache-entry", null);
- fakeHybridAddonFile.remove(false);
- });
-
- let fileURI = Services.io.newFileURI(fakeHybridAddonFile);
- let resourceURI = Services.io.newURI(`jar:${fileURI.spec}!/`, null, null);
-
- let embeddedExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({
- id, resourceURI,
- });
-
- ok(embeddedExtension, "Got the embeddedExtension object");
-
- equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 1,
- "Got the expected number of tracked embedded extension instances");
-
- do_print("waiting embeddedExtension.startup");
- let embeddedExtensionAPI = yield embeddedExtension.startup();
- ok(embeddedExtensionAPI, "Got the embeddedExtensionAPI object");
-
- let waitConnectPort = new Promise(resolve => {
- let {browser} = embeddedExtensionAPI;
- browser.runtime.onConnect.addListener(port => {
- resolve(port);
- });
- });
-
- let port = yield waitConnectPort;
-
- ok(port, "Got the Port API object");
-
- let waitPortMessage = new Promise(resolve => {
- port.onMessage.addListener((msg) => {
- resolve(msg);
- });
- });
-
- port.postMessage("legacy_extension -> webextension");
-
- let msg = yield waitPortMessage;
-
- equal(msg, "webextension -> legacy_extension",
- "LegacyExtensionContext received the expected message from the webextension");
-
- let waitForDisconnect = new Promise(resolve => {
- port.onDisconnect.addListener(resolve);
- });
-
- do_print("Wait for the disconnect port event");
- yield waitForDisconnect;
- do_print("Got the disconnect port event");
-
- yield embeddedExtension.shutdown();
-
- equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 0,
- "EmbeddedExtension instances has been untracked from the EmbeddedExtensionManager");
-});
-
-function* createManifestErrorTestCase(id, xpi, expectedError) {
- // Remove the generated xpi file and flush the its jar cache
- // on cleanup.
- do_register_cleanup(() => {
- Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
- xpi.remove(false);
- });
-
- let fileURI = Services.io.newFileURI(xpi);
- let resourceURI = Services.io.newURI(`jar:${fileURI.spec}!/`, null, null);
-
- let embeddedExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({
- id, resourceURI,
- });
-
- yield Assert.rejects(embeddedExtension.startup(), expectedError,
- "embedded extension startup rejected");
-
- // Shutdown a "never-started" addon with an embedded webextension should not
- // raise any exception, and if it does this test will fail.
- yield embeddedExtension.shutdown();
-}
-
-add_task(function* test_startup_error_empty_manifest() {
- const id = "empty-manifest@test.embedded.web.extension";
- const files = {
- "webextension/manifest.json": ``,
- };
- const expectedError = "(NS_BASE_STREAM_CLOSED)";
-
- let fakeHybridAddonFile = Extension.generateZipFile(files);
-
- yield createManifestErrorTestCase(id, fakeHybridAddonFile, expectedError);
-});
-
-add_task(function* test_startup_error_invalid_json_manifest() {
- const id = "invalid-json-manifest@test.embedded.web.extension";
- const files = {
- "webextension/manifest.json": `{ "name": }`,
- };
- const expectedError = "JSON.parse:";
-
- let fakeHybridAddonFile = Extension.generateZipFile(files);
-
- yield createManifestErrorTestCase(id, fakeHybridAddonFile, expectedError);
-});
-
-add_task(function* test_startup_error_blocking_validation_errors() {
- const id = "blocking-manifest-validation-error@test.embedded.web.extension";
- const files = {
- "webextension/manifest.json": {
- name: "embedded webextension name",
- manifest_version: 2,
- version: "1.0",
- background: {
- scripts: {},
- },
- },
- };
-
- function expectedError(actual) {
- if (actual.errors && actual.errors.length == 1 &&
- actual.errors[0].startsWith("Reading manifest:")) {
- return true;
- }
-
- return false;
- }
-
- let fakeHybridAddonFile = Extension.generateZipFile(files);
-
- yield createManifestErrorTestCase(id, fakeHybridAddonFile, expectedError);
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_localStorage.js b/toolkit/components/extensions/test/xpcshell/test_ext_localStorage.js
deleted file mode 100644
index 0f0b41085..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_localStorage.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-function backgroundScript() {
- let hasRun = localStorage.getItem("has-run");
- let result;
- if (!hasRun) {
- localStorage.setItem("has-run", "yup");
- localStorage.setItem("test-item", "item1");
- result = "item1";
- } else {
- let data = localStorage.getItem("test-item");
- if (data == "item1") {
- localStorage.setItem("test-item", "item2");
- result = "item2";
- } else if (data == "item2") {
- localStorage.removeItem("test-item");
- result = "deleted";
- } else if (!data) {
- localStorage.clear();
- result = "cleared";
- }
- }
- browser.test.sendMessage("result", result);
- browser.test.notifyPass("localStorage");
-}
-
-const ID = "test-webextension@mozilla.com";
-let extensionData = {
- manifest: {applications: {gecko: {id: ID}}},
- background: backgroundScript,
-};
-
-add_task(function* test_localStorage() {
- const RESULTS = ["item1", "item2", "deleted", "cleared", "item1"];
-
- for (let expected of RESULTS) {
- let extension = ExtensionTestUtils.loadExtension(extensionData);
-
- yield extension.startup();
-
- let actual = yield extension.awaitMessage("result");
-
- yield extension.awaitFinish("localStorage");
- yield extension.unload();
-
- equal(actual, expected, "got expected localStorage data");
- }
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_management.js b/toolkit/components/extensions/test/xpcshell/test_ext_management.js
deleted file mode 100644
index b19554a57..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_management.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_management_schema() {
- function background() {
- browser.test.assertTrue(browser.management, "browser.management API exists");
- browser.test.notifyPass("management-schema");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- manifest: {
- permissions: ["management"],
- },
- background: `(${background})()`,
- });
- yield extension.startup();
- yield extension.awaitFinish("management-schema");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_management_uninstall_self.js b/toolkit/components/extensions/test/xpcshell/test_ext_management_uninstall_self.js
deleted file mode 100644
index 7d80a9c23..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_management_uninstall_self.js
+++ /dev/null
@@ -1,135 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-Cu.import("resource://gre/modules/AddonManager.jsm");
-Cu.import("resource://testing-common/AddonTestUtils.jsm");
-Cu.import("resource://testing-common/MockRegistrar.jsm");
-
-const {promiseAddonByID} = AddonTestUtils;
-const id = "uninstall_self_test@tests.mozilla.com";
-
-const manifest = {
- applications: {
- gecko: {
- id,
- },
- },
- name: "test extension name",
- version: "1.0",
-};
-
-const waitForUninstalled = () => new Promise(resolve => {
- const listener = {
- onUninstalled: (addon) => {
- equal(addon.id, id, "The expected add-on has been uninstalled");
- AddonManager.getAddonByID(addon.id, checkedAddon => {
- equal(checkedAddon, null, "Add-on no longer exists");
- AddonManager.removeAddonListener(listener);
- resolve();
- });
- },
- };
- AddonManager.addAddonListener(listener);
-});
-
-let promptService = {
- _response: null,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptService]),
- confirmEx: function(...args) {
- this._confirmExArgs = args;
- return this._response;
- },
-};
-
-add_task(function* setup() {
- let fakePromptService = MockRegistrar.register("@mozilla.org/embedcomp/prompt-service;1", promptService);
- do_register_cleanup(() => {
- MockRegistrar.unregister(fakePromptService);
- });
- yield ExtensionTestUtils.startAddonManager();
-});
-
-add_task(function* test_management_uninstall_no_prompt() {
- function background() {
- browser.test.onMessage.addListener(msg => {
- browser.management.uninstallSelf();
- });
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- manifest,
- background,
- useAddonManager: "temporary",
- });
-
- yield extension.startup();
- let addon = yield promiseAddonByID(id);
- notEqual(addon, null, "Add-on is installed");
- extension.sendMessage("uninstall");
- yield waitForUninstalled();
- yield extension.markUnloaded();
- Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry", null);
-});
-
-add_task(function* test_management_uninstall_prompt_uninstall() {
- promptService._response = 0;
-
- function background() {
- browser.test.onMessage.addListener(msg => {
- browser.management.uninstallSelf({showConfirmDialog: true});
- });
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- manifest,
- background,
- useAddonManager: "temporary",
- });
-
- yield extension.startup();
- let addon = yield promiseAddonByID(id);
- notEqual(addon, null, "Add-on is installed");
- extension.sendMessage("uninstall");
- yield waitForUninstalled();
- yield extension.markUnloaded();
-
- // Test localization strings
- equal(promptService._confirmExArgs[1], `Uninstall ${manifest.name}`);
- equal(promptService._confirmExArgs[2],
- `The extension “${manifest.name}” is requesting to be uninstalled. What would you like to do?`);
- equal(promptService._confirmExArgs[4], "Uninstall");
- equal(promptService._confirmExArgs[5], "Keep Installed");
- Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry", null);
-});
-
-add_task(function* test_management_uninstall_prompt_keep() {
- promptService._response = 1;
-
- function background() {
- browser.test.onMessage.addListener(async msg => {
- await browser.test.assertRejects(
- browser.management.uninstallSelf({showConfirmDialog: true}),
- "User cancelled uninstall of extension",
- "Expected rejection when user declines uninstall");
-
- browser.test.sendMessage("uninstall-rejected");
- });
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- manifest,
- background,
- useAddonManager: "temporary",
- });
-
- yield extension.startup();
- let addon = yield promiseAddonByID(id);
- notEqual(addon, null, "Add-on is installed");
- extension.sendMessage("uninstall");
- yield extension.awaitMessage("uninstall-rejected");
- addon = yield promiseAddonByID(id);
- notEqual(addon, null, "Add-on remains installed");
- yield extension.unload();
- Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry", null);
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_manifest_content_security_policy.js b/toolkit/components/extensions/test/xpcshell/test_ext_manifest_content_security_policy.js
deleted file mode 100644
index 2b0084980..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_manifest_content_security_policy.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-
-add_task(function* test_manifest_csp() {
- let normalized = yield ExtensionTestUtils.normalizeManifest({
- "content_security_policy": "script-src 'self'; object-src 'none'",
- });
-
- equal(normalized.error, undefined, "Should not have an error");
- equal(normalized.errors.length, 0, "Should not have warnings");
- equal(normalized.value.content_security_policy,
- "script-src 'self'; object-src 'none'",
- "Should have the expected poilcy string");
-
-
- normalized = yield ExtensionTestUtils.normalizeManifest({
- "content_security_policy": "object-src 'none'",
- });
-
- equal(normalized.error, undefined, "Should not have an error");
-
- Assert.deepEqual(normalized.errors,
- ["Error processing content_security_policy: SyntaxError: Policy is missing a required \u2018script-src\u2019 directive"],
- "Should have the expected warning");
-
- equal(normalized.value.content_security_policy, null,
- "Invalid policy string should be omitted");
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_manifest_incognito.js b/toolkit/components/extensions/test/xpcshell/test_ext_manifest_incognito.js
deleted file mode 100644
index 94649692e..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_manifest_incognito.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-
-add_task(function* test_manifest_incognito() {
- let normalized = yield ExtensionTestUtils.normalizeManifest({
- "incognito": "spanning",
- });
-
- equal(normalized.error, undefined, "Should not have an error");
- equal(normalized.errors.length, 0, "Should not have warnings");
- equal(normalized.value.incognito,
- "spanning",
- "Should have the expected incognito string");
-
- normalized = yield ExtensionTestUtils.normalizeManifest({
- "incognito": "split",
- });
-
- equal(normalized.error, undefined, "Should not have an error");
- Assert.deepEqual(normalized.errors,
- ['Error processing incognito: Invalid enumeration value "split"'],
- "Should have the expected warning");
- equal(normalized.value.incognito, null,
- "Invalid incognito string should be omitted");
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_manifest_minimum_chrome_version.js b/toolkit/components/extensions/test/xpcshell/test_ext_manifest_minimum_chrome_version.js
deleted file mode 100644
index fad5661bb..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_manifest_minimum_chrome_version.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-
-add_task(function* test_manifest_minimum_chrome_version() {
- let normalized = yield ExtensionTestUtils.normalizeManifest({
- "minimum_chrome_version": "42",
- });
-
- equal(normalized.error, undefined, "Should not have an error");
- equal(normalized.errors.length, 0, "Should not have warnings");
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js b/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js
deleted file mode 100644
index 5a6b628f5..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging.js
+++ /dev/null
@@ -1,514 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-/* globals chrome */
-
-const PREF_MAX_READ = "webextensions.native-messaging.max-input-message-bytes";
-const PREF_MAX_WRITE = "webextensions.native-messaging.max-output-message-bytes";
-
-const ECHO_BODY = String.raw`
- import struct
- import sys
-
- while True:
- rawlen = sys.stdin.read(4)
- if len(rawlen) == 0:
- sys.exit(0)
- msglen = struct.unpack('@I', rawlen)[0]
- msg = sys.stdin.read(msglen)
-
- sys.stdout.write(struct.pack('@I', msglen))
- sys.stdout.write(msg)
-`;
-
-const INFO_BODY = String.raw`
- import json
- import os
- import struct
- import sys
-
- msg = json.dumps({"args": sys.argv, "cwd": os.getcwd()})
- sys.stdout.write(struct.pack('@I', len(msg)))
- sys.stdout.write(msg)
- sys.exit(0)
-`;
-
-const STDERR_LINES = ["hello stderr", "this should be a separate line"];
-let STDERR_MSG = STDERR_LINES.join("\\n");
-
-const STDERR_BODY = String.raw`
- import sys
- sys.stderr.write("${STDERR_MSG}")
-`;
-
-const SCRIPTS = [
- {
- name: "echo",
- description: "a native app that echoes back messages it receives",
- script: ECHO_BODY.replace(/^ {2}/gm, ""),
- },
- {
- name: "info",
- description: "a native app that gives some info about how it was started",
- script: INFO_BODY.replace(/^ {2}/gm, ""),
- },
- {
- name: "stderr",
- description: "a native app that writes to stderr and then exits",
- script: STDERR_BODY.replace(/^ {2}/gm, ""),
- },
-];
-
-add_task(function* setup() {
- yield setupHosts(SCRIPTS);
-});
-
-// Test the basic operation of native messaging with a simple
-// script that echoes back whatever message is sent to it.
-add_task(function* test_happy_path() {
- function background() {
- let port = browser.runtime.connectNative("echo");
- port.onMessage.addListener(msg => {
- browser.test.sendMessage("message", msg);
- });
- browser.test.onMessage.addListener((what, payload) => {
- if (what == "send") {
- if (payload._json) {
- let json = payload._json;
- payload.toJSON = () => json;
- delete payload._json;
- }
- port.postMessage(payload);
- }
- });
- browser.test.sendMessage("ready");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitMessage("ready");
- const tests = [
- {
- data: "this is a string",
- what: "simple string",
- },
- {
- data: "Это юникода",
- what: "unicode string",
- },
- {
- data: {test: "hello"},
- what: "simple object",
- },
- {
- data: {
- what: "An object with a few properties",
- number: 123,
- bool: true,
- nested: {what: "another object"},
- },
- what: "object with several properties",
- },
-
- {
- data: {
- ignoreme: true,
- _json: {data: "i have a tojson method"},
- },
- expected: {data: "i have a tojson method"},
- what: "object with toJSON() method",
- },
- ];
- for (let test of tests) {
- extension.sendMessage("send", test.data);
- let response = yield extension.awaitMessage("message");
- let expected = test.expected || test.data;
- deepEqual(response, expected, `Echoed a message of type ${test.what}`);
- }
-
- let procCount = yield getSubprocessCount();
- equal(procCount, 1, "subprocess is still running");
- let exitPromise = waitForSubprocessExit();
- yield extension.unload();
- yield exitPromise;
-});
-
-if (AppConstants.platform == "win") {
- // "relative.echo" has a relative path in the host manifest.
- add_task(function* test_relative_path() {
- function background() {
- let port = browser.runtime.connectNative("relative.echo");
- let MSG = "test relative echo path";
- port.onMessage.addListener(msg => {
- browser.test.assertEq(MSG, msg, "Got expected message back");
- browser.test.sendMessage("done");
- });
- port.postMessage(MSG);
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitMessage("done");
-
- let procCount = yield getSubprocessCount();
- equal(procCount, 1, "subprocess is still running");
- let exitPromise = waitForSubprocessExit();
- yield extension.unload();
- yield exitPromise;
- });
-}
-
-// Test sendNativeMessage()
-add_task(function* test_sendNativeMessage() {
- async function background() {
- let MSG = {test: "hello world"};
-
- // Check error handling
- await browser.test.assertRejects(
- browser.runtime.sendNativeMessage("nonexistent", MSG),
- /Attempt to postMessage on disconnected port/,
- "sendNativeMessage() to a nonexistent app failed");
-
- // Check regular message exchange
- let reply = await browser.runtime.sendNativeMessage("echo", MSG);
-
- let expected = JSON.stringify(MSG);
- let received = JSON.stringify(reply);
- browser.test.assertEq(expected, received, "Received echoed native message");
-
- browser.test.sendMessage("finished");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitMessage("finished");
-
- // With sendNativeMessage(), the subprocess should be disconnected
- // after exchanging a single message.
- yield waitForSubprocessExit();
-
- yield extension.unload();
-});
-
-// Test calling Port.disconnect()
-add_task(function* test_disconnect() {
- function background() {
- let port = browser.runtime.connectNative("echo");
- port.onMessage.addListener((msg, msgPort) => {
- browser.test.assertEq(port, msgPort, "onMessage handler should receive the port as the second argument");
- browser.test.sendMessage("message", msg);
- });
- port.onDisconnect.addListener(msgPort => {
- browser.test.fail("onDisconnect should not be called for disconnect()");
- });
- browser.test.onMessage.addListener((what, payload) => {
- if (what == "send") {
- if (payload._json) {
- let json = payload._json;
- payload.toJSON = () => json;
- delete payload._json;
- }
- port.postMessage(payload);
- } else if (what == "disconnect") {
- try {
- port.disconnect();
- browser.test.sendMessage("disconnect-result", {success: true});
- } catch (err) {
- browser.test.sendMessage("disconnect-result", {
- success: false,
- errmsg: err.message,
- });
- }
- }
- });
- browser.test.sendMessage("ready");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitMessage("ready");
-
- extension.sendMessage("send", "test");
- let response = yield extension.awaitMessage("message");
- equal(response, "test", "Echoed a string");
-
- let procCount = yield getSubprocessCount();
- equal(procCount, 1, "subprocess is running");
-
- extension.sendMessage("disconnect");
- response = yield extension.awaitMessage("disconnect-result");
- equal(response.success, true, "disconnect succeeded");
-
- do_print("waiting for subprocess to exit");
- yield waitForSubprocessExit();
- procCount = yield getSubprocessCount();
- equal(procCount, 0, "subprocess is no longer running");
-
- extension.sendMessage("disconnect");
- response = yield extension.awaitMessage("disconnect-result");
- equal(response.success, true, "second call to disconnect silently ignored");
-
- yield extension.unload();
-});
-
-// Test the limit on message size for writing
-add_task(function* test_write_limit() {
- Services.prefs.setIntPref(PREF_MAX_WRITE, 10);
- function clearPref() {
- Services.prefs.clearUserPref(PREF_MAX_WRITE);
- }
- do_register_cleanup(clearPref);
-
- function background() {
- const PAYLOAD = "0123456789A";
- let port = browser.runtime.connectNative("echo");
- try {
- port.postMessage(PAYLOAD);
- browser.test.sendMessage("result", null);
- } catch (ex) {
- browser.test.sendMessage("result", ex.message);
- }
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
-
- let errmsg = yield extension.awaitMessage("result");
- notEqual(errmsg, null, "native postMessage() failed for overly large message");
-
- yield extension.unload();
- yield waitForSubprocessExit();
-
- clearPref();
-});
-
-// Test the limit on message size for reading
-add_task(function* test_read_limit() {
- Services.prefs.setIntPref(PREF_MAX_READ, 10);
- function clearPref() {
- Services.prefs.clearUserPref(PREF_MAX_READ);
- }
- do_register_cleanup(clearPref);
-
- function background() {
- const PAYLOAD = "0123456789A";
- let port = browser.runtime.connectNative("echo");
- port.onDisconnect.addListener(msgPort => {
- browser.test.assertEq(port, msgPort, "onDisconnect handler should receive the port as the first argument");
- browser.test.assertEq("Native application tried to send a message of 13 bytes, which exceeds the limit of 10 bytes.", port.error && port.error.message);
- browser.test.sendMessage("result", "disconnected");
- });
- port.onMessage.addListener(msg => {
- browser.test.sendMessage("result", "message");
- });
- port.postMessage(PAYLOAD);
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
-
- let result = yield extension.awaitMessage("result");
- equal(result, "disconnected", "native port disconnected on receiving large message");
-
- yield extension.unload();
- yield waitForSubprocessExit();
-
- clearPref();
-});
-
-// Test that an extension without the nativeMessaging permission cannot
-// use native messaging.
-add_task(function* test_ext_permission() {
- function background() {
- browser.test.assertFalse("connectNative" in chrome.runtime, "chrome.runtime.connectNative does not exist without nativeMessaging permission");
- browser.test.assertFalse("connectNative" in browser.runtime, "browser.runtime.connectNative does not exist without nativeMessaging permission");
- browser.test.assertFalse("sendNativeMessage" in chrome.runtime, "chrome.runtime.sendNativeMessage does not exist without nativeMessaging permission");
- browser.test.assertFalse("sendNativeMessage" in browser.runtime, "browser.runtime.sendNativeMessage does not exist without nativeMessaging permission");
- browser.test.sendMessage("finished");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {},
- });
-
- yield extension.startup();
- yield extension.awaitMessage("finished");
- yield extension.unload();
-});
-
-// Test that an extension that is not listed in allowed_extensions for
-// a native application cannot use that application.
-add_task(function* test_app_permission() {
- function background() {
- let port = browser.runtime.connectNative("echo");
- port.onDisconnect.addListener(msgPort => {
- browser.test.assertEq(port, msgPort, "onDisconnect handler should receive the port as the first argument");
- browser.test.assertEq("This extension does not have permission to use native application echo (or the application is not installed)", port.error && port.error.message);
- browser.test.sendMessage("result", "disconnected");
- });
- port.onMessage.addListener(msg => {
- browser.test.sendMessage("result", "message");
- });
- port.postMessage({test: "test"});
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- permissions: ["nativeMessaging"],
- },
- }, "somethingelse@tests.mozilla.org");
-
- yield extension.startup();
-
- let result = yield extension.awaitMessage("result");
- equal(result, "disconnected", "connectNative() failed without native app permission");
-
- yield extension.unload();
-
- let procCount = yield getSubprocessCount();
- equal(procCount, 0, "No child process was started");
-});
-
-// Test that the command-line arguments and working directory for the
-// native application are as expected.
-add_task(function* test_child_process() {
- function background() {
- let port = browser.runtime.connectNative("info");
- port.onMessage.addListener(msg => {
- browser.test.sendMessage("result", msg);
- });
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
-
- let msg = yield extension.awaitMessage("result");
- equal(msg.args.length, 2, "Received one command line argument");
- equal(msg.args[1], getPath("info.json"), "Command line argument is the path to the native host manifest");
- equal(msg.cwd.replace(/^\/private\//, "/"), tmpDir.path,
- "Working directory is the directory containing the native appliation");
-
- let exitPromise = waitForSubprocessExit();
- yield extension.unload();
- yield exitPromise;
-});
-
-add_task(function* test_stderr() {
- function background() {
- let port = browser.runtime.connectNative("stderr");
- port.onDisconnect.addListener(msgPort => {
- browser.test.assertEq(port, msgPort, "onDisconnect handler should receive the port as the first argument");
- browser.test.assertEq(null, port.error, "Normal application exit is not an error");
- browser.test.sendMessage("finished");
- });
- }
-
- let {messages} = yield promiseConsoleOutput(function* () {
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitMessage("finished");
- yield extension.unload();
-
- yield waitForSubprocessExit();
- });
-
- let lines = STDERR_LINES.map(line => messages.findIndex(msg => msg.message.includes(line)));
- notEqual(lines[0], -1, "Saw first line of stderr output on the console");
- notEqual(lines[1], -1, "Saw second line of stderr output on the console");
- notEqual(lines[0], lines[1], "Stderr output lines are separated in the console");
-});
-
-// Test that calling connectNative() multiple times works
-// (bug 1313980 was a previous regression in this area)
-add_task(function* test_multiple_connects() {
- async function background() {
- function once() {
- return new Promise(resolve => {
- let MSG = "hello";
- let port = browser.runtime.connectNative("echo");
-
- port.onMessage.addListener(msg => {
- browser.test.assertEq(MSG, msg, "Got expected message back");
- port.disconnect();
- resolve();
- });
- port.postMessage(MSG);
- });
- }
-
- await once();
- await once();
- browser.test.notifyPass("multiple-connect");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("multiple-connect");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_perf.js b/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_perf.js
deleted file mode 100644
index 693f67dde..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_perf.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-XPCOMUtils.defineLazyModuleGetter(this, "MockRegistry",
- "resource://testing-common/MockRegistry.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm");
-
-Cu.import("resource://gre/modules/Subprocess.jsm");
-
-const MAX_ROUND_TRIP_TIME_MS = AppConstants.DEBUG || AppConstants.ASAN ? 36 : 18;
-const MAX_RETRIES = 5;
-
-
-const ECHO_BODY = String.raw`
- import struct
- import sys
-
- while True:
- rawlen = sys.stdin.read(4)
- if len(rawlen) == 0:
- sys.exit(0)
-
- msglen = struct.unpack('@I', rawlen)[0]
- msg = sys.stdin.read(msglen)
-
- sys.stdout.write(struct.pack('@I', msglen))
- sys.stdout.write(msg)
-`;
-
-const SCRIPTS = [
- {
- name: "echo",
- description: "A native app that echoes back messages it receives",
- script: ECHO_BODY.replace(/^ {2}/gm, ""),
- },
-];
-
-add_task(function* setup() {
- yield setupHosts(SCRIPTS);
-});
-
-add_task(function* test_round_trip_perf() {
- let extension = ExtensionTestUtils.loadExtension({
- background() {
- browser.test.onMessage.addListener(msg => {
- if (msg != "run-tests") {
- return;
- }
-
- let port = browser.runtime.connectNative("echo");
-
- function next() {
- port.postMessage({
- "Lorem": {
- "ipsum": {
- "dolor": [
- "sit amet",
- "consectetur adipiscing elit",
- "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
- ],
- "Ut enim": [
- "ad minim veniam",
- "quis nostrud exercitation ullamco",
- "laboris nisi ut aliquip ex ea commodo consequat.",
- ],
- "Duis": [
- "aute irure dolor in reprehenderit in",
- "voluptate velit esse cillum dolore eu",
- "fugiat nulla pariatur.",
- ],
- "Excepteur": [
- "sint occaecat cupidatat non proident",
- "sunt in culpa qui officia deserunt",
- "mollit anim id est laborum.",
- ],
- },
- },
- });
- }
-
- const COUNT = 1000;
- let now;
- function finish() {
- let roundTripTime = (Date.now() - now) / COUNT;
-
- port.disconnect();
- browser.test.sendMessage("result", roundTripTime);
- }
-
- let count = 0;
- port.onMessage.addListener(() => {
- if (count == 0) {
- // Skip the first round, since it includes the time it takes
- // the app to start up.
- now = Date.now();
- }
-
- if (count++ <= COUNT) {
- next();
- } else {
- finish();
- }
- });
-
- next();
- });
- },
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
-
- let roundTripTime = Infinity;
- for (let i = 0; i < MAX_RETRIES && roundTripTime > MAX_ROUND_TRIP_TIME_MS; i++) {
- extension.sendMessage("run-tests");
- roundTripTime = yield extension.awaitMessage("result");
- }
-
- yield extension.unload();
-
- ok(roundTripTime <= MAX_ROUND_TRIP_TIME_MS,
- `Expected round trip time (${roundTripTime}ms) to be less than ${MAX_ROUND_TRIP_TIME_MS}ms`);
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_unresponsive.js b/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_unresponsive.js
deleted file mode 100644
index a75a1d49d..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_native_messaging_unresponsive.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-const WONTDIE_BODY = String.raw`
- import signal
- import struct
- import sys
- import time
-
- signal.signal(signal.SIGTERM, signal.SIG_IGN)
-
- def spin():
- while True:
- try:
- signal.pause()
- except AttributeError:
- time.sleep(5)
-
- while True:
- rawlen = sys.stdin.read(4)
- if len(rawlen) == 0:
- spin()
-
- msglen = struct.unpack('@I', rawlen)[0]
- msg = sys.stdin.read(msglen)
-
- sys.stdout.write(struct.pack('@I', msglen))
- sys.stdout.write(msg)
-`;
-
-const SCRIPTS = [
- {
- name: "wontdie",
- description: "a native app that does not exit when stdin closes or on SIGTERM",
- script: WONTDIE_BODY.replace(/^ {2}/gm, ""),
- },
-];
-
-add_task(function* setup() {
- yield setupHosts(SCRIPTS);
-});
-
-
-// Test that an unresponsive native application still gets killed eventually
-add_task(function* test_unresponsive_native_app() {
- // XXX expose GRACEFUL_SHUTDOWN_TIME as a pref and reduce it
- // just for this test?
-
- function background() {
- let port = browser.runtime.connectNative("wontdie");
-
- const MSG = "echo me";
- // bounce a message to make sure the process actually starts
- port.onMessage.addListener(msg => {
- browser.test.assertEq(msg, MSG, "Received echoed message");
- browser.test.sendMessage("ready");
- });
- port.postMessage(MSG);
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- applications: {gecko: {id: ID}},
- permissions: ["nativeMessaging"],
- },
- });
-
- yield extension.startup();
- yield extension.awaitMessage("ready");
-
- let procCount = yield getSubprocessCount();
- equal(procCount, 1, "subprocess is running");
-
- let exitPromise = waitForSubprocessExit();
- yield extension.unload();
- yield exitPromise;
-
- procCount = yield getSubprocessCount();
- equal(procCount, 0, "subprocess was succesfully killed");
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js b/toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js
deleted file mode 100644
index 6f8b553fc..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-function backgroundScript() {
- function listener() {
- browser.test.notifyFail("listener should not be invoked");
- }
-
- browser.runtime.onMessage.addListener(listener);
- browser.runtime.onMessage.removeListener(listener);
- browser.runtime.sendMessage("hello");
-
- // Make sure that, if we somehow fail to remove the listener, then we'll run
- // the listener before the test is marked as passing.
- setTimeout(function() {
- browser.test.notifyPass("onmessage_removelistener");
- }, 0);
-}
-
-let extensionData = {
- background: backgroundScript,
-};
-
-add_task(function* test_contentscript() {
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
- yield extension.awaitFinish("onmessage_removelistener");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js
deleted file mode 100644
index 2a1342cde..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_connect_without_listener() {
- function background() {
- let port = browser.runtime.connect();
- port.onDisconnect.addListener(() => {
- browser.test.assertEq("Could not establish connection. Receiving end does not exist.", port.error && port.error.message);
- browser.test.notifyPass("port.onDisconnect was called");
- });
- }
- let extensionData = {
- background,
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
-
- yield extension.awaitFinish("port.onDisconnect was called");
-
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getBrowserInfo.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getBrowserInfo.js
deleted file mode 100644
index a280206fa..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getBrowserInfo.js
+++ /dev/null
@@ -1,26 +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";
-
-add_task(function* setup() {
- ExtensionTestUtils.mockAppInfo();
-});
-
-add_task(function* test_getBrowserInfo() {
- async function background() {
- let info = await browser.runtime.getBrowserInfo();
-
- browser.test.assertEq(info.name, "XPCShell", "name is valid");
- browser.test.assertEq(info.vendor, "Mozilla", "vendor is Mozilla");
- browser.test.assertEq(info.version, "48", "version is correct");
- browser.test.assertEq(info.buildID, "20160315", "buildID is correct");
-
- browser.test.notifyPass("runtime.getBrowserInfo");
- }
-
- const extension = ExtensionTestUtils.loadExtension({background});
- yield extension.startup();
- yield extension.awaitFinish("runtime.getBrowserInfo");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js
deleted file mode 100644
index 29bad0c10..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-function backgroundScript() {
- browser.runtime.getPlatformInfo(info => {
- let validOSs = ["mac", "win", "android", "cros", "linux", "openbsd"];
- let validArchs = ["arm", "x86-32", "x86-64"];
-
- browser.test.assertTrue(validOSs.indexOf(info.os) != -1, "OS is valid");
- browser.test.assertTrue(validArchs.indexOf(info.arch) != -1, "Architecture is valid");
- browser.test.notifyPass("runtime.getPlatformInfo");
- });
-}
-
-let extensionData = {
- background: backgroundScript,
-};
-
-add_task(function* test_contentscript() {
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
- yield extension.awaitFinish("runtime.getPlatformInfo");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js
deleted file mode 100644
index fa6461412..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js
+++ /dev/null
@@ -1,337 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-XPCOMUtils.defineLazyGetter(this, "Management", () => {
- const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
- return Management;
-});
-
-const {
- createAppInfo,
- createTempWebExtensionFile,
- promiseAddonByID,
- promiseAddonEvent,
- promiseCompleteAllInstalls,
- promiseFindAddonUpdates,
- promiseRestartManager,
- promiseShutdownManager,
- promiseStartupManager,
-} = AddonTestUtils;
-
-AddonTestUtils.init(this);
-
-// Allow for unsigned addons.
-AddonTestUtils.overrideCertDB();
-
-createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
-
-function awaitEvent(eventName) {
- return new Promise(resolve => {
- let listener = (_eventName, ...args) => {
- if (_eventName === eventName) {
- Management.off(eventName, listener);
- resolve(...args);
- }
- };
-
- Management.on(eventName, listener);
- });
-}
-
-function background() {
- let onInstalledDetails = null;
- let onStartupFired = false;
-
- browser.runtime.onInstalled.addListener(details => {
- onInstalledDetails = details;
- });
-
- browser.runtime.onStartup.addListener(() => {
- onStartupFired = true;
- });
-
- browser.test.onMessage.addListener(message => {
- if (message === "get-on-installed-details") {
- onInstalledDetails = onInstalledDetails || {fired: false};
- browser.test.sendMessage("on-installed-details", onInstalledDetails);
- } else if (message === "did-on-startup-fire") {
- browser.test.sendMessage("on-startup-fired", onStartupFired);
- } else if (message === "reload-extension") {
- browser.runtime.reload();
- }
- });
-
- browser.runtime.onUpdateAvailable.addListener(details => {
- browser.test.sendMessage("reloading");
- browser.runtime.reload();
- });
-}
-
-function* expectEvents(extension, {onStartupFired, onInstalledFired, onInstalledReason}) {
- extension.sendMessage("get-on-installed-details");
- let details = yield extension.awaitMessage("on-installed-details");
- if (onInstalledFired) {
- equal(details.reason, onInstalledReason, "runtime.onInstalled fired with the correct reason");
- } else {
- equal(details.fired, onInstalledFired, "runtime.onInstalled should not have fired");
- }
-
- extension.sendMessage("did-on-startup-fire");
- let fired = yield extension.awaitMessage("on-startup-fired");
- equal(fired, onStartupFired, `Expected runtime.onStartup to ${onStartupFired ? "" : "not "} fire`);
-}
-
-add_task(function* test_should_fire_on_addon_update() {
- const EXTENSION_ID = "test_runtime_on_installed_addon_update@tests.mozilla.org";
-
- const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity";
-
- // The test extension uses an insecure update url.
- Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
-
- const testServer = createHttpServer();
- const port = testServer.identity.primaryPort;
-
- let extension = ExtensionTestUtils.loadExtension({
- useAddonManager: "permanent",
- manifest: {
- "version": "1.0",
- "applications": {
- "gecko": {
- "id": EXTENSION_ID,
- "update_url": `http://localhost:${port}/test_update.json`,
- },
- },
- },
- background,
- });
-
- testServer.registerPathHandler("/test_update.json", (request, response) => {
- response.write(`{
- "addons": {
- "${EXTENSION_ID}": {
- "updates": [
- {
- "version": "2.0",
- "update_link": "http://localhost:${port}/addons/test_runtime_on_installed-2.0.xpi"
- }
- ]
- }
- }
- }`);
- });
-
- let webExtensionFile = createTempWebExtensionFile({
- manifest: {
- version: "2.0",
- applications: {
- gecko: {
- id: EXTENSION_ID,
- },
- },
- },
- background,
- });
-
- testServer.registerFile("/addons/test_runtime_on_installed-2.0.xpi", webExtensionFile);
-
- yield promiseStartupManager();
-
- yield extension.startup();
-
- yield expectEvents(extension, {
- onStartupFired: false,
- onInstalledFired: true,
- onInstalledReason: "install",
- });
-
- let addon = yield promiseAddonByID(EXTENSION_ID);
- equal(addon.version, "1.0", "The installed addon has the correct version");
-
- let update = yield promiseFindAddonUpdates(addon);
- let install = update.updateAvailable;
-
- let promiseInstalled = promiseAddonEvent("onInstalled");
- yield promiseCompleteAllInstalls([install]);
-
- yield extension.awaitMessage("reloading");
-
- let startupPromise = awaitEvent("ready");
-
- let [updated_addon] = yield promiseInstalled;
- equal(updated_addon.version, "2.0", "The updated addon has the correct version");
-
- extension.extension = yield startupPromise;
- extension.attachListeners();
-
- yield expectEvents(extension, {
- onStartupFired: false,
- onInstalledFired: true,
- onInstalledReason: "update",
- });
-
- yield extension.unload();
-
- yield updated_addon.uninstall();
- yield promiseShutdownManager();
-});
-
-add_task(function* test_should_fire_on_browser_update() {
- const EXTENSION_ID = "test_runtime_on_installed_browser_update@tests.mozilla.org";
-
- yield promiseStartupManager();
-
- let extension = ExtensionTestUtils.loadExtension({
- useAddonManager: "permanent",
- manifest: {
- "version": "1.0",
- "applications": {
- "gecko": {
- "id": EXTENSION_ID,
- },
- },
- },
- background,
- });
-
- yield extension.startup();
-
- yield expectEvents(extension, {
- onStartupFired: false,
- onInstalledFired: true,
- onInstalledReason: "install",
- });
-
- let startupPromise = awaitEvent("ready");
- yield promiseRestartManager("1");
- extension.extension = yield startupPromise;
- extension.attachListeners();
-
- yield expectEvents(extension, {
- onStartupFired: true,
- onInstalledFired: false,
- });
-
- // Update the browser.
- startupPromise = awaitEvent("ready");
- yield promiseRestartManager("2");
- extension.extension = yield startupPromise;
- extension.attachListeners();
-
- yield expectEvents(extension, {
- onStartupFired: true,
- onInstalledFired: true,
- onInstalledReason: "browser_update",
- });
-
- // Restart the browser.
- startupPromise = awaitEvent("ready");
- yield promiseRestartManager("2");
- extension.extension = yield startupPromise;
- extension.attachListeners();
-
- yield expectEvents(extension, {
- onStartupFired: true,
- onInstalledFired: false,
- });
-
- // Update the browser again.
- startupPromise = awaitEvent("ready");
- yield promiseRestartManager("3");
- extension.extension = yield startupPromise;
- extension.attachListeners();
-
- yield expectEvents(extension, {
- onStartupFired: true,
- onInstalledFired: true,
- onInstalledReason: "browser_update",
- });
-
- yield extension.unload();
-
- yield promiseShutdownManager();
-});
-
-add_task(function* test_should_not_fire_on_reload() {
- const EXTENSION_ID = "test_runtime_on_installed_reload@tests.mozilla.org";
-
- yield promiseStartupManager();
-
- let extension = ExtensionTestUtils.loadExtension({
- useAddonManager: "permanent",
- manifest: {
- "version": "1.0",
- "applications": {
- "gecko": {
- "id": EXTENSION_ID,
- },
- },
- },
- background,
- });
-
- yield extension.startup();
-
- yield expectEvents(extension, {
- onStartupFired: false,
- onInstalledFired: true,
- onInstalledReason: "install",
- });
-
- let startupPromise = awaitEvent("ready");
- extension.sendMessage("reload-extension");
- extension.extension = yield startupPromise;
- extension.attachListeners();
-
- yield expectEvents(extension, {
- onStartupFired: false,
- onInstalledFired: false,
- });
-
- yield extension.unload();
- yield promiseShutdownManager();
-});
-
-add_task(function* test_should_not_fire_on_restart() {
- const EXTENSION_ID = "test_runtime_on_installed_restart@tests.mozilla.org";
-
- yield promiseStartupManager();
-
- let extension = ExtensionTestUtils.loadExtension({
- useAddonManager: "permanent",
- manifest: {
- "version": "1.0",
- "applications": {
- "gecko": {
- "id": EXTENSION_ID,
- },
- },
- },
- background,
- });
-
- yield extension.startup();
-
- yield expectEvents(extension, {
- onStartupFired: false,
- onInstalledFired: true,
- onInstalledReason: "install",
- });
-
- let addon = yield promiseAddonByID(EXTENSION_ID);
- addon.userDisabled = true;
-
- let startupPromise = awaitEvent("ready");
- addon.userDisabled = false;
- extension.extension = yield startupPromise;
- extension.attachListeners();
-
- yield expectEvents(extension, {
- onStartupFired: false,
- onInstalledFired: false,
- });
-
- yield extension.markUnloaded();
- yield promiseShutdownManager();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js
deleted file mode 100644
index fec8e13dd..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* tabsSendMessageReply() {
- function background() {
- browser.runtime.onMessage.addListener((msg, sender, respond) => {
- if (msg == "respond-now") {
- respond(msg);
- } else if (msg == "respond-soon") {
- setTimeout(() => { respond(msg); }, 0);
- return true;
- } else if (msg == "respond-promise") {
- return Promise.resolve(msg);
- } else if (msg == "respond-never") {
- return;
- } else if (msg == "respond-error") {
- return Promise.reject(new Error(msg));
- } else if (msg == "throw-error") {
- throw new Error(msg);
- }
- });
-
- browser.runtime.onMessage.addListener((msg, sender, respond) => {
- if (msg == "respond-now") {
- respond("hello");
- } else if (msg == "respond-now-2") {
- respond(msg);
- }
- });
-
- let childFrame = document.createElement("iframe");
- childFrame.src = "extensionpage.html";
- document.body.appendChild(childFrame);
- }
-
- function senderScript() {
- Promise.all([
- browser.runtime.sendMessage("respond-now"),
- browser.runtime.sendMessage("respond-now-2"),
- new Promise(resolve => browser.runtime.sendMessage("respond-soon", resolve)),
- browser.runtime.sendMessage("respond-promise"),
- browser.runtime.sendMessage("respond-never"),
- new Promise(resolve => {
- browser.runtime.sendMessage("respond-never", response => { resolve(response); });
- }),
-
- browser.runtime.sendMessage("respond-error").catch(error => Promise.resolve({error})),
- browser.runtime.sendMessage("throw-error").catch(error => Promise.resolve({error})),
- ]).then(([respondNow, respondNow2, respondSoon, respondPromise, respondNever, respondNever2, respondError, throwError]) => {
- browser.test.assertEq("respond-now", respondNow, "Got the expected immediate response");
- browser.test.assertEq("respond-now-2", respondNow2, "Got the expected immediate response from the second listener");
- browser.test.assertEq("respond-soon", respondSoon, "Got the expected delayed response");
- browser.test.assertEq("respond-promise", respondPromise, "Got the expected promise response");
- browser.test.assertEq(undefined, respondNever, "Got the expected no-response resolution");
- browser.test.assertEq(undefined, respondNever2, "Got the expected no-response resolution");
-
- browser.test.assertEq("respond-error", respondError.error.message, "Got the expected error response");
- browser.test.assertEq("throw-error", throwError.error.message, "Got the expected thrown error response");
-
- browser.test.notifyPass("sendMessage");
- }).catch(e => {
- browser.test.fail(`Error: ${e} :: ${e.stack}`);
- browser.test.notifyFail("sendMessage");
- });
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- files: {
- "senderScript.js": senderScript,
- "extensionpage.html": `<!DOCTYPE html><meta charset="utf-8"><script src="senderScript.js"></script>`,
- },
- });
-
- yield extension.startup();
- yield extension.awaitFinish("sendMessage");
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_errors.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_errors.js
deleted file mode 100644
index f1a8d5a36..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_errors.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_sendMessage_error() {
- async function background() {
- let circ = {};
- circ.circ = circ;
- let testCases = [
- // [arguments, expected error string],
- [[], "runtime.sendMessage's message argument is missing"],
- [[null, null, null, null], "runtime.sendMessage's last argument is not a function"],
- [[null, null, 1], "runtime.sendMessage's options argument is invalid"],
- [[1, null, null], "runtime.sendMessage's extensionId argument is invalid"],
- [[null, null, null, null, null], "runtime.sendMessage received too many arguments"],
-
- // Even when the parameters are accepted, we still expect an error
- // because there is no onMessage listener.
- [[null, null, null], "Could not establish connection. Receiving end does not exist."],
-
- // Structural cloning doesn't work with DOM but we fall back
- // JSON serialization, so we don't expect another error.
- [[null, location, null], "Could not establish connection. Receiving end does not exist."],
-
- // Structured cloning supports cyclic self-references.
- [[null, [circ, location], null], "cyclic object value"],
- // JSON serialization does not support cyclic references.
- [[null, circ, null], "Could not establish connection. Receiving end does not exist."],
- // (the last two tests shows whether sendMessage is implemented as structured cloning).
- ];
-
- // Repeat all tests with the undefined value instead of null.
- for (let [args, expectedError] of testCases.slice()) {
- args = args.map(arg => arg === null ? undefined : arg);
- testCases.push([args, expectedError]);
- }
-
- for (let [args, expectedError] of testCases) {
- let description = `runtime.sendMessage(${args.map(String).join(", ")})`;
-
- await browser.test.assertRejects(
- browser.runtime.sendMessage(...args),
- expectedError,
- `expected error message for ${description}`);
- }
-
- browser.test.notifyPass("sendMessage parameter validation");
- }
- let extensionData = {
- background,
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
-
- yield extension.awaitFinish("sendMessage parameter validation");
-
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js
deleted file mode 100644
index f906333d2..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_sendMessage_without_listener() {
- async function background() {
- await browser.test.assertRejects(
- browser.runtime.sendMessage("msg"),
- "Could not establish connection. Receiving end does not exist.",
- "sendMessage callback was invoked");
-
- browser.test.notifyPass("sendMessage callback was invoked");
- }
- let extensionData = {
- background,
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
-
- yield extension.awaitFinish("sendMessage callback was invoked");
-
- yield extension.unload();
-});
-
-add_task(function* test_chrome_sendMessage_without_listener() {
- function background() {
- /* globals chrome */
- browser.test.assertEq(null, chrome.runtime.lastError, "no lastError before call");
- let retval = chrome.runtime.sendMessage("msg");
- browser.test.assertEq(null, chrome.runtime.lastError, "no lastError after call");
- browser.test.assertEq(undefined, retval, "return value of chrome.runtime.sendMessage without callback");
-
- let isAsyncCall = false;
- retval = chrome.runtime.sendMessage("msg", reply => {
- browser.test.assertEq(undefined, reply, "no reply");
- browser.test.assertTrue(isAsyncCall, "chrome.runtime.sendMessage's callback must be called asynchronously");
- browser.test.assertEq(undefined, retval, "return value of chrome.runtime.sendMessage with callback");
- browser.test.assertEq("Could not establish connection. Receiving end does not exist.", chrome.runtime.lastError.message);
- browser.test.notifyPass("finished chrome.runtime.sendMessage");
- });
- isAsyncCall = true;
- }
- let extensionData = {
- background,
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
-
- yield extension.awaitFinish("finished chrome.runtime.sendMessage");
-
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_self.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_self.js
deleted file mode 100644
index e4f5e951f..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_self.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-
-"use strict";
-
-add_task(function* test_sendMessage_to_self_should_not_trigger_onMessage() {
- async function background() {
- browser.runtime.onMessage.addListener(msg => {
- browser.test.assertEq("msg from child", msg);
- browser.test.notifyPass("sendMessage did not call same-frame onMessage");
- });
-
- browser.test.onMessage.addListener(msg => {
- browser.test.assertEq("sendMessage with a listener in another frame", msg);
- browser.runtime.sendMessage("should only reach another frame");
- });
-
- await browser.test.assertRejects(
- browser.runtime.sendMessage("should not trigger same-frame onMessage"),
- "Could not establish connection. Receiving end does not exist.");
-
- let anotherFrame = document.createElement("iframe");
- anotherFrame.src = browser.extension.getURL("extensionpage.html");
- document.body.appendChild(anotherFrame);
- }
-
- function lastScript() {
- browser.runtime.onMessage.addListener(msg => {
- browser.test.assertEq("should only reach another frame", msg);
- browser.runtime.sendMessage("msg from child");
- });
- browser.test.sendMessage("sendMessage callback called");
- }
-
- let extensionData = {
- background,
- files: {
- "lastScript.js": lastScript,
- "extensionpage.html": `<!DOCTYPE html><meta charset="utf-8"><script src="lastScript.js"></script>`,
- },
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
-
- yield extension.awaitMessage("sendMessage callback called");
- extension.sendMessage("sendMessage with a listener in another frame");
- yield extension.awaitFinish("sendMessage did not call same-frame onMessage");
-
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_schemas.js b/toolkit/components/extensions/test/xpcshell/test_ext_schemas.js
deleted file mode 100644
index d838be5b5..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_schemas.js
+++ /dev/null
@@ -1,1427 +0,0 @@
-"use strict";
-
-Components.utils.import("resource://gre/modules/Schemas.jsm");
-Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
-Components.utils.import("resource://gre/modules/ExtensionCommon.jsm");
-
-let {LocalAPIImplementation, SchemaAPIInterface} = ExtensionCommon;
-
-let json = [
- {namespace: "testing",
-
- properties: {
- PROP1: {value: 20},
- prop2: {type: "string"},
- prop3: {
- $ref: "submodule",
- },
- prop4: {
- $ref: "submodule",
- unsupported: true,
- },
- },
-
- types: [
- {
- id: "type1",
- type: "string",
- "enum": ["value1", "value2", "value3"],
- },
-
- {
- id: "type2",
- type: "object",
- properties: {
- prop1: {type: "integer"},
- prop2: {type: "array", items: {"$ref": "type1"}},
- },
- },
-
- {
- id: "basetype1",
- type: "object",
- properties: {
- prop1: {type: "string"},
- },
- },
-
- {
- id: "basetype2",
- choices: [
- {type: "integer"},
- ],
- },
-
- {
- $extend: "basetype1",
- properties: {
- prop2: {type: "string"},
- },
- },
-
- {
- $extend: "basetype2",
- choices: [
- {type: "string"},
- ],
- },
-
- {
- id: "submodule",
- type: "object",
- functions: [
- {
- name: "sub_foo",
- type: "function",
- parameters: [],
- returns: "integer",
- },
- ],
- },
- ],
-
- functions: [
- {
- name: "foo",
- type: "function",
- parameters: [
- {name: "arg1", type: "integer", optional: true, default: 99},
- {name: "arg2", type: "boolean", optional: true},
- ],
- },
-
- {
- name: "bar",
- type: "function",
- parameters: [
- {name: "arg1", type: "integer", optional: true},
- {name: "arg2", type: "boolean"},
- ],
- },
-
- {
- name: "baz",
- type: "function",
- parameters: [
- {name: "arg1", type: "object", properties: {
- prop1: {type: "string"},
- prop2: {type: "integer", optional: true},
- prop3: {type: "integer", unsupported: true},
- }},
- ],
- },
-
- {
- name: "qux",
- type: "function",
- parameters: [
- {name: "arg1", "$ref": "type1"},
- ],
- },
-
- {
- name: "quack",
- type: "function",
- parameters: [
- {name: "arg1", "$ref": "type2"},
- ],
- },
-
- {
- name: "quora",
- type: "function",
- parameters: [
- {name: "arg1", type: "function"},
- ],
- },
-
- {
- name: "quileute",
- type: "function",
- parameters: [
- {name: "arg1", type: "integer", optional: true},
- {name: "arg2", type: "integer"},
- ],
- },
-
- {
- name: "queets",
- type: "function",
- unsupported: true,
- parameters: [],
- },
-
- {
- name: "quintuplets",
- type: "function",
- parameters: [
- {name: "obj", type: "object", properties: [], additionalProperties: {type: "integer"}},
- ],
- },
-
- {
- name: "quasar",
- type: "function",
- parameters: [
- {name: "abc", type: "object", properties: {
- func: {type: "function", parameters: [
- {name: "x", type: "integer"},
- ]},
- }},
- ],
- },
-
- {
- name: "quosimodo",
- type: "function",
- parameters: [
- {name: "xyz", type: "object", additionalProperties: {type: "any"}},
- ],
- },
-
- {
- name: "patternprop",
- type: "function",
- parameters: [
- {
- name: "obj",
- type: "object",
- properties: {"prop1": {type: "string", pattern: "^\\d+$"}},
- patternProperties: {
- "(?i)^prop\\d+$": {type: "string"},
- "^foo\\d+$": {type: "string"},
- },
- },
- ],
- },
-
- {
- name: "pattern",
- type: "function",
- parameters: [
- {name: "arg", type: "string", pattern: "(?i)^[0-9a-f]+$"},
- ],
- },
-
- {
- name: "format",
- type: "function",
- parameters: [
- {
- name: "arg",
- type: "object",
- properties: {
- url: {type: "string", "format": "url", "optional": true},
- relativeUrl: {type: "string", "format": "relativeUrl", "optional": true},
- strictRelativeUrl: {type: "string", "format": "strictRelativeUrl", "optional": true},
- },
- },
- ],
- },
-
- {
- name: "formatDate",
- type: "function",
- parameters: [
- {
- name: "arg",
- type: "object",
- properties: {
- date: {type: "string", format: "date", optional: true},
- },
- },
- ],
- },
-
- {
- name: "deep",
- type: "function",
- parameters: [
- {
- name: "arg",
- type: "object",
- properties: {
- foo: {
- type: "object",
- properties: {
- bar: {
- type: "array",
- items: {
- type: "object",
- properties: {
- baz: {
- type: "object",
- properties: {
- required: {type: "integer"},
- optional: {type: "string", optional: true},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- ],
- },
-
- {
- name: "errors",
- type: "function",
- parameters: [
- {
- name: "arg",
- type: "object",
- properties: {
- warn: {
- type: "string",
- pattern: "^\\d+$",
- optional: true,
- onError: "warn",
- },
- ignore: {
- type: "string",
- pattern: "^\\d+$",
- optional: true,
- onError: "ignore",
- },
- default: {
- type: "string",
- pattern: "^\\d+$",
- optional: true,
- },
- },
- },
- ],
- },
-
- {
- name: "localize",
- type: "function",
- parameters: [
- {
- name: "arg",
- type: "object",
- properties: {
- foo: {type: "string", "preprocess": "localize", "optional": true},
- bar: {type: "string", "optional": true},
- url: {type: "string", "preprocess": "localize", "format": "url", "optional": true},
- },
- },
- ],
- },
-
- {
- name: "extended1",
- type: "function",
- parameters: [
- {name: "val", $ref: "basetype1"},
- ],
- },
-
- {
- name: "extended2",
- type: "function",
- parameters: [
- {name: "val", $ref: "basetype2"},
- ],
- },
- ],
-
- events: [
- {
- name: "onFoo",
- type: "function",
- },
-
- {
- name: "onBar",
- type: "function",
- extraParameters: [{
- name: "filter",
- type: "integer",
- optional: true,
- default: 1,
- }],
- },
- ],
- },
- {
- namespace: "foreign",
- properties: {
- foreignRef: {$ref: "testing.submodule"},
- },
- },
- {
- namespace: "inject",
- properties: {
- PROP1: {value: "should inject"},
- },
- },
- {
- namespace: "do-not-inject",
- properties: {
- PROP1: {value: "should not inject"},
- },
- },
-];
-
-let tallied = null;
-
-function tally(kind, ns, name, args) {
- tallied = [kind, ns, name, args];
-}
-
-function verify(...args) {
- do_check_eq(JSON.stringify(tallied), JSON.stringify(args));
- tallied = null;
-}
-
-let talliedErrors = [];
-
-function checkErrors(errors) {
- do_check_eq(talliedErrors.length, errors.length, "Got expected number of errors");
- for (let [i, error] of errors.entries()) {
- do_check_true(i in talliedErrors && talliedErrors[i].includes(error),
- `${JSON.stringify(error)} is a substring of error ${JSON.stringify(talliedErrors[i])}`);
- }
-
- talliedErrors.length = 0;
-}
-
-let permissions = new Set();
-
-class TallyingAPIImplementation extends SchemaAPIInterface {
- constructor(namespace, name) {
- super();
- this.namespace = namespace;
- this.name = name;
- }
-
- callFunction(args) {
- tally("call", this.namespace, this.name, args);
- }
-
- callFunctionNoReturn(args) {
- tally("call", this.namespace, this.name, args);
- }
-
- getProperty() {
- tally("get", this.namespace, this.name);
- }
-
- setProperty(value) {
- tally("set", this.namespace, this.name, value);
- }
-
- addListener(listener, args) {
- tally("addListener", this.namespace, this.name, [listener, args]);
- }
-
- removeListener(listener) {
- tally("removeListener", this.namespace, this.name, [listener]);
- }
-
- hasListener(listener) {
- tally("hasListener", this.namespace, this.name, [listener]);
- }
-}
-
-let wrapper = {
- url: "moz-extension://b66e3509-cdb3-44f6-8eb8-c8b39b3a1d27/",
-
- checkLoadURL(url) {
- return !url.startsWith("chrome:");
- },
-
- preprocessors: {
- localize(value, context) {
- return value.replace(/__MSG_(.*?)__/g, (m0, m1) => `${m1.toUpperCase()}`);
- },
- },
-
- logError(message) {
- talliedErrors.push(message);
- },
-
- hasPermission(permission) {
- return permissions.has(permission);
- },
-
- shouldInject(ns) {
- return ns != "do-not-inject";
- },
-
- getImplementation(namespace, name) {
- return new TallyingAPIImplementation(namespace, name);
- },
-};
-
-add_task(function* () {
- let url = "data:," + JSON.stringify(json);
- yield Schemas.load(url);
-
- let root = {};
- tallied = null;
- Schemas.inject(root, wrapper);
- do_check_eq(tallied, null);
-
- do_check_eq(root.testing.PROP1, 20, "simple value property");
- do_check_eq(root.testing.type1.VALUE1, "value1", "enum type");
- do_check_eq(root.testing.type1.VALUE2, "value2", "enum type");
-
- do_check_eq("inject" in root, true, "namespace 'inject' should be injected");
- do_check_eq("do-not-inject" in root, false, "namespace 'do-not-inject' should not be injected");
-
- root.testing.foo(11, true);
- verify("call", "testing", "foo", [11, true]);
-
- root.testing.foo(true);
- verify("call", "testing", "foo", [99, true]);
-
- root.testing.foo(null, true);
- verify("call", "testing", "foo", [99, true]);
-
- root.testing.foo(undefined, true);
- verify("call", "testing", "foo", [99, true]);
-
- root.testing.foo(11);
- verify("call", "testing", "foo", [11, null]);
-
- Assert.throws(() => root.testing.bar(11),
- /Incorrect argument types/,
- "should throw without required arg");
-
- Assert.throws(() => root.testing.bar(11, true, 10),
- /Incorrect argument types/,
- "should throw with too many arguments");
-
- root.testing.bar(true);
- verify("call", "testing", "bar", [null, true]);
-
- root.testing.baz({prop1: "hello", prop2: 22});
- verify("call", "testing", "baz", [{prop1: "hello", prop2: 22}]);
-
- root.testing.baz({prop1: "hello"});
- verify("call", "testing", "baz", [{prop1: "hello", prop2: null}]);
-
- root.testing.baz({prop1: "hello", prop2: null});
- verify("call", "testing", "baz", [{prop1: "hello", prop2: null}]);
-
- Assert.throws(() => root.testing.baz({prop2: 12}),
- /Property "prop1" is required/,
- "should throw without required property");
-
- Assert.throws(() => root.testing.baz({prop1: "hi", prop3: 12}),
- /Property "prop3" is unsupported by Firefox/,
- "should throw with unsupported property");
-
- Assert.throws(() => root.testing.baz({prop1: "hi", prop4: 12}),
- /Unexpected property "prop4"/,
- "should throw with unexpected property");
-
- Assert.throws(() => root.testing.baz({prop1: 12}),
- /Expected string instead of 12/,
- "should throw with wrong type");
-
- root.testing.qux("value2");
- verify("call", "testing", "qux", ["value2"]);
-
- Assert.throws(() => root.testing.qux("value4"),
- /Invalid enumeration value "value4"/,
- "should throw for invalid enum value");
-
- root.testing.quack({prop1: 12, prop2: ["value1", "value3"]});
- verify("call", "testing", "quack", [{prop1: 12, prop2: ["value1", "value3"]}]);
-
- Assert.throws(() => root.testing.quack({prop1: 12, prop2: ["value1", "value3", "value4"]}),
- /Invalid enumeration value "value4"/,
- "should throw for invalid array type");
-
- function f() {}
- root.testing.quora(f);
- do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["call", "testing", "quora"]));
- do_check_eq(tallied[3][0], f);
- tallied = null;
-
- let g = () => 0;
- root.testing.quora(g);
- do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["call", "testing", "quora"]));
- do_check_eq(tallied[3][0], g);
- tallied = null;
-
- root.testing.quileute(10);
- verify("call", "testing", "quileute", [null, 10]);
-
- Assert.throws(() => root.testing.queets(),
- /queets is not a function/,
- "should throw for unsupported functions");
-
- root.testing.quintuplets({a: 10, b: 20, c: 30});
- verify("call", "testing", "quintuplets", [{a: 10, b: 20, c: 30}]);
-
- Assert.throws(() => root.testing.quintuplets({a: 10, b: 20, c: 30, d: "hi"}),
- /Expected integer instead of "hi"/,
- "should throw for wrong additionalProperties type");
-
- root.testing.quasar({func: f});
- do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["call", "testing", "quasar"]));
- do_check_eq(tallied[3][0].func, f);
- tallied = null;
-
- root.testing.quosimodo({a: 10, b: 20, c: 30});
- verify("call", "testing", "quosimodo", [{a: 10, b: 20, c: 30}]);
- tallied = null;
-
- Assert.throws(() => root.testing.quosimodo(10),
- /Incorrect argument types/,
- "should throw for wrong type");
-
- root.testing.patternprop({prop1: "12", prop2: "42", Prop3: "43", foo1: "x"});
- verify("call", "testing", "patternprop", [{prop1: "12", prop2: "42", Prop3: "43", foo1: "x"}]);
- tallied = null;
-
- root.testing.patternprop({prop1: "12"});
- verify("call", "testing", "patternprop", [{prop1: "12"}]);
- tallied = null;
-
- Assert.throws(() => root.testing.patternprop({prop1: "12", foo1: null}),
- /Expected string instead of null/,
- "should throw for wrong property type");
-
- Assert.throws(() => root.testing.patternprop({prop1: "xx", prop2: "yy"}),
- /String "xx" must match \/\^\\d\+\$\//,
- "should throw for wrong property type");
-
- Assert.throws(() => root.testing.patternprop({prop1: "12", prop2: 42}),
- /Expected string instead of 42/,
- "should throw for wrong property type");
-
- Assert.throws(() => root.testing.patternprop({prop1: "12", prop2: null}),
- /Expected string instead of null/,
- "should throw for wrong property type");
-
- Assert.throws(() => root.testing.patternprop({prop1: "12", propx: "42"}),
- /Unexpected property "propx"/,
- "should throw for unexpected property");
-
- Assert.throws(() => root.testing.patternprop({prop1: "12", Foo1: "x"}),
- /Unexpected property "Foo1"/,
- "should throw for unexpected property");
-
- root.testing.pattern("DEADbeef");
- verify("call", "testing", "pattern", ["DEADbeef"]);
- tallied = null;
-
- Assert.throws(() => root.testing.pattern("DEADcow"),
- /String "DEADcow" must match \/\^\[0-9a-f\]\+\$\/i/,
- "should throw for non-match");
-
- root.testing.format({url: "http://foo/bar",
- relativeUrl: "http://foo/bar"});
- verify("call", "testing", "format", [{url: "http://foo/bar",
- relativeUrl: "http://foo/bar",
- strictRelativeUrl: null}]);
- tallied = null;
-
- root.testing.format({relativeUrl: "foo.html", strictRelativeUrl: "foo.html"});
- verify("call", "testing", "format", [{url: null,
- relativeUrl: `${wrapper.url}foo.html`,
- strictRelativeUrl: `${wrapper.url}foo.html`}]);
- tallied = null;
-
- for (let format of ["url", "relativeUrl"]) {
- Assert.throws(() => root.testing.format({[format]: "chrome://foo/content/"}),
- /Access denied/,
- "should throw for access denied");
- }
-
- for (let urlString of ["//foo.html", "http://foo/bar.html"]) {
- Assert.throws(() => root.testing.format({strictRelativeUrl: urlString}),
- /must be a relative URL/,
- "should throw for non-relative URL");
- }
-
- const dates = [
- "2016-03-04",
- "2016-03-04T08:00:00Z",
- "2016-03-04T08:00:00.000Z",
- "2016-03-04T08:00:00-08:00",
- "2016-03-04T08:00:00.000-08:00",
- "2016-03-04T08:00:00+08:00",
- "2016-03-04T08:00:00.000+08:00",
- "2016-03-04T08:00:00+0800",
- "2016-03-04T08:00:00-0800",
- ];
- dates.forEach(str => {
- root.testing.formatDate({date: str});
- verify("call", "testing", "formatDate", [{date: str}]);
- });
-
- // Make sure that a trivial change to a valid date invalidates it.
- dates.forEach(str => {
- Assert.throws(() => root.testing.formatDate({date: "0" + str}),
- /Invalid date string/,
- "should throw for invalid iso date string");
- Assert.throws(() => root.testing.formatDate({date: str + "0"}),
- /Invalid date string/,
- "should throw for invalid iso date string");
- });
-
- const badDates = [
- "I do not look anything like a date string",
- "2016-99-99",
- "2016-03-04T25:00:00Z",
- ];
- badDates.forEach(str => {
- Assert.throws(() => root.testing.formatDate({date: str}),
- /Invalid date string/,
- "should throw for invalid iso date string");
- });
-
- root.testing.deep({foo: {bar: [{baz: {required: 12, optional: "42"}}]}});
- verify("call", "testing", "deep", [{foo: {bar: [{baz: {required: 12, optional: "42"}}]}}]);
- tallied = null;
-
- Assert.throws(() => root.testing.deep({foo: {bar: [{baz: {optional: "42"}}]}}),
- /Type error for parameter arg \(Error processing foo\.bar\.0\.baz: Property "required" is required\) for testing\.deep/,
- "should throw with the correct object path");
-
- Assert.throws(() => root.testing.deep({foo: {bar: [{baz: {required: 12, optional: 42}}]}}),
- /Type error for parameter arg \(Error processing foo\.bar\.0\.baz\.optional: Expected string instead of 42\) for testing\.deep/,
- "should throw with the correct object path");
-
-
- talliedErrors.length = 0;
-
- root.testing.errors({warn: "0123", ignore: "0123", default: "0123"});
- verify("call", "testing", "errors", [{warn: "0123", ignore: "0123", default: "0123"}]);
- checkErrors([]);
-
- root.testing.errors({warn: "0123", ignore: "x123", default: "0123"});
- verify("call", "testing", "errors", [{warn: "0123", ignore: null, default: "0123"}]);
- checkErrors([]);
-
- root.testing.errors({warn: "x123", ignore: "0123", default: "0123"});
- verify("call", "testing", "errors", [{warn: null, ignore: "0123", default: "0123"}]);
- checkErrors([
- 'String "x123" must match /^\\d+$/',
- ]);
-
-
- root.testing.onFoo.addListener(f);
- do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["addListener", "testing", "onFoo"]));
- do_check_eq(tallied[3][0], f);
- do_check_eq(JSON.stringify(tallied[3][1]), JSON.stringify([]));
- tallied = null;
-
- root.testing.onFoo.removeListener(f);
- do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["removeListener", "testing", "onFoo"]));
- do_check_eq(tallied[3][0], f);
- tallied = null;
-
- root.testing.onFoo.hasListener(f);
- do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["hasListener", "testing", "onFoo"]));
- do_check_eq(tallied[3][0], f);
- tallied = null;
-
- Assert.throws(() => root.testing.onFoo.addListener(10),
- /Invalid listener/,
- "addListener with non-function should throw");
-
- root.testing.onBar.addListener(f, 10);
- do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["addListener", "testing", "onBar"]));
- do_check_eq(tallied[3][0], f);
- do_check_eq(JSON.stringify(tallied[3][1]), JSON.stringify([10]));
- tallied = null;
-
- root.testing.onBar.addListener(f);
- do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["addListener", "testing", "onBar"]));
- do_check_eq(tallied[3][0], f);
- do_check_eq(JSON.stringify(tallied[3][1]), JSON.stringify([1]));
- tallied = null;
-
- Assert.throws(() => root.testing.onBar.addListener(f, "hi"),
- /Incorrect argument types/,
- "addListener with wrong extra parameter should throw");
-
- let target = {prop1: 12, prop2: ["value1", "value3"]};
- let proxy = new Proxy(target, {});
- Assert.throws(() => root.testing.quack(proxy),
- /Expected a plain JavaScript object, got a Proxy/,
- "should throw when passing a Proxy");
-
- if (Symbol.toStringTag) {
- let stringTarget = {prop1: 12, prop2: ["value1", "value3"]};
- stringTarget[Symbol.toStringTag] = () => "[object Object]";
- let stringProxy = new Proxy(stringTarget, {});
- Assert.throws(() => root.testing.quack(stringProxy),
- /Expected a plain JavaScript object, got a Proxy/,
- "should throw when passing a Proxy");
- }
-
-
- root.testing.localize({foo: "__MSG_foo__", bar: "__MSG_foo__", url: "__MSG_http://example.com/__"});
- verify("call", "testing", "localize", [{foo: "FOO", bar: "__MSG_foo__", url: "http://example.com/"}]);
- tallied = null;
-
-
- Assert.throws(() => root.testing.localize({url: "__MSG_/foo/bar__"}),
- /\/FOO\/BAR is not a valid URL\./,
- "should throw for invalid URL");
-
-
- root.testing.extended1({prop1: "foo", prop2: "bar"});
- verify("call", "testing", "extended1", [{prop1: "foo", prop2: "bar"}]);
- tallied = null;
-
- Assert.throws(() => root.testing.extended1({prop1: "foo", prop2: 12}),
- /Expected string instead of 12/,
- "should throw for wrong property type");
-
- Assert.throws(() => root.testing.extended1({prop1: "foo"}),
- /Property "prop2" is required/,
- "should throw for missing property");
-
- Assert.throws(() => root.testing.extended1({prop1: "foo", prop2: "bar", prop3: "xxx"}),
- /Unexpected property "prop3"/,
- "should throw for extra property");
-
-
- root.testing.extended2("foo");
- verify("call", "testing", "extended2", ["foo"]);
- tallied = null;
-
- root.testing.extended2(12);
- verify("call", "testing", "extended2", [12]);
- tallied = null;
-
- Assert.throws(() => root.testing.extended2(true),
- /Incorrect argument types/,
- "should throw for wrong argument type");
-
- root.testing.prop3.sub_foo();
- verify("call", "testing.prop3", "sub_foo", []);
- tallied = null;
-
- Assert.throws(() => root.testing.prop4.sub_foo(),
- /root.testing.prop4 is undefined/,
- "should throw for unsupported submodule");
-
- root.foreign.foreignRef.sub_foo();
- verify("call", "foreign.foreignRef", "sub_foo", []);
- tallied = null;
-});
-
-let deprecatedJson = [
- {namespace: "deprecated",
-
- properties: {
- accessor: {
- type: "string",
- writable: true,
- deprecated: "This is not the property you are looking for",
- },
- },
-
- types: [
- {
- "id": "Type",
- "type": "string",
- },
- ],
-
- functions: [
- {
- name: "property",
- type: "function",
- parameters: [
- {
- name: "arg",
- type: "object",
- properties: {
- foo: {
- type: "string",
- },
- },
- additionalProperties: {
- type: "any",
- deprecated: "Unknown property",
- },
- },
- ],
- },
-
- {
- name: "value",
- type: "function",
- parameters: [
- {
- name: "arg",
- choices: [
- {
- type: "integer",
- },
- {
- type: "string",
- deprecated: "Please use an integer, not ${value}",
- },
- ],
- },
- ],
- },
-
- {
- name: "choices",
- type: "function",
- parameters: [
- {
- name: "arg",
- deprecated: "You have no choices",
- choices: [
- {
- type: "integer",
- },
- ],
- },
- ],
- },
-
- {
- name: "ref",
- type: "function",
- parameters: [
- {
- name: "arg",
- choices: [
- {
- $ref: "Type",
- deprecated: "Deprecated alias",
- },
- ],
- },
- ],
- },
-
- {
- name: "method",
- type: "function",
- deprecated: "Do not call this method",
- parameters: [
- ],
- },
- ],
-
- events: [
- {
- name: "onDeprecated",
- type: "function",
- deprecated: "This event does not work",
- },
- ],
- },
-];
-
-add_task(function* testDeprecation() {
- let url = "data:," + JSON.stringify(deprecatedJson);
- yield Schemas.load(url);
-
- let root = {};
- Schemas.inject(root, wrapper);
-
- talliedErrors.length = 0;
-
-
- root.deprecated.property({foo: "bar", xxx: "any", yyy: "property"});
- verify("call", "deprecated", "property", [{foo: "bar", xxx: "any", yyy: "property"}]);
- checkErrors([
- "Error processing xxx: Unknown property",
- "Error processing yyy: Unknown property",
- ]);
-
- root.deprecated.value(12);
- verify("call", "deprecated", "value", [12]);
- checkErrors([]);
-
- root.deprecated.value("12");
- verify("call", "deprecated", "value", ["12"]);
- checkErrors(["Please use an integer, not \"12\""]);
-
- root.deprecated.choices(12);
- verify("call", "deprecated", "choices", [12]);
- checkErrors(["You have no choices"]);
-
- root.deprecated.ref("12");
- verify("call", "deprecated", "ref", ["12"]);
- checkErrors(["Deprecated alias"]);
-
- root.deprecated.method();
- verify("call", "deprecated", "method", []);
- checkErrors(["Do not call this method"]);
-
-
- void root.deprecated.accessor;
- verify("get", "deprecated", "accessor", null);
- checkErrors(["This is not the property you are looking for"]);
-
- root.deprecated.accessor = "x";
- verify("set", "deprecated", "accessor", "x");
- checkErrors(["This is not the property you are looking for"]);
-
-
- root.deprecated.onDeprecated.addListener(() => {});
- checkErrors(["This event does not work"]);
-
- root.deprecated.onDeprecated.removeListener(() => {});
- checkErrors(["This event does not work"]);
-
- root.deprecated.onDeprecated.hasListener(() => {});
- checkErrors(["This event does not work"]);
-});
-
-
-let choicesJson = [
- {namespace: "choices",
-
- types: [
- ],
-
- functions: [
- {
- name: "meh",
- type: "function",
- parameters: [
- {
- name: "arg",
- choices: [
- {
- type: "string",
- enum: ["foo", "bar", "baz"],
- },
- {
- type: "string",
- pattern: "florg.*meh",
- },
- {
- type: "integer",
- minimum: 12,
- maximum: 42,
- },
- ],
- },
- ],
- },
-
- {
- name: "foo",
- type: "function",
- parameters: [
- {
- name: "arg",
- choices: [
- {
- type: "object",
- properties: {
- blurg: {
- type: "string",
- unsupported: true,
- optional: true,
- },
- },
- additionalProperties: {
- type: "string",
- },
- },
- {
- type: "string",
- },
- {
- type: "array",
- minItems: 2,
- maxItems: 3,
- items: {
- type: "integer",
- },
- },
- ],
- },
- ],
- },
-
- {
- name: "bar",
- type: "function",
- parameters: [
- {
- name: "arg",
- choices: [
- {
- type: "object",
- properties: {
- baz: {
- type: "string",
- },
- },
- },
- {
- type: "array",
- items: {
- type: "integer",
- },
- },
- ],
- },
- ],
- },
- ]},
-];
-
-add_task(function* testChoices() {
- let url = "data:," + JSON.stringify(choicesJson);
- yield Schemas.load(url);
-
- let root = {};
- Schemas.inject(root, wrapper);
-
- talliedErrors.length = 0;
-
- Assert.throws(() => root.choices.meh("frog"),
- /Value must either: be one of \["foo", "bar", "baz"\], match the pattern \/florg\.\*meh\/, or be an integer value/);
-
- Assert.throws(() => root.choices.meh(4),
- /be a string value, or be at least 12/);
-
- Assert.throws(() => root.choices.meh(43),
- /be a string value, or be no greater than 42/);
-
-
- Assert.throws(() => root.choices.foo([]),
- /be an object value, be a string value, or have at least 2 items/);
-
- Assert.throws(() => root.choices.foo([1, 2, 3, 4]),
- /be an object value, be a string value, or have at most 3 items/);
-
- Assert.throws(() => root.choices.foo({foo: 12}),
- /.foo must be a string value, be a string value, or be an array value/);
-
- Assert.throws(() => root.choices.foo({blurg: "foo"}),
- /not contain an unsupported "blurg" property, be a string value, or be an array value/);
-
-
- Assert.throws(() => root.choices.bar({}),
- /contain the required "baz" property, or be an array value/);
-
- Assert.throws(() => root.choices.bar({baz: "x", quux: "y"}),
- /not contain an unexpected "quux" property, or be an array value/);
-
- Assert.throws(() => root.choices.bar({baz: "x", quux: "y", foo: "z"}),
- /not contain the unexpected properties \[foo, quux\], or be an array value/);
-});
-
-
-let permissionsJson = [
- {namespace: "noPerms",
-
- types: [],
-
- functions: [
- {
- name: "noPerms",
- type: "function",
- parameters: [],
- },
-
- {
- name: "fooPerm",
- type: "function",
- permissions: ["foo"],
- parameters: [],
- },
- ]},
-
- {namespace: "fooPerm",
-
- permissions: ["foo"],
-
- types: [],
-
- functions: [
- {
- name: "noPerms",
- type: "function",
- parameters: [],
- },
-
- {
- name: "fooBarPerm",
- type: "function",
- permissions: ["foo.bar"],
- parameters: [],
- },
- ]},
-];
-
-add_task(function* testPermissions() {
- let url = "data:," + JSON.stringify(permissionsJson);
- yield Schemas.load(url);
-
- let root = {};
- Schemas.inject(root, wrapper);
-
- equal(typeof root.noPerms, "object", "noPerms namespace should exist");
- equal(typeof root.noPerms.noPerms, "function", "noPerms.noPerms method should exist");
-
- ok(!("fooPerm" in root.noPerms), "noPerms.fooPerm should not method exist");
-
- ok(!("fooPerm" in root), "fooPerm namespace should not exist");
-
-
- do_print('Add "foo" permission');
- permissions.add("foo");
-
- root = {};
- Schemas.inject(root, wrapper);
-
- equal(typeof root.noPerms, "object", "noPerms namespace should exist");
- equal(typeof root.noPerms.noPerms, "function", "noPerms.noPerms method should exist");
- equal(typeof root.noPerms.fooPerm, "function", "noPerms.fooPerm method should exist");
-
- equal(typeof root.fooPerm, "object", "fooPerm namespace should exist");
- equal(typeof root.fooPerm.noPerms, "function", "noPerms.noPerms method should exist");
-
- ok(!("fooBarPerm" in root.fooPerm), "fooPerm.fooBarPerm method should not exist");
-
-
- do_print('Add "foo.bar" permission');
- permissions.add("foo.bar");
-
- root = {};
- Schemas.inject(root, wrapper);
-
- equal(typeof root.noPerms, "object", "noPerms namespace should exist");
- equal(typeof root.noPerms.noPerms, "function", "noPerms.noPerms method should exist");
- equal(typeof root.noPerms.fooPerm, "function", "noPerms.fooPerm method should exist");
-
- equal(typeof root.fooPerm, "object", "fooPerm namespace should exist");
- equal(typeof root.fooPerm.noPerms, "function", "noPerms.noPerms method should exist");
- equal(typeof root.fooPerm.fooBarPerm, "function", "noPerms.fooBarPerm method should exist");
-});
-
-let nestedNamespaceJson = [
- {
- "namespace": "nested.namespace",
- "types": [
- {
- "id": "CustomType",
- "type": "object",
- "events": [
- {
- "name": "onEvent",
- },
- ],
- "properties": {
- "url": {
- "type": "string",
- },
- },
- "functions": [
- {
- "name": "functionOnCustomType",
- "type": "function",
- "parameters": [
- {
- "name": "title",
- "type": "string",
- },
- ],
- },
- ],
- },
- ],
- "properties": {
- "instanceOfCustomType": {
- "$ref": "CustomType",
- },
- },
- "functions": [
- {
- "name": "create",
- "type": "function",
- "parameters": [
- {
- "name": "title",
- "type": "string",
- },
- ],
- },
- ],
- },
-];
-
-add_task(function* testNestedNamespace() {
- let url = "data:," + JSON.stringify(nestedNamespaceJson);
-
- yield Schemas.load(url);
-
- let root = {};
- Schemas.inject(root, wrapper);
-
- talliedErrors.length = 0;
-
- ok(root.nested, "The root object contains the first namespace level");
- ok(root.nested.namespace, "The first level object contains the second namespace level");
-
- ok(root.nested.namespace.create, "Got the expected function in the nested namespace");
- do_check_eq(typeof root.nested.namespace.create, "function",
- "The property is a function as expected");
-
- let {instanceOfCustomType} = root.nested.namespace;
-
- ok(instanceOfCustomType,
- "Got the expected instance of the CustomType defined in the schema");
- ok(instanceOfCustomType.functionOnCustomType,
- "Got the expected method in the CustomType instance");
-
- // TODO: test support events and properties in a SubModuleType defined in the schema,
- // once implemented, e.g.:
- //
- // ok(instanceOfCustomType.url,
- // "Got the expected property defined in the CustomType instance)
- //
- // ok(instanceOfCustomType.onEvent &&
- // instanceOfCustomType.onEvent.addListener &&
- // typeof instanceOfCustomType.onEvent.addListener == "function",
- // "Got the expected event defined in the CustomType instance");
-});
-
-add_task(function* testLocalAPIImplementation() {
- let countGet2 = 0;
- let countProp3 = 0;
- let countProp3SubFoo = 0;
-
- let testingApiObj = {
- get PROP1() {
- // PROP1 is a schema-defined constant.
- throw new Error("Unexpected get PROP1");
- },
- get prop2() {
- ++countGet2;
- return "prop2 val";
- },
- get prop3() {
- throw new Error("Unexpected get prop3");
- },
- set prop3(v) {
- // prop3 is a submodule, defined as a function, so the API should not pass
- // through assignment to prop3.
- throw new Error("Unexpected set prop3");
- },
- };
- let submoduleApiObj = {
- get sub_foo() {
- ++countProp3;
- return () => {
- return ++countProp3SubFoo;
- };
- },
- };
-
- let localWrapper = {
- shouldInject(ns) {
- return ns == "testing" || ns == "testing.prop3";
- },
- getImplementation(ns, name) {
- do_check_true(ns == "testing" || ns == "testing.prop3");
- if (ns == "testing.prop3" && name == "sub_foo") {
- // It is fine to use `null` here because we don't call async functions.
- return new LocalAPIImplementation(submoduleApiObj, name, null);
- }
- // It is fine to use `null` here because we don't call async functions.
- return new LocalAPIImplementation(testingApiObj, name, null);
- },
- };
-
- let root = {};
- Schemas.inject(root, localWrapper);
- do_check_eq(countGet2, 0);
- do_check_eq(countProp3, 0);
- do_check_eq(countProp3SubFoo, 0);
-
- do_check_eq(root.testing.PROP1, 20);
-
- do_check_eq(root.testing.prop2, "prop2 val");
- do_check_eq(countGet2, 1);
-
- do_check_eq(root.testing.prop2, "prop2 val");
- do_check_eq(countGet2, 2);
-
- do_print(JSON.stringify(root.testing));
- do_check_eq(root.testing.prop3.sub_foo(), 1);
- do_check_eq(countProp3, 1);
- do_check_eq(countProp3SubFoo, 1);
-
- do_check_eq(root.testing.prop3.sub_foo(), 2);
- do_check_eq(countProp3, 2);
- do_check_eq(countProp3SubFoo, 2);
-
- root.testing.prop3.sub_foo = () => { return "overwritten"; };
- do_check_eq(root.testing.prop3.sub_foo(), "overwritten");
-
- root.testing.prop3 = {sub_foo() { return "overwritten again"; }};
- do_check_eq(root.testing.prop3.sub_foo(), "overwritten again");
- do_check_eq(countProp3SubFoo, 2);
-});
-
-
-let defaultsJson = [
- {namespace: "defaultsJson",
-
- types: [],
-
- functions: [
- {
- name: "defaultFoo",
- type: "function",
- parameters: [
- {name: "arg", type: "object", optional: true, properties: {
- prop1: {type: "integer", optional: true},
- }, default: {prop1: 1}},
- ],
- returns: {
- type: "object",
- },
- },
- ]},
-];
-
-add_task(function* testDefaults() {
- let url = "data:," + JSON.stringify(defaultsJson);
- yield Schemas.load(url);
-
- let testingApiObj = {
- defaultFoo: function(arg) {
- if (Object.keys(arg) != "prop1") {
- throw new Error(`Received the expected default object, default: ${JSON.stringify(arg)}`);
- }
- arg.newProp = 1;
- return arg;
- },
- };
-
- let localWrapper = {
- shouldInject(ns) {
- return true;
- },
- getImplementation(ns, name) {
- return new LocalAPIImplementation(testingApiObj, name, null);
- },
- };
-
- let root = {};
- Schemas.inject(root, localWrapper);
-
- deepEqual(root.defaultsJson.defaultFoo(), {prop1: 1, newProp: 1});
- deepEqual(root.defaultsJson.defaultFoo({prop1: 2}), {prop1: 2, newProp: 1});
- deepEqual(root.defaultsJson.defaultFoo(), {prop1: 1, newProp: 1});
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_schemas_allowed_contexts.js b/toolkit/components/extensions/test/xpcshell/test_ext_schemas_allowed_contexts.js
deleted file mode 100644
index 606459764..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_schemas_allowed_contexts.js
+++ /dev/null
@@ -1,147 +0,0 @@
-"use strict";
-
-Components.utils.import("resource://gre/modules/Schemas.jsm");
-
-let schemaJson = [
- {
- namespace: "noAllowedContexts",
- properties: {
- prop1: {type: "object"},
- prop2: {type: "object", allowedContexts: ["test_zero", "test_one"]},
- prop3: {type: "number", value: 1},
- prop4: {type: "number", value: 1, allowedContexts: ["numeric_one"]},
- },
- },
- {
- namespace: "defaultContexts",
- defaultContexts: ["test_two"],
- properties: {
- prop1: {type: "object"},
- prop2: {type: "object", allowedContexts: ["test_three"]},
- prop3: {type: "number", value: 1},
- prop4: {type: "number", value: 1, allowedContexts: ["numeric_two"]},
- },
- },
- {
- namespace: "withAllowedContexts",
- allowedContexts: ["test_four"],
- properties: {
- prop1: {type: "object"},
- prop2: {type: "object", allowedContexts: ["test_five"]},
- prop3: {type: "number", value: 1},
- prop4: {type: "number", value: 1, allowedContexts: ["numeric_three"]},
- },
- },
- {
- namespace: "withAllowedContextsAndDefault",
- allowedContexts: ["test_six"],
- defaultContexts: ["test_seven"],
- properties: {
- prop1: {type: "object"},
- prop2: {type: "object", allowedContexts: ["test_eight"]},
- prop3: {type: "number", value: 1},
- prop4: {type: "number", value: 1, allowedContexts: ["numeric_four"]},
- },
- },
- {
- namespace: "with_submodule",
- defaultContexts: ["test_nine"],
- types: [{
- id: "subtype",
- type: "object",
- functions: [{
- name: "noAllowedContexts",
- type: "function",
- parameters: [],
- }, {
- name: "allowedContexts",
- allowedContexts: ["test_ten"],
- type: "function",
- parameters: [],
- }],
- }],
- properties: {
- prop1: {$ref: "subtype"},
- prop2: {$ref: "subtype", allowedContexts: ["test_eleven"]},
- },
- },
-];
-add_task(function* testRestrictions() {
- let url = "data:," + JSON.stringify(schemaJson);
- yield Schemas.load(url);
- let results = {};
- let localWrapper = {
- shouldInject(ns, name, allowedContexts) {
- name = name === null ? ns : ns + "." + name;
- results[name] = allowedContexts.join(",");
- return true;
- },
- getImplementation() {
- // The actual implementation is not significant for this test.
- // Let's take this opportunity to see if schema generation is free of
- // exceptions even when somehow getImplementation does not return an
- // implementation.
- },
- };
-
- let root = {};
- Schemas.inject(root, localWrapper);
-
- function verify(path, expected) {
- let obj = root;
- for (let thing of path.split(".")) {
- try {
- obj = obj[thing];
- } catch (e) {
- // Blech.
- }
- }
-
- let result = results[path];
- equal(result, expected);
- }
-
- verify("noAllowedContexts", "");
- verify("noAllowedContexts.prop1", "");
- verify("noAllowedContexts.prop2", "test_zero,test_one");
- verify("noAllowedContexts.prop3", "");
- verify("noAllowedContexts.prop4", "numeric_one");
-
- verify("defaultContexts", "");
- verify("defaultContexts.prop1", "test_two");
- verify("defaultContexts.prop2", "test_three");
- verify("defaultContexts.prop3", "test_two");
- verify("defaultContexts.prop4", "numeric_two");
-
- verify("withAllowedContexts", "test_four");
- verify("withAllowedContexts.prop1", "");
- verify("withAllowedContexts.prop2", "test_five");
- verify("withAllowedContexts.prop3", "");
- verify("withAllowedContexts.prop4", "numeric_three");
-
- verify("withAllowedContextsAndDefault", "test_six");
- verify("withAllowedContextsAndDefault.prop1", "test_seven");
- verify("withAllowedContextsAndDefault.prop2", "test_eight");
- verify("withAllowedContextsAndDefault.prop3", "test_seven");
- verify("withAllowedContextsAndDefault.prop4", "numeric_four");
-
- verify("with_submodule", "");
- verify("with_submodule.prop1", "test_nine");
- verify("with_submodule.prop1.noAllowedContexts", "test_nine");
- verify("with_submodule.prop1.allowedContexts", "test_ten");
- verify("with_submodule.prop2", "test_eleven");
- // Note: test_nine inherits allowed contexts from the namespace, not from
- // submodule. There is no "defaultContexts" for submodule types to not
- // complicate things.
- verify("with_submodule.prop1.noAllowedContexts", "test_nine");
- verify("with_submodule.prop1.allowedContexts", "test_ten");
-
- // This is a constant, so it does not matter that getImplementation does not
- // return an implementation since the API injector should take care of it.
- equal(root.noAllowedContexts.prop3, 1);
-
- Assert.throws(() => root.noAllowedContexts.prop1,
- /undefined/,
- "Should throw when the implementation is absent.");
-});
-
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_schemas_api_injection.js b/toolkit/components/extensions/test/xpcshell/test_ext_schemas_api_injection.js
deleted file mode 100644
index 36d88d722..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_schemas_api_injection.js
+++ /dev/null
@@ -1,102 +0,0 @@
-"use strict";
-
-Components.utils.import("resource://gre/modules/ExtensionCommon.jsm");
-Components.utils.import("resource://gre/modules/Schemas.jsm");
-
-let {
- BaseContext,
- SchemaAPIManager,
-} = ExtensionCommon;
-
-let nestedNamespaceJson = [
- {
- "namespace": "backgroundAPI.testnamespace",
- "functions": [
- {
- "name": "create",
- "type": "function",
- "parameters": [
- {
- "name": "title",
- "type": "string",
- },
- ],
- "returns": {
- "type": "string",
- },
- },
- ],
- },
- {
- "namespace": "noBackgroundAPI.testnamespace",
- "functions": [
- {
- "name": "create",
- "type": "function",
- "parameters": [
- {
- "name": "title",
- "type": "string",
- },
- ],
- },
- ],
- },
-];
-
-let global = this;
-class StubContext extends BaseContext {
- constructor() {
- let fakeExtension = {id: "test@web.extension"};
- super("addon_child", fakeExtension);
- this.sandbox = Cu.Sandbox(global);
- this.viewType = "background";
- }
-
- get cloneScope() {
- return this.sandbox;
- }
-}
-
-add_task(function* testSchemaAPIInjection() {
- let url = "data:," + JSON.stringify(nestedNamespaceJson);
-
- // Load the schema of the fake APIs.
- yield Schemas.load(url);
-
- let apiManager = new SchemaAPIManager("addon");
-
- // Register an API that will skip the background page.
- apiManager.registerSchemaAPI("noBackgroundAPI.testnamespace", "addon_child", context => {
- // This API should not be available in this context, return null so that
- // the schema wrapper is removed as well.
- return null;
- });
-
- // Register an API that will skip any but the background page.
- apiManager.registerSchemaAPI("backgroundAPI.testnamespace", "addon_child", context => {
- if (context.viewType === "background") {
- return {
- backgroundAPI: {
- testnamespace: {
- create(title) {
- return title;
- },
- },
- },
- };
- }
-
- // This API should not be available in this context, return null so that
- // the schema wrapper is removed as well.
- return null;
- });
-
- let context = new StubContext();
- let browserObj = {};
- apiManager.generateAPIs(context, browserObj);
-
- do_check_eq(browserObj.noBackgroundAPI, undefined);
- const res = browserObj.backgroundAPI.testnamespace.create("param-value");
- do_check_eq(res, "param-value");
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_schemas_async.js b/toolkit/components/extensions/test/xpcshell/test_ext_schemas_async.js
deleted file mode 100644
index 6397d1f96..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_schemas_async.js
+++ /dev/null
@@ -1,232 +0,0 @@
-"use strict";
-
-Components.utils.import("resource://gre/modules/ExtensionCommon.jsm");
-Components.utils.import("resource://gre/modules/Schemas.jsm");
-
-let {BaseContext, LocalAPIImplementation} = ExtensionCommon;
-
-let schemaJson = [
- {
- namespace: "testnamespace",
- functions: [{
- name: "one_required",
- type: "function",
- parameters: [{
- name: "first",
- type: "function",
- parameters: [],
- }],
- }, {
- name: "one_optional",
- type: "function",
- parameters: [{
- name: "first",
- type: "function",
- parameters: [],
- optional: true,
- }],
- }, {
- name: "async_required",
- type: "function",
- async: "first",
- parameters: [{
- name: "first",
- type: "function",
- parameters: [],
- }],
- }, {
- name: "async_optional",
- type: "function",
- async: "first",
- parameters: [{
- name: "first",
- type: "function",
- parameters: [],
- optional: true,
- }],
- }],
- },
-];
-
-const global = this;
-class StubContext extends BaseContext {
- constructor() {
- let fakeExtension = {id: "test@web.extension"};
- super("testEnv", fakeExtension);
- this.sandbox = Cu.Sandbox(global);
- }
-
- get cloneScope() {
- return this.sandbox;
- }
-
- get principal() {
- return Cu.getObjectPrincipal(this.sandbox);
- }
-}
-
-let context;
-
-function generateAPIs(extraWrapper, apiObj) {
- context = new StubContext();
- let localWrapper = {
- shouldInject() {
- return true;
- },
- getImplementation(namespace, name) {
- return new LocalAPIImplementation(apiObj, name, context);
- },
- };
- Object.assign(localWrapper, extraWrapper);
-
- let root = {};
- Schemas.inject(root, localWrapper);
- return root.testnamespace;
-}
-
-add_task(function* testParameterValidation() {
- yield Schemas.load("data:," + JSON.stringify(schemaJson));
-
- let testnamespace;
- function assertThrows(name, ...args) {
- Assert.throws(() => testnamespace[name](...args),
- /Incorrect argument types/,
- `Expected testnamespace.${name}(${args.map(String).join(", ")}) to throw.`);
- }
- function assertNoThrows(name, ...args) {
- try {
- testnamespace[name](...args);
- } catch (e) {
- do_print(`testnamespace.${name}(${args.map(String).join(", ")}) unexpectedly threw.`);
- throw new Error(e);
- }
- }
- let cb = () => {};
-
- for (let isChromeCompat of [true, false]) {
- do_print(`Testing API validation with isChromeCompat=${isChromeCompat}`);
- testnamespace = generateAPIs({
- isChromeCompat,
- }, {
- one_required() {},
- one_optional() {},
- async_required() {},
- async_optional() {},
- });
-
- assertThrows("one_required");
- assertThrows("one_required", null);
- assertNoThrows("one_required", cb);
- assertThrows("one_required", cb, null);
- assertThrows("one_required", cb, cb);
-
- assertNoThrows("one_optional");
- assertNoThrows("one_optional", null);
- assertNoThrows("one_optional", cb);
- assertThrows("one_optional", cb, null);
- assertThrows("one_optional", cb, cb);
-
- // Schema-based validation happens before an async method is called, so
- // errors should be thrown synchronously.
-
- // The parameter was declared as required, but there was also an "async"
- // attribute with the same value as the parameter name, so the callback
- // parameter is actually optional.
- assertNoThrows("async_required");
- assertNoThrows("async_required", null);
- assertNoThrows("async_required", cb);
- assertThrows("async_required", cb, null);
- assertThrows("async_required", cb, cb);
-
- assertNoThrows("async_optional");
- assertNoThrows("async_optional", null);
- assertNoThrows("async_optional", cb);
- assertThrows("async_optional", cb, null);
- assertThrows("async_optional", cb, cb);
- }
-});
-
-add_task(function* testAsyncResults() {
- yield Schemas.load("data:," + JSON.stringify(schemaJson));
- function* runWithCallback(func) {
- do_print(`Calling testnamespace.${func.name}, expecting callback with result`);
- return yield new Promise(resolve => {
- let result = "uninitialized value";
- let returnValue = func(reply => {
- result = reply;
- resolve(result);
- });
- // When a callback is given, the return value must be missing.
- do_check_eq(returnValue, undefined);
- // Callback must be called asynchronously.
- do_check_eq(result, "uninitialized value");
- });
- }
-
- function* runFailCallback(func) {
- do_print(`Calling testnamespace.${func.name}, expecting callback with error`);
- return yield new Promise(resolve => {
- func(reply => {
- do_check_eq(reply, undefined);
- resolve(context.lastError.message); // eslint-disable-line no-undef
- });
- });
- }
-
- for (let isChromeCompat of [true, false]) {
- do_print(`Testing API invocation with isChromeCompat=${isChromeCompat}`);
- let testnamespace = generateAPIs({
- isChromeCompat,
- }, {
- async_required(cb) {
- do_check_eq(cb, undefined);
- return Promise.resolve(1);
- },
- async_optional(cb) {
- do_check_eq(cb, undefined);
- return Promise.resolve(2);
- },
- });
- if (!isChromeCompat) { // No promises for chrome.
- do_print("testnamespace.async_required should be a Promise");
- let promise = testnamespace.async_required();
- do_check_true(promise instanceof context.cloneScope.Promise);
- do_check_eq(yield promise, 1);
-
- do_print("testnamespace.async_optional should be a Promise");
- promise = testnamespace.async_optional();
- do_check_true(promise instanceof context.cloneScope.Promise);
- do_check_eq(yield promise, 2);
- }
-
- do_check_eq(yield* runWithCallback(testnamespace.async_required), 1);
- do_check_eq(yield* runWithCallback(testnamespace.async_optional), 2);
-
- let otherSandbox = Cu.Sandbox(null, {});
- let errorFactories = [
- msg => { throw new context.cloneScope.Error(msg); },
- msg => context.cloneScope.Promise.reject({message: msg}),
- msg => Cu.evalInSandbox(`throw new Error("${msg}")`, otherSandbox),
- msg => Cu.evalInSandbox(`Promise.reject({message: "${msg}"})`, otherSandbox),
- ];
- for (let makeError of errorFactories) {
- do_print(`Testing callback/promise with error caused by: ${makeError}`);
- testnamespace = generateAPIs({
- isChromeCompat,
- }, {
- async_required() { return makeError("ONE"); },
- async_optional() { return makeError("TWO"); },
- });
-
- if (!isChromeCompat) { // No promises for chrome.
- yield Assert.rejects(testnamespace.async_required(), /ONE/,
- "should reject testnamespace.async_required()").catch(() => {});
- yield Assert.rejects(testnamespace.async_optional(), /TWO/,
- "should reject testnamespace.async_optional()").catch(() => {});
- }
-
- do_check_eq(yield* runFailCallback(testnamespace.async_required), "ONE");
- do_check_eq(yield* runFailCallback(testnamespace.async_optional), "TWO");
- }
- }
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_simple.js b/toolkit/components/extensions/test/xpcshell/test_ext_simple.js
deleted file mode 100644
index 91b10354c..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_simple.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-add_task(function* test_simple() {
- let extensionData = {
- manifest: {
- "name": "Simple extension test",
- "version": "1.0",
- "manifest_version": 2,
- "description": "",
- },
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
- yield extension.unload();
-});
-
-add_task(function* test_background() {
- function background() {
- browser.test.log("running background script");
-
- browser.test.onMessage.addListener((x, y) => {
- browser.test.assertEq(x, 10, "x is 10");
- browser.test.assertEq(y, 20, "y is 20");
-
- browser.test.notifyPass("background test passed");
- });
-
- browser.test.sendMessage("running", 1);
- }
-
- let extensionData = {
- background,
- manifest: {
- "name": "Simple extension test",
- "version": "1.0",
- "manifest_version": 2,
- "description": "",
- },
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
-
- let [, x] = yield Promise.all([extension.startup(), extension.awaitMessage("running")]);
- equal(x, 1, "got correct value from extension");
-
- extension.sendMessage(10, 20);
- yield extension.awaitFinish();
- yield extension.unload();
-});
-
-add_task(function* test_extensionTypes() {
- let extensionData = {
- background: function() {
- browser.test.assertEq(typeof browser.extensionTypes, "object", "browser.extensionTypes exists");
- browser.test.assertEq(typeof browser.extensionTypes.RunAt, "object", "browser.extensionTypes.RunAt exists");
- browser.test.notifyPass("extentionTypes test passed");
- },
- };
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
-
- yield extension.startup();
- yield extension.awaitFinish();
- yield extension.unload();
-});
-
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_storage.js b/toolkit/components/extensions/test/xpcshell/test_ext_storage.js
deleted file mode 100644
index df46dfb63..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_storage.js
+++ /dev/null
@@ -1,334 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-const STORAGE_SYNC_PREF = "webextensions.storage.sync.enabled";
-Cu.import("resource://gre/modules/Preferences.jsm");
-
-/**
- * Utility function to ensure that all supported APIs for getting are
- * tested.
- *
- * @param {string} areaName
- * either "local" or "sync" according to what we want to test
- * @param {string} prop
- * "key" to look up using the storage API
- * @param {Object} value
- * "value" to compare against
- */
-async function checkGetImpl(areaName, prop, value) {
- let storage = browser.storage[areaName];
-
- let data = await storage.get(null);
- browser.test.assertEq(value, data[prop], `null getter worked for ${prop} in ${areaName}`);
-
- data = await storage.get(prop);
- browser.test.assertEq(value, data[prop], `string getter worked for ${prop} in ${areaName}`);
-
- data = await storage.get([prop]);
- browser.test.assertEq(value, data[prop], `array getter worked for ${prop} in ${areaName}`);
-
- data = await storage.get({[prop]: undefined});
- browser.test.assertEq(value, data[prop], `object getter worked for ${prop} in ${areaName}`);
-}
-
-add_task(function* test_local_cache_invalidation() {
- function background(checkGet) {
- browser.test.onMessage.addListener(async msg => {
- if (msg === "set-initial") {
- await browser.storage.local.set({"test-prop1": "value1", "test-prop2": "value2"});
- browser.test.sendMessage("set-initial-done");
- } else if (msg === "check") {
- await checkGet("local", "test-prop1", "value1");
- await checkGet("local", "test-prop2", "value2");
- browser.test.sendMessage("check-done");
- }
- });
-
- browser.test.sendMessage("ready");
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- manifest: {
- permissions: ["storage"],
- },
- background: `(${background})(${checkGetImpl})`,
- });
-
- yield extension.startup();
- yield extension.awaitMessage("ready");
-
- extension.sendMessage("set-initial");
- yield extension.awaitMessage("set-initial-done");
-
- Services.obs.notifyObservers(null, "extension-invalidate-storage-cache", "");
-
- extension.sendMessage("check");
- yield extension.awaitMessage("check-done");
-
- yield extension.unload();
-});
-
-add_task(function* test_config_flag_needed() {
- function background() {
- let promises = [];
- let apiTests = [
- {method: "get", args: ["foo"]},
- {method: "set", args: [{foo: "bar"}]},
- {method: "remove", args: ["foo"]},
- {method: "clear", args: []},
- ];
- apiTests.forEach(testDef => {
- promises.push(browser.test.assertRejects(
- browser.storage.sync[testDef.method](...testDef.args),
- "Please set webextensions.storage.sync.enabled to true in about:config",
- `storage.sync.${testDef.method} is behind a flag`));
- });
-
- Promise.all(promises).then(() => browser.test.notifyPass("flag needed"));
- }
-
- ok(!Preferences.get(STORAGE_SYNC_PREF));
- let extension = ExtensionTestUtils.loadExtension({
- manifest: {
- permissions: ["storage"],
- },
- background: `(${background})(${checkGetImpl})`,
- });
-
- yield extension.startup();
- yield extension.awaitFinish("flag needed");
- yield extension.unload();
-});
-
-add_task(function* test_reloading_extensions_works() {
- // Just some random extension ID that we can re-use
- const extensionId = "my-extension-id@1";
-
- function loadExtension() {
- function background() {
- browser.storage.sync.set({"a": "b"}).then(() => {
- browser.test.notifyPass("set-works");
- });
- }
-
- return ExtensionTestUtils.loadExtension({
- manifest: {
- permissions: ["storage"],
- },
- background: `(${background})()`,
- }, extensionId);
- }
-
- Preferences.set(STORAGE_SYNC_PREF, true);
-
- let extension1 = loadExtension();
-
- yield extension1.startup();
- yield extension1.awaitFinish("set-works");
- yield extension1.unload();
-
- let extension2 = loadExtension();
-
- yield extension2.startup();
- yield extension2.awaitFinish("set-works");
- yield extension2.unload();
-
- Preferences.reset(STORAGE_SYNC_PREF);
-});
-
-do_register_cleanup(() => {
- Preferences.reset(STORAGE_SYNC_PREF);
-});
-
-add_task(function* test_backgroundScript() {
- async function backgroundScript(checkGet) {
- let globalChanges, gResolve;
- function clearGlobalChanges() {
- globalChanges = new Promise(resolve => { gResolve = resolve; });
- }
- clearGlobalChanges();
- let expectedAreaName;
-
- browser.storage.onChanged.addListener((changes, areaName) => {
- browser.test.assertEq(expectedAreaName, areaName,
- "Expected area name received by listener");
- gResolve(changes);
- });
-
- async function checkChanges(areaName, changes, message) {
- function checkSub(obj1, obj2) {
- for (let prop in obj1) {
- browser.test.assertTrue(obj1[prop] !== undefined,
- `checkChanges ${areaName} ${prop} is missing (${message})`);
- browser.test.assertTrue(obj2[prop] !== undefined,
- `checkChanges ${areaName} ${prop} is missing (${message})`);
- browser.test.assertEq(obj1[prop].oldValue, obj2[prop].oldValue,
- `checkChanges ${areaName} ${prop} old (${message})`);
- browser.test.assertEq(obj1[prop].newValue, obj2[prop].newValue,
- `checkChanges ${areaName} ${prop} new (${message})`);
- }
- }
-
- const recentChanges = await globalChanges;
- checkSub(changes, recentChanges);
- checkSub(recentChanges, changes);
- clearGlobalChanges();
- }
-
- /* eslint-disable dot-notation */
- async function runTests(areaName) {
- expectedAreaName = areaName;
- let storage = browser.storage[areaName];
- // Set some data and then test getters.
- try {
- await storage.set({"test-prop1": "value1", "test-prop2": "value2"});
- await checkChanges(areaName,
- {"test-prop1": {newValue: "value1"}, "test-prop2": {newValue: "value2"}},
- "set (a)");
-
- await checkGet(areaName, "test-prop1", "value1");
- await checkGet(areaName, "test-prop2", "value2");
-
- let data = await storage.get({"test-prop1": undefined, "test-prop2": undefined, "other": "default"});
- browser.test.assertEq("value1", data["test-prop1"], "prop1 correct (a)");
- browser.test.assertEq("value2", data["test-prop2"], "prop2 correct (a)");
- browser.test.assertEq("default", data["other"], "other correct");
-
- data = await storage.get(["test-prop1", "test-prop2", "other"]);
- browser.test.assertEq("value1", data["test-prop1"], "prop1 correct (b)");
- browser.test.assertEq("value2", data["test-prop2"], "prop2 correct (b)");
- browser.test.assertFalse("other" in data, "other correct");
-
- // Remove data in various ways.
- await storage.remove("test-prop1");
- await checkChanges(areaName, {"test-prop1": {oldValue: "value1"}}, "remove string");
-
- data = await storage.get(["test-prop1", "test-prop2"]);
- browser.test.assertFalse("test-prop1" in data, "prop1 absent (remove string)");
- browser.test.assertTrue("test-prop2" in data, "prop2 present (remove string)");
-
- await storage.set({"test-prop1": "value1"});
- await checkChanges(areaName, {"test-prop1": {newValue: "value1"}}, "set (c)");
-
- data = await storage.get(["test-prop1", "test-prop2"]);
- browser.test.assertEq(data["test-prop1"], "value1", "prop1 correct (c)");
- browser.test.assertEq(data["test-prop2"], "value2", "prop2 correct (c)");
-
- await storage.remove(["test-prop1", "test-prop2"]);
- await checkChanges(areaName,
- {"test-prop1": {oldValue: "value1"}, "test-prop2": {oldValue: "value2"}},
- "remove array");
-
- data = await storage.get(["test-prop1", "test-prop2"]);
- browser.test.assertFalse("test-prop1" in data, "prop1 absent (remove array)");
- browser.test.assertFalse("test-prop2" in data, "prop2 absent (remove array)");
-
- // test storage.clear
- await storage.set({"test-prop1": "value1", "test-prop2": "value2"});
- // Make sure that set() handler happened before we clear the
- // promise again.
- await globalChanges;
-
- clearGlobalChanges();
- await storage.clear();
-
- await checkChanges(areaName,
- {"test-prop1": {oldValue: "value1"}, "test-prop2": {oldValue: "value2"}},
- "clear");
- data = await storage.get(["test-prop1", "test-prop2"]);
- browser.test.assertFalse("test-prop1" in data, "prop1 absent (clear)");
- browser.test.assertFalse("test-prop2" in data, "prop2 absent (clear)");
-
- // Make sure we can store complex JSON data.
- // known previous values
- await storage.set({"test-prop1": "value1", "test-prop2": "value2"});
-
- // Make sure the set() handler landed.
- await globalChanges;
-
- clearGlobalChanges();
- await storage.set({
- "test-prop1": {
- str: "hello",
- bool: true,
- null: null,
- undef: undefined,
- obj: {},
- arr: [1, 2],
- date: new Date(0),
- regexp: /regexp/,
- func: function func() {},
- window,
- },
- });
-
- await storage.set({"test-prop2": function func() {}});
- const recentChanges = await globalChanges;
-
- browser.test.assertEq("value1", recentChanges["test-prop1"].oldValue, "oldValue correct");
- browser.test.assertEq("object", typeof(recentChanges["test-prop1"].newValue), "newValue is obj");
- clearGlobalChanges();
-
- data = await storage.get({"test-prop1": undefined, "test-prop2": undefined});
- let obj = data["test-prop1"];
-
- browser.test.assertEq("hello", obj.str, "string part correct");
- browser.test.assertEq(true, obj.bool, "bool part correct");
- browser.test.assertEq(null, obj.null, "null part correct");
- browser.test.assertEq(undefined, obj.undef, "undefined part correct");
- browser.test.assertEq(undefined, obj.func, "function part correct");
- browser.test.assertEq(undefined, obj.window, "window part correct");
- browser.test.assertEq("1970-01-01T00:00:00.000Z", obj.date, "date part correct");
- browser.test.assertEq("/regexp/", obj.regexp, "regexp part correct");
- browser.test.assertEq("object", typeof(obj.obj), "object part correct");
- browser.test.assertTrue(Array.isArray(obj.arr), "array part present");
- browser.test.assertEq(1, obj.arr[0], "arr[0] part correct");
- browser.test.assertEq(2, obj.arr[1], "arr[1] part correct");
- browser.test.assertEq(2, obj.arr.length, "arr.length part correct");
-
- obj = data["test-prop2"];
-
- browser.test.assertEq("[object Object]", {}.toString.call(obj), "function serialized as a plain object");
- browser.test.assertEq(0, Object.keys(obj).length, "function serialized as an empty object");
- } catch (e) {
- browser.test.fail(`Error: ${e} :: ${e.stack}`);
- browser.test.notifyFail("storage");
- }
- }
-
- browser.test.onMessage.addListener(msg => {
- let promise;
- if (msg === "test-local") {
- promise = runTests("local");
- } else if (msg === "test-sync") {
- promise = runTests("sync");
- }
- promise.then(() => browser.test.sendMessage("test-finished"));
- });
-
- browser.test.sendMessage("ready");
- }
-
- let extensionData = {
- background: `(${backgroundScript})(${checkGetImpl})`,
- manifest: {
- permissions: ["storage"],
- },
- };
-
- Preferences.set(STORAGE_SYNC_PREF, true);
-
- let extension = ExtensionTestUtils.loadExtension(extensionData);
- yield extension.startup();
- yield extension.awaitMessage("ready");
-
- extension.sendMessage("test-local");
- yield extension.awaitMessage("test-finished");
-
- extension.sendMessage("test-sync");
- yield extension.awaitMessage("test-finished");
-
- Preferences.reset(STORAGE_SYNC_PREF);
- yield extension.unload();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_topSites.js b/toolkit/components/extensions/test/xpcshell/test_ext_topSites.js
deleted file mode 100644
index eb3f552ed..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_ext_topSites.js
+++ /dev/null
@@ -1,85 +0,0 @@
-"use strict";
-
-Cu.import("resource://gre/modules/NewTabUtils.jsm");
-
-
-function TestProvider(getLinksFn) {
- this.getLinks = getLinksFn;
- this._observers = new Set();
-}
-
-TestProvider.prototype = {
- addObserver: function(observer) {
- this._observers.add(observer);
- },
- notifyLinkChanged: function(link, index = -1, deleted = false) {
- this._notifyObservers("onLinkChanged", link, index, deleted);
- },
- notifyManyLinksChanged: function() {
- this._notifyObservers("onManyLinksChanged");
- },
- _notifyObservers: function(observerMethodName, ...args) {
- args.unshift(this);
- for (let obs of this._observers) {
- if (obs[observerMethodName]) {
- obs[observerMethodName].apply(NewTabUtils.links, args);
- }
- }
- },
-};
-
-function makeLinks(links) {
- // Important: To avoid test failures due to clock jitter on Windows XP, call
- // Date.now() once here, not each time through the loop.
- let frecency = 0;
- let now = Date.now() * 1000;
- let places = [];
- links.map((link, i) => {
- places.push({
- url: link.url,
- title: link.title,
- lastVisitDate: now - i,
- frecency: frecency++,
- });
- });
- return places;
-}
-
-add_task(function* test_topSites() {
- let expect = [{url: "http://example.com/", title: "site#-1"},
- {url: "http://example0.com/", title: "site#0"},
- {url: "http://example1.com/", title: "site#1"},
- {url: "http://example2.com/", title: "site#2"},
- {url: "http://example3.com/", title: "site#3"}];
-
- let extension = ExtensionTestUtils.loadExtension({
- manifest: {
- "permissions": [
- "topSites",
- ],
- },
- background() {
- browser.topSites.get(result => {
- browser.test.sendMessage("done", result);
- });
- },
- });
-
-
- let expectedLinks = makeLinks(expect);
- let provider = new TestProvider(done => done(expectedLinks));
-
- NewTabUtils.initWithoutProviders();
- NewTabUtils.links.addProvider(provider);
-
- yield NewTabUtils.links.populateCache();
-
- yield extension.startup();
-
- let result = yield extension.awaitMessage("done");
- Assert.deepEqual(expect, result, "got topSites");
-
- yield extension.unload();
-
- NewTabUtils.links.removeProvider(provider);
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_getAPILevelForWindow.js b/toolkit/components/extensions/test/xpcshell/test_getAPILevelForWindow.js
deleted file mode 100644
index 68741a6cc..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_getAPILevelForWindow.js
+++ /dev/null
@@ -1,55 +0,0 @@
-"use strict";
-
-Cu.import("resource://gre/modules/ExtensionManagement.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-function createWindowWithAddonId(addonId) {
- let baseURI = Services.io.newURI("about:blank", null, null);
- let originAttributes = {addonId};
- let principal = Services.scriptSecurityManager
- .createCodebasePrincipal(baseURI, originAttributes);
- let chromeNav = Services.appShell.createWindowlessBrowser(true);
- let interfaceRequestor = chromeNav.QueryInterface(Ci.nsIInterfaceRequestor);
- let docShell = interfaceRequestor.getInterface(Ci.nsIDocShell);
- docShell.createAboutBlankContentViewer(principal);
-
- return {chromeNav, window: docShell.contentViewer.DOMDocument.defaultView};
-}
-
-add_task(function* test_eventpages() {
- const {getAPILevelForWindow, getAddonIdForWindow} = ExtensionManagement;
- const {NO_PRIVILEGES, FULL_PRIVILEGES} = ExtensionManagement.API_LEVELS;
- const FAKE_ADDON_ID = "fakeAddonId";
- const OTHER_ADDON_ID = "otherFakeAddonId";
- const EMPTY_ADDON_ID = "";
-
- let fakeAddonId = createWindowWithAddonId(FAKE_ADDON_ID);
- equal(getAddonIdForWindow(fakeAddonId.window), FAKE_ADDON_ID,
- "the window has the expected addonId");
-
- let apiLevel = getAPILevelForWindow(fakeAddonId.window, FAKE_ADDON_ID);
- equal(apiLevel, FULL_PRIVILEGES,
- "apiLevel for the window with the right addonId should be FULL_PRIVILEGES");
-
- apiLevel = getAPILevelForWindow(fakeAddonId.window, OTHER_ADDON_ID);
- equal(apiLevel, NO_PRIVILEGES,
- "apiLevel for the window with a different addonId should be NO_PRIVILEGES");
-
- fakeAddonId.chromeNav.close();
-
- // NOTE: check that window with an empty addon Id (which are window that are
- // not Extensions pages) always get no WebExtensions APIs.
- let emptyAddonId = createWindowWithAddonId(EMPTY_ADDON_ID);
- equal(getAddonIdForWindow(emptyAddonId.window), EMPTY_ADDON_ID,
- "the window has the expected addonId");
-
- apiLevel = getAPILevelForWindow(emptyAddonId.window, EMPTY_ADDON_ID);
- equal(apiLevel, NO_PRIVILEGES,
- "apiLevel for empty addonId should be NO_PRIVILEGES");
-
- apiLevel = getAPILevelForWindow(emptyAddonId.window, OTHER_ADDON_ID);
- equal(apiLevel, NO_PRIVILEGES,
- "apiLevel for an 'empty addonId' window should be always NO_PRIVILEGES");
-
- emptyAddonId.chromeNav.close();
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_locale_converter.js b/toolkit/components/extensions/test/xpcshell/test_locale_converter.js
deleted file mode 100644
index c8b1ee92b..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_locale_converter.js
+++ /dev/null
@@ -1,133 +0,0 @@
-"use strict";
-
-const convService = Cc["@mozilla.org/streamConverters;1"]
- .getService(Ci.nsIStreamConverterService);
-
-const UUID = "72b61ee3-aceb-476c-be1b-0822b036c9f1";
-const ADDON_ID = "test@web.extension";
-const URI = NetUtil.newURI(`moz-extension://${UUID}/file.css`);
-
-const FROM_TYPE = "application/vnd.mozilla.webext.unlocalized";
-const TO_TYPE = "text/css";
-
-
-function StringStream(string) {
- let stream = Cc["@mozilla.org/io/string-input-stream;1"]
- .createInstance(Ci.nsIStringInputStream);
-
- stream.data = string;
- return stream;
-}
-
-
-// Initialize the policy service with a stub localizer for our
-// add-on ID.
-add_task(function* init() {
- const aps = Cc["@mozilla.org/addons/policy-service;1"]
- .getService(Ci.nsIAddonPolicyService).wrappedJSObject;
-
- let oldCallback = aps.setExtensionURIToAddonIdCallback(uri => {
- if (uri.host == UUID) {
- return ADDON_ID;
- }
- });
-
- aps.setAddonLocalizeCallback(ADDON_ID, string => {
- return string.replace(/__MSG_(.*?)__/g, "<localized-$1>");
- });
-
- do_register_cleanup(() => {
- aps.setExtensionURIToAddonIdCallback(oldCallback);
- aps.setAddonLocalizeCallback(ADDON_ID, null);
- });
-});
-
-
-// Test that the synchronous converter works as expected with a
-// simple string.
-add_task(function* testSynchronousConvert() {
- let stream = StringStream("Foo __MSG_xxx__ bar __MSG_yyy__ baz");
-
- let resultStream = convService.convert(stream, FROM_TYPE, TO_TYPE, URI);
-
- let result = NetUtil.readInputStreamToString(resultStream, resultStream.available());
-
- equal(result, "Foo <localized-xxx> bar <localized-yyy> baz");
-});
-
-
-// Test that the asynchronous converter works as expected with input
-// split into multiple chunks, and a boundary in the middle of a
-// replacement token.
-add_task(function* testAsyncConvert() {
- let listener;
- let awaitResult = new Promise((resolve, reject) => {
- listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener]),
-
- onDataAvailable(request, context, inputStream, offset, count) {
- this.resultParts.push(NetUtil.readInputStreamToString(inputStream, count));
- },
-
- onStartRequest() {
- ok(!("resultParts" in this));
- this.resultParts = [];
- },
-
- onStopRequest(request, context, statusCode) {
- if (!Components.isSuccessCode(statusCode)) {
- reject(new Error(statusCode));
- }
-
- resolve(this.resultParts.join("\n"));
- },
- };
- });
-
- let parts = ["Foo __MSG_x", "xx__ bar __MSG_yyy__ baz"];
-
- let converter = convService.asyncConvertData(FROM_TYPE, TO_TYPE, listener, URI);
- converter.onStartRequest(null, null);
-
- for (let part of parts) {
- converter.onDataAvailable(null, null, StringStream(part), 0, part.length);
- }
-
- converter.onStopRequest(null, null, Cr.NS_OK);
-
-
- let result = yield awaitResult;
- equal(result, "Foo <localized-xxx> bar <localized-yyy> baz");
-});
-
-
-// Test that attempting to initialize a converter with the URI of a
-// nonexistent WebExtension fails.
-add_task(function* testInvalidUUID() {
- let uri = NetUtil.newURI("moz-extension://eb4f3be8-41c9-4970-aa6d-b84d1ecc02b2/file.css");
- let stream = StringStream("Foo __MSG_xxx__ bar __MSG_yyy__ baz");
-
- // Assert.throws raise a TypeError exception when the expected param
- // is an arrow function. (See Bug 1237961 for rationale)
- let expectInvalidContextException = function(e) {
- return e.result === Cr.NS_ERROR_INVALID_ARG && /Invalid context/.test(e);
- };
-
- Assert.throws(() => {
- convService.convert(stream, FROM_TYPE, TO_TYPE, uri);
- }, expectInvalidContextException);
-
- Assert.throws(() => {
- let listener = {QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener])};
-
- convService.asyncConvertData(FROM_TYPE, TO_TYPE, listener, uri);
- }, expectInvalidContextException);
-});
-
-
-// Test that an empty stream does not throw an NS_ERROR_ILLEGAL_VALUE.
-add_task(function* testEmptyStream() {
- let stream = StringStream("");
- let resultStream = convService.convert(stream, FROM_TYPE, TO_TYPE, URI);
- equal(resultStream.data, "");
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_locale_data.js b/toolkit/components/extensions/test/xpcshell/test_locale_data.js
deleted file mode 100644
index c3cd44e57..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_locale_data.js
+++ /dev/null
@@ -1,130 +0,0 @@
-"use strict";
-
-Cu.import("resource://gre/modules/Extension.jsm");
-
-/* globals ExtensionData */
-
-const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
-
-function* generateAddon(data) {
- let id = uuidGenerator.generateUUID().number;
-
- data = Object.assign({embedded: true}, data);
- data.manifest = Object.assign({applications: {gecko: {id}}}, data.manifest);
-
- let xpi = Extension.generateXPI(data);
- do_register_cleanup(() => {
- Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
- xpi.remove(false);
- });
-
- let fileURI = Services.io.newFileURI(xpi);
- let jarURI = NetUtil.newURI(`jar:${fileURI.spec}!/webextension/`);
-
- let extension = new ExtensionData(jarURI);
- yield extension.readManifest();
-
- return extension;
-}
-
-add_task(function* testMissingDefaultLocale() {
- let extension = yield generateAddon({
- "files": {
- "_locales/en_US/messages.json": {},
- },
- });
-
- equal(extension.errors.length, 0, "No errors reported");
-
- yield extension.initAllLocales();
-
- equal(extension.errors.length, 1, "One error reported");
-
- do_print(`Got error: ${extension.errors[0]}`);
-
- ok(extension.errors[0].includes('"default_locale" property is required'),
- "Got missing default_locale error");
-});
-
-
-add_task(function* testInvalidDefaultLocale() {
- let extension = yield generateAddon({
- "manifest": {
- "default_locale": "en",
- },
-
- "files": {
- "_locales/en_US/messages.json": {},
- },
- });
-
- equal(extension.errors.length, 1, "One error reported");
-
- do_print(`Got error: ${extension.errors[0]}`);
-
- ok(extension.errors[0].includes("Loading locale file _locales/en/messages.json"),
- "Got invalid default_locale error");
-
- yield extension.initAllLocales();
-
- equal(extension.errors.length, 2, "Two errors reported");
-
- do_print(`Got error: ${extension.errors[1]}`);
-
- ok(extension.errors[1].includes('"default_locale" property must correspond'),
- "Got invalid default_locale error");
-});
-
-
-add_task(function* testUnexpectedDefaultLocale() {
- let extension = yield generateAddon({
- "manifest": {
- "default_locale": "en_US",
- },
- });
-
- equal(extension.errors.length, 1, "One error reported");
-
- do_print(`Got error: ${extension.errors[0]}`);
-
- ok(extension.errors[0].includes("Loading locale file _locales/en-US/messages.json"),
- "Got invalid default_locale error");
-
- yield extension.initAllLocales();
-
- equal(extension.errors.length, 2, "One error reported");
-
- do_print(`Got error: ${extension.errors[1]}`);
-
- ok(extension.errors[1].includes('"default_locale" property must correspond'),
- "Got unexpected default_locale error");
-});
-
-
-add_task(function* testInvalidSyntax() {
- let extension = yield generateAddon({
- "manifest": {
- "default_locale": "en_US",
- },
-
- "files": {
- "_locales/en_US/messages.json": '{foo: {message: "bar", description: "baz"}}',
- },
- });
-
- equal(extension.errors.length, 1, "No errors reported");
-
- do_print(`Got error: ${extension.errors[0]}`);
-
- ok(extension.errors[0].includes("Loading locale file _locales\/en_US\/messages\.json: SyntaxError"),
- "Got syntax error");
-
- yield extension.initAllLocales();
-
- equal(extension.errors.length, 2, "One error reported");
-
- do_print(`Got error: ${extension.errors[1]}`);
-
- ok(extension.errors[1].includes("Loading locale file _locales\/en_US\/messages\.json: SyntaxError"),
- "Got syntax error");
-});
diff --git a/toolkit/components/extensions/test/xpcshell/test_native_messaging.js b/toolkit/components/extensions/test/xpcshell/test_native_messaging.js
deleted file mode 100644
index 1fcb7799e..000000000
--- a/toolkit/components/extensions/test/xpcshell/test_native_messaging.js
+++ /dev/null
@@ -1,302 +0,0 @@
-"use strict";
-
-/* global OS, HostManifestManager, NativeApp */
-Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/AsyncShutdown.jsm");
-Cu.import("resource://gre/modules/ExtensionCommon.jsm");
-Cu.import("resource://gre/modules/FileUtils.jsm");
-Cu.import("resource://gre/modules/Schemas.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-const {Subprocess, SubprocessImpl} = Cu.import("resource://gre/modules/Subprocess.jsm");
-Cu.import("resource://gre/modules/NativeMessaging.jsm");
-Cu.import("resource://gre/modules/osfile.jsm");
-
-let registry = null;
-if (AppConstants.platform == "win") {
- Cu.import("resource://testing-common/MockRegistry.jsm");
- registry = new MockRegistry();
- do_register_cleanup(() => {
- registry.shutdown();
- });
-}
-
-const REGPATH = "Software\\Mozilla\\NativeMessagingHosts";
-
-const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json";
-
-let dir = FileUtils.getDir("TmpD", ["NativeMessaging"]);
-dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
-
-let userDir = dir.clone();
-userDir.append("user");
-userDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
-
-let globalDir = dir.clone();
-globalDir.append("global");
-globalDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
-
-let dirProvider = {
- getFile(property) {
- if (property == "XREUserNativeMessaging") {
- return userDir.clone();
- } else if (property == "XRESysNativeMessaging") {
- return globalDir.clone();
- }
- return null;
- },
-};
-
-Services.dirsvc.registerProvider(dirProvider);
-
-do_register_cleanup(() => {
- Services.dirsvc.unregisterProvider(dirProvider);
- dir.remove(true);
-});
-
-function writeManifest(path, manifest) {
- if (typeof manifest != "string") {
- manifest = JSON.stringify(manifest);
- }
- return OS.File.writeAtomic(path, manifest);
-}
-
-let PYTHON;
-add_task(function* setup() {
- yield Schemas.load(BASE_SCHEMA);
-
- PYTHON = yield Subprocess.pathSearch("python2.7");
- if (PYTHON == null) {
- PYTHON = yield Subprocess.pathSearch("python");
- }
- notEqual(PYTHON, null, "Found a suitable python interpreter");
-});
-
-let global = this;
-
-// Test of HostManifestManager.lookupApplication() begin here...
-let context = {
- url: null,
- jsonStringify(...args) { return JSON.stringify(...args); },
- cloneScope: global,
- logError() {},
- preprocessors: {},
- callOnClose: () => {},
- forgetOnClose: () => {},
-};
-
-class MockContext extends ExtensionCommon.BaseContext {
- constructor(extensionId) {
- let fakeExtension = {id: extensionId};
- super("testEnv", fakeExtension);
- this.sandbox = Cu.Sandbox(global);
- }
-
- get cloneScope() {
- return global;
- }
-
- get principal() {
- return Cu.getObjectPrincipal(this.sandbox);
- }
-}
-
-let templateManifest = {
- name: "test",
- description: "this is only a test",
- path: "/bin/cat",
- type: "stdio",
- allowed_extensions: ["extension@tests.mozilla.org"],
-};
-
-add_task(function* test_nonexistent_manifest() {
- let result = yield HostManifestManager.lookupApplication("test", context);
- equal(result, null, "lookupApplication returns null for non-existent application");
-});
-
-const USER_TEST_JSON = OS.Path.join(userDir.path, "test.json");
-
-add_task(function* test_good_manifest() {
- yield writeManifest(USER_TEST_JSON, templateManifest);
- if (registry) {
- registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
- `${REGPATH}\\test`, "", USER_TEST_JSON);
- }
-
- let result = yield HostManifestManager.lookupApplication("test", context);
- notEqual(result, null, "lookupApplication finds a good manifest");
- equal(result.path, USER_TEST_JSON, "lookupApplication returns the correct path");
- deepEqual(result.manifest, templateManifest, "lookupApplication returns the manifest contents");
-});
-
-add_task(function* test_invalid_json() {
- yield writeManifest(USER_TEST_JSON, "this is not valid json");
- let result = yield HostManifestManager.lookupApplication("test", context);
- equal(result, null, "lookupApplication ignores bad json");
-});
-
-add_task(function* test_invalid_name() {
- let manifest = Object.assign({}, templateManifest);
- manifest.name = "../test";
- yield writeManifest(USER_TEST_JSON, manifest);
- let result = yield HostManifestManager.lookupApplication("test", context);
- equal(result, null, "lookupApplication ignores an invalid name");
-});
-
-add_task(function* test_name_mismatch() {
- let manifest = Object.assign({}, templateManifest);
- manifest.name = "not test";
- yield writeManifest(USER_TEST_JSON, manifest);
- let result = yield HostManifestManager.lookupApplication("test", context);
- let what = (AppConstants.platform == "win") ? "registry key" : "json filename";
- equal(result, null, `lookupApplication ignores mistmatch between ${what} and name property`);
-});
-
-add_task(function* test_missing_props() {
- const PROPS = [
- "name",
- "description",
- "path",
- "type",
- "allowed_extensions",
- ];
- for (let prop of PROPS) {
- let manifest = Object.assign({}, templateManifest);
- delete manifest[prop];
-
- yield writeManifest(USER_TEST_JSON, manifest);
- let result = yield HostManifestManager.lookupApplication("test", context);
- equal(result, null, `lookupApplication ignores missing ${prop}`);
- }
-});
-
-add_task(function* test_invalid_type() {
- let manifest = Object.assign({}, templateManifest);
- manifest.type = "bogus";
- yield writeManifest(USER_TEST_JSON, manifest);
- let result = yield HostManifestManager.lookupApplication("test", context);
- equal(result, null, "lookupApplication ignores invalid type");
-});
-
-add_task(function* test_no_allowed_extensions() {
- let manifest = Object.assign({}, templateManifest);
- manifest.allowed_extensions = [];
- yield writeManifest(USER_TEST_JSON, manifest);
- let result = yield HostManifestManager.lookupApplication("test", context);
- equal(result, null, "lookupApplication ignores manifest with no allowed_extensions");
-});
-
-const GLOBAL_TEST_JSON = OS.Path.join(globalDir.path, "test.json");
-let globalManifest = Object.assign({}, templateManifest);
-globalManifest.description = "This manifest is from the systemwide directory";
-
-add_task(function* good_manifest_system_dir() {
- yield OS.File.remove(USER_TEST_JSON);
- yield writeManifest(GLOBAL_TEST_JSON, globalManifest);
- if (registry) {
- registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
- `${REGPATH}\\test`, "", null);
- registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
- `${REGPATH}\\test`, "", GLOBAL_TEST_JSON);
- }
-
- let where = (AppConstants.platform == "win") ? "registry location" : "directory";
- let result = yield HostManifestManager.lookupApplication("test", context);
- notEqual(result, null, `lookupApplication finds a manifest in the system-wide ${where}`);
- equal(result.path, GLOBAL_TEST_JSON, `lookupApplication returns path in the system-wide ${where}`);
- deepEqual(result.manifest, globalManifest, `lookupApplication returns manifest contents from the system-wide ${where}`);
-});
-
-add_task(function* test_user_dir_precedence() {
- yield writeManifest(USER_TEST_JSON, templateManifest);
- if (registry) {
- registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
- `${REGPATH}\\test`, "", USER_TEST_JSON);
- }
- // global test.json and LOCAL_MACHINE registry key on windows are
- // still present from the previous test
-
- let result = yield HostManifestManager.lookupApplication("test", context);
- notEqual(result, null, "lookupApplication finds a manifest when entries exist in both user-specific and system-wide locations");
- equal(result.path, USER_TEST_JSON, "lookupApplication returns the user-specific path when user-specific and system-wide entries both exist");
- deepEqual(result.manifest, templateManifest, "lookupApplication returns user-specific manifest contents with user-specific and system-wide entries both exist");
-});
-
-// Test shutdown handling in NativeApp
-add_task(function* test_native_app_shutdown() {
- const SCRIPT = String.raw`
-import signal
-import struct
-import sys
-
-signal.signal(signal.SIGTERM, signal.SIG_IGN)
-
-while True:
- rawlen = sys.stdin.read(4)
- if len(rawlen) == 0:
- signal.pause()
- msglen = struct.unpack('@I', rawlen)[0]
- msg = sys.stdin.read(msglen)
-
- sys.stdout.write(struct.pack('@I', msglen))
- sys.stdout.write(msg)
- `;
-
- let scriptPath = OS.Path.join(userDir.path, "wontdie.py");
- let manifestPath = OS.Path.join(userDir.path, "wontdie.json");
-
- const ID = "native@tests.mozilla.org";
- let manifest = {
- name: "wontdie",
- description: "test async shutdown of native apps",
- type: "stdio",
- allowed_extensions: [ID],
- };
-
- if (AppConstants.platform == "win") {
- yield OS.File.writeAtomic(scriptPath, SCRIPT);
-
- let batPath = OS.Path.join(userDir.path, "wontdie.bat");
- let batBody = `@ECHO OFF\n${PYTHON} -u "${scriptPath}" %*\n`;
- yield OS.File.writeAtomic(batPath, batBody);
- yield OS.File.setPermissions(batPath, {unixMode: 0o755});
-
- manifest.path = batPath;
- yield writeManifest(manifestPath, manifest);
-
- registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
- `${REGPATH}\\wontdie`, "", manifestPath);
- } else {
- yield OS.File.writeAtomic(scriptPath, `#!${PYTHON} -u\n${SCRIPT}`);
- yield OS.File.setPermissions(scriptPath, {unixMode: 0o755});
- manifest.path = scriptPath;
- yield writeManifest(manifestPath, manifest);
- }
-
- let mockContext = new MockContext(ID);
- let app = new NativeApp(mockContext, "wontdie");
-
- // send a message and wait for the reply to make sure the app is running
- let MSG = "test";
- let recvPromise = new Promise(resolve => {
- let listener = (what, msg) => {
- equal(msg, MSG, "Received test message");
- app.off("message", listener);
- resolve();
- };
- app.on("message", listener);
- });
-
- let buffer = NativeApp.encodeMessage(mockContext, MSG);
- app.send(buffer);
- yield recvPromise;
-
- app._cleanup();
-
- do_print("waiting for async shutdown");
- Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
- AsyncShutdown.profileBeforeChange._trigger();
- Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
-
- let procs = yield SubprocessImpl.Process.getWorker().call("getProcesses", []);
- equal(procs.size, 0, "native process exited");
-});
diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini
deleted file mode 100644
index d2c6fd5d0..000000000
--- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini
+++ /dev/null
@@ -1,69 +0,0 @@
-[DEFAULT]
-head = head.js
-tail =
-firefox-appdir = browser
-skip-if = appname == "thunderbird"
-support-files =
- data/** head_sync.js
-tags = webextensions
-
-[test_csp_custom_policies.js]
-[test_csp_validator.js]
-[test_ext_alarms.js]
-[test_ext_alarms_does_not_fire.js]
-[test_ext_alarms_periodic.js]
-[test_ext_alarms_replaces.js]
-[test_ext_apimanager.js]
-[test_ext_api_permissions.js]
-[test_ext_background_generated_load_events.js]
-[test_ext_background_generated_reload.js]
-[test_ext_background_global_history.js]
-skip-if = os == "android" # Android does not use Places for history.
-[test_ext_background_private_browsing.js]
-[test_ext_background_runtime_connect_params.js]
-[test_ext_background_sub_windows.js]
-[test_ext_background_window_properties.js]
-skip-if = os == "android"
-[test_ext_contexts.js]
-[test_ext_downloads.js]
-[test_ext_downloads_download.js]
-skip-if = os == "android"
-[test_ext_downloads_misc.js]
-skip-if = os == "android"
-[test_ext_downloads_search.js]
-skip-if = os == "android"
-[test_ext_experiments.js]
-skip-if = release_or_beta
-[test_ext_extension.js]
-[test_ext_idle.js]
-[test_ext_json_parser.js]
-[test_ext_localStorage.js]
-[test_ext_management.js]
-[test_ext_management_uninstall_self.js]
-[test_ext_manifest_content_security_policy.js]
-[test_ext_manifest_incognito.js]
-[test_ext_manifest_minimum_chrome_version.js]
-[test_ext_onmessage_removelistener.js]
-[test_ext_runtime_connect_no_receiver.js]
-[test_ext_runtime_getBrowserInfo.js]
-[test_ext_runtime_getPlatformInfo.js]
-[test_ext_runtime_onInstalled_and_onStartup.js]
-[test_ext_runtime_sendMessage.js]
-[test_ext_runtime_sendMessage_errors.js]
-[test_ext_runtime_sendMessage_no_receiver.js]
-[test_ext_runtime_sendMessage_self.js]
-[test_ext_schemas.js]
-[test_ext_schemas_api_injection.js]
-[test_ext_schemas_async.js]
-[test_ext_schemas_allowed_contexts.js]
-[test_ext_simple.js]
-[test_ext_storage.js]
-[test_ext_topSites.js]
-skip-if = os == "android"
-[test_getAPILevelForWindow.js]
-[test_ext_legacy_extension_context.js]
-[test_ext_legacy_extension_embedding.js]
-[test_locale_converter.js]
-[test_locale_data.js]
-[test_native_messaging.js]
-skip-if = os == "android"