summaryrefslogtreecommitdiffstats
path: root/toolkit/components/backgroundtasks/BackgroundTasksTestUtils.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/backgroundtasks/BackgroundTasksTestUtils.sys.mjs')
-rw-r--r--toolkit/components/backgroundtasks/BackgroundTasksTestUtils.sys.mjs137
1 files changed, 137 insertions, 0 deletions
diff --git a/toolkit/components/backgroundtasks/BackgroundTasksTestUtils.sys.mjs b/toolkit/components/backgroundtasks/BackgroundTasksTestUtils.sys.mjs
new file mode 100644
index 0000000000..72a9d3e4f3
--- /dev/null
+++ b/toolkit/components/backgroundtasks/BackgroundTasksTestUtils.sys.mjs
@@ -0,0 +1,137 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
+
+import { Subprocess } from "resource://gre/modules/Subprocess.sys.mjs";
+
+function getFirefoxExecutableFilename() {
+ if (AppConstants.platform === "win") {
+ return AppConstants.MOZ_APP_NAME + ".exe";
+ }
+ if (AppConstants.platform == "linux") {
+ return AppConstants.MOZ_APP_NAME + "-bin";
+ }
+ return AppConstants.MOZ_APP_NAME;
+}
+
+// Returns a nsIFile to the firefox.exe (really, application) executable file.
+function getFirefoxExecutableFile() {
+ let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ file = Services.dirsvc.get("GreBinD", Ci.nsIFile);
+
+ file.append(getFirefoxExecutableFilename());
+ return file;
+}
+
+export var BackgroundTasksTestUtils = {
+ init(scope) {
+ this.testScope = scope;
+ },
+
+ async do_backgroundtask(
+ task,
+ options = { extraArgs: [], extraEnv: {}, onStdoutLine: null }
+ ) {
+ options = Object.assign({}, options);
+ options.extraArgs = options.extraArgs || [];
+ options.extraEnv = options.extraEnv || {};
+
+ let command = getFirefoxExecutableFile().path;
+ let args = ["--backgroundtask", task];
+ args.push(...options.extraArgs);
+
+ // Ensure `resource://testing-common` gets mapped.
+ let protocolHandler = Services.io
+ .getProtocolHandler("resource")
+ .QueryInterface(Ci.nsIResProtocolHandler);
+
+ let uri = protocolHandler.getSubstitution("testing-common");
+ const { Assert } = this.testScope;
+ Assert.ok(!!uri, "resource://testing-common is not substituted");
+
+ // The equivalent of _TESTING_MODULES_DIR in xpcshell.
+ options.extraEnv.XPCSHELL_TESTING_MODULES_URI = uri.spec;
+
+ // Now we can actually invoke the process.
+ console.info(`launching background task`, {
+ command,
+ args,
+ extraEnv: options.extraEnv,
+ });
+ let { proc, readPromise } = await Subprocess.call({
+ command,
+ arguments: args,
+ environment: options.extraEnv,
+ environmentAppend: true,
+ stderr: "stdout",
+ }).then(p => {
+ p.stdin.close().catch(() => {
+ // It's possible that the process exists before we close stdin.
+ // In that case, we should ignore the errors.
+ });
+ const dumpPipe = async pipe => {
+ // We must assemble all of the string fragments from stdout.
+ let leftover = "";
+ let data = await pipe.readString();
+ while (data) {
+ data = leftover + data;
+ // When the string is empty and the separator is not empty,
+ // split() returns an array containing one empty string,
+ // rather than an empty array, i.e., we always have
+ // `lines.length > 0`.
+ let lines = data.split(/\r\n|\r|\n/);
+ for (let line of lines.slice(0, -1)) {
+ dump(`${p.pid}> ${line}\n`);
+ if (options.onStdoutLine) {
+ options.onStdoutLine(line, p);
+ }
+ }
+ leftover = lines[lines.length - 1];
+ data = await pipe.readString();
+ }
+
+ if (leftover.length) {
+ dump(`${p.pid}> ${leftover}\n`);
+ if (options.onStdoutLine) {
+ options.onStdoutLine(leftover, p);
+ }
+ }
+ };
+ let readPromise = dumpPipe(p.stdout);
+
+ return { proc: p, readPromise };
+ });
+
+ let { exitCode } = await proc.wait();
+ try {
+ // Read from the output pipe.
+ await readPromise;
+ } catch (e) {
+ if (e.message !== "File closed") {
+ throw e;
+ }
+ }
+
+ return exitCode;
+ },
+
+ // Setup that allows to use the profile service in xpcshell tests,
+ // lifted from `toolkit/profile/xpcshell/head.js`.
+ setupProfileService() {
+ let gProfD = this.testScope.do_get_profile();
+ let gDataHome = gProfD.clone();
+ gDataHome.append("data");
+ gDataHome.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
+ let gDataHomeLocal = gProfD.clone();
+ gDataHomeLocal.append("local");
+ gDataHomeLocal.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
+
+ let xreDirProvider = Cc["@mozilla.org/xre/directory-provider;1"].getService(
+ Ci.nsIXREDirProvider
+ );
+ xreDirProvider.setUserDataDirectory(gDataHome, false);
+ xreDirProvider.setUserDataDirectory(gDataHomeLocal, true);
+ },
+};