tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_SessionStoreBackupResource.js (8739B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 https://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const { SessionStoreBackupResource } = ChromeUtils.importESModule(
      7  "resource:///modules/backup/SessionStoreBackupResource.sys.mjs"
      8 );
      9 const { SessionStore } = ChromeUtils.importESModule(
     10  "resource:///modules/sessionstore/SessionStore.sys.mjs"
     11 );
     12 const { NetUtil } = ChromeUtils.importESModule(
     13  "resource://gre/modules/NetUtil.sys.mjs"
     14 );
     15 
     16 const TOTAL_COOKIES = 10;
     17 
     18 add_setup(async () => {
     19  // Start the cookieservice, to force creation of a database.
     20  // Get the sessionCookies to join the initialization in cookie thread
     21  Services.cookies.sessionCookies;
     22 
     23  Services.prefs.setBoolPref(
     24    "network.cookieJarSettings.unblocked_for_testing",
     25    true
     26  );
     27 
     28  let uri = NetUtil.newURI("https://foo.com/");
     29  let channel = NetUtil.newChannel({
     30    uri,
     31    loadUsingSystemPrincipal: true,
     32    contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
     33  });
     34  for (let i = 0; i < TOTAL_COOKIES; ++i) {
     35    uri = NetUtil.newURI("https://" + i + ".com/");
     36    Services.cookies.setCookieStringFromHttp(uri, "oh=hai", channel);
     37  }
     38 
     39  Assert.equal(Services.cookies.sessionCookies.length, TOTAL_COOKIES);
     40 
     41  let state = SessionStore.getCurrentState(true);
     42  Assert.equal(
     43    state.cookies.length,
     44    TOTAL_COOKIES,
     45    "The cookies are part of the session"
     46  );
     47 });
     48 
     49 /**
     50 * Tests that we can measure the Session Store JSON and backups directory.
     51 */
     52 add_task(async function test_measure() {
     53  const EXPECTED_KILOBYTES_FOR_BACKUPS_DIR = 1000;
     54  Services.fog.testResetFOG();
     55 
     56  // Create the sessionstore-backups directory.
     57  let tempDir = PathUtils.tempDir;
     58  let sessionStoreBackupsPath = PathUtils.join(
     59    tempDir,
     60    "sessionstore-backups",
     61    "restore.jsonlz4"
     62  );
     63  await createKilobyteSizedFile(
     64    sessionStoreBackupsPath,
     65    EXPECTED_KILOBYTES_FOR_BACKUPS_DIR
     66  );
     67 
     68  let sessionStoreBackupResource = new SessionStoreBackupResource();
     69  await sessionStoreBackupResource.measure(tempDir);
     70 
     71  let sessionStoreBackupsDirectoryMeasurement =
     72    Glean.browserBackup.sessionStoreBackupsDirectorySize.testGetValue();
     73  let sessionStoreMeasurement =
     74    Glean.browserBackup.sessionStoreSize.testGetValue();
     75  let scalars = TelemetryTestUtils.getProcessScalars("parent", false, false);
     76 
     77  // Compare glean vs telemetry measurements
     78  TelemetryTestUtils.assertScalar(
     79    scalars,
     80    "browser.backup.session_store_backups_directory_size",
     81    sessionStoreBackupsDirectoryMeasurement,
     82    "Glean and telemetry measurements for session store backups directory should be equal"
     83  );
     84  TelemetryTestUtils.assertScalar(
     85    scalars,
     86    "browser.backup.session_store_size",
     87    sessionStoreMeasurement,
     88    "Glean and telemetry measurements for session store should be equal"
     89  );
     90 
     91  // Compare glean measurements vs actual file sizes
     92  Assert.equal(
     93    sessionStoreBackupsDirectoryMeasurement,
     94    EXPECTED_KILOBYTES_FOR_BACKUPS_DIR,
     95    "Should have collected the correct glean measurement for the sessionstore-backups directory"
     96  );
     97 
     98  // Session store measurement is from `getCurrentState`, so exact size is unknown.
     99  Assert.greater(
    100    sessionStoreMeasurement,
    101    0,
    102    "Should have collected a measurement for the session store"
    103  );
    104 
    105  await IOUtils.remove(sessionStoreBackupsPath);
    106 });
    107 
    108 /**
    109 * Test that the backup method correctly copies items from the profile directory
    110 * into the staging directory when the backup is encrypted.
    111 */
    112 add_task(async function test_backup_encrypted() {
    113  await testBackupHelper(true /* isEncrypted */);
    114 });
    115 
    116 /**
    117 * Test that the backup method correctly copies items from the profile directory
    118 * into the staging directory when the backup is not encrypted.
    119 */
    120 add_task(async function test_backup_not_encrypted() {
    121  await testBackupHelper(false /* isEncrypted */);
    122 });
    123 
    124 /**
    125 * A helper method that does the work of setting up a SessionStoreBackupResource
    126 * and all of the testing infrastructure needed to test its backup() method.
    127 *
    128 * @param {boolean} isEncrypted
    129 *   True if the test is for an encrypted backup.
    130 */
    131 async function testBackupHelper(isEncrypted) {
    132  let sandbox = sinon.createSandbox();
    133 
    134  let sessionStoreBackupResource = new SessionStoreBackupResource();
    135  let sourcePath = await IOUtils.createUniqueDirectory(
    136    PathUtils.tempDir,
    137    "SessionStoreBackupResource-source-test"
    138  );
    139  let stagingPath = await IOUtils.createUniqueDirectory(
    140    PathUtils.tempDir,
    141    "SessionStoreBackupResource-staging-test"
    142  );
    143 
    144  const simpleCopyFiles = [
    145    { path: ["sessionstore-backups", "test-sessionstore-backup.jsonlz4"] },
    146    { path: ["sessionstore-backups", "test-sessionstore-recovery.baklz4"] },
    147  ];
    148  await createTestFiles(sourcePath, simpleCopyFiles);
    149 
    150  let sessionStoreState = SessionStore.getCurrentState(true);
    151  let manifestEntry = await sessionStoreBackupResource.backup(
    152    stagingPath,
    153    sourcePath,
    154    isEncrypted
    155  );
    156  Assert.equal(
    157    manifestEntry,
    158    null,
    159    "SessionStoreBackupResource.backup should return null as its ManifestEntry"
    160  );
    161 
    162  /**
    163   * We don't expect the actual file sessionstore.jsonlz4 to exist in the profile directory before calling the backup method.
    164   * Instead, verify that it is created by the backup method and exists in the staging folder right after.
    165   */
    166  await assertFilesExist(stagingPath, [
    167    ...simpleCopyFiles,
    168    { path: "sessionstore.jsonlz4" },
    169  ]);
    170 
    171  /**
    172   * Do a deep comparison between the recorded session state before backup and the file made in the staging folder
    173   * to verify that information about session state was correctly written for backup.
    174   */
    175  let sessionStoreStateStaged = await IOUtils.readJSON(
    176    PathUtils.join(stagingPath, "sessionstore.jsonlz4"),
    177    { decompress: true }
    178  );
    179 
    180  /**
    181   * These timestamps might be slightly different from one another, so we'll exclude
    182   * them from the comparison.
    183   */
    184  delete sessionStoreStateStaged.session.lastUpdate;
    185  delete sessionStoreState.session.lastUpdate;
    186 
    187  // Expect that the copy does not include cookies.
    188  Assert.equal(
    189    sessionStoreStateStaged.cookies.length,
    190    0,
    191    "expected no cookies in copied session state"
    192  );
    193  // Delete the cookies from the original, to allow comparison with deepEqual
    194  sessionStoreState.cookies = [];
    195 
    196  Assert.deepEqual(
    197    sessionStoreStateStaged,
    198    sessionStoreState,
    199    "sessionstore.jsonlz4 in the staging folder matches the recorded session state"
    200  );
    201 
    202  await maybeRemovePath(stagingPath);
    203  await maybeRemovePath(sourcePath);
    204 
    205  sandbox.restore();
    206 }
    207 
    208 /**
    209 * Test that the recover method correctly copies items from the recovery
    210 * directory into the destination profile directory.
    211 */
    212 add_task(async function test_recover() {
    213  let sessionStoreBackupResource = new SessionStoreBackupResource();
    214  let recoveryPath = await IOUtils.createUniqueDirectory(
    215    PathUtils.tempDir,
    216    "SessionStoreBackupResource-recovery-test"
    217  );
    218  let destProfilePath = await IOUtils.createUniqueDirectory(
    219    PathUtils.tempDir,
    220    "SessionStoreBackupResource-test-profile"
    221  );
    222 
    223  const simpleCopyFiles = [
    224    { path: ["sessionstore-backups", "test-sessionstore-backup.jsonlz4"] },
    225    { path: ["sessionstore-backups", "test-sessionstore-recovery.baklz4"] },
    226  ];
    227  await createTestFiles(recoveryPath, simpleCopyFiles);
    228 
    229  // We backup a copy of sessionstore.jsonlz4, so ensure it exists in the recovery path
    230  let sessionStoreState = SessionStore.getCurrentState(true);
    231  let sessionStoreBackupPath = PathUtils.join(
    232    recoveryPath,
    233    "sessionstore.jsonlz4"
    234  );
    235  await IOUtils.writeJSON(sessionStoreBackupPath, sessionStoreState, {
    236    compress: true,
    237  });
    238 
    239  // The backup method is expected to have returned a null ManifestEntry
    240  let postRecoveryEntry = await sessionStoreBackupResource.recover(
    241    null /* manifestEntry */,
    242    recoveryPath,
    243    destProfilePath
    244  );
    245  Assert.equal(
    246    postRecoveryEntry,
    247    null,
    248    "SessionStoreBackupResource.recover should return null as its post recovery entry"
    249  );
    250 
    251  await assertFilesExist(destProfilePath, [
    252    ...simpleCopyFiles,
    253    { path: "sessionstore.jsonlz4" },
    254  ]);
    255 
    256  let sessionStateCopied = await IOUtils.readJSON(
    257    PathUtils.join(destProfilePath, "sessionstore.jsonlz4"),
    258    { decompress: true }
    259  );
    260 
    261  /**
    262   * These timestamps might be slightly different from one another, so we'll exclude
    263   * them from the comparison.
    264   */
    265  delete sessionStateCopied.session.lastUpdate;
    266  delete sessionStoreState.session.lastUpdate;
    267  Assert.deepEqual(
    268    sessionStateCopied,
    269    sessionStoreState,
    270    "sessionstore.jsonlz4 in the destination profile folder matches the backed up session state"
    271  );
    272 
    273  await maybeRemovePath(recoveryPath);
    274  await maybeRemovePath(destProfilePath);
    275 });