Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: os == 'android'
- Manifest: toolkit/profile/test/xpcshell/xpcshell.toml
/* Any copyright is dedicated to the Public Domain.
const { EXIT_CODE } = ChromeUtils.importESModule(
"resource://gre/modules/BackgroundTasksManager.sys.mjs"
);
const { setTimeout } = ChromeUtils.importESModule(
"resource://gre/modules/Timer.sys.mjs"
);
/**
* Tests that attempts to remove the profile directories complete.
*/
add_setup(() => {
// Make sure the profile service is initialised.
let { didCreate } = selectStartupProfile();
Assert.ok(didCreate, "Should have created a new profile.");
});
function wait(ms) {
// There isn't really a way to detect that the background task has started waiting so we must rely
// on a timeout here.
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
return new Promise(resolve => setTimeout(resolve, ms));
}
function runDeletionTask(rootDir, localDir, timeout) {
let binary = Services.dirsvc.get("XREExeF", Ci.nsIFile);
binary.leafName = binary.leafName.replace(
"xpcshell",
AppConstants.MOZ_BUILD_APP == "browser" ? "firefox" : "thunderbird"
);
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(binary);
process.noShell = true;
process.startHidden = true;
let args = [
"--backgroundtask",
"removeProfileFiles",
rootDir.path,
localDir.path,
String(timeout),
];
console.log("Executing", binary.path, ...args);
return new Promise(resolve => {
process.runwAsync(args, args.length, () => {
resolve(process.exitValue);
});
});
}
// Test that in-process file deletion works.
add_task(async () => {
let service = getProfileService();
let profile = service.createProfile(null, "Test2");
// Basic test that file deletion works.
await service.removeProfileFilesByPath(profile.rootDir, profile.localDir, 0);
Assert.ok(
!(await IOUtils.exists(profile.rootDir.path)),
"Should have deleted the root dir"
);
Assert.ok(
!(await IOUtils.exists(profile.localDir.path)),
"Should have deleted the local dir"
);
});
// Tests that background task profile deletion works.
add_task(
{
skip_if: () => !AppConstants.MOZ_BACKGROUNDTASKS,
},
async () => {
let service = getProfileService();
let profile = service.createProfile(null, "Test3");
let testRootFile = PathUtils.join(profile.rootDir.path, "test.txt");
await IOUtils.writeUTF8(testRootFile, "hello");
let testLocalFile = PathUtils.join(profile.localDir.path, "test.txt");
await IOUtils.writeUTF8(testLocalFile, "goodbye");
let exitCode = await runDeletionTask(profile.rootDir, profile.localDir, 0);
Assert.equal(
exitCode,
EXIT_CODE.SUCCESS,
"Process should have completed successfully"
);
Assert.ok(
!(await IOUtils.exists(profile.rootDir.path)),
"Should have deleted the root dir"
);
Assert.ok(
!(await IOUtils.exists(profile.localDir.path)),
"Should have deleted the local dir"
);
}
);
// Tests that the background task cannot delete a locked profile directory.
add_task(
{
skip_if: () => !AppConstants.MOZ_BACKGROUNDTASKS,
},
async () => {
let service = getProfileService();
let profile = service.createProfile(null, "Test4");
let testRootFile = PathUtils.join(profile.rootDir.path, "test.txt");
await IOUtils.writeUTF8(testRootFile, "hello");
let testLocalFile = PathUtils.join(profile.localDir.path, "test.txt");
await IOUtils.writeUTF8(testLocalFile, "goodbye");
let lock = profile.lock({});
// With no timeout the task will exit as soon as it fails to obtain the lock.
let exitCode = await runDeletionTask(profile.rootDir, profile.localDir, 0);
Assert.equal(
exitCode,
EXIT_CODE.EXCEPTION,
"Process should not have completed successfully"
);
Assert.ok(
await IOUtils.exists(testRootFile),
"Should not have deleted the root dir"
);
Assert.ok(
await IOUtils.exists(testLocalFile),
"Should not have deleted the local dir"
);
lock.unlock();
// But now it can succeed.
exitCode = await runDeletionTask(profile.rootDir, profile.localDir, 0);
Assert.equal(
exitCode,
EXIT_CODE.SUCCESS,
"Process should have completed successfully"
);
Assert.ok(
!(await IOUtils.exists(profile.rootDir.path)),
"Should have deleted the root dir"
);
Assert.ok(
!(await IOUtils.exists(profile.localDir.path)),
"Should have deleted the local dir"
);
}
);
// Tests that the background task can wait for the profile lock.
add_task(
{
skip_if: () => !AppConstants.MOZ_BACKGROUNDTASKS,
},
async () => {
let service = getProfileService();
let profile = service.createProfile(null, "Test5");
let testRootFile = PathUtils.join(profile.rootDir.path, "test.txt");
await IOUtils.writeUTF8(testRootFile, "hello");
let testLocalFile = PathUtils.join(profile.localDir.path, "test.txt");
await IOUtils.writeUTF8(testLocalFile, "goodbye");
let lock = profile.lock({});
let deletionPromise = runDeletionTask(
profile.rootDir,
profile.localDir,
20
);
// Wait a few seconds to allow the background task to start running. Allow
// longer for debug builds.
await wait(AppConstants.DEBUG ? 4000 : 1000);
Assert.ok(
await IOUtils.exists(testRootFile),
"Should not have deleted the root dir"
);
Assert.ok(
await IOUtils.exists(testLocalFile),
"Should not have deleted the local dir"
);
// Now unlock and the deletion should complete.
lock.unlock();
let exitCode = await deletionPromise;
Assert.equal(
exitCode,
EXIT_CODE.SUCCESS,
"Process should have completed successfully"
);
Assert.ok(
!(await IOUtils.exists(profile.rootDir.path)),
"Should have deleted the root dir"
);
Assert.ok(
!(await IOUtils.exists(profile.localDir.path)),
"Should have deleted the local dir"
);
}
);