/**
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

add_task(async function testSteps() {
  const principal = getPrincipal("http://example.com");

  const dataFile = getRelativeFile(
    "storage/default/http+++example.com/ls/data.sqlite"
  );

  const usageJournalFile = getRelativeFile(
    "storage/default/http+++example.com/ls/usage-journal"
  );

  const usageFile = getRelativeFile(
    "storage/default/http+++example.com/ls/usage"
  );

  const data = {};
  data.key = "foo";
  data.value = "bar";
  data.usage = data.key.length + data.value.length;

  async function createStorageForMigration(createUsageDir) {
    info("Clearing");

    let request = clear();
    await requestFinished(request);

    info("Installing package");

    // The profile contains storage.sqlite and webappsstore.sqlite. The file
    // create_db.js in the package was run locally, specifically it was
    // temporarily added to xpcshell.ini and then executed:
    // mach xpcshell-test --interactive dom/localstorage/test/unit/create_db.js
    installPackage("usageAfterMigration_profile");

    if (createUsageDir) {
      // Origin must be initialized before the usage dir is created.

      info("Initializing storage");

      request = initStorage();
      await requestFinished(request);

      info("Initializing temporary storage");

      request = initTemporaryStorage();
      await requestFinished(request);

      info("Initializing origin");

      request = initTemporaryOrigin("default", principal);
      await requestFinished(request);

      info("Creating usage as a directory");

      // This will cause a failure during migration.
      usageFile.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
    }
  }

  function verifyData() {
    ok(dataFile.exists(), "Data file does exist");
  }

  async function verifyUsage(success) {
    info("Verifying usage in memory");

    let request = getCachedOriginUsage(principal);
    await requestFinished(request);

    if (success) {
      is(request.result, data.usage, "Correct usage");
    } else {
      is(request.result, 0, "Zero usage");
    }

    info("Verifying usage on disk");

    if (success) {
      ok(!usageJournalFile.exists(), "Usage journal file doesn't exist");
      ok(usageFile.exists(), "Usage file does exist");
      let usage = await readUsageFromUsageFile(usageFile);
      is(usage, data.usage, "Correct usage");
    } else {
      ok(usageJournalFile.exists(), "Usage journal file does exist");
      ok(usageFile.exists(), "Usage file does exist");
    }
  }

  info("Setting prefs");

  Services.prefs.setBoolPref(
    "dom.storage.enable_unsupported_legacy_implementation",
    false
  );

  info("Stage 1 - Testing usage after successful data migration");

  await createStorageForMigration(/* createUsageDir */ false);

  info("Getting storage");

  let storage = getLocalStorage(principal);

  info("Opening");

  storage.open();

  verifyData();

  await verifyUsage(/* success */ true);

  info("Stage 2 - Testing usage after unsuccessful data migration");

  await createStorageForMigration(/* createUsageDir */ true);

  info("Getting storage");

  storage = getLocalStorage(principal);

  info("Opening");

  try {
    storage.open();
    ok(false, "Should have thrown");
  } catch (ex) {
    ok(true, "Did throw");
  }

  verifyData();

  await verifyUsage(/* success */ false);

  info("Stage 3 - Testing usage after unsuccessful/successful data migration");

  await createStorageForMigration(/* createUsageDir */ true);

  info("Getting storage");

  storage = getLocalStorage(principal);

  info("Opening");

  try {
    storage.open();
    ok(false, "Should have thrown");
  } catch (ex) {
    ok(true, "Did throw");
  }

  usageFile.remove(true);

  info("Opening");

  storage.open();

  verifyData();

  await verifyUsage(/* success */ true);
});
