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

const protocol = require("devtools/shared/protocol");
const {AddonManager} = require("resource://gre/modules/AddonManager.jsm");

startupAddonsManager();

function promiseAddonEvent(event) {
  return new Promise(resolve => {
    let listener = {
      [event]: function (...args) {
        AddonManager.removeAddonListener(listener);
        resolve(args);
      }
    };

    AddonManager.addAddonListener(listener);
  });
}

function* findAddonInRootList(client, addonId) {
  const result = yield client.listAddons();
  const addonActor = result.addons.filter(addon => addon.id === addonId)[0];
  ok(addonActor, `Found add-on actor for ${addonId}`);
  return addonActor;
}

function* reloadAddon(client, addonActor) {
  // The add-on will be re-installed after a successful reload.
  const onInstalled = promiseAddonEvent("onInstalled");
  yield client.request({to: addonActor.actor, type: "reload"});
  yield onInstalled;
}

function getSupportFile(path) {
  const allowMissing = false;
  return do_get_file(path, allowMissing);
}

add_task(function* testReloadExitedAddon() {
  const client = yield new Promise(resolve => {
    get_chrome_actors(client => resolve(client));
  });

  // Install our main add-on to trigger reloads on.
  const addonFile = getSupportFile("addons/web-extension");
  const installedAddon = yield AddonManager.installTemporaryAddon(
    addonFile);

  // Install a decoy add-on.
  const addonFile2 = getSupportFile("addons/web-extension2");
  const installedAddon2 = yield AddonManager.installTemporaryAddon(
    addonFile2);

  let addonActor = yield findAddonInRootList(client, installedAddon.id);

  yield reloadAddon(client, addonActor);

  // Uninstall the decoy add-on, which should cause its actor to exit.
  const onUninstalled = promiseAddonEvent("onUninstalled");
  installedAddon2.uninstall();
  const [uninstalledAddon] = yield onUninstalled;

  // Try to re-list all add-ons after a reload.
  // This was throwing an exception because of the exited actor.
  const newAddonActor = yield findAddonInRootList(client, installedAddon.id);
  equal(newAddonActor.id, addonActor.id);

  // The actor id should be the same after the reload
  equal(newAddonActor.actor, addonActor.actor);

  const onAddonListChanged = new Promise((resolve) => {
    client.addListener("addonListChanged", function listener() {
      client.removeListener("addonListChanged", listener);
      resolve();
    });
  });

  // Install an upgrade version of the first add-on.
  const addonUpgradeFile = getSupportFile("addons/web-extension-upgrade");
  const upgradedAddon = yield AddonManager.installTemporaryAddon(
    addonUpgradeFile);

  // Waiting for addonListChanged unsolicited event
  yield onAddonListChanged;

  // re-list all add-ons after an upgrade.
  const upgradedAddonActor = yield findAddonInRootList(client, upgradedAddon.id);
  equal(upgradedAddonActor.id, addonActor.id);
  // The actor id should be the same after the upgrade.
  equal(upgradedAddonActor.actor, addonActor.actor);

  // The addon metadata has been updated.
  equal(upgradedAddonActor.name, "Test Addons Actor Upgrade");

  yield close(client);
});
