Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: os == 'android'
- Manifest: browser/components/backup/tests/xpcshell/xpcshell.toml
/* Any copyright is dedicated to the Public Domain.
"use strict";
const { SessionStoreBackupResource } = ChromeUtils.importESModule(
"resource:///modules/backup/SessionStoreBackupResource.sys.mjs"
);
const { SessionStore } = ChromeUtils.importESModule(
"resource:///modules/sessionstore/SessionStore.sys.mjs"
);
const { NetUtil } = ChromeUtils.importESModule(
"resource://gre/modules/NetUtil.sys.mjs"
);
const TOTAL_COOKIES = 10;
add_setup(async () => {
// Start the cookieservice, to force creation of a database.
// Get the sessionCookies to join the initialization in cookie thread
Services.cookies.sessionCookies;
Services.prefs.setBoolPref(
"network.cookieJarSettings.unblocked_for_testing",
true
);
let channel = NetUtil.newChannel({
uri,
loadUsingSystemPrincipal: true,
contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
});
for (let i = 0; i < TOTAL_COOKIES; ++i) {
uri = NetUtil.newURI("https://" + i + ".com/");
Services.cookies.setCookieStringFromHttp(uri, "oh=hai", channel);
}
Assert.equal(Services.cookies.sessionCookies.length, TOTAL_COOKIES);
let state = SessionStore.getCurrentState(true);
Assert.equal(
state.cookies.length,
TOTAL_COOKIES,
"The cookies are part of the session"
);
});
/**
* Tests that we can measure the Session Store JSON and backups directory.
*/
add_task(async function test_measure() {
const EXPECTED_KILOBYTES_FOR_BACKUPS_DIR = 1000;
Services.fog.testResetFOG();
// Create the sessionstore-backups directory.
let tempDir = PathUtils.tempDir;
let sessionStoreBackupsPath = PathUtils.join(
tempDir,
"sessionstore-backups",
"restore.jsonlz4"
);
await createKilobyteSizedFile(
sessionStoreBackupsPath,
EXPECTED_KILOBYTES_FOR_BACKUPS_DIR
);
let sessionStoreBackupResource = new SessionStoreBackupResource();
await sessionStoreBackupResource.measure(tempDir);
let sessionStoreBackupsDirectoryMeasurement =
Glean.browserBackup.sessionStoreBackupsDirectorySize.testGetValue();
let sessionStoreMeasurement =
Glean.browserBackup.sessionStoreSize.testGetValue();
let scalars = TelemetryTestUtils.getProcessScalars("parent", false, false);
// Compare glean vs telemetry measurements
TelemetryTestUtils.assertScalar(
scalars,
"browser.backup.session_store_backups_directory_size",
sessionStoreBackupsDirectoryMeasurement,
"Glean and telemetry measurements for session store backups directory should be equal"
);
TelemetryTestUtils.assertScalar(
scalars,
"browser.backup.session_store_size",
sessionStoreMeasurement,
"Glean and telemetry measurements for session store should be equal"
);
// Compare glean measurements vs actual file sizes
Assert.equal(
sessionStoreBackupsDirectoryMeasurement,
EXPECTED_KILOBYTES_FOR_BACKUPS_DIR,
"Should have collected the correct glean measurement for the sessionstore-backups directory"
);
// Session store measurement is from `getCurrentState`, so exact size is unknown.
Assert.greater(
sessionStoreMeasurement,
0,
"Should have collected a measurement for the session store"
);
await IOUtils.remove(sessionStoreBackupsPath);
});
/**
* Test that the backup method correctly copies items from the profile directory
* into the staging directory when the backup is encrypted.
*/
add_task(async function test_backup_encrypted() {
await testBackupHelper(true /* isEncrypted */);
});
/**
* Test that the backup method correctly copies items from the profile directory
* into the staging directory when the backup is not encrypted.
*/
add_task(async function test_backup_not_encrypted() {
await testBackupHelper(false /* isEncrypted */);
});
/**
* A helper method that does the work of setting up a SessionStoreBackupResource
* and all of the testing infrastructure needed to test its backup() method.
*
* @param {boolean} isEncrypted
* True if the test is for an encrypted backup.
*/
async function testBackupHelper(isEncrypted) {
let sandbox = sinon.createSandbox();
let sessionStoreBackupResource = new SessionStoreBackupResource();
let sourcePath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"SessionStoreBackupResource-source-test"
);
let stagingPath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"SessionStoreBackupResource-staging-test"
);
const simpleCopyFiles = [
{ path: ["sessionstore-backups", "test-sessionstore-backup.jsonlz4"] },
{ path: ["sessionstore-backups", "test-sessionstore-recovery.baklz4"] },
];
await createTestFiles(sourcePath, simpleCopyFiles);
let sessionStoreState = SessionStore.getCurrentState(true);
let manifestEntry = await sessionStoreBackupResource.backup(
stagingPath,
sourcePath,
isEncrypted
);
Assert.equal(
manifestEntry,
null,
"SessionStoreBackupResource.backup should return null as its ManifestEntry"
);
/**
* We don't expect the actual file sessionstore.jsonlz4 to exist in the profile directory before calling the backup method.
* Instead, verify that it is created by the backup method and exists in the staging folder right after.
*/
await assertFilesExist(stagingPath, [
...simpleCopyFiles,
{ path: "sessionstore.jsonlz4" },
]);
/**
* Do a deep comparison between the recorded session state before backup and the file made in the staging folder
* to verify that information about session state was correctly written for backup.
*/
let sessionStoreStateStaged = await IOUtils.readJSON(
PathUtils.join(stagingPath, "sessionstore.jsonlz4"),
{ decompress: true }
);
/**
* These timestamps might be slightly different from one another, so we'll exclude
* them from the comparison.
*/
delete sessionStoreStateStaged.session.lastUpdate;
delete sessionStoreState.session.lastUpdate;
if (!isEncrypted) {
// If we're not encrypting, then we expect the cookies array to be empty.
sessionStoreState.cookies = [];
}
Assert.deepEqual(
sessionStoreStateStaged,
sessionStoreState,
"sessionstore.jsonlz4 in the staging folder matches the recorded session state"
);
await maybeRemovePath(stagingPath);
await maybeRemovePath(sourcePath);
sandbox.restore();
}
/**
* Test that the recover method correctly copies items from the recovery
* directory into the destination profile directory.
*/
add_task(async function test_recover() {
let sessionStoreBackupResource = new SessionStoreBackupResource();
let recoveryPath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"SessionStoreBackupResource-recovery-test"
);
let destProfilePath = await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"SessionStoreBackupResource-test-profile"
);
const simpleCopyFiles = [
{ path: ["sessionstore-backups", "test-sessionstore-backup.jsonlz4"] },
{ path: ["sessionstore-backups", "test-sessionstore-recovery.baklz4"] },
];
await createTestFiles(recoveryPath, simpleCopyFiles);
// We backup a copy of sessionstore.jsonlz4, so ensure it exists in the recovery path
let sessionStoreState = SessionStore.getCurrentState(true);
let sessionStoreBackupPath = PathUtils.join(
recoveryPath,
"sessionstore.jsonlz4"
);
await IOUtils.writeJSON(sessionStoreBackupPath, sessionStoreState, {
compress: true,
});
// The backup method is expected to have returned a null ManifestEntry
let postRecoveryEntry = await sessionStoreBackupResource.recover(
null /* manifestEntry */,
recoveryPath,
destProfilePath
);
Assert.equal(
postRecoveryEntry,
null,
"SessionStoreBackupResource.recover should return null as its post recovery entry"
);
await assertFilesExist(destProfilePath, [
...simpleCopyFiles,
{ path: "sessionstore.jsonlz4" },
]);
let sessionStateCopied = await IOUtils.readJSON(
PathUtils.join(destProfilePath, "sessionstore.jsonlz4"),
{ decompress: true }
);
/**
* These timestamps might be slightly different from one another, so we'll exclude
* them from the comparison.
*/
delete sessionStateCopied.session.lastUpdate;
delete sessionStoreState.session.lastUpdate;
Assert.deepEqual(
sessionStateCopied,
sessionStoreState,
"sessionstore.jsonlz4 in the destination profile folder matches the backed up session state"
);
await maybeRemovePath(recoveryPath);
await maybeRemovePath(destProfilePath);
});