summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/browser/browser_ext_process_crash_handling.js
blob: 09ded0bcc1bc38ea2926ec329a02a15d695ccdf4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

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

const { ExtensionProcessCrashObserver, Management } =
  ChromeUtils.importESModule("resource://gre/modules/Extension.sys.mjs");

AddonTestUtils.initMochitest(this);

add_task(async function test_ExtensionProcessCrashObserver() {
  let mv2Extension = ExtensionTestUtils.loadExtension({
    useAddonManager: "temporary",
    manifest: {
      manifest_version: 2,
    },
    background() {
      browser.test.sendMessage("background_running");
    },
  });

  await mv2Extension.startup();
  await mv2Extension.awaitMessage("background_running");

  let { currentProcessChildID, lastCrashedProcessChildID } =
    ExtensionProcessCrashObserver;

  Assert.notEqual(
    currentProcessChildID,
    undefined,
    "Expect ExtensionProcessCrashObserver.currentProcessChildID to be set"
  );

  Assert.equal(
    ChromeUtils.getAllDOMProcesses().find(
      pp => pp.childID == currentProcessChildID
    )?.remoteType,
    "extension",
    "Expect a child process with remoteType extension to be found for the process childID set"
  );

  Assert.notEqual(
    lastCrashedProcessChildID,
    currentProcessChildID,
    "Expect lastCrashedProcessChildID to not be set to the same value that currentProcessChildID is set"
  );

  let mv3Extension = ExtensionTestUtils.loadExtension({
    useAddonManager: "temporary",
    manifest: {
      manifest_version: 3,
    },
    background() {
      browser.test.sendMessage("background_running");
    },
  });

  const waitForExtensionBrowserInserted = () =>
    new Promise(resolve => {
      const listener = (_eventName, browser) => {
        if (!browser.getAttribute("webextension-view-type") === "background") {
          return;
        }
        Management.off("extension-browser-inserted", listener);
        resolve(browser);
      };
      Management.on("extension-browser-inserted", listener);
    });

  const waitForExtensionProcessCrashNotified = () =>
    new Promise(resolve => {
      Management.once("extension-process-crash", (_evt, data) => resolve(data));
    });

  const promiseBackgroundBrowser = waitForExtensionBrowserInserted();

  const promiseExtensionProcessCrashNotified =
    waitForExtensionProcessCrashNotified();

  await mv3Extension.startup();
  await mv3Extension.awaitMessage("background_running");
  const bgPageBrowser = await promiseBackgroundBrowser;

  info("Force extension process crash");
  // NOTE: shouldShowTabCrashPage option needs to be set to false
  // to make sure crashFrame method resolves without waiting for a
  // tab crash page (which is not going to be shown for a background
  // page browser element).
  await BrowserTestUtils.crashFrame(
    bgPageBrowser,
    /* shouldShowTabCrashPage */ false
  );

  info("Verify ExtensionProcessCrashObserver after extension process crash");
  Assert.equal(
    ExtensionProcessCrashObserver.lastCrashedProcessChildID,
    currentProcessChildID,
    "Expect ExtensionProcessCrashObserver.lastCrashedProcessChildID to be set to the expected childID"
  );

  info("Expect the same childID to have been notified as a Management event");
  Assert.deepEqual(
    await promiseExtensionProcessCrashNotified,
    { childID: currentProcessChildID },
    "Got the expected childID notified as part of the extension-process-crash Management event"
  );

  info("Wait for mv3 extension shutdown");
  await mv3Extension.unload();
  info("Wait for mv2 extension shutdown");
  await mv2Extension.unload();
});