summaryrefslogtreecommitdiffstats
path: root/toolkit/components/taskscheduler/tests/xpcshell/test_TaskSchedulerWinImpl.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/taskscheduler/tests/xpcshell/test_TaskSchedulerWinImpl.js')
-rw-r--r--toolkit/components/taskscheduler/tests/xpcshell/test_TaskSchedulerWinImpl.js291
1 files changed, 291 insertions, 0 deletions
diff --git a/toolkit/components/taskscheduler/tests/xpcshell/test_TaskSchedulerWinImpl.js b/toolkit/components/taskscheduler/tests/xpcshell/test_TaskSchedulerWinImpl.js
new file mode 100644
index 0000000000..ed1be3e49b
--- /dev/null
+++ b/toolkit/components/taskscheduler/tests/xpcshell/test_TaskSchedulerWinImpl.js
@@ -0,0 +1,291 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+"use strict";
+
+// Unit tests for Windows scheduled task generation.
+
+const { updateAppInfo } = ChromeUtils.importESModule(
+ "resource://testing-common/AppInfo.sys.mjs"
+);
+updateAppInfo();
+
+const { TaskScheduler } = ChromeUtils.importESModule(
+ "resource://gre/modules/TaskScheduler.sys.mjs"
+);
+
+const { WinImpl } = ChromeUtils.importESModule(
+ "resource://gre/modules/TaskSchedulerWinImpl.sys.mjs"
+);
+
+const WinSvc = Cc["@mozilla.org/win-task-scheduler-service;1"].getService(
+ Ci.nsIWinTaskSchedulerService
+);
+
+const uuidGenerator = Services.uuid;
+
+function randomName() {
+ return (
+ "moz-taskschd-test-" + uuidGenerator.generateUUID().toString().slice(1, -1)
+ );
+}
+
+const gFolderName = randomName();
+
+// Override task folder name, to prevent colliding with other tests.
+WinImpl._taskFolderName = function () {
+ return gFolderName;
+};
+WinImpl._taskFolderNameParts = function () {
+ return {
+ parentName: "\\",
+ subName: gFolderName,
+ };
+};
+
+registerCleanupFunction(async () => {
+ await TaskScheduler.deleteAllTasks();
+});
+
+add_task(async function test_create() {
+ const taskName = "test-task-1";
+ const rawTaskName = WinImpl._formatTaskName(taskName);
+ const folderName = WinImpl._taskFolderName();
+ const exePath = "C:\\Program Files\\XYZ\\123.exe";
+ const workingDir = "C:\\Program Files\\XYZ";
+ const argsIn = [
+ "x.txt",
+ "c:\\x.txt",
+ 'C:\\"HELLO WORLD".txt',
+ "only space.txt",
+ ];
+ const expectedArgsOutStr = [
+ "x.txt",
+ "c:\\x.txt",
+ '"C:\\\\\\"HELLO WORLD\\".txt"',
+ '"only space.txt"',
+ ].join(" ");
+ const description = "Entities: < &. Non-ASCII: abc😀def.";
+ const intervalSecsIn = 2 * 60 * 60; // 2 hours
+ const expectedIntervalOutWin10 = "PT2H"; // Windows 10 regroups by hours and minutes
+ const expectedIntervalOutWin7 = `PT${intervalSecsIn}S`; // Windows 7 doesn't regroup
+
+ await TaskScheduler.registerTask(taskName, exePath, intervalSecsIn, {
+ disabled: true,
+ args: argsIn,
+ description,
+ workingDirectory: workingDir,
+ });
+
+ // Read back the task
+ const readBackXML = WinSvc.getTaskXML(folderName, rawTaskName);
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(readBackXML, "text/xml");
+ Assert.equal(doc.documentElement.tagName, "Task");
+
+ // Check for the values set above
+ Assert.equal(doc.querySelector("Actions Exec Command").textContent, exePath);
+ Assert.equal(
+ doc.querySelector("Actions Exec WorkingDirectory").textContent,
+ workingDir
+ );
+ Assert.equal(
+ doc.querySelector("Actions Exec Arguments").textContent,
+ expectedArgsOutStr
+ );
+ Assert.equal(
+ doc.querySelector("RegistrationInfo Description").textContent,
+ description
+ );
+ Assert.equal(
+ doc.querySelector("RegistrationInfo Author").textContent,
+ Services.appinfo.vendor
+ );
+
+ Assert.equal(doc.querySelector("Settings Enabled").textContent, "false");
+
+ // Note: It's a little too tricky to check for a specific StartBoundary value reliably here, given
+ // that it gets set relative to Date.now(), so I'm skipping that.
+ const intervalOut = doc.querySelector(
+ "Triggers TimeTrigger Repetition Interval"
+ ).textContent;
+ Assert.ok(
+ intervalOut == expectedIntervalOutWin7 ||
+ intervalOut == expectedIntervalOutWin10
+ );
+
+ // Validate the XML
+ WinSvc.validateTaskDefinition(readBackXML);
+
+ // Update
+ const updatedExePath = "C:\\Program Files (x86)\\ABC\\foo.exe";
+ const updatedIntervalSecsIn = 3 * 60 * 60; // 3 hours
+ const expectedUpdatedIntervalOutWin10 = "PT3H";
+ const expectedUpdatedIntervalOutWin7 = `PT${updatedIntervalSecsIn}S`;
+
+ await TaskScheduler.registerTask(
+ taskName,
+ updatedExePath,
+ updatedIntervalSecsIn,
+ {
+ disabled: true,
+ args: argsIn,
+ description,
+ workingDirectory: workingDir,
+ }
+ );
+
+ // Read back the updated task
+ const readBackUpdatedXML = WinSvc.getTaskXML(folderName, rawTaskName);
+ const updatedDoc = parser.parseFromString(readBackUpdatedXML, "text/xml");
+ Assert.equal(updatedDoc.documentElement.tagName, "Task");
+
+ // Check for updated values
+ Assert.equal(
+ updatedDoc.querySelector("Actions Exec Command").textContent,
+ updatedExePath
+ );
+
+ Assert.notEqual(
+ doc.querySelector("Triggers TimeTrigger StartBoundary").textContent,
+ updatedDoc.querySelector("Triggers TimeTrigger StartBoundary").textContent
+ );
+ const updatedIntervalOut = updatedDoc.querySelector(
+ "Triggers TimeTrigger Repetition Interval"
+ ).textContent;
+ Assert.ok(
+ updatedIntervalOut == expectedUpdatedIntervalOutWin7 ||
+ updatedIntervalOut == expectedUpdatedIntervalOutWin10
+ );
+
+ // Check that the folder really was there
+ {
+ const { parentName, subName } = WinImpl._taskFolderNameParts();
+ let threw;
+ try {
+ WinSvc.deleteFolder(parentName, subName);
+ } catch (ex) {
+ threw = ex;
+ }
+ Assert.equal(threw.result, Cr.NS_ERROR_FILE_DIR_NOT_EMPTY);
+ }
+
+ // Delete
+ await TaskScheduler.deleteAllTasks();
+
+ // Check that the folder is gone
+ {
+ const { parentName, subName } = WinImpl._taskFolderNameParts();
+ let threw;
+ try {
+ WinSvc.deleteFolder(parentName, subName);
+ } catch (ex) {
+ threw = ex;
+ }
+ Assert.equal(threw.result, Cr.NS_ERROR_FILE_NOT_FOUND);
+ }
+
+ // Format and validate the XML with the task not disabled
+ const enabledXML = WinImpl._formatTaskDefinitionXML(exePath, intervalSecsIn, {
+ args: argsIn,
+ description,
+ workingDirectory: workingDir,
+ });
+ Assert.equal(WinSvc.validateTaskDefinition(enabledXML), 0 /* S_OK */);
+
+ // Format and validate with no options
+ const basicXML = WinImpl._formatTaskDefinitionXML(
+ "foo",
+ TaskScheduler.MIN_INTERVAL_SECONDS
+ );
+ Assert.equal(WinSvc.validateTaskDefinition(basicXML), 0 /* S_OK */);
+});
+
+add_task(async function test_migrate() {
+ // Create task name with nameVersion1
+ const taskName = "test-task-1";
+ const rawTaskNameV1 = WinImpl._formatTaskName(taskName, { nameVersion: 1 });
+ const rawTaskNameV2 = WinImpl._formatTaskName(taskName, { nameVersion: 2 });
+ const folderName = WinImpl._taskFolderName();
+ const exePath = "C:\\Program Files\\XYZ\\123.exe";
+ const workingDir = "C:\\Program Files\\XYZ";
+ const argsIn = [
+ "x.txt",
+ "c:\\x.txt",
+ 'C:\\"HELLO WORLD".txt',
+ "only space.txt",
+ ];
+ const expectedArgsOutStr = [
+ "x.txt",
+ "c:\\x.txt",
+ '"C:\\\\\\"HELLO WORLD\\".txt"',
+ '"only space.txt"',
+ ].join(" ");
+ const description = "Entities: < &. Non-ASCII: abc😀def.";
+ const intervalSecsIn = 2 * 60 * 60; // 2 hours
+ const expectedIntervalOut = "PT2H"; // 2 hours
+
+ const queries = [
+ ["Actions Exec Command", exePath],
+ ["Actions Exec WorkingDirectory", workingDir],
+ ["Actions Exec Arguments", expectedArgsOutStr],
+ ["RegistrationInfo Description", description],
+ ["RegistrationInfo Author", Services.appinfo.vendor],
+ ["Settings Enabled", "false"],
+ ["Triggers TimeTrigger Repetition Interval", expectedIntervalOut],
+ ];
+
+ await TaskScheduler.registerTask(taskName, exePath, intervalSecsIn, {
+ disabled: true,
+ args: argsIn,
+ description,
+ workingDirectory: workingDir,
+ nameVersion: 1,
+ });
+
+ ok(
+ WinImpl.taskExists(taskName, { nameVersion: 1 }),
+ "Task exists with nameVersion1"
+ );
+ const originalTaskXML = WinSvc.getTaskXML(folderName, rawTaskNameV1);
+ const parser = new DOMParser();
+ const docV1 = parser.parseFromString(originalTaskXML, "text/xml");
+
+ Assert.equal(docV1.documentElement.tagName, "Task");
+
+ // Check for the values set above
+ for (let [sel, expected] of queries) {
+ Assert.equal(
+ docV1.querySelector(sel).textContent,
+ expected,
+ `Task V1 ${sel} had expected textContent`
+ );
+ }
+
+ // Update task name format to nameVersion2
+ WinImpl._updateTaskNameFormat(taskName);
+ ok(
+ WinImpl.taskExists(taskName, { nameVersion: 2 }),
+ "Task exists with nameVersion2"
+ );
+ ok(
+ !WinImpl.taskExists(taskName, { nameVersion: 1 }),
+ "Task with nameVersion1 successfully deleted"
+ );
+
+ // Check that the new task XML is still valid
+ const newTaskXML = WinSvc.getTaskXML(folderName, rawTaskNameV2);
+ Assert.equal(WinSvc.validateTaskDefinition(newTaskXML), 0 /* S_OK */);
+ const docV2 = parser.parseFromString(newTaskXML, "text/xml");
+
+ Assert.equal(docV2.documentElement.tagName, "Task");
+
+ // Check that the updated values still match the provided ones.
+ for (let [sel, expected] of queries) {
+ Assert.equal(
+ docV2.querySelector(sel).textContent,
+ expected,
+ `Task V2 ${sel} had expected textContent`
+ );
+ }
+});