// META: script=/common/get-host-info.sub.js
// META: script=/common/utils.js
// META: script=/fetch/fetch-later/resources/fetch-later-helper.js

'use strict';

const kQuotaPerOrigin = 64 * 1024;  // 64 kilobytes per spec.
const {ORIGIN, HTTPS_NOTSAMESITE_ORIGIN} = get_host_info();

// Runs a test case that cover a single fetchLater() call with `body` in its
// request payload. The call is not expected to throw any errors.
function fetchLaterPostTest(body, description) {
  test(() => {
    const controller = new AbortController();
    const result = fetchLater(
        '/fetch-later',
        {method: 'POST', signal: controller.signal, body: body});
    assert_false(result.activated);
    // Release quota taken by the pending request for subsequent tests.
    controller.abort();
  }, description);
}

// Test small payload for each supported data types.
for (const [dataType, skipCharset] of Object.entries(
         BeaconDataTypeToSkipCharset)) {
  fetchLaterPostTest(
      makeBeaconData(generateSequentialData(0, 1024, skipCharset), dataType),
      `A fetchLater() call accept small data in POST request of ${dataType}.`);
}

// Test various size of payloads for the same origin.
for (const dataType in BeaconDataType) {
  if (dataType !== BeaconDataType.FormData &&
      dataType !== BeaconDataType.URLSearchParams) {
    // Skips FormData & URLSearchParams, as browser adds extra bytes to them
    // in addition to the user-provided content. It is difficult to test a
    // request right at the quota limit.
    fetchLaterPostTest(
        // Generates data that is exactly 64 kilobytes.
        makeBeaconData(generatePayload(kQuotaPerOrigin), dataType),
        `A single fetchLater() call takes up the per-origin quota for its ` +
            `body of ${dataType}.`);
  }
}

// Test empty payload.
for (const dataType in BeaconDataType) {
  test(
      () => {
        assert_throws_js(
            TypeError, () => fetchLater('/', {method: 'POST', body: ''}));
      },
      `A single fetchLater() call does not accept empty data in POST request ` +
          `of ${dataType}.`);
}

// Test oversized payload.
for (const dataType in BeaconDataType) {
  test(
      () => {
        assert_throws_dom(
            'QuotaExceededError',
            () => fetchLater('/fetch-later', {
              method: 'POST',
              // Generates data that exceeds 64 kilobytes.
              body:
                  makeBeaconData(generatePayload(kQuotaPerOrigin + 1), dataType)
            }));
      },
      `A single fetchLater() call is not allowed to exceed per-origin quota ` +
          `for its body of ${dataType}.`);
}

// Test accumulated oversized request.
for (const dataType in BeaconDataType) {
  test(
      () => {
        const controller = new AbortController();
        // Makes the 1st call that sends only half of allowed quota.
        fetchLater('/fetch-later', {
          method: 'POST',
          signal: controller.signal,
          body: makeBeaconData(generatePayload(kQuotaPerOrigin / 2), dataType)
        });

        // Makes the 2nd call that sends half+1 of allowed quota.
        assert_throws_dom('QuotaExceededError', () => {
          fetchLater('/fetch-later', {
            method: 'POST',
            signal: controller.signal,
            body: makeBeaconData(
                generatePayload(kQuotaPerOrigin / 2 + 1), dataType)
          });
        });
        // Release quota taken by the pending requests for subsequent tests.
        controller.abort();
      },
      `The 2nd fetchLater() call is not allowed to exceed per-origin quota ` +
          `for its body of ${dataType}.`);
}

// Test various size of payloads across different origins.
for (const dataType in BeaconDataType) {
  test(
      () => {
        const controller = new AbortController();
        // Makes the 1st call that sends only half of allowed quota.
        fetchLater('/fetch-later', {
          method: 'POST',
          signal: controller.signal,
          body: makeBeaconData(generatePayload(kQuotaPerOrigin / 2), dataType)
        });

        // Makes the 2nd call that sends half+1 of allowed quota, but to a
        // different origin.
        fetchLater(`${HTTPS_NOTSAMESITE_ORIGIN}/fetch-later`, {
          method: 'POST',
          signal: controller.signal,
          body:
              makeBeaconData(generatePayload(kQuotaPerOrigin / 2 + 1), dataType)
        });
        // Release quota taken by the pending requests for subsequent tests.
        controller.abort();
      },
      `The 2nd fetchLater() call to another origin does not exceed per-origin` +
          ` quota for its body of ${dataType}.`);
}
