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

const { FileUtils } = ChromeUtils.importESModule(
  "resource://testing-common/dom/quota/test/modules/FileUtils.sys.mjs"
);
const { PrincipalUtils } = ChromeUtils.importESModule(
  "resource://testing-common/dom/quota/test/modules/PrincipalUtils.sys.mjs"
);
const { QuotaUtils } = ChromeUtils.importESModule(
  "resource://testing-common/dom/quota/test/modules/QuotaUtils.sys.mjs"
);

/**
 * This test is mainly to verify that L2 related cached usage information is
 * stable across a forced metadata restoration and consists of these steps:
 *  - Install a packaged profile
 *  - Initialize storage and temporary storage
 *  - Get full origin metadata (cached in memory)
 *  - Shutdown storage
 *  - Remove the origin metadata file on disk (forces restoration)
 *  - Initialize storage and temporary storage
 *  - Get full origin metadata (cached in memory)
 *  - Compare cached usage information
 *
 * This test is intended to catch changes that would require bumping
 * kCurrentQuotaVersion.
 *
 * If the comparison of cached usage information fails, it is very likely that
 * kCurrentQuotaVersion needs to be bumped.
 *
 * See also the documentation for kCurrentQuotaVersion in Constants.h.
 *
 * Note: This test currently contains only the essential coverage for
 * detecting L2 cache validity issues. In the future, the packaged profile
 * could be generated using more comprehensive data creation methods, and a
 * separate test could be added to leverage the conditioned profiles
 * infrastructure. However, a custom test with its own pre-packaged profile
 * will still be needed, since we do not have control over the contents of
 * conditioned profiles.
 */
async function testSecondaryCacheValidity() {
  const principal = PrincipalUtils.createPrincipal("http://example42.com");
  const metadata = FileUtils.getFile(
    "storage/default/http+++example42.com/.metadata-v2"
  );

  info("Clearing storage");

  {
    const request = Services.qms.clear();
    await QuotaUtils.requestFinished(request);
  }

  info("Installing package");

  // The profile contains a single origin directory in the default repository
  // populated with basic data for all quota clients. It was created locally
  // using the make_secondaryCacheValidity.js script, which can be
  // executed like this:
  // mach xpcshell-test --interactive dom/quota/test/xpcshell/make_secondaryCacheValidity.js
  // After running _execute_test() and quit(), additional manual steps are
  // needed:
  // 1. Remove the folder "storage/temporary".
  // 2. Remove the file "storage/ls-archive.sqlite".
  // 3. Remove the file "storage/default/http+++example42.com/cache/caches.sqlite-wal".
  // 4. Remove the file "storage/default/http+++example42.com/idb/2320029346mByDIdnedxe.sqlite-wal".
  installPackage("secondaryCacheValidity_profile");

  info("Initializing storage");

  {
    const request = Services.qms.init();
    await QuotaUtils.requestFinished(request);
  }

  info("Initializing temporary storage");

  {
    const request = Services.qms.initTemporaryStorage();
    await QuotaUtils.requestFinished(request);
  }

  info("Getting full origin metadata");

  {
    const request = Services.qms.getFullOriginMetadata("default", principal);
    await QuotaUtils.requestFinished(request);
  }

  info("Getting full origin metadata");

  const fullOriginMetadataBefore = await (async function () {
    const request = Services.qms.getFullOriginMetadata("default", principal);
    await QuotaUtils.requestFinished(request);
    return request.result;
  })();

  info("Shutting down storage");

  {
    const request = Services.qms.reset();
    await QuotaUtils.requestFinished(request);
  }

  info("Removing origin metadata");

  metadata.remove(false);

  info("Initializing storage");

  {
    const request = Services.qms.init();
    await QuotaUtils.requestFinished(request);
  }

  info("Initializing temporary storage");

  {
    const request = Services.qms.initTemporaryStorage();
    await QuotaUtils.requestFinished(request);
  }

  info("Getting full origin metadata");

  const fullOriginMetadataAfter = await (async function () {
    const request = Services.qms.getFullOriginMetadata("default", principal);
    await QuotaUtils.requestFinished(request);
    return request.result;
  })();

  info("Verifying full origin metadata");

  Assert.notEqual(
    BigInt(fullOriginMetadataBefore.lastAccessTime),
    BigInt(fullOriginMetadataAfter.lastAccessTime),
    "Last access times are not the same"
  );

  info("Client usages before: " + fullOriginMetadataBefore.clientUsages);
  info("Client usages after: " + fullOriginMetadataAfter.clientUsages);

  Assert.equal(
    fullOriginMetadataBefore.clientUsages,
    fullOriginMetadataAfter.clientUsages,
    "Client usages are the same"
  );

  info("Origin usgae before: " + fullOriginMetadataBefore.originUsage);
  info("Origin usage after: " + fullOriginMetadataAfter.originUsage);

  Assert.equal(
    fullOriginMetadataBefore.originUsage,
    fullOriginMetadataAfter.originUsage,
    "Origin usage is the same"
  );
}

/* exported testSteps */
async function testSteps() {
  add_task(
    {
      pref_set: [["dom.quotaManager.loadQuotaFromCache", false]],
    },
    testSecondaryCacheValidity
  );
}
