/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";

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

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

// Force ServiceWorkerRegistrar to init by calling do_get_profile.
// (This has to be called before AddonTestUtils.init, because it does
// also call do_get_profile internally but it doesn't notify
// profile-after-change).
do_get_profile(true);

AddonTestUtils.init(this);

const server = createHttpServer({ hosts: ["localhost"] });

server.registerPathHandler("/sw.js", (request, response) => {
  info(`/sw.js is being requested: ${JSON.stringify(request)}`);
  response.setHeader("Content-Type", "application/javascript");
  response.write("");
});

add_task(async function setup_prefs() {
  equal(
    Services.prefs.getBoolPref("browser.tabs.remote.autostart"),
    true,
    "e10s is expected to be enabled"
  );

  // Enable nsIServiceWorkerManager.registerForTest.
  Services.prefs.setBoolPref("dom.serviceWorkers.testing.enabled", true);

  registerCleanupFunction(() => {
    Services.prefs.clearUserPref("dom.serviceWorkers.testing.enabled");
  });
});

/**
 * This test installs a ServiceWorker via test API and verify that the install
 * process spawns a new process. (Normally ServiceWorker installation won't
 * cause a new content process to be spawned because the call to register must
 * be coming from within an existing content process, but the registerForTest
 * API allows us to bypass this restriction.)
 *
 * This models the real-world situation of a push notification being received
 * from the network which results in a ServiceWorker being spawned without their
 * necessarily being an existing content process to host it (especially under Fission).
 */
add_task(async function launch_remoteworkers_in_new_processes() {
  const swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService(
    Ci.nsIServiceWorkerManager
  );

  const ssm = Services.scriptSecurityManager;

  const initialChildCount = Services.ppmm.childCount;

  // A test service worker that should spawn a regular web content child process.
  const swRegInfoWeb = await swm.registerForTest(
    ssm.createContentPrincipal(Services.io.newURI("http://localhost"), {}),
    "http://localhost/scope",
    "http://localhost/sw.js"
  );
  swRegInfoWeb.QueryInterface(Ci.nsIServiceWorkerRegistrationInfo);

  info(
    `web content service worker registered: ${JSON.stringify({
      principal: swRegInfoWeb.principal.spec,
      scope: swRegInfoWeb.scope,
    })}`
  );

  info("Wait new process to be launched");
  await TestUtils.waitForCondition(() => {
    return Services.ppmm.childCount - initialChildCount >= 1;
  }, "wait for a new child processes to be started");

  // Wait both workers to become active to be sure that. besides spawning
  // the new child processes as expected, the two remote worker have been
  // able to run successfully (in other word their remote worker data did
  // pass successfull the IsRemoteTypeAllowed check in RemoteworkerChild).
  info("Wait for webcontent worker to become active");
  await TestUtils.waitForCondition(
    () => swRegInfoWeb.activeWorker,
    `wait workers for scope ${swRegInfoWeb.scope} to be active`
  );
});
