tor-browser

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

test_PlacesBackupResource.js (12158B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 https://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const { PlacesBackupResource } = ChromeUtils.importESModule(
      7  "resource:///modules/backup/PlacesBackupResource.sys.mjs"
      8 );
      9 const { PlacesDBUtils } = ChromeUtils.importESModule(
     10  "resource://gre/modules/PlacesDBUtils.sys.mjs"
     11 );
     12 
     13 registerCleanupFunction(() => {
     14  /**
     15   * Even though test_backup_no_saved_history clears user prefs too,
     16   * clear them here as well in case that test fails and we don't
     17   * reach the end of the test, which handles the cleanup.
     18   */
     19  Services.prefs.clearUserPref(HISTORY_ENABLED_PREF);
     20  Services.prefs.clearUserPref(SANITIZE_ON_SHUTDOWN_PREF);
     21 });
     22 
     23 /**
     24 * Tests that we can measure Places DB related files in the profile directory.
     25 */
     26 add_task(async function test_measure() {
     27  Services.fog.testResetFOG();
     28 
     29  const EXPECTED_PLACES_DB_SIZE = 5240;
     30  const EXPECTED_FAVICONS_DB_SIZE = 5240;
     31 
     32  // Create resource files in temporary directory
     33  const tempDir = PathUtils.tempDir;
     34  let tempPlacesDBPath = PathUtils.join(tempDir, "places.sqlite");
     35  let tempFaviconsDBPath = PathUtils.join(tempDir, "favicons.sqlite");
     36  await createKilobyteSizedFile(tempPlacesDBPath, EXPECTED_PLACES_DB_SIZE);
     37  await createKilobyteSizedFile(tempFaviconsDBPath, EXPECTED_FAVICONS_DB_SIZE);
     38 
     39  let placesBackupResource = new PlacesBackupResource();
     40  await placesBackupResource.measure(tempDir);
     41 
     42  let placesMeasurement = Glean.browserBackup.placesSize.testGetValue();
     43  let faviconsMeasurement = Glean.browserBackup.faviconsSize.testGetValue();
     44  let scalars = TelemetryTestUtils.getProcessScalars("parent", false, false);
     45 
     46  // Compare glean vs telemetry measurements
     47  TelemetryTestUtils.assertScalar(
     48    scalars,
     49    "browser.backup.places_size",
     50    placesMeasurement,
     51    "Glean and telemetry measurements for places.sqlite should be equal"
     52  );
     53  TelemetryTestUtils.assertScalar(
     54    scalars,
     55    "browser.backup.favicons_size",
     56    faviconsMeasurement,
     57    "Glean and telemetry measurements for favicons.sqlite should be equal"
     58  );
     59 
     60  // Compare glean measurements vs actual file sizes
     61  Assert.equal(
     62    placesMeasurement,
     63    EXPECTED_PLACES_DB_SIZE,
     64    "Should have collected the correct glean measurement for places.sqlite"
     65  );
     66  Assert.equal(
     67    faviconsMeasurement,
     68    EXPECTED_FAVICONS_DB_SIZE,
     69    "Should have collected the correct glean measurement for favicons.sqlite"
     70  );
     71 
     72  await maybeRemovePath(tempPlacesDBPath);
     73  await maybeRemovePath(tempFaviconsDBPath);
     74 });
     75 
     76 /**
     77 * Tests that the backup method correctly copies places.sqlite and
     78 * favicons.sqlite from the profile directory into the staging directory.
     79 */
     80 add_task(async function test_backup() {
     81  Services.fog.testResetFOG();
     82  const placesTimeHistogram = TelemetryTestUtils.getAndClearHistogram(
     83    "BROWSER_BACKUP_PLACES_TIME_MS"
     84  );
     85  const faviconsTimeHistogram = TelemetryTestUtils.getAndClearHistogram(
     86    "BROWSER_BACKUP_FAVICONS_TIME_MS"
     87  );
     88  let sandbox = sinon.createSandbox();
     89 
     90  let placesBackupResource = new PlacesBackupResource();
     91  let sourcePath = await IOUtils.createUniqueDirectory(
     92    PathUtils.tempDir,
     93    "PlacesBackupResource-source-test"
     94  );
     95  let stagingPath = await IOUtils.createUniqueDirectory(
     96    PathUtils.tempDir,
     97    "PlacesBackupResource-staging-test"
     98  );
     99 
    100  // Make sure these files exist in the source directory, otherwise
    101  // BackupResource will skip attempting to back them up.
    102  await createTestFiles(sourcePath, [
    103    { path: "places.sqlite" },
    104    { path: "favicons.sqlite" },
    105  ]);
    106 
    107  let fakeConnection = {
    108    backup: sandbox.stub().resolves(true),
    109    close: sandbox.stub().resolves(true),
    110  };
    111  sandbox.stub(Sqlite, "openConnection").returns(fakeConnection);
    112  sandbox.stub(PlacesDBUtils, "removeDownloadsMetadataFromDb");
    113 
    114  let manifestEntry = await placesBackupResource.backup(
    115    stagingPath,
    116    sourcePath
    117  );
    118  Assert.equal(
    119    manifestEntry,
    120    null,
    121    "PlacesBackupResource.backup should return null as its ManifestEntry"
    122  );
    123 
    124  Assert.ok(
    125    PlacesDBUtils.removeDownloadsMetadataFromDb.calledOnce,
    126    "PlacesDBUtils.removeDownloadsMetadataFromDb was called"
    127  );
    128  Assert.ok(
    129    fakeConnection.backup.calledTwice,
    130    "Backup should have been called twice"
    131  );
    132  Assert.ok(
    133    fakeConnection.backup.firstCall.calledWith(
    134      PathUtils.join(stagingPath, "places.sqlite")
    135    ),
    136    "places.sqlite should have been backed up first"
    137  );
    138  Assert.ok(
    139    fakeConnection.backup.secondCall.calledWith(
    140      PathUtils.join(stagingPath, "favicons.sqlite")
    141    ),
    142    "favicons.sqlite should have been backed up second"
    143  );
    144  // Validate timing metrics
    145  assertSingleTimeMeasurement(Glean.browserBackup.placesTime.testGetValue());
    146  assertSingleTimeMeasurement(Glean.browserBackup.faviconsTime.testGetValue());
    147  assertHistogramMeasurementQuantity(placesTimeHistogram, 1);
    148  assertHistogramMeasurementQuantity(faviconsTimeHistogram, 1);
    149 
    150  await maybeRemovePath(stagingPath);
    151  await maybeRemovePath(sourcePath);
    152 
    153  sandbox.restore();
    154 });
    155 
    156 /**
    157 * Tests that we don't backup history is the user is clearing browsing history
    158 * on shutdown.
    159 */
    160 add_task(async function test_backup_no_saved_history() {
    161  Services.fog.testResetFOG();
    162  const placesTimeHistogram = TelemetryTestUtils.getAndClearHistogram(
    163    "BROWSER_BACKUP_PLACES_TIME_MS"
    164  );
    165  const faviconsTimeHistogram = TelemetryTestUtils.getAndClearHistogram(
    166    "BROWSER_BACKUP_FAVICONS_TIME_MS"
    167  );
    168  let sandbox = sinon.createSandbox();
    169 
    170  let sourcePath = await IOUtils.createUniqueDirectory(
    171    PathUtils.tempDir,
    172    "PlacesBackupResource-source-test"
    173  );
    174  let stagingPath = await IOUtils.createUniqueDirectory(
    175    PathUtils.tempDir,
    176    "PlacesBackupResource-staging-test"
    177  );
    178 
    179  let fakeConnection = {
    180    backup: sandbox.stub().resolves(true),
    181    close: sandbox.stub().resolves(true),
    182  };
    183  sandbox.stub(Sqlite, "openConnection").returns(fakeConnection);
    184 
    185  /**
    186   * First verify that remember history pref alone affects backup file type for places,
    187   * despite sanitize on shutdown pref value.
    188   */
    189  Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, false);
    190  Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, false);
    191 
    192  Assert.ok(
    193    !PlacesBackupResource.canBackupResource,
    194    "Cannot backup places when history is disabled"
    195  );
    196 
    197  // PlacesBackupResource should not be called when canBackupResource is false
    198  // The test is just verifying the check works correctly
    199  // Validate no timing metrics
    200  Assert.equal(
    201    Glean.browserBackup.placesTime.testGetValue(),
    202    null,
    203    "Should not have timed places backup when it did not occur"
    204  );
    205  Assert.equal(
    206    Glean.browserBackup.faviconsTime.testGetValue(),
    207    null,
    208    "Should not have timed favicons backup when it did not occur"
    209  );
    210  assertHistogramMeasurementQuantity(placesTimeHistogram, 0);
    211  assertHistogramMeasurementQuantity(faviconsTimeHistogram, 0);
    212 
    213  /**
    214   * Now verify that the sanitize shutdown pref also prevents backup of places.
    215   */
    216  Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, true);
    217  Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, true);
    218  Services.prefs.setBoolPref(HISTORY_CLEARED_ON_SHUTDOWN_PREF, true);
    219 
    220  Assert.ok(
    221    !PlacesBackupResource.canBackupResource,
    222    "Cannot backup places when sanitizeOnShutdown and history cleared on shutdown are enabled"
    223  );
    224 
    225  // PlacesBackupResource should not be called when canBackupResource is false
    226  // The test is just verifying the check works correctly
    227  // Validate no timing metrics
    228  Assert.equal(
    229    Glean.browserBackup.placesTime.testGetValue(),
    230    null,
    231    "Should not have timed places backup when it did not occur"
    232  );
    233  Assert.equal(
    234    Glean.browserBackup.faviconsTime.testGetValue(),
    235    null,
    236    "Should not have timed favicons backup when it did not occur"
    237  );
    238  assertHistogramMeasurementQuantity(placesTimeHistogram, 0);
    239  assertHistogramMeasurementQuantity(faviconsTimeHistogram, 0);
    240 
    241  await maybeRemovePath(stagingPath);
    242  await maybeRemovePath(sourcePath);
    243 
    244  sandbox.restore();
    245  Services.prefs.clearUserPref(HISTORY_ENABLED_PREF);
    246  Services.prefs.clearUserPref(SANITIZE_ON_SHUTDOWN_PREF);
    247  Services.prefs.clearUserPref(HISTORY_CLEARED_ON_SHUTDOWN_PREF);
    248 });
    249 
    250 /**
    251 * Tests that we don't backup history if permanent private browsing is enabled
    252 */
    253 add_task(async function test_backup_private_browsing() {
    254  Services.fog.testResetFOG();
    255  const placesTimeHistogram = TelemetryTestUtils.getAndClearHistogram(
    256    "BROWSER_BACKUP_PLACES_TIME_MS"
    257  );
    258  const faviconsTimeHistogram = TelemetryTestUtils.getAndClearHistogram(
    259    "BROWSER_BACKUP_FAVICONS_TIME_MS"
    260  );
    261  let sandbox = sinon.createSandbox();
    262 
    263  let sourcePath = await IOUtils.createUniqueDirectory(
    264    PathUtils.tempDir,
    265    "PlacesBackupResource-source-test"
    266  );
    267  let stagingPath = await IOUtils.createUniqueDirectory(
    268    PathUtils.tempDir,
    269    "PlacesBackupResource-staging-test"
    270  );
    271 
    272  let fakeConnection = {
    273    backup: sandbox.stub().resolves(true),
    274    close: sandbox.stub().resolves(true),
    275  };
    276  sandbox.stub(Sqlite, "openConnection").returns(fakeConnection);
    277  sandbox.stub(PrivateBrowsingUtils, "permanentPrivateBrowsing").value(true);
    278 
    279  Assert.ok(
    280    !PlacesBackupResource.canBackupResource,
    281    "Cannot backup places when permanent private browsing is enabled"
    282  );
    283 
    284  // PlacesBackupResource should not be called when canBackupResource is false
    285  // The test is just verifying the check works correctly
    286  // Validate no timing metrics
    287  Assert.equal(
    288    Glean.browserBackup.placesTime.testGetValue(),
    289    null,
    290    "Should not have timed places backup when it did not occur"
    291  );
    292  Assert.equal(
    293    Glean.browserBackup.faviconsTime.testGetValue(),
    294    null,
    295    "Should not have timed favicons backup when it did not occur"
    296  );
    297  assertHistogramMeasurementQuantity(placesTimeHistogram, 0);
    298  assertHistogramMeasurementQuantity(faviconsTimeHistogram, 0);
    299 
    300  await maybeRemovePath(stagingPath);
    301  await maybeRemovePath(sourcePath);
    302 
    303  sandbox.restore();
    304 });
    305 
    306 /**
    307 * Test that the recover method correctly copies places.sqlite and favicons.sqlite
    308 * from the recovery directory into the destination profile directory.
    309 */
    310 add_task(async function test_recover() {
    311  let placesBackupResource = new PlacesBackupResource();
    312  let recoveryPath = await IOUtils.createUniqueDirectory(
    313    PathUtils.tempDir,
    314    "PlacesBackupResource-recovery-test"
    315  );
    316  let destProfilePath = await IOUtils.createUniqueDirectory(
    317    PathUtils.tempDir,
    318    "PlacesBackupResource-test-profile"
    319  );
    320 
    321  const simpleCopyFiles = [
    322    { path: "places.sqlite" },
    323    { path: "favicons.sqlite" },
    324  ];
    325  await createTestFiles(recoveryPath, simpleCopyFiles);
    326 
    327  // The backup method is expected to have returned a null ManifestEntry
    328  let postRecoveryEntry = await placesBackupResource.recover(
    329    null /* manifestEntry */,
    330    recoveryPath,
    331    destProfilePath
    332  );
    333  Assert.equal(
    334    postRecoveryEntry,
    335    null,
    336    "PlacesBackupResource.recover should return null as its post recovery entry"
    337  );
    338 
    339  await assertFilesExist(destProfilePath, simpleCopyFiles);
    340 
    341  await maybeRemovePath(recoveryPath);
    342  await maybeRemovePath(destProfilePath);
    343 });
    344 
    345 /**
    346 * Tests the canBackupResource method with various pref configurations.
    347 */
    348 add_task(async function test_canBackupResource() {
    349  Assert.ok(
    350    PlacesBackupResource.canBackupResource,
    351    "Should be able to backup by default"
    352  );
    353 
    354  Services.prefs.setBoolPref(HISTORY_ENABLED_PREF, false);
    355  Assert.ok(
    356    !PlacesBackupResource.canBackupResource,
    357    "Cannot backup when history is disabled"
    358  );
    359  Services.prefs.clearUserPref(HISTORY_ENABLED_PREF);
    360 
    361  Assert.ok(
    362    PlacesBackupResource.canBackupResource,
    363    "Should be able to backup after clearing pref"
    364  );
    365 
    366  Services.prefs.setBoolPref(SANITIZE_ON_SHUTDOWN_PREF, true);
    367  Services.prefs.setBoolPref(HISTORY_CLEARED_ON_SHUTDOWN_PREF, true);
    368  Assert.ok(
    369    !PlacesBackupResource.canBackupResource,
    370    "Cannot backup when sanitizeOnShutdown and history cleared on shutdown are enabled"
    371  );
    372 
    373  Services.prefs.clearUserPref(SANITIZE_ON_SHUTDOWN_PREF);
    374  Services.prefs.clearUserPref(HISTORY_CLEARED_ON_SHUTDOWN_PREF);
    375 });