tor-browser

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

test_shutdownDuringAllTemporaryOriginsInitialization.js (6470B)


      1 /**
      2 * Any copyright is dedicated to the Public Domain.
      3 * http://creativecommons.org/publicdomain/zero/1.0/
      4 */
      5 
      6 const { FileUtils } = ChromeUtils.importESModule(
      7  "resource://testing-common/dom/quota/test/modules/FileUtils.sys.mjs"
      8 );
      9 const { PrincipalUtils } = ChromeUtils.importESModule(
     10  "resource://testing-common/dom/quota/test/modules/PrincipalUtils.sys.mjs"
     11 );
     12 const { QuotaUtils } = ChromeUtils.importESModule(
     13  "resource://testing-common/dom/quota/test/modules/QuotaUtils.sys.mjs"
     14 );
     15 const { TestUtils } = ChromeUtils.importESModule(
     16  "resource://testing-common/TestUtils.sys.mjs"
     17 );
     18 
     19 /**
     20 * This test verifies the behavior when a shutdown occurs during the
     21 * initialization of all temporary origins in the background.
     22 *
     23 * Test Setup & Procedure:
     24 * 1. Lazy Origin Initialization Enabled
     25 *    - The test runs with lazy origin initialization enabled, meaning that
     26 *      calling `Services.qms.initTemporaryStorage` does not initialize
     27 *      individual origins.
     28 *
     29 * 2. Preparation of Existing Profile
     30 *    - Two origins belonging to the same eTLD+1 group are created.
     31 *
     32 * 3. Removal of Metadata Files
     33 *    - Metadata files are removed to force restoration, providing a way
     34 *      to check whether origin initialization has occurred.
     35 *
     36 * 4. Triggering Initialization of All Temporary Origins
     37 *    - The test explicitly triggers the initialization of all temporary
     38 *      origins by calling `Services.qms.initializeAllTemporaryOrigins`.
     39 *
     40 * 5. Inducing a Controlled Shutdown
     41 *    - The test waits for the first origin to begin initialization.
     42 *    - Once initialization starts, shutdown is triggered.
     43 *    - A 2-second delay is introduced in origin initialization to ensure
     44 *      the shutdown signal has time to propagate.
     45 *
     46 * 6. Expected Behavior & Verification
     47 *    - Due to the shutdown, the second origin does not initialize.
     48 *    - Since active operations are not available during shutdown, the test
     49 *      verifies initialization by checking whether the metadata file has
     50 *      been restored for the given origin.
     51 *
     52 * Notes & Justification:
     53 * - This approach has been successfully used in other tests to handle
     54 *   shutdown scenarios.
     55 * - See also:
     56 *   https://searchfox.org/mozilla-central/rev/d5baa11e35e0186c3c867f4948010f0742198467/modules/libpref/init/StaticPrefList.yaml#3789-3846
     57 */
     58 async function testShutdownDuringAllTemporaryOriginsInitialization() {
     59  // This test creates two origins belonging to the same eTLD+1 group on
     60  // purpose to test specific shutdown check.
     61  const principal1 = PrincipalUtils.createPrincipal("https://1.example.com");
     62  const principal2 = PrincipalUtils.createPrincipal("https://2.example.com");
     63  const metadata1 = FileUtils.getFile(
     64    "storage/default/https+++1.example.com/.metadata-v2"
     65  );
     66  const metadata2 = FileUtils.getFile(
     67    "storage/default/https+++2.example.com/.metadata-v2"
     68  );
     69 
     70  // Preparation phase: simulating an existing profile with pre-existing
     71  // storage. At least two temporary origins must already exist.
     72  info("Clearing storage");
     73 
     74  {
     75    const request = Services.qms.clear();
     76    await QuotaUtils.requestFinished(request);
     77  }
     78 
     79  info("Initializing storage");
     80 
     81  {
     82    const request = Services.qms.init();
     83    await QuotaUtils.requestFinished(request);
     84  }
     85 
     86  info("Initializing temporary storage");
     87 
     88  {
     89    const request = Services.qms.initTemporaryStorage();
     90    await QuotaUtils.requestFinished(request);
     91  }
     92 
     93  info("Initializing temporary origin");
     94 
     95  {
     96    const request = Services.qms.initializeTemporaryOrigin(
     97      "default",
     98      principal1,
     99      /* aCreateIfNonExistent */ true
    100    );
    101    await QuotaUtils.requestFinished(request);
    102  }
    103 
    104  info("Initializing temporary origin");
    105 
    106  {
    107    const request = Services.qms.initializeTemporaryOrigin(
    108      "default",
    109      principal2,
    110      /* aCreateIfNonExistent */ true
    111    );
    112    await QuotaUtils.requestFinished(request);
    113  }
    114 
    115  // Restore the original uninitialized state to force reinitialization of both
    116  // storage and temporary storage.
    117  info("Shutting down storage");
    118 
    119  {
    120    const request = Services.qms.reset();
    121    await QuotaUtils.requestFinished(request);
    122  }
    123 
    124  // Reinitialize storage and temporary storage.
    125  info("Initializing storage");
    126 
    127  {
    128    const request = Services.qms.init();
    129    await QuotaUtils.requestFinished(request);
    130  }
    131 
    132  info("Initializing temporary storage");
    133 
    134  {
    135    const request = Services.qms.initTemporaryStorage();
    136    await QuotaUtils.requestFinished(request);
    137  }
    138 
    139  info("Removing origin metadata");
    140 
    141  metadata1.remove(false);
    142 
    143  info("Removing origin metadata");
    144 
    145  metadata2.remove(false);
    146 
    147  // Now trigger the initialization of all temporary origins, which normally
    148  // happens automatically when incremental origin initialization is enabled
    149  // and temporary storage initialization is complete.
    150  info("Starting all temporary origins initialization");
    151 
    152  const initPromise = (async function () {
    153    const request = Services.qms.initializeAllTemporaryOrigins();
    154    const promise = QuotaUtils.requestFinished(request);
    155    return promise;
    156  })();
    157 
    158  info("Waiting for origin initialization to start");
    159 
    160  await TestUtils.topicObserved("QuotaManager::OriginInitializationStarted");
    161 
    162  info("Starting shutdown");
    163 
    164  QuotaUtils.startShutdown();
    165 
    166  info("Waiting for all temoporary origins initialization to finish");
    167 
    168  await initPromise;
    169 
    170  info("Metadata file for first origin exists: " + metadata1.exists());
    171 
    172  info("Metadata file for second origin exists: " + metadata2.exists());
    173 
    174  // Once shutdown has started, we can no longer use the Quota Manager Service
    175  // to check the initialization status of origins, as any new operation will
    176  // fail. However, we can determine if the initialization of all origins was
    177  // aborted due to shutdown by checking for the existence of origin metadata
    178  // files, which were artificially removed earlier.
    179  Assert.notEqual(
    180    metadata1.exists(),
    181    metadata2.exists(),
    182    "Metadata for the second origin is not restored"
    183  );
    184 }
    185 
    186 /* exported testSteps */
    187 async function testSteps() {
    188  add_task(
    189    {
    190      pref_set: [
    191        ["dom.quotaManager.temporaryStorage.lazyOriginInitialization", true],
    192        ["dom.quotaManager.loadQuotaFromCache", false],
    193        ["dom.quotaManager.loadQuotaFromSecondaryCache", false],
    194        ["dom.quotaManager.originInitialization.pauseOnIOThreadMs", 2000],
    195      ],
    196    },
    197    testShutdownDuringAllTemporaryOriginsInitialization
    198  );
    199 }