/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const { TelemetryTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/TelemetryTestUtils.sys.mjs"
);

let indexes_10_100 = [
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 27, 30,
  33, 37, 41, 46, 51, 57, 63, 70, 78, 87, 97, 108, 120, 133, 148, 165, 184, 205,
  228, 254, 282, 314, 349, 388, 431, 479, 533, 593, 659, 733, 815, 906, 1008,
  1121, 1247, 1387, 1542, 1715, 1907, 2121, 2359, 2623, 2917, 3244, 3607, 4011,
  4460, 4960, 5516, 6134, 6821, 7585, 8435, 9380, 10431, 11600, 12900, 14345,
  15952, 17739, 19727, 21937, 24395, 27129, 30169, 33549, 37308, 41488, 46137,
  51307, 57056, 63449, 70559, 78465, 87257, 97035, 107908, 120000,
];

let indexes_gt_100 = [
  0, 30000, 30643, 31300, 31971, 32657, 33357, 34072, 34803, 35549, 36311,
  37090, 37885, 38697, 39527, 40375, 41241, 42125, 43028, 43951, 44894, 45857,
  46840, 47845, 48871, 49919, 50990, 52084, 53201, 54342, 55507, 56697, 57913,
  59155, 60424, 61720, 63044, 64396, 65777, 67188, 68629, 70101, 71604, 73140,
  74709, 76311, 77948, 79620, 81327, 83071, 84853, 86673, 88532, 90431, 92370,
  94351, 96374, 98441, 100552, 102708, 104911, 107161, 109459, 111806, 114204,
  116653, 119155, 121710, 124320, 126986, 129709, 132491, 135332, 138234,
  141199, 144227, 147320, 150479, 153706, 157002, 160369, 163808, 167321,
  170909, 174574, 178318, 182142, 186048, 190038, 194114, 198277, 202529,
  206872, 211309, 215841, 220470, 225198, 230028, 234961, 240000,
];

registerCleanupFunction(async () => {
  http3_clear_prefs();
  Services.prefs.clearUserPref(
    "toolkit.telemetry.testing.overrideProductsCheck"
  );
});

add_task(async function setup() {
  // Enable the collection (during test) for all products so even products
  // that don't collect the data will be able to run the test without failure.
  Services.prefs.setBoolPref(
    "toolkit.telemetry.testing.overrideProductsCheck",
    true
  );

  await http3_setup_tests("h3-29");
});

let Http3Listener = function () {};

Http3Listener.prototype = {
  onStartRequest: function testOnStartRequest(request) {
    Assert.equal(request.status, Cr.NS_OK);
    Assert.equal(request.responseStatus, 200);
  },

  onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
    read_stream(stream, cnt);
  },

  onStopRequest: function testOnStopRequest(request, status) {
    let httpVersion = "";
    try {
      httpVersion = request.protocolVersion;
    } catch (e) {}
    Assert.equal(httpVersion, "h3-29");
    this.finish();
  },
};

function chanPromise(chan, listener) {
  return new Promise(resolve => {
    function finish(result) {
      resolve(result);
    }
    listener.finish = finish;
    chan.asyncOpen(listener);
  });
}

function makeChan(uri, amount) {
  let chan = NetUtil.newChannel({
    uri,
    loadUsingSystemPrincipal: true,
  }).QueryInterface(Ci.nsIHttpChannel);
  chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;

  let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
    Ci.nsIStringInputStream
  );
  stream.data = generateContent(amount);
  let uchan = chan.QueryInterface(Ci.nsIUploadChannel);
  uchan.setUploadStream(stream, "text/plain", stream.available());
  chan.requestMethod = "POST";
  return chan;
}

// Generate a post.
function generateContent(size) {
  let content = "";
  for (let i = 0; i < size; i++) {
    content += "0";
  }
  return content;
}

async function test_large_post(amount, hist_name, key, indexes) {
  let hist = TelemetryTestUtils.getAndClearKeyedHistogram(hist_name);

  let listener = new Http3Listener();
  listener.amount = amount;
  let chan = makeChan("https://foo.example.com/post", amount);
  let tchan = chan.QueryInterface(Ci.nsITimedChannel);
  tchan.timingEnabled = true;
  await chanPromise(chan, listener);

  let time = (tchan.responseStartTime - tchan.requestStartTime) / 1000;
  let i = 0;
  while (i < indexes.length && time > indexes[i + 1]) {
    i += 1;
  }
  TelemetryTestUtils.assertKeyedHistogramValue(hist, key, indexes[i], 1);
}

add_task(async function test_11M() {
  await test_large_post(
    11 * (1 << 20),
    "HTTP3_UPLOAD_TIME_10M_100M",
    "uses_http3_10_50",
    indexes_10_100
  );
});

add_task(async function test_51M() {
  await test_large_post(
    51 * (1 << 20),
    "HTTP3_UPLOAD_TIME_10M_100M",
    "uses_http3_50_100",
    indexes_10_100
  );
});

add_task(async function test_101M() {
  await test_large_post(
    101 * (1 << 20),
    "HTTP3_UPLOAD_TIME_GT_100M",
    "uses_http3",
    indexes_gt_100
  );
});
