Merge lp:~osomon/webbrowser-app/webProcessStatus into lp:webbrowser-app

Proposed by Olivier Tilloy
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
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-app-autopilot on python3-psutil.

To post a comment you must log in.
1009. By Olivier Tilloy

Revert unnecessary version bump.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1010. By Olivier Tilloy

Also bump the build dependency on oxide to allow unit tests to run at build time.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1018. By Olivier Tilloy

Merge the latest changes from trunk and resolve conflicts.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1021. By Olivier Tilloy

Merge the latest changes from trunk.

1022. By Olivier Tilloy

Update imports.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Riccardo Padovani (rpadovani) wrote :

Useful function, thanks!

lgtm, just a note in the code I don't understand.

review: Needs Information
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.

Revision history for this message
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1026. By Olivier Tilloy

Update the tab model’s current index when a tab before the current one is removed.

Revision history for this message
Riccardo Padovani (rpadovani) wrote :

Lgtm now, thanks!

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2015-08-25 13:56:58 +0000
+++ debian/control 2015-09-02 16:48:16 +0000
@@ -122,6 +122,7 @@
122 autopilot-qt5,122 autopilot-qt5,
123 python3-autopilot,123 python3-autopilot,
124 python3-fixtures,124 python3-fixtures,
125 python3-psutil,
125 ubuntu-ui-toolkit-autopilot,126 ubuntu-ui-toolkit-autopilot,
126 webbrowser-app (>= ${binary:Version}),127 webbrowser-app (>= ${binary:Version}),
127Description: Ubuntu web browser autopilot tests128Description: Ubuntu web browser autopilot tests
128129
=== added file 'src/app/WebProcessMonitor.qml'
--- src/app/WebProcessMonitor.qml 1970-01-01 00:00:00 +0000
+++ src/app/WebProcessMonitor.qml 2015-09-02 16:48:16 +0000
@@ -0,0 +1,79 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.4
20import com.canonical.Oxide 1.8 as Oxide
21
22Item {
23 id: monitor
24
25 visible: false
26
27 property var webview: null
28
29 readonly property bool killed: webview &&
30 (webview.webProcessStatus == Oxide.WebView.WebProcessKilled)
31 readonly property bool crashed: webview &&
32 (webview.webProcessStatus == Oxide.WebView.WebProcessCrashed)
33
34 // When the renderer process is killed (most likely by the system’s
35 // OOM killer), try to reload the page once, and if this results in
36 // the process being killed again within one minute, then display
37 // the sad tab.
38
39 readonly property int killedRetries: internal.killedRetries
40
41 QtObject {
42 id: internal
43 property int killedRetries: 0
44 }
45
46 Connections {
47 target: webview
48 onWebProcessStatusChanged: {
49 if (webview.webProcessStatus == Oxide.WebView.WebProcessKilled) {
50 if (internal.killedRetries == 0) {
51 // Do not attempt reloading right away, this would result in a crash
52 delayedReload.restart()
53 }
54 }
55 }
56 }
57
58 Timer {
59 id: delayedReload
60 interval: 100
61 onTriggered: {
62 monitorTimer.restart()
63 monitor.webview.reload()
64 internal.killedRetries++
65 }
66 }
67
68 Timer {
69 id: monitorTimer
70 interval: 60000 // 1 minute
71 onTriggered: internal.killedRetries = 0
72 }
73
74 onWebviewChanged: {
75 internal.killedRetries = 0
76 delayedReload.stop()
77 monitorTimer.stop()
78 }
79}
080
=== modified file 'src/app/webbrowser/Browser.qml'
--- src/app/webbrowser/Browser.qml 2015-08-27 14:02:05 +0000
+++ src/app/webbrowser/Browser.qml 2015-09-02 16:48:16 +0000
@@ -206,6 +206,7 @@
206206
207 Loader {207 Loader {
208 id: newTabViewLoader208 id: newTabViewLoader
209
209 anchors {210 anchors {
210 fill: tabContainer211 fill: tabContainer
211 topMargin: (chrome.state == "shown") ? chrome.height : 0212 topMargin: (chrome.state == "shown") ? chrome.height : 0
@@ -290,6 +291,27 @@
290 }291 }
291 }292 }
292293
294 Loader {
295 anchors {
296 fill: tabContainer
297 topMargin: (chrome.state == "shown") ? chrome.height : 0
298 }
299
300 active: webProcessMonitor.crashed || (webProcessMonitor.killed && !currentWebview.loading)
301
302 sourceComponent: SadTab {
303 webview: currentWebview
304 onCloseTabRequested: internal.closeCurrentTab()
305 }
306
307 WebProcessMonitor {
308 id: webProcessMonitor
309 webview: currentWebview
310 }
311
312 asynchronous: true
313 }
314
293 SearchEngine {315 SearchEngine {
294 id: currentSearchEngine316 id: currentSearchEngine
295 searchPaths: searchEnginesSearchPaths317 searchPaths: searchEnginesSearchPaths
@@ -603,16 +625,7 @@
603 }625 }
604 chromeOffset: chrome.height - invisibleTabChrome.height626 chromeOffset: chrome.height - invisibleTabChrome.height
605 onTabSelected: recentView.closeAndSwitchToTab(index)627 onTabSelected: recentView.closeAndSwitchToTab(index)
606 onTabClosed: {628 onTabClosed: internal.closeTab(index)
607 var tab = tabsModel.remove(index)
608 if (tab) {
609 tab.close()
610 }
611 if (tabsModel.count === 0) {
612 browser.openUrlInNewTab("", true)
613 recentView.reset()
614 }
615 }
616 }629 }
617630
618 Toolbar {631 Toolbar {
@@ -1192,6 +1205,23 @@
1192 }1205 }
1193 }1206 }
11941207
1208 function closeTab(index) {
1209 var tab = tabsModel.remove(index)
1210 if (tab) {
1211 tab.close()
1212 }
1213 if (tabsModel.count === 0) {
1214 browser.openUrlInNewTab("", true)
1215 recentView.reset()
1216 }
1217 }
1218
1219 function closeCurrentTab() {
1220 if (tabsModel.count > 0) {
1221 closeTab(tabsModel.currentIndex)
1222 }
1223 }
1224
1195 function switchToTab(index) {1225 function switchToTab(index) {
1196 tabsModel.currentIndex = index1226 tabsModel.currentIndex = index
1197 var tab = tabsModel.currentTab1227 var tab = tabsModel.currentTab
@@ -1205,15 +1235,6 @@
1205 }1235 }
1206 }1236 }
12071237
1208 function closeCurrentTab() {
1209 if (tabsModel.count > 0) {
1210 var tab = tabsModel.remove(tabsModel.currentIndex)
1211 if (tab) {
1212 tab.close()
1213 }
1214 }
1215 }
1216
1217 function focusAddressBar(selectContent) {1238 function focusAddressBar(selectContent) {
1218 chrome.forceActiveFocus()1239 chrome.forceActiveFocus()
1219 Qt.inputMethod.show() // work around http://pad.lv/13160571240 Qt.inputMethod.show() // work around http://pad.lv/1316057
12201241
=== added file 'src/app/webbrowser/SadTab.qml'
--- src/app/webbrowser/SadTab.qml 1970-01-01 00:00:00 +0000
+++ src/app/webbrowser/SadTab.qml 2015-09-02 16:48:16 +0000
@@ -0,0 +1,92 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.4
20import Ubuntu.Components 1.3
21import com.canonical.Oxide 1.8 as Oxide
22
23Rectangle {
24 property var webview
25
26 signal closeTabRequested()
27
28 Column {
29 anchors {
30 fill: parent
31 margins: units.gu(4)
32 }
33 spacing: units.gu(4)
34
35 Image {
36 anchors.horizontalCenter: parent.horizontalCenter
37 source: "assets/tab-error.png"
38 }
39
40 Label {
41 anchors {
42 left: parent.left
43 right: parent.right
44 }
45
46 wrapMode: Text.Wrap
47 horizontalAlignment: Text.AlignHCenter
48 text: webview ? i18n.tr("The rendering process has been closed for this tab.") : ""
49 }
50
51 Label {
52 anchors {
53 left: parent.left
54 right: parent.right
55 }
56
57 wrapMode: Text.Wrap
58 horizontalAlignment: Text.AlignHCenter
59 font.weight: Font.Light
60 text: {
61 if (!webview) {
62 return ""
63 } else if (webview.webProcessStatus == Oxide.WebView.WebProcessCrashed) {
64 // TRANSLATORS: %1 is the URL of the page that crashed the renderer process
65 return i18n.tr("Something went wrong while displaying %1.").arg(webview.url)
66 } else if (webview.webProcessStatus == Oxide.WebView.WebProcessKilled) {
67 return i18n.tr("The system is low on memory and can't display this webpage. Try closing unneeded tabs and reloading.")
68 } else {
69 return ""
70 }
71 }
72 }
73
74 Row {
75 anchors.horizontalCenter: parent.horizontalCenter
76 spacing: units.gu(2)
77
78 Button {
79 objectName: "closeTabButton"
80 text: i18n.tr("Close tab")
81 onClicked: closeTabRequested()
82 }
83
84 Button {
85 objectName: "reloadButton"
86 text: i18n.tr("Reload")
87 color: UbuntuColors.green
88 onClicked: webview.reload()
89 }
90 }
91 }
92}
093
=== added file 'src/app/webbrowser/assets/tab-error@27.png'
1Binary 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 differ94Binary 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
=== modified file 'src/app/webbrowser/tabs-model.cpp'
--- src/app/webbrowser/tabs-model.cpp 2015-06-22 11:46:54 +0000
+++ src/app/webbrowser/tabs-model.cpp 2015-09-02 16:48:16 +0000
@@ -154,10 +154,11 @@
154 if (!checkValidTabIndex(index)) {154 if (!checkValidTabIndex(index)) {
155 m_currentIndex = m_tabs.count() - 1;155 m_currentIndex = m_tabs.count() - 1;
156 Q_EMIT currentIndexChanged();156 Q_EMIT currentIndexChanged();
157 Q_EMIT currentTabChanged();
158 } else {
159 Q_EMIT currentTabChanged();
160 }157 }
158 Q_EMIT currentTabChanged();
159 } else if (m_currentIndex > index) {
160 m_currentIndex -= 1;
161 Q_EMIT currentIndexChanged();
161 }162 }
162 return tab;163 return tab;
163}164}
164165
=== modified file 'tests/autopilot/webbrowser_app/emulators/browser.py'
--- tests/autopilot/webbrowser_app/emulators/browser.py 2015-08-25 13:56:58 +0000
+++ tests/autopilot/webbrowser_app/emulators/browser.py 2015-09-02 16:48:16 +0000
@@ -109,6 +109,9 @@
109 def get_error_sheet(self):109 def get_error_sheet(self):
110 return self.select_single("ErrorSheet")110 return self.select_single("ErrorSheet")
111111
112 def get_sad_tab(self):
113 return self.wait_select_single(SadTab)
114
112 def get_suggestions(self):115 def get_suggestions(self):
113 return self.select_single(Suggestions)116 return self.select_single(Suggestions)
114117
@@ -314,6 +317,19 @@
314 key=lambda item: item.globalRect.y)317 key=lambda item: item.globalRect.y)
315318
316319
320class SadTab(uitk.UbuntuUIToolkitCustomProxyObjectBase):
321
322 @autopilot.logging.log_action(logger.info)
323 def click_close_tab_button(self):
324 button = self.select_single("Button", objectName="closeTabButton")
325 self.pointing_device.click_object(button)
326
327 @autopilot.logging.log_action(logger.info)
328 def click_reload_button(self):
329 button = self.select_single("Button", objectName="reloadButton")
330 self.pointing_device.click_object(button)
331
332
317class GeolocationPermissionRequest(uitk.UbuntuUIToolkitCustomProxyObjectBase):333class GeolocationPermissionRequest(uitk.UbuntuUIToolkitCustomProxyObjectBase):
318334
319 def get_deny_button(self):335 def get_deny_button(self):
320336
=== modified file 'tests/autopilot/webbrowser_app/tests/__init__.py'
--- tests/autopilot/webbrowser_app/tests/__init__.py 2015-08-12 12:31:56 +0000
+++ tests/autopilot/webbrowser_app/tests/__init__.py 2015-09-02 16:48:16 +0000
@@ -18,11 +18,13 @@
1818
19import os19import os
20import shutil20import shutil
21import signal
21import tempfile22import tempfile
22import time23import time
23import urllib.request24import urllib.request
2425
25import fixtures26import fixtures
27import psutil
26from testtools.matchers import Equals, NotEquals28from testtools.matchers import Equals, NotEquals
2729
28from autopilot.matchers import Eventually30from autopilot.matchers import Eventually
@@ -213,6 +215,15 @@
213 ping = urllib.request.urlopen(url)215 ping = urllib.request.urlopen(url)
214 self.assertThat(ping.read(), Equals(b"pong"))216 self.assertThat(ping.read(), Equals(b"pong"))
215217
218 def kill_web_processes(self, signal=signal.SIGKILL):
219 children = psutil.Process(self.app.pid).children(True)
220 for child in children:
221 if child.name() == 'oxide-renderer':
222 for arg in child.cmdline():
223 if '--type=renderer' in arg:
224 os.kill(child.pid, signal)
225 break
226
216227
217class StartOpenRemotePageTestCaseBase(BrowserTestCaseBase):228class StartOpenRemotePageTestCaseBase(BrowserTestCaseBase):
218229
219230
=== added file 'tests/autopilot/webbrowser_app/tests/test_sad_tab.py'
--- tests/autopilot/webbrowser_app/tests/test_sad_tab.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/webbrowser_app/tests/test_sad_tab.py 2015-09-02 16:48:16 +0000
@@ -0,0 +1,74 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright 2015 Canonical
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import signal
18import time
19
20from autopilot.platform import model
21
22from webbrowser_app.tests import StartOpenRemotePageTestCaseBase
23
24
25class TestSadTab(StartOpenRemotePageTestCaseBase):
26
27 def _kill_web_process(self):
28 self.kill_web_processes()
29 # The first time the web process is killed, the browser attempts to
30 # reload the page gracefully (after a short delay), hoping the process
31 # won’t be killed again.
32 time.sleep(1)
33 self.main_window.wait_until_page_loaded(self.url)
34
35 self.kill_web_processes()
36 # The second time around, the browser displays a sad tab.
37 return self.main_window.get_sad_tab()
38
39 def test_reload_web_process_killed(self):
40 sad_tab = self._kill_web_process()
41 sad_tab.click_reload_button()
42 sad_tab.wait_until_destroyed()
43 self.assert_home_page_eventually_loaded()
44
45 def test_close_tab_web_process_killed(self):
46 sad_tab = self._kill_web_process()
47 sad_tab.click_close_tab_button()
48 if model() == 'Desktop':
49 # On desktop, closing the last open tab exits the application
50 self.app.process.wait()
51 return
52 sad_tab.wait_until_destroyed()
53 self.main_window.get_new_tab_view()
54
55 def _crash_web_process(self):
56 self.kill_web_processes(signal.SIGSEGV)
57 # A crash of the web process displays the sad tab right away
58 return self.main_window.get_sad_tab()
59
60 def test_reload_web_process_crashed(self):
61 sad_tab = self._crash_web_process()
62 sad_tab.click_reload_button()
63 sad_tab.wait_until_destroyed()
64 self.assert_home_page_eventually_loaded()
65
66 def test_close_tab_web_process_crashed(self):
67 sad_tab = self._crash_web_process()
68 sad_tab.click_close_tab_button()
69 if model() == 'Desktop':
70 # On desktop, closing the last open tab exits the application
71 self.app.process.wait()
72 return
73 sad_tab.wait_until_destroyed()
74 self.main_window.get_new_tab_view()
075
=== added file 'tests/unittests/qml/tst_WebProcessMonitor.qml'
--- tests/unittests/qml/tst_WebProcessMonitor.qml 1970-01-01 00:00:00 +0000
+++ tests/unittests/qml/tst_WebProcessMonitor.qml 2015-09-02 16:48:16 +0000
@@ -0,0 +1,108 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.4
20import QtTest 1.0
21import com.canonical.Oxide 1.8 as Oxide
22import "../../../src/app"
23
24WebProcessMonitor {
25 id: monitor
26
27 Item {
28 id: webviewMock
29
30 property int webProcessStatus
31
32 property int reloadCalled
33 function reload() {
34 webProcessStatus = Oxide.WebView.WebProcessRunning
35 reloadCalled++
36 }
37 }
38
39 TestCase {
40 name: "WebProcessMonitor"
41
42 function init() {
43 webviewMock.webProcessStatus = Oxide.WebView.WebProcessRunning
44 webviewMock.reloadCalled = 0
45 }
46
47 function test_no_webview() {
48 monitor.webview = null
49 compare(monitor.killedRetries, 0)
50 verify(!monitor.killed)
51 verify(!monitor.crashed)
52 }
53
54 function test_killed() {
55 monitor.webview = webviewMock
56 compare(monitor.killedRetries, 0)
57
58 webviewMock.webProcessStatus = Oxide.WebView.WebProcessKilled
59 verify(monitor.killed)
60 verify(!monitor.crashed)
61 tryCompare(monitor, "killedRetries", 1)
62 tryCompare(webviewMock, "reloadCalled", 1)
63 verify(!monitor.killed)
64 verify(!monitor.crashed)
65 compare(monitor.killedRetries, 1)
66
67 webviewMock.webProcessStatus = Oxide.WebView.WebProcessKilled
68 verify(monitor.killed)
69 verify(!monitor.crashed)
70 compare(monitor.killedRetries, 1)
71 compare(webviewMock.reloadCalled, 1)
72 }
73
74 function test_crashed() {
75 monitor.webview = webviewMock
76 compare(monitor.killedRetries, 0)
77
78 webviewMock.webProcessStatus = Oxide.WebView.WebProcessCrashed
79 verify(!monitor.killed)
80 verify(monitor.crashed)
81 compare(monitor.killedRetries, 0)
82 compare(webviewMock.reloadCalled, 0)
83
84 webviewMock.webProcessStatus = Oxide.WebView.WebProcessRunning
85 verify(!monitor.killed)
86 verify(!monitor.crashed)
87 compare(monitor.killedRetries, 0)
88 compare(webviewMock.reloadCalled, 0)
89 }
90
91 function test_change_webview() {
92 monitor.webview = webviewMock
93 compare(monitor.killedRetries, 0)
94 verify(!monitor.killed)
95 verify(!monitor.crashed)
96
97 webviewMock.webProcessStatus = Oxide.WebView.WebProcessKilled
98 verify(monitor.killed)
99 verify(!monitor.crashed)
100 tryCompare(monitor, "killedRetries", 1)
101
102 monitor.webview = null
103 compare(monitor.killedRetries, 0)
104 verify(!monitor.killed)
105 verify(!monitor.crashed)
106 }
107 }
108}
0109
=== modified file 'tests/unittests/tabs-model/tst_TabsModelTests.cpp'
--- tests/unittests/tabs-model/tst_TabsModelTests.cpp 2015-08-10 15:22:00 +0000
+++ tests/unittests/tabs-model/tst_TabsModelTests.cpp 2015-09-02 16:48:16 +0000
@@ -246,39 +246,62 @@
246246
247 void shouldUpdateCurrentTabWhenRemoving()247 void shouldUpdateCurrentTabWhenRemoving()
248 {248 {
249 QSignalSpy spy(model, SIGNAL(currentTabChanged()));249 QSignalSpy tabSpy(model, SIGNAL(currentTabChanged()));
250 QSignalSpy indexSpy(model, SIGNAL(currentIndexChanged()));
250251
251 // Adding a tab to an empty model should update the current tab.252 // Adding a tab to an empty model should update the current tab.
252 // Removing the last tab from the model should update it too.253 // Removing the last tab from the model should update it too.
253 model->add(createTab());254 model->add(createTab());
255 tabSpy.clear();
256 indexSpy.clear();
254 delete model->remove(0);257 delete model->remove(0);
255 QCOMPARE(spy.count(), 2);258 QCOMPARE(tabSpy.count(), 1);
259 QCOMPARE(indexSpy.count(), 1);
256260
257 // When removing a tab after the current one,261 // When removing a tab after the current one, neither the
258 // the current tab shouldn’t change.262 // current tab nor the current index should change.
259 QQuickItem* tab1 = createTab();263 QQuickItem* tab1 = createTab();
260 model->add(tab1);264 model->add(tab1);
261 model->add(createTab());265 model->add(createTab());
262 spy.clear();266 tabSpy.clear();
267 indexSpy.clear();
263 delete model->remove(1);268 delete model->remove(1);
264 QCOMPARE(model->currentTab(), tab1);269 QCOMPARE(model->currentTab(), tab1);
265 QVERIFY(spy.isEmpty());270 QVERIFY(tabSpy.isEmpty());
271 QVERIFY(indexSpy.isEmpty());
266272
267 // When removing the current tab, if there is a tab after it,273 // When removing the current tab, if there is a tab after it, it
268 // it becomes the current one.274 // becomes the current one, and thus the current index doesn’t change.
269 QQuickItem* tab2 = createTab();275 QQuickItem* tab2 = createTab();
270 model->add(tab2);276 model->add(tab2);
271 spy.clear();277 tabSpy.clear();
278 indexSpy.clear();
272 delete model->remove(0);279 delete model->remove(0);
273 QCOMPARE(spy.count(), 1);280 QCOMPARE(tabSpy.count(), 1);
281 QVERIFY(indexSpy.isEmpty());
274 QCOMPARE(model->currentTab(), tab2);282 QCOMPARE(model->currentTab(), tab2);
275283
284 // When removing a tab before the current one, the current
285 // tab doesn’t change but the current index is updated.
286 QQuickItem* tab3 = createTab();
287 model->add(tab3);
288 model->setCurrentIndex(1);
289 tabSpy.clear();
290 indexSpy.clear();
291 delete model->remove(0);
292 QVERIFY(tabSpy.isEmpty());
293 QCOMPARE(indexSpy.count(), 1);
294 QCOMPARE(model->currentIndex(), 0);
295
276 // When removing the current tab, if it was the last one, the296 // When removing the current tab, if it was the last one, the
277 // current tab should be reset to 0.297 // current tab should be reset to 0.
278 spy.clear();298 tabSpy.clear();
299 indexSpy.clear();
279 delete model->remove(0);300 delete model->remove(0);
280 QCOMPARE(spy.count(), 1);301 QCOMPARE(tabSpy.count(), 1);
302 QCOMPARE(indexSpy.count(), 1);
281 QCOMPARE(model->currentTab(), (QObject*) nullptr);303 QCOMPARE(model->currentTab(), (QObject*) nullptr);
304 QCOMPARE(model->currentIndex(), -1);
282 }305 }
283306
284 void shouldReturnData()307 void shouldReturnData()

Subscribers

People subscribed via source and target branches

to status/vote changes: