mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-11 13:48:23 +02:00
***
Bug 1514594: Part 3a - Change ChromeUtils.import to return an exports object; not pollute global. r=mccr8
This changes the behavior of ChromeUtils.import() to return an exports object,
rather than a module global, in all cases except when `null` is passed as a
second argument, and changes the default behavior not to pollute the global
scope with the module's exports. Thus, the following code written for the old
model:
ChromeUtils.import("resource://gre/modules/Services.jsm");
is approximately the same as the following, in the new model:
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
Since the two behaviors are mutually incompatible, this patch will land with a
scripted rewrite to update all existing callers to use the new model rather
than the old.
***
Bug 1514594: Part 3b - Mass rewrite all JS code to use the new ChromeUtils.import API. rs=Gijs
This was done using the followng script:
https://bitbucket.org/kmaglione/m-c-rewrites/src/tip/processors/cu-import-exports.jsm
***
Bug 1514594: Part 3c - Update ESLint plugin for ChromeUtils.import API changes. r=Standard8
Differential Revision: https://phabricator.services.mozilla.com/D16747
***
Bug 1514594: Part 3d - Remove/fix hundreds of duplicate imports from sync tests. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16748
***
Bug 1514594: Part 3e - Remove no-op ChromeUtils.import() calls. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16749
***
Bug 1514594: Part 3f.1 - Cleanup various test corner cases after mass rewrite. r=Gijs
***
Bug 1514594: Part 3f.2 - Cleanup various non-test corner cases after mass rewrite. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16750
--HG--
extra : rebase_source : 359574ee3064c90f33bf36c2ebe3159a24cc8895
extra : histedit_source : b93c8f42808b1599f9122d7842d2c0b3e656a594%2C64a3a4e3359dc889e2ab2b49461bab9e27fc10a7
313 lines
11 KiB
JavaScript
313 lines
11 KiB
JavaScript
"use strict";
|
|
|
|
const {AsyncShutdown} = ChromeUtils.import("resource://gre/modules/AsyncShutdown.jsm");
|
|
const {ExtensionCommon} = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
|
|
const {NativeManifests} = ChromeUtils.import("resource://gre/modules/NativeManifests.jsm");
|
|
const {FileUtils} = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
|
const {Schemas} = ChromeUtils.import("resource://gre/modules/Schemas.jsm");
|
|
const {Subprocess, SubprocessImpl} = ChromeUtils.import("resource://gre/modules/Subprocess.jsm", null);
|
|
const {NativeApp} = ChromeUtils.import("resource://gre/modules/NativeMessaging.jsm");
|
|
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
|
|
|
let registry = null;
|
|
if (AppConstants.platform == "win") {
|
|
var {MockRegistry} = ChromeUtils.import("resource://testing-common/MockRegistry.jsm");
|
|
registry = new MockRegistry();
|
|
registerCleanupFunction(() => {
|
|
registry.shutdown();
|
|
});
|
|
}
|
|
|
|
const REGPATH = "Software\\Mozilla\\NativeMessagingHosts";
|
|
|
|
const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json";
|
|
|
|
const TYPE_SLUG = AppConstants.platform === "linux" ? "native-messaging-hosts" : "NativeMessagingHosts";
|
|
|
|
let dir = FileUtils.getDir("TmpD", ["NativeManifests"]);
|
|
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);
|
|
|
|
OS.File.makeDir(OS.Path.join(userDir.path, TYPE_SLUG));
|
|
OS.File.makeDir(OS.Path.join(globalDir.path, TYPE_SLUG));
|
|
|
|
let dirProvider = {
|
|
getFile(property) {
|
|
if (property == "XREUserNativeManifests") {
|
|
return userDir.clone();
|
|
} else if (property == "XRESysNativeManifests") {
|
|
return globalDir.clone();
|
|
}
|
|
return null;
|
|
},
|
|
};
|
|
|
|
Services.dirsvc.registerProvider(dirProvider);
|
|
|
|
registerCleanupFunction(() => {
|
|
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(async function setup() {
|
|
await Schemas.load(BASE_SCHEMA);
|
|
|
|
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
|
try {
|
|
PYTHON = await Subprocess.pathSearch(env.get("PYTHON"));
|
|
} catch (e) {
|
|
notEqual(PYTHON, null, `Can't find a suitable python interpreter ${e.message}`);
|
|
}
|
|
});
|
|
|
|
let global = this;
|
|
|
|
// Test of NativeManifests.lookupApplication() begin here...
|
|
let context = {
|
|
extension: {
|
|
id: "extension@tests.mozilla.org",
|
|
},
|
|
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"],
|
|
};
|
|
|
|
function lookupApplication(app, ctx) {
|
|
return NativeManifests.lookupManifest("stdio", app, ctx);
|
|
}
|
|
|
|
add_task(async function test_nonexistent_manifest() {
|
|
let result = await lookupApplication("test", context);
|
|
equal(result, null, "lookupApplication returns null for non-existent application");
|
|
});
|
|
|
|
const USER_TEST_JSON = OS.Path.join(userDir.path, TYPE_SLUG, "test.json");
|
|
|
|
add_task(async function test_good_manifest() {
|
|
await writeManifest(USER_TEST_JSON, templateManifest);
|
|
if (registry) {
|
|
registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
|
`${REGPATH}\\test`, "", USER_TEST_JSON);
|
|
}
|
|
|
|
let result = await 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(async function test_invalid_json() {
|
|
await writeManifest(USER_TEST_JSON, "this is not valid json");
|
|
let result = await lookupApplication("test", context);
|
|
equal(result, null, "lookupApplication ignores bad json");
|
|
});
|
|
|
|
add_task(async function test_invalid_name() {
|
|
let manifest = Object.assign({}, templateManifest);
|
|
manifest.name = "../test";
|
|
await writeManifest(USER_TEST_JSON, manifest);
|
|
let result = await lookupApplication("test", context);
|
|
equal(result, null, "lookupApplication ignores an invalid name");
|
|
});
|
|
|
|
add_task(async function test_name_mismatch() {
|
|
let manifest = Object.assign({}, templateManifest);
|
|
manifest.name = "not test";
|
|
await writeManifest(USER_TEST_JSON, manifest);
|
|
let result = await 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(async 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];
|
|
|
|
await writeManifest(USER_TEST_JSON, manifest);
|
|
let result = await lookupApplication("test", context);
|
|
equal(result, null, `lookupApplication ignores missing ${prop}`);
|
|
}
|
|
});
|
|
|
|
add_task(async function test_invalid_type() {
|
|
let manifest = Object.assign({}, templateManifest);
|
|
manifest.type = "bogus";
|
|
await writeManifest(USER_TEST_JSON, manifest);
|
|
let result = await lookupApplication("test", context);
|
|
equal(result, null, "lookupApplication ignores invalid type");
|
|
});
|
|
|
|
add_task(async function test_no_allowed_extensions() {
|
|
let manifest = Object.assign({}, templateManifest);
|
|
manifest.allowed_extensions = [];
|
|
await writeManifest(USER_TEST_JSON, manifest);
|
|
let result = await lookupApplication("test", context);
|
|
equal(result, null, "lookupApplication ignores manifest with no allowed_extensions");
|
|
});
|
|
|
|
const GLOBAL_TEST_JSON = OS.Path.join(globalDir.path, TYPE_SLUG, "test.json");
|
|
let globalManifest = Object.assign({}, templateManifest);
|
|
globalManifest.description = "This manifest is from the systemwide directory";
|
|
|
|
add_task(async function good_manifest_system_dir() {
|
|
await OS.File.remove(USER_TEST_JSON);
|
|
await 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 = await 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(async function test_user_dir_precedence() {
|
|
await 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 = await 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(async 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, TYPE_SLUG, "wontdie.py");
|
|
let manifestPath = OS.Path.join(userDir.path, TYPE_SLUG, "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") {
|
|
await OS.File.writeAtomic(scriptPath, SCRIPT);
|
|
|
|
let batPath = OS.Path.join(userDir.path, TYPE_SLUG, "wontdie.bat");
|
|
let batBody = `@ECHO OFF\n${PYTHON} -u "${scriptPath}" %*\n`;
|
|
await OS.File.writeAtomic(batPath, batBody);
|
|
await OS.File.setPermissions(batPath, {unixMode: 0o755});
|
|
|
|
manifest.path = batPath;
|
|
await writeManifest(manifestPath, manifest);
|
|
|
|
registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
|
`${REGPATH}\\wontdie`, "", manifestPath);
|
|
} else {
|
|
await OS.File.writeAtomic(scriptPath, `#!${PYTHON} -u\n${SCRIPT}`);
|
|
await OS.File.setPermissions(scriptPath, {unixMode: 0o755});
|
|
manifest.path = scriptPath;
|
|
await 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(new StructuredCloneHolder(buffer));
|
|
await recvPromise;
|
|
|
|
app._cleanup();
|
|
|
|
info("waiting for async shutdown");
|
|
Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
|
|
AsyncShutdown.profileBeforeChange._trigger();
|
|
Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
|
|
|
|
let procs = await SubprocessImpl.Process.getWorker().call("getProcesses", []);
|
|
equal(procs.size, 0, "native process exited");
|
|
});
|