Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
"use strict";
const { PreferencesBackupResource } = ChromeUtils.importESModule(
"resource:///modules/backup/PreferencesBackupResource.sys.mjs"
);
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
SelectableProfileService:
"resource:///modules/profiles/SelectableProfileService.sys.mjs",
});
const STORE_ID_PREF = "toolkit.profiles.storeID";
add_task(async function test_recover_regular_profile_no_storeID_in_prefs() {
let sandbox = sinon.createSandbox();
let preferencesBackupResource = new PreferencesBackupResource();
let recoveryPath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"PreferencesBackupResource-recover-regular-test"
);
let destProfilePath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"PreferencesBackupResource-dest-regular-test"
);
await createTestFiles(recoveryPath, [{ path: "prefs.js" }]);
sandbox.stub(lazy.SelectableProfileService, "currentProfile").value(null);
let postRecoveryEntry = await preferencesBackupResource.recover(
{ profilePath: "/some/original/path" },
recoveryPath,
destProfilePath
);
Assert.equal(postRecoveryEntry, null, "recover() should return null");
let prefsContent = await IOUtils.readUTF8(
PathUtils.join(destProfilePath, "prefs.js")
);
Assert.ok(
!prefsContent.includes(STORE_ID_PREF),
"prefs.js should not contain storeID when recovering into a regular profile"
);
await maybeRemovePath(recoveryPath);
await maybeRemovePath(destProfilePath);
sandbox.restore();
});
add_task(async function test_recover_into_selectable_profile_writes_storeID() {
let sandbox = sinon.createSandbox();
let preferencesBackupResource = new PreferencesBackupResource();
let recoveryPath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"PreferencesBackupResource-recover-selectable-test"
);
let destProfilePath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"PreferencesBackupResource-dest-selectable-test"
);
await createTestFiles(recoveryPath, [{ path: "prefs.js" }]);
const TEST_STORE_ID = "test-store-id-12345";
sandbox
.stub(lazy.SelectableProfileService, "currentProfile")
.value({ id: 1 });
sandbox.stub(lazy.SelectableProfileService, "getDBPref").resolves(true);
sandbox
.stub(lazy.SelectableProfileService, "flushSharedPrefToDatabase")
.resolves();
sandbox
.stub(lazy.SelectableProfileService, "addSelectableProfilePrefs")
.callsFake(async profileDirPath => {
// This does something similar to what the actual addSelectableProfilePrefs does
const prefs = [
`user_pref("browser.profiles.enabled", true);`,
`user_pref("browser.profiles.created", true);`,
`user_pref("${STORE_ID_PREF}", "${TEST_STORE_ID}");`,
];
await IOUtils.writeUTF8(
PathUtils.join(profileDirPath, "prefs.js"),
prefs.join("\n") + "\n",
{ mode: "appendOrCreate" }
);
});
let postRecoveryEntry = await preferencesBackupResource.recover(
{ profilePath: "/some/original/path" },
recoveryPath,
destProfilePath
);
Assert.equal(postRecoveryEntry, null, "recover() should return null");
let prefsContent = await IOUtils.readUTF8(
PathUtils.join(destProfilePath, "prefs.js")
);
Assert.ok(
prefsContent.includes(`user_pref("${STORE_ID_PREF}", "${TEST_STORE_ID}");`),
"prefs.js should contain the storeID when recovering into a selectable profile"
);
await maybeRemovePath(recoveryPath);
await maybeRemovePath(destProfilePath);
sandbox.restore();
});
add_task(async function test_recover_overwrites_stale_selectable_prefs() {
let sandbox = sinon.createSandbox();
let preferencesBackupResource = new PreferencesBackupResource();
let recoveryPath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"PreferencesBackupResource-recover-stale-test"
);
let destProfilePath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"PreferencesBackupResource-dest-stale-test"
);
const STALE_STORE_ID = "stale-old-store-id";
const CORRECT_STORE_ID = "correct-new-store-id";
// Create a backup prefs.js with stale selectable profile prefs
await IOUtils.writeUTF8(
PathUtils.join(recoveryPath, "prefs.js"),
`user_pref("${STORE_ID_PREF}", "${STALE_STORE_ID}");\n` +
`user_pref("browser.profiles.enabled", false);\n` +
`user_pref("some.user.pref", "user-value");\n`
);
sandbox
.stub(lazy.SelectableProfileService, "currentProfile")
.value({ id: 1 });
sandbox.stub(lazy.SelectableProfileService, "getDBPref").resolves(true);
sandbox
.stub(lazy.SelectableProfileService, "flushSharedPrefToDatabase")
.resolves();
sandbox
.stub(lazy.SelectableProfileService, "addSelectableProfilePrefs")
.callsFake(async profileDirPath => {
const prefs = [
`user_pref("browser.profiles.enabled", true);`,
`user_pref("browser.profiles.created", true);`,
`user_pref("${STORE_ID_PREF}", "${CORRECT_STORE_ID}");`,
];
await IOUtils.writeUTF8(
PathUtils.join(profileDirPath, "prefs.js"),
prefs.join("\n") + "\n",
{ mode: "appendOrCreate" }
);
});
await preferencesBackupResource.recover(
{ profilePath: "/some/original/path" },
recoveryPath,
destProfilePath
);
let prefsContent = await IOUtils.readUTF8(
PathUtils.join(destProfilePath, "prefs.js")
);
// Verify both stale and correct storeID appear (stale from backup, correct appended)
Assert.ok(
prefsContent.includes(
`user_pref("${STORE_ID_PREF}", "${STALE_STORE_ID}");`
),
"prefs.js should still contain the stale storeID from backup"
);
Assert.ok(
prefsContent.includes(
`user_pref("${STORE_ID_PREF}", "${CORRECT_STORE_ID}");`
),
"prefs.js should contain the correct storeID appended at the end"
);
// Verify the correct storeID appears AFTER the stale one - the last pref value is the one
// that will be set!
let staleIndex = prefsContent.indexOf(
`user_pref("${STORE_ID_PREF}", "${STALE_STORE_ID}");`
);
let correctIndex = prefsContent.indexOf(
`user_pref("${STORE_ID_PREF}", "${CORRECT_STORE_ID}");`
);
Assert.greater(
correctIndex,
staleIndex,
"The correct storeID should appear after the stale one so it takes precedence"
);
// Verify user prefs from backup are preserved
Assert.ok(
prefsContent.includes('user_pref("some.user.pref", "user-value");'),
"User prefs from backup should be preserved"
);
// Verify the corrected browser.profiles.enabled appears after the stale one
let staleEnabledIndex = prefsContent.indexOf(
'user_pref("browser.profiles.enabled", false);'
);
let correctEnabledIndex = prefsContent.indexOf(
'user_pref("browser.profiles.enabled", true);'
);
Assert.greater(
correctEnabledIndex,
staleEnabledIndex,
"The correct browser.profiles.enabled should appear after the stale one"
);
await maybeRemovePath(recoveryPath);
await maybeRemovePath(destProfilePath);
sandbox.restore();
});
/**
* Test that recovering into a selectable profile uses the most restrictive
* data collection settings between the backup and the profile group.
*/
add_task(async function test_recover_data_collection_prefs_most_restrictive() {
let sandbox = sinon.createSandbox();
let preferencesBackupResource = new PreferencesBackupResource();
let recoveryPath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"PreferencesBackupResource-data-collection-test"
);
let destProfilePath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"PreferencesBackupResource-dest-data-collection-test"
);
// Set initial values - we'll verify these change (or don't) based on backup vs group
Services.prefs.setBoolPref("browser.discovery.enabled", true);
Services.prefs.setBoolPref("datareporting.healthreport.uploadEnabled", false);
Services.prefs.setBoolPref("app.shield.optoutstudies.enabled", true);
// Get default for a pref we'll omit from backup to test the default fallback
const defaults = Services.prefs.getDefaultBranch(null);
const usageUploadDefault = defaults.getBoolPref(
"datareporting.usage.uploadEnabled",
false
);
Services.prefs.clearUserPref("datareporting.usage.uploadEnabled");
// Create backup prefs.js - note datareporting.usage.uploadEnabled is missing
await IOUtils.writeUTF8(
PathUtils.join(recoveryPath, "prefs.js"),
`user_pref("browser.discovery.enabled", false);\n` +
`user_pref("datareporting.healthreport.uploadEnabled", true);\n` +
`user_pref("app.shield.optoutstudies.enabled", true);\n`
);
sandbox
.stub(lazy.SelectableProfileService, "currentProfile")
.value({ id: 1 });
// Group has all data collection prefs ENABLED
sandbox.stub(lazy.SelectableProfileService, "getDBPref").resolves(true);
sandbox
.stub(lazy.SelectableProfileService, "flushSharedPrefToDatabase")
.resolves();
sandbox
.stub(lazy.SelectableProfileService, "addSelectableProfilePrefs")
.resolves();
await preferencesBackupResource.recover(
{ profilePath: "/some/original/path" },
recoveryPath,
destProfilePath
);
// backup=false, group=true -> set to false (most restrictive)
Assert.equal(
Services.prefs.getBoolPref("browser.discovery.enabled"),
false,
"browser.discovery.enabled: backup=false, group=true -> false"
);
// backup=true, group=true -> no change needed (both enabled)
Assert.equal(
Services.prefs.getBoolPref("datareporting.healthreport.uploadEnabled"),
false,
"datareporting.healthreport.uploadEnabled: backup=true, group=false -> false"
);
Assert.equal(
Services.prefs.getBoolPref("app.shield.optoutstudies.enabled"),
true,
"app.shield.optoutstudies.enabled: backup=true, group=true -> stays true"
);
// backup=missing, group=true -> uses default value
Assert.equal(
Services.prefs.getBoolPref("datareporting.usage.uploadEnabled"),
usageUploadDefault,
"datareporting.usage.uploadEnabled: backup=missing -> uses default"
);
Assert.ok(
lazy.SelectableProfileService.addSelectableProfilePrefs.calledOnceWith(
destProfilePath
),
"addSelectableProfilePrefs should be called with destProfilePath"
);
// Clean up prefs set during test
Services.prefs.clearUserPref("browser.discovery.enabled");
Services.prefs.clearUserPref("datareporting.healthreport.uploadEnabled");
Services.prefs.clearUserPref("app.shield.optoutstudies.enabled");
Services.prefs.clearUserPref("datareporting.usage.uploadEnabled");
await maybeRemovePath(recoveryPath);
await maybeRemovePath(destProfilePath);
sandbox.restore();
});