Merge lp:~osomon/webbrowser-app/webProcessStatus into lp:webbrowser-app
- webProcessStatus
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Olivier Tilloy |
Approved revision: | 1026 |
Merged at revision: | 1159 |
Proposed branch: | lp:~osomon/webbrowser-app/webProcessStatus |
Merge into: | lp:webbrowser-app |
Diff against target: |
650 lines (+460/-34) 10 files modified
debian/control (+1/-0) src/app/WebProcessMonitor.qml (+79/-0) src/app/webbrowser/Browser.qml (+40/-19) src/app/webbrowser/SadTab.qml (+92/-0) src/app/webbrowser/tabs-model.cpp (+4/-3) tests/autopilot/webbrowser_app/emulators/browser.py (+16/-0) tests/autopilot/webbrowser_app/tests/__init__.py (+11/-0) tests/autopilot/webbrowser_app/tests/test_sad_tab.py (+74/-0) tests/unittests/qml/tst_WebProcessMonitor.qml (+108/-0) tests/unittests/tabs-model/tst_TabsModelTests.cpp (+35/-12) |
To merge this branch: | bzr merge lp:~osomon/webbrowser-app/webProcessStatus |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Riccardo Padovani (community) | Approve | ||
Ubuntu Phablet Team | Pending | ||
Review via email: mp+259040@code.launchpad.net |
Commit message
Display a friendly message when the renderer process crashes or is killed.
This adds a runtime dependency for webbrowser-
Description of the change
- 1009. By Olivier Tilloy
-
Revert unnecessary version bump.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 1010. By Olivier Tilloy
-
Also bump the build dependency on oxide to allow unit tests to run at build time.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1010
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1011. By Olivier Tilloy
-
Count the number of retries (but keep it limited to one for now).
- 1012. By Olivier Tilloy
-
Merge the latest changes from trunk and resolve a conflict.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1012
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1013. By Olivier Tilloy
-
Simplify the code a bit.
- 1014. By Olivier Tilloy
-
Merge the latest changes from trunk and resolve a couple of conflicts.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1014
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1015. By Olivier Tilloy
-
Make the SadTab component browser-specific.
- 1016. By Olivier Tilloy
-
Updated SadTab to match visual specification.
- 1017. By Olivier Tilloy
-
Fix the sad tab disappearing after a minute.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1017
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1018. By Olivier Tilloy
-
Merge the latest changes from trunk and resolve conflicts.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1018
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1019. By Olivier Tilloy
-
Merge the latest changes from trunk and resolve a conflict.
- 1020. By Olivier Tilloy
-
Fix autopilot tests on desktop where closing the last open tab exits the application.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1020
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1021. By Olivier Tilloy
-
Merge the latest changes from trunk.
- 1022. By Olivier Tilloy
-
Update imports.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1022
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Riccardo Padovani (rpadovani) wrote : | # |
Useful function, thanks!
lgtm, just a note in the code I don't understand.
- 1023. By Olivier Tilloy
-
Merge the latest changes from trunk.
- 1024. By Olivier Tilloy
-
Fix closing the current tab (the assumption that the current tab is always the first one is not valid any longer).
- 1025. By Olivier Tilloy
-
Use name() instead of exe() to avoid raising an AccessDenied exception.
Olivier Tilloy (osomon) wrote : | # |
> I don't understand this: if it should close the current tab,
> why does it close the first?
Very good catch, thanks Riccardo!
The assumption [current tab == first tab] used to be true when we supported only the mobile form factor, where the current tab was always pushed to the top of the stack. This is not valid any longer, so I updated the code to reflect that.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1025
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1026. By Olivier Tilloy
-
Update the tab model’s current index when a tab before the current one is removed.
Riccardo Padovani (rpadovani) wrote : | # |
Lgtm now, thanks!
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1026
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2015-08-25 13:56:58 +0000 |
3 | +++ debian/control 2015-09-02 16:48:16 +0000 |
4 | @@ -122,6 +122,7 @@ |
5 | autopilot-qt5, |
6 | python3-autopilot, |
7 | python3-fixtures, |
8 | + python3-psutil, |
9 | ubuntu-ui-toolkit-autopilot, |
10 | webbrowser-app (>= ${binary:Version}), |
11 | Description: Ubuntu web browser autopilot tests |
12 | |
13 | === added file 'src/app/WebProcessMonitor.qml' |
14 | --- src/app/WebProcessMonitor.qml 1970-01-01 00:00:00 +0000 |
15 | +++ src/app/WebProcessMonitor.qml 2015-09-02 16:48:16 +0000 |
16 | @@ -0,0 +1,79 @@ |
17 | +/* |
18 | + * Copyright 2015 Canonical Ltd. |
19 | + * |
20 | + * This file is part of webbrowser-app. |
21 | + * |
22 | + * webbrowser-app is free software; you can redistribute it and/or modify |
23 | + * it under the terms of the GNU General Public License as published by |
24 | + * the Free Software Foundation; version 3. |
25 | + * |
26 | + * webbrowser-app is distributed in the hope that it will be useful, |
27 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
28 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
29 | + * GNU General Public License for more details. |
30 | + * |
31 | + * You should have received a copy of the GNU General Public License |
32 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
33 | + */ |
34 | + |
35 | +import QtQuick 2.4 |
36 | +import com.canonical.Oxide 1.8 as Oxide |
37 | + |
38 | +Item { |
39 | + id: monitor |
40 | + |
41 | + visible: false |
42 | + |
43 | + property var webview: null |
44 | + |
45 | + readonly property bool killed: webview && |
46 | + (webview.webProcessStatus == Oxide.WebView.WebProcessKilled) |
47 | + readonly property bool crashed: webview && |
48 | + (webview.webProcessStatus == Oxide.WebView.WebProcessCrashed) |
49 | + |
50 | + // When the renderer process is killed (most likely by the system’s |
51 | + // OOM killer), try to reload the page once, and if this results in |
52 | + // the process being killed again within one minute, then display |
53 | + // the sad tab. |
54 | + |
55 | + readonly property int killedRetries: internal.killedRetries |
56 | + |
57 | + QtObject { |
58 | + id: internal |
59 | + property int killedRetries: 0 |
60 | + } |
61 | + |
62 | + Connections { |
63 | + target: webview |
64 | + onWebProcessStatusChanged: { |
65 | + if (webview.webProcessStatus == Oxide.WebView.WebProcessKilled) { |
66 | + if (internal.killedRetries == 0) { |
67 | + // Do not attempt reloading right away, this would result in a crash |
68 | + delayedReload.restart() |
69 | + } |
70 | + } |
71 | + } |
72 | + } |
73 | + |
74 | + Timer { |
75 | + id: delayedReload |
76 | + interval: 100 |
77 | + onTriggered: { |
78 | + monitorTimer.restart() |
79 | + monitor.webview.reload() |
80 | + internal.killedRetries++ |
81 | + } |
82 | + } |
83 | + |
84 | + Timer { |
85 | + id: monitorTimer |
86 | + interval: 60000 // 1 minute |
87 | + onTriggered: internal.killedRetries = 0 |
88 | + } |
89 | + |
90 | + onWebviewChanged: { |
91 | + internal.killedRetries = 0 |
92 | + delayedReload.stop() |
93 | + monitorTimer.stop() |
94 | + } |
95 | +} |
96 | |
97 | === modified file 'src/app/webbrowser/Browser.qml' |
98 | --- src/app/webbrowser/Browser.qml 2015-08-27 14:02:05 +0000 |
99 | +++ src/app/webbrowser/Browser.qml 2015-09-02 16:48:16 +0000 |
100 | @@ -206,6 +206,7 @@ |
101 | |
102 | Loader { |
103 | id: newTabViewLoader |
104 | + |
105 | anchors { |
106 | fill: tabContainer |
107 | topMargin: (chrome.state == "shown") ? chrome.height : 0 |
108 | @@ -290,6 +291,27 @@ |
109 | } |
110 | } |
111 | |
112 | + Loader { |
113 | + anchors { |
114 | + fill: tabContainer |
115 | + topMargin: (chrome.state == "shown") ? chrome.height : 0 |
116 | + } |
117 | + |
118 | + active: webProcessMonitor.crashed || (webProcessMonitor.killed && !currentWebview.loading) |
119 | + |
120 | + sourceComponent: SadTab { |
121 | + webview: currentWebview |
122 | + onCloseTabRequested: internal.closeCurrentTab() |
123 | + } |
124 | + |
125 | + WebProcessMonitor { |
126 | + id: webProcessMonitor |
127 | + webview: currentWebview |
128 | + } |
129 | + |
130 | + asynchronous: true |
131 | + } |
132 | + |
133 | SearchEngine { |
134 | id: currentSearchEngine |
135 | searchPaths: searchEnginesSearchPaths |
136 | @@ -603,16 +625,7 @@ |
137 | } |
138 | chromeOffset: chrome.height - invisibleTabChrome.height |
139 | onTabSelected: recentView.closeAndSwitchToTab(index) |
140 | - onTabClosed: { |
141 | - var tab = tabsModel.remove(index) |
142 | - if (tab) { |
143 | - tab.close() |
144 | - } |
145 | - if (tabsModel.count === 0) { |
146 | - browser.openUrlInNewTab("", true) |
147 | - recentView.reset() |
148 | - } |
149 | - } |
150 | + onTabClosed: internal.closeTab(index) |
151 | } |
152 | |
153 | Toolbar { |
154 | @@ -1192,6 +1205,23 @@ |
155 | } |
156 | } |
157 | |
158 | + function closeTab(index) { |
159 | + var tab = tabsModel.remove(index) |
160 | + if (tab) { |
161 | + tab.close() |
162 | + } |
163 | + if (tabsModel.count === 0) { |
164 | + browser.openUrlInNewTab("", true) |
165 | + recentView.reset() |
166 | + } |
167 | + } |
168 | + |
169 | + function closeCurrentTab() { |
170 | + if (tabsModel.count > 0) { |
171 | + closeTab(tabsModel.currentIndex) |
172 | + } |
173 | + } |
174 | + |
175 | function switchToTab(index) { |
176 | tabsModel.currentIndex = index |
177 | var tab = tabsModel.currentTab |
178 | @@ -1205,15 +1235,6 @@ |
179 | } |
180 | } |
181 | |
182 | - function closeCurrentTab() { |
183 | - if (tabsModel.count > 0) { |
184 | - var tab = tabsModel.remove(tabsModel.currentIndex) |
185 | - if (tab) { |
186 | - tab.close() |
187 | - } |
188 | - } |
189 | - } |
190 | - |
191 | function focusAddressBar(selectContent) { |
192 | chrome.forceActiveFocus() |
193 | Qt.inputMethod.show() // work around http://pad.lv/1316057 |
194 | |
195 | === added file 'src/app/webbrowser/SadTab.qml' |
196 | --- src/app/webbrowser/SadTab.qml 1970-01-01 00:00:00 +0000 |
197 | +++ src/app/webbrowser/SadTab.qml 2015-09-02 16:48:16 +0000 |
198 | @@ -0,0 +1,92 @@ |
199 | +/* |
200 | + * Copyright 2015 Canonical Ltd. |
201 | + * |
202 | + * This file is part of webbrowser-app. |
203 | + * |
204 | + * webbrowser-app is free software; you can redistribute it and/or modify |
205 | + * it under the terms of the GNU General Public License as published by |
206 | + * the Free Software Foundation; version 3. |
207 | + * |
208 | + * webbrowser-app is distributed in the hope that it will be useful, |
209 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
210 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
211 | + * GNU General Public License for more details. |
212 | + * |
213 | + * You should have received a copy of the GNU General Public License |
214 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
215 | + */ |
216 | + |
217 | +import QtQuick 2.4 |
218 | +import Ubuntu.Components 1.3 |
219 | +import com.canonical.Oxide 1.8 as Oxide |
220 | + |
221 | +Rectangle { |
222 | + property var webview |
223 | + |
224 | + signal closeTabRequested() |
225 | + |
226 | + Column { |
227 | + anchors { |
228 | + fill: parent |
229 | + margins: units.gu(4) |
230 | + } |
231 | + spacing: units.gu(4) |
232 | + |
233 | + Image { |
234 | + anchors.horizontalCenter: parent.horizontalCenter |
235 | + source: "assets/tab-error.png" |
236 | + } |
237 | + |
238 | + Label { |
239 | + anchors { |
240 | + left: parent.left |
241 | + right: parent.right |
242 | + } |
243 | + |
244 | + wrapMode: Text.Wrap |
245 | + horizontalAlignment: Text.AlignHCenter |
246 | + text: webview ? i18n.tr("The rendering process has been closed for this tab.") : "" |
247 | + } |
248 | + |
249 | + Label { |
250 | + anchors { |
251 | + left: parent.left |
252 | + right: parent.right |
253 | + } |
254 | + |
255 | + wrapMode: Text.Wrap |
256 | + horizontalAlignment: Text.AlignHCenter |
257 | + font.weight: Font.Light |
258 | + text: { |
259 | + if (!webview) { |
260 | + return "" |
261 | + } else if (webview.webProcessStatus == Oxide.WebView.WebProcessCrashed) { |
262 | + // TRANSLATORS: %1 is the URL of the page that crashed the renderer process |
263 | + return i18n.tr("Something went wrong while displaying %1.").arg(webview.url) |
264 | + } else if (webview.webProcessStatus == Oxide.WebView.WebProcessKilled) { |
265 | + return i18n.tr("The system is low on memory and can't display this webpage. Try closing unneeded tabs and reloading.") |
266 | + } else { |
267 | + return "" |
268 | + } |
269 | + } |
270 | + } |
271 | + |
272 | + Row { |
273 | + anchors.horizontalCenter: parent.horizontalCenter |
274 | + spacing: units.gu(2) |
275 | + |
276 | + Button { |
277 | + objectName: "closeTabButton" |
278 | + text: i18n.tr("Close tab") |
279 | + onClicked: closeTabRequested() |
280 | + } |
281 | + |
282 | + Button { |
283 | + objectName: "reloadButton" |
284 | + text: i18n.tr("Reload") |
285 | + color: UbuntuColors.green |
286 | + onClicked: webview.reload() |
287 | + } |
288 | + } |
289 | + } |
290 | +} |
291 | |
292 | === added file 'src/app/webbrowser/assets/tab-error@27.png' |
293 | Binary files src/app/webbrowser/assets/tab-error@27.png 1970-01-01 00:00:00 +0000 and src/app/webbrowser/assets/tab-error@27.png 2015-09-02 16:48:16 +0000 differ |
294 | === modified file 'src/app/webbrowser/tabs-model.cpp' |
295 | --- src/app/webbrowser/tabs-model.cpp 2015-06-22 11:46:54 +0000 |
296 | +++ src/app/webbrowser/tabs-model.cpp 2015-09-02 16:48:16 +0000 |
297 | @@ -154,10 +154,11 @@ |
298 | if (!checkValidTabIndex(index)) { |
299 | m_currentIndex = m_tabs.count() - 1; |
300 | Q_EMIT currentIndexChanged(); |
301 | - Q_EMIT currentTabChanged(); |
302 | - } else { |
303 | - Q_EMIT currentTabChanged(); |
304 | } |
305 | + Q_EMIT currentTabChanged(); |
306 | + } else if (m_currentIndex > index) { |
307 | + m_currentIndex -= 1; |
308 | + Q_EMIT currentIndexChanged(); |
309 | } |
310 | return tab; |
311 | } |
312 | |
313 | === modified file 'tests/autopilot/webbrowser_app/emulators/browser.py' |
314 | --- tests/autopilot/webbrowser_app/emulators/browser.py 2015-08-25 13:56:58 +0000 |
315 | +++ tests/autopilot/webbrowser_app/emulators/browser.py 2015-09-02 16:48:16 +0000 |
316 | @@ -109,6 +109,9 @@ |
317 | def get_error_sheet(self): |
318 | return self.select_single("ErrorSheet") |
319 | |
320 | + def get_sad_tab(self): |
321 | + return self.wait_select_single(SadTab) |
322 | + |
323 | def get_suggestions(self): |
324 | return self.select_single(Suggestions) |
325 | |
326 | @@ -314,6 +317,19 @@ |
327 | key=lambda item: item.globalRect.y) |
328 | |
329 | |
330 | +class SadTab(uitk.UbuntuUIToolkitCustomProxyObjectBase): |
331 | + |
332 | + @autopilot.logging.log_action(logger.info) |
333 | + def click_close_tab_button(self): |
334 | + button = self.select_single("Button", objectName="closeTabButton") |
335 | + self.pointing_device.click_object(button) |
336 | + |
337 | + @autopilot.logging.log_action(logger.info) |
338 | + def click_reload_button(self): |
339 | + button = self.select_single("Button", objectName="reloadButton") |
340 | + self.pointing_device.click_object(button) |
341 | + |
342 | + |
343 | class GeolocationPermissionRequest(uitk.UbuntuUIToolkitCustomProxyObjectBase): |
344 | |
345 | def get_deny_button(self): |
346 | |
347 | === modified file 'tests/autopilot/webbrowser_app/tests/__init__.py' |
348 | --- tests/autopilot/webbrowser_app/tests/__init__.py 2015-08-12 12:31:56 +0000 |
349 | +++ tests/autopilot/webbrowser_app/tests/__init__.py 2015-09-02 16:48:16 +0000 |
350 | @@ -18,11 +18,13 @@ |
351 | |
352 | import os |
353 | import shutil |
354 | +import signal |
355 | import tempfile |
356 | import time |
357 | import urllib.request |
358 | |
359 | import fixtures |
360 | +import psutil |
361 | from testtools.matchers import Equals, NotEquals |
362 | |
363 | from autopilot.matchers import Eventually |
364 | @@ -213,6 +215,15 @@ |
365 | ping = urllib.request.urlopen(url) |
366 | self.assertThat(ping.read(), Equals(b"pong")) |
367 | |
368 | + def kill_web_processes(self, signal=signal.SIGKILL): |
369 | + children = psutil.Process(self.app.pid).children(True) |
370 | + for child in children: |
371 | + if child.name() == 'oxide-renderer': |
372 | + for arg in child.cmdline(): |
373 | + if '--type=renderer' in arg: |
374 | + os.kill(child.pid, signal) |
375 | + break |
376 | + |
377 | |
378 | class StartOpenRemotePageTestCaseBase(BrowserTestCaseBase): |
379 | |
380 | |
381 | === added file 'tests/autopilot/webbrowser_app/tests/test_sad_tab.py' |
382 | --- tests/autopilot/webbrowser_app/tests/test_sad_tab.py 1970-01-01 00:00:00 +0000 |
383 | +++ tests/autopilot/webbrowser_app/tests/test_sad_tab.py 2015-09-02 16:48:16 +0000 |
384 | @@ -0,0 +1,74 @@ |
385 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
386 | +# |
387 | +# Copyright 2015 Canonical |
388 | +# |
389 | +# This program is free software: you can redistribute it and/or modify it |
390 | +# under the terms of the GNU General Public License version 3, as published |
391 | +# by the Free Software Foundation. |
392 | +# |
393 | +# This program is distributed in the hope that it will be useful, |
394 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
395 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
396 | +# GNU General Public License for more details. |
397 | +# |
398 | +# You should have received a copy of the GNU General Public License |
399 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
400 | + |
401 | +import signal |
402 | +import time |
403 | + |
404 | +from autopilot.platform import model |
405 | + |
406 | +from webbrowser_app.tests import StartOpenRemotePageTestCaseBase |
407 | + |
408 | + |
409 | +class TestSadTab(StartOpenRemotePageTestCaseBase): |
410 | + |
411 | + def _kill_web_process(self): |
412 | + self.kill_web_processes() |
413 | + # The first time the web process is killed, the browser attempts to |
414 | + # reload the page gracefully (after a short delay), hoping the process |
415 | + # won’t be killed again. |
416 | + time.sleep(1) |
417 | + self.main_window.wait_until_page_loaded(self.url) |
418 | + |
419 | + self.kill_web_processes() |
420 | + # The second time around, the browser displays a sad tab. |
421 | + return self.main_window.get_sad_tab() |
422 | + |
423 | + def test_reload_web_process_killed(self): |
424 | + sad_tab = self._kill_web_process() |
425 | + sad_tab.click_reload_button() |
426 | + sad_tab.wait_until_destroyed() |
427 | + self.assert_home_page_eventually_loaded() |
428 | + |
429 | + def test_close_tab_web_process_killed(self): |
430 | + sad_tab = self._kill_web_process() |
431 | + sad_tab.click_close_tab_button() |
432 | + if model() == 'Desktop': |
433 | + # On desktop, closing the last open tab exits the application |
434 | + self.app.process.wait() |
435 | + return |
436 | + sad_tab.wait_until_destroyed() |
437 | + self.main_window.get_new_tab_view() |
438 | + |
439 | + def _crash_web_process(self): |
440 | + self.kill_web_processes(signal.SIGSEGV) |
441 | + # A crash of the web process displays the sad tab right away |
442 | + return self.main_window.get_sad_tab() |
443 | + |
444 | + def test_reload_web_process_crashed(self): |
445 | + sad_tab = self._crash_web_process() |
446 | + sad_tab.click_reload_button() |
447 | + sad_tab.wait_until_destroyed() |
448 | + self.assert_home_page_eventually_loaded() |
449 | + |
450 | + def test_close_tab_web_process_crashed(self): |
451 | + sad_tab = self._crash_web_process() |
452 | + sad_tab.click_close_tab_button() |
453 | + if model() == 'Desktop': |
454 | + # On desktop, closing the last open tab exits the application |
455 | + self.app.process.wait() |
456 | + return |
457 | + sad_tab.wait_until_destroyed() |
458 | + self.main_window.get_new_tab_view() |
459 | |
460 | === added file 'tests/unittests/qml/tst_WebProcessMonitor.qml' |
461 | --- tests/unittests/qml/tst_WebProcessMonitor.qml 1970-01-01 00:00:00 +0000 |
462 | +++ tests/unittests/qml/tst_WebProcessMonitor.qml 2015-09-02 16:48:16 +0000 |
463 | @@ -0,0 +1,108 @@ |
464 | +/* |
465 | + * Copyright 2015 Canonical Ltd. |
466 | + * |
467 | + * This file is part of webbrowser-app. |
468 | + * |
469 | + * webbrowser-app is free software; you can redistribute it and/or modify |
470 | + * it under the terms of the GNU General Public License as published by |
471 | + * the Free Software Foundation; version 3. |
472 | + * |
473 | + * webbrowser-app is distributed in the hope that it will be useful, |
474 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
475 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
476 | + * GNU General Public License for more details. |
477 | + * |
478 | + * You should have received a copy of the GNU General Public License |
479 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
480 | + */ |
481 | + |
482 | +import QtQuick 2.4 |
483 | +import QtTest 1.0 |
484 | +import com.canonical.Oxide 1.8 as Oxide |
485 | +import "../../../src/app" |
486 | + |
487 | +WebProcessMonitor { |
488 | + id: monitor |
489 | + |
490 | + Item { |
491 | + id: webviewMock |
492 | + |
493 | + property int webProcessStatus |
494 | + |
495 | + property int reloadCalled |
496 | + function reload() { |
497 | + webProcessStatus = Oxide.WebView.WebProcessRunning |
498 | + reloadCalled++ |
499 | + } |
500 | + } |
501 | + |
502 | + TestCase { |
503 | + name: "WebProcessMonitor" |
504 | + |
505 | + function init() { |
506 | + webviewMock.webProcessStatus = Oxide.WebView.WebProcessRunning |
507 | + webviewMock.reloadCalled = 0 |
508 | + } |
509 | + |
510 | + function test_no_webview() { |
511 | + monitor.webview = null |
512 | + compare(monitor.killedRetries, 0) |
513 | + verify(!monitor.killed) |
514 | + verify(!monitor.crashed) |
515 | + } |
516 | + |
517 | + function test_killed() { |
518 | + monitor.webview = webviewMock |
519 | + compare(monitor.killedRetries, 0) |
520 | + |
521 | + webviewMock.webProcessStatus = Oxide.WebView.WebProcessKilled |
522 | + verify(monitor.killed) |
523 | + verify(!monitor.crashed) |
524 | + tryCompare(monitor, "killedRetries", 1) |
525 | + tryCompare(webviewMock, "reloadCalled", 1) |
526 | + verify(!monitor.killed) |
527 | + verify(!monitor.crashed) |
528 | + compare(monitor.killedRetries, 1) |
529 | + |
530 | + webviewMock.webProcessStatus = Oxide.WebView.WebProcessKilled |
531 | + verify(monitor.killed) |
532 | + verify(!monitor.crashed) |
533 | + compare(monitor.killedRetries, 1) |
534 | + compare(webviewMock.reloadCalled, 1) |
535 | + } |
536 | + |
537 | + function test_crashed() { |
538 | + monitor.webview = webviewMock |
539 | + compare(monitor.killedRetries, 0) |
540 | + |
541 | + webviewMock.webProcessStatus = Oxide.WebView.WebProcessCrashed |
542 | + verify(!monitor.killed) |
543 | + verify(monitor.crashed) |
544 | + compare(monitor.killedRetries, 0) |
545 | + compare(webviewMock.reloadCalled, 0) |
546 | + |
547 | + webviewMock.webProcessStatus = Oxide.WebView.WebProcessRunning |
548 | + verify(!monitor.killed) |
549 | + verify(!monitor.crashed) |
550 | + compare(monitor.killedRetries, 0) |
551 | + compare(webviewMock.reloadCalled, 0) |
552 | + } |
553 | + |
554 | + function test_change_webview() { |
555 | + monitor.webview = webviewMock |
556 | + compare(monitor.killedRetries, 0) |
557 | + verify(!monitor.killed) |
558 | + verify(!monitor.crashed) |
559 | + |
560 | + webviewMock.webProcessStatus = Oxide.WebView.WebProcessKilled |
561 | + verify(monitor.killed) |
562 | + verify(!monitor.crashed) |
563 | + tryCompare(monitor, "killedRetries", 1) |
564 | + |
565 | + monitor.webview = null |
566 | + compare(monitor.killedRetries, 0) |
567 | + verify(!monitor.killed) |
568 | + verify(!monitor.crashed) |
569 | + } |
570 | + } |
571 | +} |
572 | |
573 | === modified file 'tests/unittests/tabs-model/tst_TabsModelTests.cpp' |
574 | --- tests/unittests/tabs-model/tst_TabsModelTests.cpp 2015-08-10 15:22:00 +0000 |
575 | +++ tests/unittests/tabs-model/tst_TabsModelTests.cpp 2015-09-02 16:48:16 +0000 |
576 | @@ -246,39 +246,62 @@ |
577 | |
578 | void shouldUpdateCurrentTabWhenRemoving() |
579 | { |
580 | - QSignalSpy spy(model, SIGNAL(currentTabChanged())); |
581 | + QSignalSpy tabSpy(model, SIGNAL(currentTabChanged())); |
582 | + QSignalSpy indexSpy(model, SIGNAL(currentIndexChanged())); |
583 | |
584 | // Adding a tab to an empty model should update the current tab. |
585 | // Removing the last tab from the model should update it too. |
586 | model->add(createTab()); |
587 | + tabSpy.clear(); |
588 | + indexSpy.clear(); |
589 | delete model->remove(0); |
590 | - QCOMPARE(spy.count(), 2); |
591 | + QCOMPARE(tabSpy.count(), 1); |
592 | + QCOMPARE(indexSpy.count(), 1); |
593 | |
594 | - // When removing a tab after the current one, |
595 | - // the current tab shouldn’t change. |
596 | + // When removing a tab after the current one, neither the |
597 | + // current tab nor the current index should change. |
598 | QQuickItem* tab1 = createTab(); |
599 | model->add(tab1); |
600 | model->add(createTab()); |
601 | - spy.clear(); |
602 | + tabSpy.clear(); |
603 | + indexSpy.clear(); |
604 | delete model->remove(1); |
605 | QCOMPARE(model->currentTab(), tab1); |
606 | - QVERIFY(spy.isEmpty()); |
607 | + QVERIFY(tabSpy.isEmpty()); |
608 | + QVERIFY(indexSpy.isEmpty()); |
609 | |
610 | - // When removing the current tab, if there is a tab after it, |
611 | - // it becomes the current one. |
612 | + // When removing the current tab, if there is a tab after it, it |
613 | + // becomes the current one, and thus the current index doesn’t change. |
614 | QQuickItem* tab2 = createTab(); |
615 | model->add(tab2); |
616 | - spy.clear(); |
617 | + tabSpy.clear(); |
618 | + indexSpy.clear(); |
619 | delete model->remove(0); |
620 | - QCOMPARE(spy.count(), 1); |
621 | + QCOMPARE(tabSpy.count(), 1); |
622 | + QVERIFY(indexSpy.isEmpty()); |
623 | QCOMPARE(model->currentTab(), tab2); |
624 | |
625 | + // When removing a tab before the current one, the current |
626 | + // tab doesn’t change but the current index is updated. |
627 | + QQuickItem* tab3 = createTab(); |
628 | + model->add(tab3); |
629 | + model->setCurrentIndex(1); |
630 | + tabSpy.clear(); |
631 | + indexSpy.clear(); |
632 | + delete model->remove(0); |
633 | + QVERIFY(tabSpy.isEmpty()); |
634 | + QCOMPARE(indexSpy.count(), 1); |
635 | + QCOMPARE(model->currentIndex(), 0); |
636 | + |
637 | // When removing the current tab, if it was the last one, the |
638 | // current tab should be reset to 0. |
639 | - spy.clear(); |
640 | + tabSpy.clear(); |
641 | + indexSpy.clear(); |
642 | delete model->remove(0); |
643 | - QCOMPARE(spy.count(), 1); |
644 | + QCOMPARE(tabSpy.count(), 1); |
645 | + QCOMPARE(indexSpy.count(), 1); |
646 | QCOMPARE(model->currentTab(), (QObject*) nullptr); |
647 | + QCOMPARE(model->currentIndex(), -1); |
648 | } |
649 | |
650 | void shouldReturnData() |
FAILED: Continuous integration, rev:1009 jenkins. qa.ubuntu. com/job/ webbrowser- app-ci/ 1759/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 2791/console jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- amd64-ci/ 516/console jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- armhf-ci/ 516/console jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- i386-ci/ 516/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 2789/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/webbrowser- app-ci/ 1759/rebuild
http://