/* 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/. */

"use strict";

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

const network = Glean.network;

const page_probes = [
  { name: "tlsHandshake", probe: network.tlsHandshake },
  { name: "dnsStart", probe: network.dnsStart },
  { name: "dnsEnd", probe: network.dnsEnd },
  { name: "tcpConnection", probe: network.tcpConnection },
  { name: "openToFirstSent", probe: network.openToFirstSent },
  { name: "firstSentToLastReceived", probe: network.firstSentToLastReceived },
  { name: "openToFirstReceived", probe: network.openToFirstReceived },
  { name: "completeLoad", probe: network.completeLoad },
  { name: "completeLoadNet", probe: network.completeLoadNet },
];

const sub_probes = [
  { name: "subTlsHandshake", probe: network.subTlsHandshake },
  { name: "subDnsStart", probe: network.subDnsStart },
  { name: "subDnsEnd", probe: network.subDnsEnd },
  { name: "subTcpConnection", probe: network.subTcpConnection },
  { name: "subOpenToFirstSent", probe: network.subOpenToFirstSent },
  {
    name: "subFirstSentToLastReceived",
    probe: network.subFirstSentToLastReceived,
  },
  { name: "subOpenToFirstReceived", probe: network.subOpenToFirstReceived },
  { name: "subCompleteLoad", probe: network.subCompleteLoad },
  { name: "subCompleteLoadNet", probe: network.subCompleteLoadNet },
];

add_setup(function test_setup() {
  Services.fog.initializeFOG();
});

registerCleanupFunction(() => {
  Services.fog.testResetFOG();
});

async function test_loadgroup_glean_http2(page, probes) {
  let loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(
    Ci.nsILoadGroup
  );
  let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
    Ci.nsIX509CertDB
  );

  addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");

  Services.fog.testResetFOG();

  let server = new NodeHTTP2Server();
  await server.start();
  registerCleanupFunction(async () => {
    await server.stop();
  });

  let loadListener = {
    onStartRequest: () => {},
    onStopRequest: () => {
      for (const { name, probe } of probes) {
        info(`testing ${name}`);
        const result = probe.testGetValue();
        // Ensure there are non-zero count, sum, and first value
        Assert.less(0, result.count);
        Assert.less(0, result.sum);
        Assert.less(0, Object.values(result.values)[0]);
      }
    },
    QueryInterface: ChromeUtils.generateQI([
      "nsIRequestObserver",
      "nsISupportsWeakReference",
    ]),
  };
  loadGroup.groupObserver = loadListener;

  await server.registerPathHandler("/", (req, resp) => {
    resp.writeHead(200);
    resp.end("a".repeat(100));
  });
  let chan = NetUtil.newChannel({
    uri: `https://localhost:${server.port()}`,
    loadUsingSystemPrincipal: true,
  }).QueryInterface(Ci.nsIHttpChannel);

  if (page) {
    loadGroup.defaultLoadRequest = chan;
  } else {
    // Set mDefaultLoadRequest to a dummy channel when testing sub
    await server.registerPathHandler("/dummy", (req, resp) => {
      resp.writeHead(404);
      resp.end();
    });
    let dummy = NetUtil.newChannel({
      uri: `https://localhost:${server.port()}/dummy`,
      loadUsingSystemPrincipal: true,
    }).QueryInterface(Ci.nsIHttpChannel);
    loadGroup.defaultLoadRequest = dummy;
  }

  loadGroup.addRequest(chan, null);
  await new Promise(resolve => {
    chan.asyncOpen(new ChannelListener(resolve, null, CL_ALLOW_UNKNOWN_CL));
  });
  loadGroup.removeRequest(chan, null, Cr.NS_OK);

  loadGroup = null;

  Cu.forceCC();
  Cu.forceGC();

  const result = page
    ? network.pageLoadSize.page.testGetValue()
    : network.pageLoadSize.subresources.testGetValue();
  Assert.greater(result.sum, 100, "size should > 100");
}

add_task(async function test_loadgroup_glean_http2_page() {
  await test_loadgroup_glean_http2(true, page_probes);
});

add_task(async function test_loadgroup_glean_http2_sub() {
  await test_loadgroup_glean_http2(false, sub_probes);
});
