tor-browser

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

test_qm_first_initialization_attempt.js (22600B)


      1 /**
      2 * Any copyright is dedicated to the Public Domain.
      3 * http://creativecommons.org/publicdomain/zero/1.0/
      4 */
      5 
      6 const { AppConstants } = ChromeUtils.importESModule(
      7  "resource://gre/modules/AppConstants.sys.mjs"
      8 );
      9 const { TelemetryTestUtils } = ChromeUtils.importESModule(
     10  "resource://testing-common/TelemetryTestUtils.sys.mjs"
     11 );
     12 
     13 const storageDirName = "storage";
     14 const storageFileName = "storage.sqlite";
     15 const indexedDBDirName = "indexedDB";
     16 const persistentStorageDirName = "storage/persistent";
     17 const histogramName = "QM_FIRST_INITIALIZATION_ATTEMPT";
     18 
     19 const testcases = [
     20  {
     21    mainKey: "Storage",
     22    async setup(expectedInitResult) {
     23      if (!expectedInitResult) {
     24        // Make the database unusable by creating it as a directory (not a
     25        // file).
     26        const storageFile = getRelativeFile(storageFileName);
     27        storageFile.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
     28      }
     29    },
     30    initFunction: init,
     31    expectedSnapshots: {
     32      initFailure: {
     33        // mainKey
     34        Storage: {
     35          values: [1, 0],
     36        },
     37      },
     38      initFailureThenSuccess: {
     39        // mainKey
     40        Storage: {
     41          values: [1, 1, 0],
     42        },
     43      },
     44    },
     45  },
     46  {
     47    mainKey: "TemporaryStorage",
     48    async setup(expectedInitResult) {
     49      // We need to initialize storage before populating the repositories. If
     50      // we don't do that, the storage directory created for the repositories
     51      // would trigger storage upgrades (from version 0 to current version).
     52      let request = init();
     53      await requestFinished(request);
     54 
     55      populateRepository("temporary");
     56      populateRepository("default");
     57 
     58      if (!expectedInitResult) {
     59        makeRepositoryUnusable("temporary");
     60        makeRepositoryUnusable("default");
     61      }
     62    },
     63    initFunction: initTemporaryStorage,
     64    getExpectedSnapshots() {
     65      const expectedSnapshotsInNightly = {
     66        initFailure: {
     67          Storage: {
     68            values: [0, 1, 0],
     69          },
     70          TemporaryRepository: {
     71            values: [1, 0],
     72          },
     73          DefaultRepository: {
     74            values: [1, 0],
     75          },
     76          // mainKey
     77          TemporaryStorage: {
     78            values: [1, 0],
     79          },
     80        },
     81        initFailureThenSuccess: {
     82          Storage: {
     83            values: [0, 2, 0],
     84          },
     85          TemporaryRepository: {
     86            values: [1, 1, 0],
     87          },
     88          DefaultRepository: {
     89            values: [1, 1, 0],
     90          },
     91          // mainKey
     92          TemporaryStorage: {
     93            values: [1, 1, 0],
     94          },
     95        },
     96      };
     97 
     98      const expectedSnapshotsInOthers = {
     99        initFailure: {
    100          Storage: {
    101            values: [0, 1, 0],
    102          },
    103          TemporaryRepository: {
    104            values: [1, 0],
    105          },
    106          // mainKey
    107          TemporaryStorage: {
    108            values: [1, 0],
    109          },
    110        },
    111        initFailureThenSuccess: {
    112          Storage: {
    113            values: [0, 2, 0],
    114          },
    115          TemporaryRepository: {
    116            values: [1, 1, 0],
    117          },
    118          DefaultRepository: {
    119            values: [0, 1, 0],
    120          },
    121          // mainKey
    122          TemporaryStorage: {
    123            values: [1, 1, 0],
    124          },
    125        },
    126      };
    127 
    128      return AppConstants.NIGHTLY_BUILD
    129        ? expectedSnapshotsInNightly
    130        : expectedSnapshotsInOthers;
    131    },
    132  },
    133  {
    134    mainKey: "DefaultRepository",
    135    async setup(expectedInitResult) {
    136      // See the comment for "TemporaryStorage".
    137      let request = init();
    138      await requestFinished(request);
    139 
    140      populateRepository("default");
    141 
    142      if (!expectedInitResult) {
    143        makeRepositoryUnusable("default");
    144      }
    145    },
    146    initFunction: initTemporaryStorage,
    147    expectedSnapshots: {
    148      initFailure: {
    149        Storage: {
    150          values: [0, 1, 0],
    151        },
    152        TemporaryRepository: {
    153          values: [0, 1, 0],
    154        },
    155        // mainKey
    156        DefaultRepository: {
    157          values: [1, 0],
    158        },
    159        TemporaryStorage: {
    160          values: [1, 0],
    161        },
    162      },
    163      initFailureThenSuccess: {
    164        Storage: {
    165          values: [0, 2, 0],
    166        },
    167        TemporaryRepository: {
    168          values: [0, 2, 0],
    169        },
    170        // mainKey
    171        DefaultRepository: {
    172          values: [1, 1, 0],
    173        },
    174        TemporaryStorage: {
    175          values: [1, 1, 0],
    176        },
    177      },
    178    },
    179  },
    180  {
    181    mainKey: "TemporaryRepository",
    182    async setup(expectedInitResult) {
    183      // See the comment for "TemporaryStorage".
    184      let request = init();
    185      await requestFinished(request);
    186 
    187      populateRepository("temporary");
    188 
    189      if (!expectedInitResult) {
    190        makeRepositoryUnusable("temporary");
    191      }
    192    },
    193    initFunction: initTemporaryStorage,
    194    getExpectedSnapshots() {
    195      const expectedSnapshotsInNightly = {
    196        initFailure: {
    197          Storage: {
    198            values: [0, 1, 0],
    199          },
    200          // mainKey
    201          TemporaryRepository: {
    202            values: [1, 0],
    203          },
    204          DefaultRepository: {
    205            values: [0, 1, 0],
    206          },
    207          TemporaryStorage: {
    208            values: [1, 0],
    209          },
    210        },
    211        initFailureThenSuccess: {
    212          Storage: {
    213            values: [0, 2, 0],
    214          },
    215          // mainKey
    216          TemporaryRepository: {
    217            values: [1, 1, 0],
    218          },
    219          DefaultRepository: {
    220            values: [0, 2, 0],
    221          },
    222          TemporaryStorage: {
    223            values: [1, 1, 0],
    224          },
    225        },
    226      };
    227 
    228      const expectedSnapshotsInOthers = {
    229        initFailure: {
    230          Storage: {
    231            values: [0, 1, 0],
    232          },
    233          // mainKey
    234          TemporaryRepository: {
    235            values: [1, 0],
    236          },
    237          TemporaryStorage: {
    238            values: [1, 0],
    239          },
    240        },
    241        initFailureThenSuccess: {
    242          Storage: {
    243            values: [0, 2, 0],
    244          },
    245          // mainKey
    246          TemporaryRepository: {
    247            values: [1, 1, 0],
    248          },
    249          DefaultRepository: {
    250            values: [0, 1, 0],
    251          },
    252          TemporaryStorage: {
    253            values: [1, 1, 0],
    254          },
    255        },
    256      };
    257 
    258      return AppConstants.NIGHTLY_BUILD
    259        ? expectedSnapshotsInNightly
    260        : expectedSnapshotsInOthers;
    261    },
    262  },
    263  {
    264    mainKey: "UpgradeStorageFrom0_0To1_0",
    265    async setup(expectedInitResult) {
    266      // storage used prior FF 49 (storage version 0.0)
    267      installPackage("version0_0_profile");
    268 
    269      if (!expectedInitResult) {
    270        installPackage("version0_0_make_it_unusable");
    271      }
    272    },
    273    initFunction: init,
    274    expectedSnapshots: {
    275      initFailure: {
    276        // mainKey
    277        UpgradeStorageFrom0_0To1_0: {
    278          values: [1, 0],
    279        },
    280        Storage: {
    281          values: [1, 0],
    282        },
    283      },
    284      initFailureThenSuccess: {
    285        // mainKey
    286        UpgradeStorageFrom0_0To1_0: {
    287          values: [1, 1, 0],
    288        },
    289        UpgradeStorageFrom1_0To2_0: {
    290          values: [0, 1, 0],
    291        },
    292        UpgradeStorageFrom2_0To2_1: {
    293          values: [0, 1, 0],
    294        },
    295        UpgradeStorageFrom2_1To2_2: {
    296          values: [0, 1, 0],
    297        },
    298        UpgradeStorageFrom2_2To2_3: {
    299          values: [0, 1, 0],
    300        },
    301        Storage: {
    302          values: [1, 1, 0],
    303        },
    304      },
    305    },
    306  },
    307  {
    308    mainKey: "UpgradeStorageFrom1_0To2_0",
    309    async setup(expectedInitResult) {
    310      // storage used by FF 49-54 (storage version 1.0)
    311      installPackage("version1_0_profile");
    312 
    313      if (!expectedInitResult) {
    314        installPackage("version1_0_make_it_unusable");
    315      }
    316    },
    317    initFunction: init,
    318    expectedSnapshots: {
    319      initFailure: {
    320        // mainKey
    321        UpgradeStorageFrom1_0To2_0: {
    322          values: [1, 0],
    323        },
    324        Storage: {
    325          values: [1, 0],
    326        },
    327      },
    328      initFailureThenSuccess: {
    329        // mainKey
    330        UpgradeStorageFrom1_0To2_0: {
    331          values: [1, 1, 0],
    332        },
    333        UpgradeStorageFrom2_0To2_1: {
    334          values: [0, 1, 0],
    335        },
    336        UpgradeStorageFrom2_1To2_2: {
    337          values: [0, 1, 0],
    338        },
    339        UpgradeStorageFrom2_2To2_3: {
    340          values: [0, 1, 0],
    341        },
    342        Storage: {
    343          values: [1, 1, 0],
    344        },
    345      },
    346    },
    347  },
    348  {
    349    mainKey: "UpgradeStorageFrom2_0To2_1",
    350    async setup(expectedInitResult) {
    351      // storage used by FF 55-56 (storage version 2.0)
    352      installPackage("version2_0_profile");
    353 
    354      if (!expectedInitResult) {
    355        installPackage("version2_0_make_it_unusable");
    356      }
    357    },
    358    initFunction: init,
    359    expectedSnapshots: {
    360      initFailure: {
    361        // mainKey
    362        UpgradeStorageFrom2_0To2_1: {
    363          values: [1, 0],
    364        },
    365        Storage: {
    366          values: [1, 0],
    367        },
    368      },
    369      initFailureThenSuccess: {
    370        // mainKey
    371        UpgradeStorageFrom2_0To2_1: {
    372          values: [1, 1, 0],
    373        },
    374        UpgradeStorageFrom2_1To2_2: {
    375          values: [0, 1, 0],
    376        },
    377        UpgradeStorageFrom2_2To2_3: {
    378          values: [0, 1, 0],
    379        },
    380        Storage: {
    381          values: [1, 1, 0],
    382        },
    383      },
    384    },
    385  },
    386  {
    387    mainKey: "UpgradeStorageFrom2_1To2_2",
    388    async setup(expectedInitResult) {
    389      // storage used by FF 57-67 (storage version 2.1)
    390      installPackage("version2_1_profile");
    391 
    392      if (!expectedInitResult) {
    393        installPackage("version2_1_make_it_unusable");
    394      }
    395    },
    396    initFunction: init,
    397    expectedSnapshots: {
    398      initFailure: {
    399        // mainKey
    400        UpgradeStorageFrom2_1To2_2: {
    401          values: [1, 0],
    402        },
    403        Storage: {
    404          values: [1, 0],
    405        },
    406      },
    407      initFailureThenSuccess: {
    408        // mainKey
    409        UpgradeStorageFrom2_1To2_2: {
    410          values: [1, 1, 0],
    411        },
    412        UpgradeStorageFrom2_2To2_3: {
    413          values: [0, 1, 0],
    414        },
    415        Storage: {
    416          values: [1, 1, 0],
    417        },
    418      },
    419    },
    420  },
    421  {
    422    mainKey: "UpgradeStorageFrom2_2To2_3",
    423    async setup(expectedInitResult) {
    424      // storage used by FF 68-69 (storage version 2.2)
    425      installPackage("version2_2_profile");
    426 
    427      if (!expectedInitResult) {
    428        installPackage(
    429          "version2_2_make_it_unusable",
    430          /* allowFileOverwrites */ true
    431        );
    432      }
    433    },
    434    initFunction: init,
    435    expectedSnapshots: {
    436      initFailure: {
    437        // mainKey
    438        UpgradeStorageFrom2_2To2_3: {
    439          values: [1, 0],
    440        },
    441        Storage: {
    442          values: [1, 0],
    443        },
    444      },
    445      initFailureThenSuccess: {
    446        // mainKey
    447        UpgradeStorageFrom2_2To2_3: {
    448          values: [1, 1, 0],
    449        },
    450        Storage: {
    451          values: [1, 1, 0],
    452        },
    453      },
    454    },
    455  },
    456  {
    457    mainKey: "UpgradeFromIndexedDBDirectory",
    458    async setup(expectedInitResult) {
    459      const indexedDBDir = getRelativeFile(indexedDBDirName);
    460      indexedDBDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
    461 
    462      if (!expectedInitResult) {
    463        // "indexedDB" directory will be moved under "storage" directory and at
    464        // the same time renamed to "persistent". Create a storage file to cause
    465        // the moves to fail.
    466        const storageFile = getRelativeFile(storageDirName);
    467        storageFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
    468      }
    469    },
    470    initFunction: init,
    471    expectedSnapshots: {
    472      initFailure: {
    473        // mainKey
    474        UpgradeFromIndexedDBDirectory: {
    475          values: [1, 0],
    476        },
    477        Storage: {
    478          values: [1, 0],
    479        },
    480      },
    481      initFailureThenSuccess: {
    482        // mainKey
    483        UpgradeFromIndexedDBDirectory: {
    484          values: [1, 1, 0],
    485        },
    486        UpgradeFromPersistentStorageDirectory: {
    487          values: [0, 1, 0],
    488        },
    489        UpgradeStorageFrom0_0To1_0: {
    490          values: [0, 1, 0],
    491        },
    492        UpgradeStorageFrom1_0To2_0: {
    493          values: [0, 1, 0],
    494        },
    495        UpgradeStorageFrom2_0To2_1: {
    496          values: [0, 1, 0],
    497        },
    498        UpgradeStorageFrom2_1To2_2: {
    499          values: [0, 1, 0],
    500        },
    501        UpgradeStorageFrom2_2To2_3: {
    502          values: [0, 1, 0],
    503        },
    504        Storage: {
    505          values: [1, 1, 0],
    506        },
    507      },
    508    },
    509  },
    510  {
    511    mainKey: "UpgradeFromPersistentStorageDirectory",
    512    async setup(expectedInitResult) {
    513      const persistentStorageDir = getRelativeFile(persistentStorageDirName);
    514      persistentStorageDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
    515 
    516      if (!expectedInitResult) {
    517        // Create a metadata directory to break creating or upgrading directory
    518        // metadata files.
    519        const metadataDir = getRelativeFile(
    520          "storage/persistent/https+++bad.example.com/.metadata"
    521        );
    522        metadataDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
    523      }
    524    },
    525    initFunction: init,
    526    expectedSnapshots: {
    527      initFailure: {
    528        // mainKey
    529        UpgradeFromPersistentStorageDirectory: {
    530          values: [1, 0],
    531        },
    532        Storage: {
    533          values: [1, 0],
    534        },
    535      },
    536      initFailureThenSuccess: {
    537        // mainKey
    538        UpgradeFromPersistentStorageDirectory: {
    539          values: [1, 1, 0],
    540        },
    541        UpgradeStorageFrom0_0To1_0: {
    542          values: [0, 1, 0],
    543        },
    544        UpgradeStorageFrom1_0To2_0: {
    545          values: [0, 1, 0],
    546        },
    547        UpgradeStorageFrom2_0To2_1: {
    548          values: [0, 1, 0],
    549        },
    550        UpgradeStorageFrom2_1To2_2: {
    551          values: [0, 1, 0],
    552        },
    553        UpgradeStorageFrom2_2To2_3: {
    554          values: [0, 1, 0],
    555        },
    556        Storage: {
    557          values: [1, 1, 0],
    558        },
    559      },
    560    },
    561  },
    562  {
    563    mainKey: "PersistentOrigin",
    564    async setup(expectedInitResult) {
    565      // We need to initialize storage before creating the origin files. If we
    566      // don't do that, the storage directory created for the origin files
    567      // would trigger storage upgrades (from version 0 to current version).
    568      let request = init();
    569      await requestFinished(request);
    570 
    571      if (!expectedInitResult) {
    572        const originFiles = [
    573          getRelativeFile("storage/permanent/https+++example.com"),
    574          getRelativeFile("storage/permanent/https+++example1.com"),
    575          getRelativeFile("storage/default/https+++example2.com"),
    576        ];
    577 
    578        for (const originFile of originFiles) {
    579          originFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
    580        }
    581      }
    582 
    583      request = initTemporaryStorage();
    584      await requestFinished(request);
    585    },
    586    initFunctions: [
    587      {
    588        name: initPersistentOrigin,
    589        args: [getPrincipal("https://example.com")],
    590      },
    591      {
    592        name: initPersistentOrigin,
    593        args: [getPrincipal("https://example1.com")],
    594      },
    595      {
    596        name: initTemporaryOrigin,
    597        args: [
    598          "default",
    599          getPrincipal("https://example2.com"),
    600          /* createIfNonExistent */ true,
    601        ],
    602      },
    603    ],
    604    expectedSnapshots: {
    605      initFailure: {
    606        Storage: {
    607          values: [0, 1, 0],
    608        },
    609        TemporaryRepository: {
    610          values: [0, 1, 0],
    611        },
    612        DefaultRepository: {
    613          values: [0, 1, 0],
    614        },
    615        TemporaryStorage: {
    616          values: [0, 1, 0],
    617        },
    618        // mainKey
    619        PersistentOrigin: {
    620          values: [2, 0],
    621        },
    622        TemporaryOrigin: {
    623          values: [1, 0],
    624        },
    625      },
    626      initFailureThenSuccess: {
    627        Storage: {
    628          values: [0, 2, 0],
    629        },
    630        TemporaryRepository: {
    631          values: [0, 2, 0],
    632        },
    633        DefaultRepository: {
    634          values: [0, 2, 0],
    635        },
    636        TemporaryStorage: {
    637          values: [0, 2, 0],
    638        },
    639        // mainKey
    640        PersistentOrigin: {
    641          values: [2, 2, 0],
    642        },
    643        TemporaryOrigin: {
    644          values: [1, 1, 0],
    645        },
    646      },
    647    },
    648  },
    649  {
    650    mainKey: "TemporaryOrigin",
    651    async setup(expectedInitResult) {
    652      // See the comment for "PersistentOrigin".
    653      let request = init();
    654      await requestFinished(request);
    655 
    656      if (!expectedInitResult) {
    657        const originFiles = [
    658          getRelativeFile("storage/temporary/https+++example.com"),
    659          getRelativeFile("storage/default/https+++example.com"),
    660          getRelativeFile("storage/default/https+++example1.com"),
    661          getRelativeFile("storage/permanent/https+++example2.com"),
    662        ];
    663 
    664        for (const originFile of originFiles) {
    665          originFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
    666        }
    667      }
    668 
    669      request = initTemporaryStorage();
    670      await requestFinished(request);
    671    },
    672    initFunctions: [
    673      {
    674        name: initTemporaryOrigin,
    675        args: [
    676          "temporary",
    677          getPrincipal("https://example.com"),
    678          /* createIfNonExistent */ true,
    679        ],
    680      },
    681      {
    682        name: initTemporaryOrigin,
    683        args: [
    684          "default",
    685          getPrincipal("https://example.com"),
    686          /* createIfNonExistent */ true,
    687        ],
    688      },
    689      {
    690        name: initTemporaryOrigin,
    691        args: [
    692          "default",
    693          getPrincipal("https://example1.com"),
    694          /* createIfNonExistent */ true,
    695        ],
    696      },
    697      {
    698        name: initPersistentOrigin,
    699        args: [getPrincipal("https://example2.com")],
    700      },
    701    ],
    702    // Only the first result of EnsureTemporaryOriginIsInitialized per origin
    703    // should be reported. Thus, only the results for (temporary, example.com),
    704    // and (default, example1.com) should be reported.
    705    expectedSnapshots: {
    706      initFailure: {
    707        Storage: {
    708          values: [0, 1, 0],
    709        },
    710        TemporaryRepository: {
    711          values: [0, 1, 0],
    712        },
    713        DefaultRepository: {
    714          values: [0, 1, 0],
    715        },
    716        TemporaryStorage: {
    717          values: [0, 1, 0],
    718        },
    719        PersistentOrigin: {
    720          values: [1, 0],
    721        },
    722        // mainKey
    723        TemporaryOrigin: {
    724          values: [2, 0],
    725        },
    726      },
    727      initFailureThenSuccess: {
    728        Storage: {
    729          values: [0, 2, 0],
    730        },
    731        TemporaryRepository: {
    732          values: [0, 2, 0],
    733        },
    734        DefaultRepository: {
    735          values: [0, 2, 0],
    736        },
    737        TemporaryStorage: {
    738          values: [0, 2, 0],
    739        },
    740        PersistentOrigin: {
    741          values: [1, 1, 0],
    742        },
    743        // mainKey
    744        TemporaryOrigin: {
    745          values: [2, 2, 0],
    746        },
    747      },
    748    },
    749  },
    750 ];
    751 
    752 loadScript("dom/quota/test/xpcshell/common/utils.js");
    753 
    754 function verifyHistogram(histogram, mainKey, expectedSnapshot) {
    755  const snapshot = histogram.snapshot();
    756 
    757  ok(
    758    mainKey in snapshot,
    759    `The histogram ${histogram.name()} must contain the main key ${mainKey}`
    760  );
    761 
    762  const keys = Object.keys(snapshot);
    763 
    764  is(
    765    keys.length,
    766    Object.keys(expectedSnapshot).length,
    767    `The number of keys must match the expected number of keys for ` +
    768      `${histogram.name()}`
    769  );
    770 
    771  for (const key of keys) {
    772    ok(
    773      key in expectedSnapshot,
    774      `The key ${key} must match the expected keys for ${histogram.name()}`
    775    );
    776 
    777    const values = Object.entries(snapshot[key].values);
    778    const expectedValues = expectedSnapshot[key].values;
    779 
    780    is(
    781      values.length,
    782      expectedValues.length,
    783      `The number of values should match the expected number of values for ` +
    784        `${histogram.name()}`
    785    );
    786 
    787    for (let [i, val] of values) {
    788      is(
    789        val,
    790        expectedValues[i],
    791        `Expected counts should match for ${histogram.name()} at index ${i}`
    792      );
    793    }
    794  }
    795 }
    796 
    797 async function testSteps() {
    798  let request;
    799  for (const testcase of testcases) {
    800    const mainKey = testcase.mainKey;
    801 
    802    info(`Verifying ${histogramName} histogram for the main key ${mainKey}`);
    803 
    804    const histogram =
    805      TelemetryTestUtils.getAndClearKeyedHistogram(histogramName);
    806 
    807    for (const expectedInitResult of [false, true]) {
    808      info(
    809        `Verifying the histogram when the initialization ` +
    810          `${expectedInitResult ? "failed and then succeeds" : "fails"}`
    811      );
    812 
    813      await testcase.setup(expectedInitResult);
    814 
    815      const msg = `Should ${expectedInitResult ? "not " : ""} have thrown`;
    816 
    817      // Call the initialization function twice, so we can verify below that
    818      // only the first initialization attempt has been reported.
    819      for (let i = 0; i < 2; ++i) {
    820        let initFunctions;
    821 
    822        if (testcase.initFunctions) {
    823          initFunctions = testcase.initFunctions;
    824        } else {
    825          initFunctions = [
    826            {
    827              name: testcase.initFunction,
    828              args: [],
    829            },
    830          ];
    831        }
    832 
    833        for (const initFunction of initFunctions) {
    834          request = initFunction.name(...initFunction.args);
    835          try {
    836            await requestFinished(request);
    837            ok(expectedInitResult, msg);
    838          } catch (ex) {
    839            ok(!expectedInitResult, msg);
    840          }
    841        }
    842      }
    843 
    844      const expectedSnapshots = testcase.getExpectedSnapshots
    845        ? testcase.getExpectedSnapshots()
    846        : testcase.expectedSnapshots;
    847 
    848      const expectedSnapshot = expectedInitResult
    849        ? expectedSnapshots.initFailureThenSuccess
    850        : expectedSnapshots.initFailure;
    851 
    852      verifyHistogram(histogram, mainKey, expectedSnapshot);
    853 
    854      // The first initialization attempt has been reported in the histogram
    855      // and any new attemps wouldn't be reported if we didn't reset or clear
    856      // the storage here. We need a clean profile for the next iteration
    857      // anyway.
    858      // However, the clear storage operation needs initialized storage, so
    859      // clearing can fail if the storage is unusable and it can also increase
    860      // some of the telemetry counters. Instead of calling clear, we can just
    861      // call reset and clear profile manually.
    862      request = reset();
    863      await requestFinished(request);
    864 
    865      const indexedDBDir = getRelativeFile(indexedDBDirName);
    866      if (indexedDBDir.exists()) {
    867        indexedDBDir.remove(false);
    868      }
    869 
    870      const storageDir = getRelativeFile(storageDirName);
    871      if (storageDir.exists()) {
    872        storageDir.remove(true);
    873      }
    874 
    875      const storageFile = getRelativeFile(storageFileName);
    876      if (storageFile.exists()) {
    877        // It could be a non empty directory, so remove it recursively.
    878        storageFile.remove(true);
    879      }
    880    }
    881  }
    882 }