tor-browser

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

test_BackupService_regeneration.js (20644B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 https://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const { NetUtil } = ChromeUtils.importESModule(
      7  "resource://gre/modules/NetUtil.sys.mjs"
      8 );
      9 const { PlacesTestUtils } = ChromeUtils.importESModule(
     10  "resource://testing-common/PlacesTestUtils.sys.mjs"
     11 );
     12 const { PlacesUtils } = ChromeUtils.importESModule(
     13  "resource://gre/modules/PlacesUtils.sys.mjs"
     14 );
     15 const { TestUtils } = ChromeUtils.importESModule(
     16  "resource://testing-common/TestUtils.sys.mjs"
     17 );
     18 const { DownloadHistory } = ChromeUtils.importESModule(
     19  "resource://gre/modules/DownloadHistory.sys.mjs"
     20 );
     21 const { AddonTestUtils } = ChromeUtils.importESModule(
     22  "resource://testing-common/AddonTestUtils.sys.mjs"
     23 );
     24 const { ExtensionTestUtils } = ChromeUtils.importESModule(
     25  "resource://testing-common/ExtensionXPCShellUtils.sys.mjs"
     26 );
     27 const { formAutofillStorage } = ChromeUtils.importESModule(
     28  "resource://autofill/FormAutofillStorage.sys.mjs"
     29 );
     30 const { Sanitizer } = ChromeUtils.importESModule(
     31  "resource:///modules/Sanitizer.sys.mjs"
     32 );
     33 const { NewTabUtils } = ChromeUtils.importESModule(
     34  "resource://gre/modules/NewTabUtils.sys.mjs"
     35 );
     36 const { CookieXPCShellUtils } = ChromeUtils.importESModule(
     37  "resource://testing-common/CookieXPCShellUtils.sys.mjs"
     38 );
     39 
     40 ExtensionTestUtils.init(this);
     41 AddonTestUtils.init(this);
     42 AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1");
     43 
     44 const nsLoginInfo = new Components.Constructor(
     45  "@mozilla.org/login-manager/loginInfo;1",
     46  Ci.nsILoginInfo,
     47  "init"
     48 );
     49 
     50 /**
     51 * This suite of tests ensures that the current backup will be deleted, and
     52 * a new one generated when certain user actions occur.
     53 */
     54 
     55 /**
     56 * Adds a history visit to the Places database.
     57 *
     58 * @param {string} uriString
     59 *   A string representation of the URI to add a visit for.
     60 * @param {number} [timestamp=Date.now()]
     61 *   The timestamp for the visit to be used. By default, this is the current
     62 *   date and time.
     63 * @returns {Promise<undefined>}
     64 */
     65 async function addTestHistory(uriString, timestamp = Date.now()) {
     66  let uri = NetUtil.newURI(uriString);
     67  await PlacesTestUtils.addVisits({
     68    uri,
     69    transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
     70    visitDate: timestamp * 1000,
     71  });
     72 }
     73 
     74 let gCookieCounter = 0;
     75 
     76 const COOKIE_HOST = "example.com";
     77 const COOKIE_PATH = "/";
     78 const COOKIE_ORIGIN_ATTRIBUTES = Object.freeze({});
     79 
     80 /**
     81 * Adds a new non-session cookie to the cookie database with the host set
     82 * as COOKIE_HOST, the path as COOKIE_PATH, with the origin attributes of
     83 * COOKIE_ORIGIN_ATTRIBUTES and a generated name and value.
     84 *
     85 * @param {boolean} isSessionCookie
     86 *   True if the cookie should be a session cookie.
     87 * @returns {string}
     88 *   The name of the cookie that was generated.
     89 */
     90 function addTestCookie(isSessionCookie) {
     91  gCookieCounter++;
     92  let name = `Cookie name: ${gCookieCounter}`;
     93 
     94  const cv = Services.cookies.add(
     95    COOKIE_HOST,
     96    COOKIE_PATH,
     97    name,
     98    `Cookie value: ${gCookieCounter}`,
     99    false,
    100    false,
    101    isSessionCookie,
    102    Date.now() + 1000,
    103    COOKIE_ORIGIN_ATTRIBUTES,
    104    Ci.nsICookie.SAMESITE_UNSET,
    105    Ci.nsICookie.SCHEME_HTTP
    106  );
    107  Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
    108 
    109  return name;
    110 }
    111 
    112 /**
    113 * A helper function that sets up a BackupService to be instrumented to detect
    114 * a backup regeneration, and then runs an async taskFn to ensure that the
    115 * regeneration occurs.
    116 *
    117 * @param {Function} taskFn
    118 *   The async function to run after the BackupService has been set up. It is
    119 *   not passed any arguments.
    120 * @param {string} msg
    121 *   The message to write in the assertion when the regeneration occurs.
    122 */
    123 async function expectRegeneration(taskFn, msg) {
    124  let sandbox = sinon.createSandbox();
    125  // Override the default REGENERATION_DEBOUNCE_RATE_MS to 0 so that we don't
    126  // have to wait long for the debouncer to fire. We need to do this before
    127  // we construct the BackupService that we'll use for the test.
    128  sandbox.stub(BackupService, "REGENERATION_DEBOUNCE_RATE_MS").get(() => 0);
    129 
    130  let bs = new BackupService();
    131 
    132  // Now we set up a stub on the BackupService to detect calls to
    133  // createbackupOnIdleDispatch
    134  let createBackupDeferred = Promise.withResolvers();
    135  sandbox.stub(bs, "createBackupOnIdleDispatch").callsFake(options => {
    136    Assert.ok(true, "Saw createBackupOnIdleDispatch call");
    137    Assert.equal(
    138      options.reason,
    139      "user deleted some data",
    140      "Backup was recorded as being caused by user data deletion"
    141    );
    142    createBackupDeferred.resolve();
    143    return Promise.resolve();
    144  });
    145 
    146  // Creating a new backup will only occur if scheduled backups are enabled,
    147  // so let's set the pref...
    148  Services.prefs.setBoolPref("browser.backup.scheduled.enabled", true);
    149  Services.prefs.setBoolPref("browser.backup.archive.enabled", true);
    150  // But also stub out `onIdle` so that we don't get any interference during
    151  // our test by the idle service.
    152  sandbox.stub(bs, "onIdle").returns();
    153 
    154  bs.initBackupScheduler();
    155 
    156  await taskFn();
    157 
    158  // We'll wait for 1 second before considering the regeneration a bust.
    159  let timeoutPromise = new Promise((resolve, reject) =>
    160    // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    161    setTimeout(() => {
    162      reject();
    163    }, 1000)
    164  );
    165 
    166  try {
    167    await Promise.race([createBackupDeferred.promise, timeoutPromise]);
    168    Assert.ok(true, msg);
    169  } catch (e) {
    170    Assert.ok(false, "Timed out waiting for regeneration.");
    171  }
    172 
    173  bs.uninitBackupScheduler();
    174  Services.prefs.clearUserPref("browser.backup.scheduled.enabled");
    175  sandbox.restore();
    176 }
    177 
    178 /**
    179 * A helper function that sets up a BackupService to be instrumented to detect
    180 * a backup regeneration, and then runs an async taskFn to ensure that the
    181 * regeneration DOES NOT occur.
    182 *
    183 * @param {Function} taskFn
    184 *   The async function to run after the BackupService has been set up. It is
    185 *   not passed any arguments.
    186 * @param {string} msg
    187 *   The message to write in the assertion when the regeneration does not occur
    188 *   within the timeout.
    189 */
    190 async function expectNoRegeneration(taskFn, msg) {
    191  let sandbox = sinon.createSandbox();
    192  // Override the default REGENERATION_DEBOUNCE_RATE_MS to 0 so that we don't
    193  // have to wait long for the debouncer to fire. We need to do this before
    194  // we construct the BackupService that we'll use for the test.
    195  sandbox.stub(BackupService, "REGENERATION_DEBOUNCE_RATE_MS").get(() => 0);
    196 
    197  let bs = new BackupService();
    198 
    199  // Now we set up some stubs on the BackupService to detect calls to
    200  // deleteLastBackup and createbackupOnIdleDispatch, which are both called
    201  // on regeneration. We share the same Promise here because in either of these
    202  // being called, this test is a failure.
    203  let regenerationPromise = Promise.withResolvers();
    204  sandbox.stub(bs, "deleteLastBackup").callsFake(() => {
    205    Assert.ok(false, "Unexpectedly saw deleteLastBackup call");
    206    regenerationPromise.reject();
    207    return Promise.resolve();
    208  });
    209 
    210  sandbox.stub(bs, "createBackupOnIdleDispatch").callsFake(() => {
    211    Assert.ok(false, "Unexpectedly saw createBackupOnIdleDispatch call");
    212    regenerationPromise.reject();
    213    return Promise.resolve();
    214  });
    215 
    216  // Creating a new backup will only occur if scheduled backups are enabled,
    217  // so let's set the pref...
    218  Services.prefs.setBoolPref("browser.backup.scheduled.enabled", true);
    219  // But also stub out `onIdle` so that we don't get any interference during
    220  // our test by the idle service.
    221  sandbox.stub(bs, "onIdle").resolves();
    222 
    223  bs.initBackupScheduler();
    224 
    225  await taskFn();
    226 
    227  // We'll wait for 1 second, and if we don't see the regeneration attempt,
    228  // we'll assume it's not coming.
    229  let timeoutPromise = new Promise(resolve =>
    230    // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    231    setTimeout(() => {
    232      Assert.ok(true, "Saw no regeneration within 1 second.");
    233      resolve();
    234    }, 1000)
    235  );
    236 
    237  try {
    238    await Promise.race([regenerationPromise.promise, timeoutPromise]);
    239    Assert.ok(true, msg);
    240  } catch (e) {
    241    Assert.ok(false, "Saw an unexpected regeneration.");
    242  }
    243 
    244  bs.uninitBackupScheduler();
    245  Services.prefs.clearUserPref("browser.backup.scheduled.enabled");
    246  sandbox.restore();
    247 }
    248 
    249 add_setup(() => {
    250  CookieXPCShellUtils.createServer({ hosts: ["example.com"] });
    251  Services.prefs.setBoolPref("dom.security.https_first", false);
    252 
    253  // Allow all cookies.
    254  Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
    255  Services.prefs.setBoolPref(
    256    "network.cookieJarSettings.unblocked_for_testing",
    257    true
    258  );
    259 });
    260 
    261 /**
    262 * Tests that backup regeneration occurs on the page-removed PlacesObserver
    263 * event that indicates manual user deletion of a page from history.
    264 */
    265 add_task(async function test_page_removed_reason_deleted() {
    266  const PAGE_URI = "https://test.com";
    267  await addTestHistory(PAGE_URI);
    268  await expectRegeneration(async () => {
    269    await PlacesUtils.history.remove(PAGE_URI);
    270  }, "Saw regeneration on page-removed via user deletion.");
    271 });
    272 
    273 /**
    274 * Tests that backup regeneration does not occur on the page-removed
    275 * PlacesObserver event that indicates automatic deletion of a page from
    276 * history.
    277 */
    278 add_task(async function test_page_removed_reason_expired() {
    279  const PAGE_URI = "https://test.com";
    280  await addTestHistory(
    281    PAGE_URI,
    282    0 /* Timestamp at 0 is wayyyyy in the past, in the 1960's - it's the UNIX epoch start date */
    283  );
    284  await expectNoRegeneration(async () => {
    285    // This is how the Places tests force expiration, so we'll do it the same
    286    // way.
    287    let promise = TestUtils.topicObserved(
    288      PlacesUtils.TOPIC_EXPIRATION_FINISHED
    289    );
    290    let expire = Cc["@mozilla.org/places/expiration;1"].getService(
    291      Ci.nsIObserver
    292    );
    293    expire.observe(null, "places-debug-start-expiration", -1);
    294    await promise;
    295  }, "Saw no regeneration on page-removed via expiration.");
    296 });
    297 
    298 /**
    299 * Tests that backup regeneration occurs on the history-cleared PlacesObserver
    300 * event that indicates clearing of all user history.
    301 */
    302 add_task(async function test_history_cleared() {
    303  const PAGE_URI = "https://test.com";
    304  await addTestHistory(PAGE_URI);
    305  await expectRegeneration(async () => {
    306    await PlacesUtils.history.clear();
    307  }, "Saw regeneration on history-cleared.");
    308 });
    309 
    310 /**
    311 * Tests that backup regeneration occurs when removing a download from history.
    312 */
    313 add_task(async function test_download_removed() {
    314  const FAKE_FILE_PATH = PathUtils.join(PathUtils.tempDir, "somefile.zip");
    315  let download = {
    316    source: {
    317      url: "https://test.com/somefile",
    318      isPrivate: false,
    319    },
    320    target: { path: FAKE_FILE_PATH },
    321  };
    322  await DownloadHistory.addDownloadToHistory(download);
    323 
    324  await expectRegeneration(async () => {
    325    await PlacesUtils.history.remove(download.source.url);
    326  }, "Saw regeneration on download removal.");
    327 });
    328 
    329 /**
    330 * Tests that backup regeneration occurs when clearing all downloads.
    331 */
    332 add_task(async function test_all_downloads_removed() {
    333  const FAKE_FILE_PATH = PathUtils.join(PathUtils.tempDir, "somefile.zip");
    334  let download1 = {
    335    source: {
    336      url: "https://test.com/somefile",
    337      isPrivate: false,
    338    },
    339    target: { path: FAKE_FILE_PATH },
    340  };
    341  let download2 = {
    342    source: {
    343      url: "https://test.com/somefile2",
    344      isPrivate: false,
    345    },
    346    target: { path: FAKE_FILE_PATH },
    347  };
    348  await DownloadHistory.addDownloadToHistory(download1);
    349  await DownloadHistory.addDownloadToHistory(download2);
    350 
    351  await expectRegeneration(async () => {
    352    await PlacesUtils.history.removeVisitsByFilter({
    353      transition: PlacesUtils.history.TRANSITIONS.DOWNLOAD,
    354    });
    355  }, "Saw regeneration on all downloads removed.");
    356 });
    357 
    358 /**
    359 * Tests that backup regeneration occurs when removing a password.
    360 */
    361 add_task(async function test_password_removed() {
    362  let login = new nsLoginInfo(
    363    "https://example.com",
    364    "https://example.com",
    365    null,
    366    "notifyu1",
    367    "notifyp1",
    368    "user",
    369    "pass"
    370  );
    371  await Services.logins.addLoginAsync(login);
    372 
    373  await expectRegeneration(async () => {
    374    Services.logins.removeLogin(login);
    375  }, "Saw regeneration on password removed.");
    376 });
    377 
    378 /**
    379 * Tests that backup regeneration occurs when all passwords are removed.
    380 */
    381 add_task(async function test_all_passwords_removed() {
    382  let login1 = new nsLoginInfo(
    383    "https://example.com",
    384    "https://example.com",
    385    null,
    386    "notifyu1",
    387    "notifyp1",
    388    "user",
    389    "pass"
    390  );
    391  let login2 = new nsLoginInfo(
    392    "https://example.com",
    393    "https://example.com",
    394    null,
    395    "",
    396    "notifyp1",
    397    "",
    398    "pass"
    399  );
    400 
    401  await Services.logins.addLoginAsync(login1);
    402  await Services.logins.addLoginAsync(login2);
    403 
    404  await expectRegeneration(async () => {
    405    Services.logins.removeAllLogins();
    406  }, "Saw regeneration on all passwords removed.");
    407 });
    408 
    409 /**
    410 * Tests that backup regeneration occurs when removing a bookmark.
    411 */
    412 add_task(async function test_bookmark_removed() {
    413  let bookmark = await PlacesUtils.bookmarks.insert({
    414    parentGuid: PlacesUtils.bookmarks.unfiledGuid,
    415    url: "data:text/plain,Content",
    416    title: "Regeneration Test Bookmark",
    417  });
    418 
    419  await expectRegeneration(async () => {
    420    await PlacesUtils.bookmarks.remove(bookmark);
    421  }, "Saw regeneration on bookmark removed.");
    422 });
    423 
    424 /**
    425 * Tests that backup regeneration occurs when all bookmarks are removed.
    426 */
    427 add_task(async function test_all_bookmarks_removed() {
    428  await PlacesUtils.bookmarks.insert({
    429    parentGuid: PlacesUtils.bookmarks.unfiledGuid,
    430    url: "data:text/plain,Content",
    431    title: "Regeneration Test Bookmark 1",
    432  });
    433  await PlacesUtils.bookmarks.insert({
    434    parentGuid: PlacesUtils.bookmarks.unfiledGuid,
    435    url: "data:text/plain,Content2",
    436    title: "Regeneration Test Bookmark 2",
    437  });
    438 
    439  await expectRegeneration(async () => {
    440    await PlacesUtils.bookmarks.eraseEverything();
    441  }, "Saw regeneration on all bookmarks removed.");
    442 });
    443 
    444 /**
    445 * Tests that backup regeneration occurs when an addon is uninstalled.
    446 */
    447 add_task(async function test_addon_uninstalled() {
    448  await AddonTestUtils.promiseStartupManager();
    449 
    450  let testExtension = ExtensionTestUtils.loadExtension({
    451    manifest: {
    452      name: "Some test extension",
    453      browser_specific_settings: {
    454        gecko: { id: "test-backup-regeneration@ext-0" },
    455      },
    456    },
    457    useAddonManager: "temporary",
    458  });
    459 
    460  await testExtension.startup();
    461 
    462  await expectRegeneration(async () => {
    463    await testExtension.unload();
    464  }, "Saw regeneration on test extension uninstall.");
    465 });
    466 
    467 /**
    468 * Tests that backup regeneration occurs when removing a payment method.
    469 */
    470 add_task(async function test_payment_method_removed() {
    471  await formAutofillStorage.initialize();
    472  let guid = await formAutofillStorage.creditCards.add({
    473    "cc-name": "Foxy the Firefox",
    474    "cc-number": "5555555555554444",
    475    "cc-exp-month": 5,
    476    "cc-exp-year": 2099,
    477  });
    478 
    479  await expectRegeneration(async () => {
    480    await formAutofillStorage.creditCards.remove(guid);
    481  }, "Saw regeneration on payment method removal.");
    482 });
    483 
    484 /**
    485 * Tests that backup regeneration occurs when removing an address.
    486 */
    487 add_task(async function test_address_removed() {
    488  await formAutofillStorage.initialize();
    489  let guid = await formAutofillStorage.addresses.add({
    490    "given-name": "John",
    491    "additional-name": "R.",
    492    "family-name": "Smith",
    493    organization: "World Wide Web Consortium",
    494    "street-address": "32 Vassar Street\\\nMIT Room 32-G524",
    495    "address-level2": "Cambridge",
    496    "address-level1": "MA",
    497    "postal-code": "02139",
    498    country: "US",
    499    tel: "+15195555555",
    500    email: "user@example.com",
    501  });
    502 
    503  await expectRegeneration(async () => {
    504    await formAutofillStorage.addresses.remove(guid);
    505  }, "Saw regeneration on address removal.");
    506 });
    507 
    508 /**
    509 * Tests that backup regeneration occurs after any kind of data sanitization.
    510 */
    511 add_task(async function test_sanitization() {
    512  await expectRegeneration(async () => {
    513    await Sanitizer.sanitize(["cookiesAndStorage"]);
    514  }, "Saw regeneration on sanitization of cookies and storage.");
    515 
    516  await expectRegeneration(async () => {
    517    await Sanitizer.sanitize(["siteSettings"]);
    518  }, "Saw regeneration on sanitization of site settings.");
    519 });
    520 
    521 /**
    522 * Tests that backup regeneration occurs after a permission is removed.
    523 */
    524 add_task(async function test_permission_removed() {
    525  let principal =
    526    Services.scriptSecurityManager.createContentPrincipalFromOrigin(
    527      "https://test-permission-site.com"
    528    );
    529  const PERMISSION_TYPE = "desktop-notification";
    530  Services.perms.addFromPrincipal(
    531    principal,
    532    PERMISSION_TYPE,
    533    Services.perms.ALLOW_ACTION
    534  );
    535 
    536  await expectRegeneration(async () => {
    537    Services.perms.removeFromPrincipal(principal, PERMISSION_TYPE);
    538  }, "Saw regeneration on permission removal.");
    539 });
    540 
    541 /**
    542 * Tests that backup regeneration occurs when persistent and session cookies are
    543 * removed.
    544 */
    545 add_task(async function test_cookies_removed() {
    546  for (let isSessionCookie of [false, true]) {
    547    Services.cookies.removeAll();
    548 
    549    // First, let's remove a single cookie by host, path, name and origin
    550    // attrbutes.
    551    let name = addTestCookie(isSessionCookie);
    552 
    553    if (isSessionCookie) {
    554      Assert.equal(
    555        Services.cookies.sessionCookies.length,
    556        1,
    557        "Make sure we actually added a session cookie."
    558      );
    559    } else {
    560      Assert.equal(
    561        Services.cookies.sessionCookies.length,
    562        0,
    563        "Make sure we actually added a persistent cookie."
    564      );
    565    }
    566 
    567    await expectRegeneration(async () => {
    568      Services.cookies.remove(
    569        COOKIE_HOST,
    570        name,
    571        COOKIE_PATH,
    572        COOKIE_ORIGIN_ATTRIBUTES
    573      );
    574    }, "Saw regeneration on single cookie removal.");
    575 
    576    // Now remove all cookies for a particular host.
    577    addTestCookie(isSessionCookie);
    578    addTestCookie(isSessionCookie);
    579 
    580    await expectRegeneration(async () => {
    581      Services.cookies.removeCookiesFromExactHost(COOKIE_HOST, "{}");
    582    }, "Saw regeneration on cookie removal by host.");
    583 
    584    // Now remove all cookies.
    585    const COOKIES_TO_ADD = 10;
    586    for (let i = 0; i < COOKIES_TO_ADD; ++i) {
    587      addTestCookie(isSessionCookie);
    588    }
    589 
    590    await expectRegeneration(async () => {
    591      Services.cookies.removeAll();
    592    }, "Saw regeneration on all cookie removal.");
    593  }
    594 });
    595 
    596 /**
    597 * Tests that backup regeneration does not occur if a cookie is removed due
    598 * to expiry.
    599 */
    600 add_task(async function test_cookies_not_removed_expiry() {
    601  await expectNoRegeneration(async () => {
    602    const COOKIE = "test=test";
    603    await CookieXPCShellUtils.setCookieToDocument(
    604      "http://example.com/",
    605      COOKIE
    606    );
    607 
    608    // Now expire that cookie by using the same value, but setting the expires
    609    // directive to sometime wayyyyy in the past.
    610    const EXPIRE = `${COOKIE}; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
    611    await CookieXPCShellUtils.setCookieToDocument(
    612      "http://example.com/",
    613      EXPIRE
    614    );
    615  }, "Saw no regeneration on cookie expiry.");
    616 });
    617 
    618 /**
    619 * Tests that backup regeneration occurs when newtab links are blocked.
    620 */
    621 add_task(async function test_newtab_link_blocked() {
    622  NewTabUtils.init();
    623 
    624  await expectRegeneration(async () => {
    625    NewTabUtils.activityStreamLinks.blockURL("https://example.com");
    626  }, "Saw regeneration on the blocking of a newtab link");
    627 });
    628 
    629 /**
    630 * Tests that backup regeneration occurs when sanitizeOnShutdown is enabled
    631 * or disabled
    632 */
    633 add_task(async function test_sanitizeOnShutdown_regeneration() {
    634  await expectRegeneration(() => {
    635    Services.prefs.setBoolPref("privacy.sanitize.sanitizeOnShutdown", true);
    636  }, "Saw a regeneration when sanitizeOnShutdown was enabled");
    637 
    638  await expectRegeneration(() => {
    639    Services.prefs.setBoolPref("privacy.sanitize.sanitizeOnShutdown", false);
    640  }, "Saw a regeneration when sanitizeOnShutdown was disabled");
    641 
    642  Services.prefs.clearUserPref("privacy.sanitize.sanitizeOnShutdown");
    643 });
    644 
    645 /**
    646 * Tests that setting up a regeneration without archiveEnabledStatus being true
    647 * leads to NO regeneration upon data mutation
    648 */
    649 add_task(async function test_enabledStatus_no_regeneration() {
    650  let bookmark = await PlacesUtils.bookmarks.insert({
    651    parentGuid: PlacesUtils.bookmarks.unfiledGuid,
    652    url: "data:text/plain,Content",
    653    title: "Regeneration Test Bookmark",
    654  });
    655 
    656  Services.prefs.setBoolPref("browser.backup.archive.enabled", false);
    657 
    658  await expectNoRegeneration(async () => {
    659    await PlacesUtils.bookmarks.remove(bookmark);
    660  }, "Saw no regeneration on bookmark removed.");
    661 
    662  Services.prefs.clearUserPref("browser.backup.archive.enabled");
    663 });