summaryrefslogtreecommitdiffstats
path: root/browser/modules/test/browser_ProcessHangNotifications.js
blob: 597be611a715b3bd3d1d2c7d2d5035df1fbfaa9b (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

Cu.import("resource://gre/modules/UpdateUtils.jsm");

function getNotificationBox(aWindow) {
  return aWindow.document.getElementById("high-priority-global-notificationbox");
}

function promiseNotificationShown(aWindow, aName) {
  return new Promise((resolve) => {
    let notification = getNotificationBox(aWindow);
    notification.addEventListener("AlertActive", function active() {
      notification.removeEventListener("AlertActive", active, true);
      is(notification.allNotifications.length, 1, "Notification Displayed.");
      resolve(notification);
    });
  });
}

function promiseReportCallMade(aValue) {
  return new Promise((resolve) => {
    let old = gTestHangReport.testCallback;
    gTestHangReport.testCallback = function (val) {
      gTestHangReport.testCallback = old;
      is(aValue, val, "was the correct method call made on the hang report object?");
      resolve();
    };
  });
}

function pushPrefs(...aPrefs) {
  return new Promise((resolve) => {
    SpecialPowers.pushPrefEnv({"set": aPrefs}, resolve);
    resolve();
  });
}

function popPrefs() {
  return new Promise((resolve) => {
    SpecialPowers.popPrefEnv(resolve);
    resolve();
  });
}

let gTestHangReport = {
  SLOW_SCRIPT: 1,
  PLUGIN_HANG: 2,

  TEST_CALLBACK_CANCELED: 1,
  TEST_CALLBACK_TERMSCRIPT: 2,
  TEST_CALLBACK_TERMPLUGIN: 3,

  _hangType: 1,
  _tcb: function (aCallbackType) {},

  get hangType() {
    return this._hangType;
  },

  set hangType(aValue) {
    this._hangType = aValue;
  },

  set testCallback(aValue) {
    this._tcb = aValue;
  },

  QueryInterface: function (aIID) {
    if (aIID.equals(Components.interfaces.nsIHangReport) ||
        aIID.equals(Components.interfaces.nsISupports))
      return this;
    throw Components.results.NS_NOINTERFACE;
  },

  userCanceled: function () {
    this._tcb(this.TEST_CALLBACK_CANCELED);
  },

  terminateScript: function () {
    this._tcb(this.TEST_CALLBACK_TERMSCRIPT);
  },

  terminatePlugin: function () {
    this._tcb(this.TEST_CALLBACK_TERMPLUGIN);
  },

  isReportForBrowser: function(aFrameLoader) {
    return true;
  }
};

// on dev edition we add a button for js debugging of hung scripts.
let buttonCount = (UpdateUtils.UpdateChannel == "aurora" ? 3 : 2);

/**
 * Test if hang reports receive a terminate script callback when the user selects
 * stop in response to a script hang.
 */

add_task(function* terminateScriptTest() {
  let promise = promiseNotificationShown(window, "process-hang");
  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
  let notification = yield promise;

  let buttons = notification.currentNotification.getElementsByTagName("button");
  // Fails on aurora on-push builds, bug 1232204
  // is(buttons.length, buttonCount, "proper number of buttons");

  // Click the "Stop It" button, we should get a terminate script callback
  gTestHangReport.hangType = gTestHangReport.SLOW_SCRIPT;
  promise = promiseReportCallMade(gTestHangReport.TEST_CALLBACK_TERMSCRIPT);
  buttons[0].click();
  yield promise;
});

/**
 * Test if hang reports receive user canceled callbacks after a user selects wait
 * and the browser frees up from a script hang on its own.
 */

add_task(function* waitForScriptTest() {
  let promise = promiseNotificationShown(window, "process-hang");
  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
  let notification = yield promise;

  let buttons = notification.currentNotification.getElementsByTagName("button");
  // Fails on aurora on-push builds, bug 1232204
  // is(buttons.length, buttonCount, "proper number of buttons");

  yield pushPrefs(["browser.hangNotification.waitPeriod", 1000]);

  function nocbcheck() {
    ok(false, "received a callback?");
  }
  let oldcb = gTestHangReport.testCallback;
  gTestHangReport.testCallback = nocbcheck;
  // Click the "Wait" button this time, we shouldn't get a callback at all.
  buttons[1].click();
  gTestHangReport.testCallback = oldcb;

  // send another hang pulse, we should not get a notification here
  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
  is(notification.currentNotification, null, "no notification should be visible");

  gTestHangReport.testCallback = function() {};
  Services.obs.notifyObservers(gTestHangReport, "clear-hang-report", null);
  gTestHangReport.testCallback = oldcb;

  yield popPrefs();
});

/**
 * Test if hang reports receive user canceled callbacks after the content
 * process stops sending hang notifications.
 */

add_task(function* hangGoesAwayTest() {
  yield pushPrefs(["browser.hangNotification.expiration", 1000]);

  let promise = promiseNotificationShown(window, "process-hang");
  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
  yield promise;

  promise = promiseReportCallMade(gTestHangReport.TEST_CALLBACK_CANCELED);
  Services.obs.notifyObservers(gTestHangReport, "clear-hang-report", null);
  yield promise;

  yield popPrefs();
});

/**
 * Tests if hang reports receive a terminate plugin callback when the user selects
 * stop in response to a plugin hang.
 */

add_task(function* terminatePluginTest() {
  let promise = promiseNotificationShown(window, "process-hang");
  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
  let notification = yield promise;

  let buttons = notification.currentNotification.getElementsByTagName("button");
  // Fails on aurora on-push builds, bug 1232204
  // is(buttons.length, buttonCount, "proper number of buttons");

  // Click the "Stop It" button, we should get a terminate script callback
  gTestHangReport.hangType = gTestHangReport.PLUGIN_HANG;
  promise = promiseReportCallMade(gTestHangReport.TEST_CALLBACK_TERMPLUGIN);
  buttons[0].click();
  yield promise;
});