Merge lp:~abreu-alexandre/webbrowser-app/handle-webapp-renderer-crash into lp:webbrowser-app

Proposed by Alexandre Abreu
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 1215
Merged at revision: 1217
Proposed branch: lp:~abreu-alexandre/webbrowser-app/handle-webapp-renderer-crash
Merge into: lp:webbrowser-app
Diff against target: 434 lines (+291/-22)
6 files modified
src/app/webcontainer/CMakeLists.txt (+4/-0)
src/app/webcontainer/PopupWindowOverlay.qml (+17/-1)
src/app/webcontainer/SadPage.qml (+56/-0)
src/app/webcontainer/WebApp.qml (+41/-21)
tests/autopilot/webapp_container/tests/__init__.py (+11/-0)
tests/autopilot/webapp_container/tests/test_sad_tab.py (+162/-0)
To merge this branch: bzr merge lp:~abreu-alexandre/webbrowser-app/handle-webapp-renderer-crash
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Olivier Tilloy Approve
Review via email: mp+271865@code.launchpad.net

Commit message

Handle webapp webview renderer crashes

Description of the change

Handle webapp webview renderer crashes

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

Has this been signed off by the design team? I mentioned to them last week that you were going to implement something similar to what exists in the browser for the webapp container, and they agreed that the wording might require some tweaking. The mention of "tabs" in the default sad tab message that is used for the browser might be misleading in the context of the webapp container, especially if no overlay is currently being displayed.

One tiny remark: the SadTab autopilot proxy object should be defined in test_sad_tab.py, since it’s not used anywhere else.

Other than that, this looks good to me and seems to work well.

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

> One tiny remark: the SadTab autopilot proxy object should be defined in
> test_sad_tab.py, since it’s not used anywhere else.

updated

> Other than that, this looks good to me and seems to work well.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1199. By CI Train Bot Account

Resync trunk.

1200. By Olivier Tilloy

Update translation template.

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

I updated the UI (and obviously the rest) to simplify it and remove the user message so that it can land in OTA-7. Once it lands I'll create a ubuntu-ux task to verify and tweak that behavior (with a more meaningful message),

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1201. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1202. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1203. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1204. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1205. By Launchpad Translations on behalf of phablet-team

Launchpad automatic translations update.

1206. By Michael Sheldon

Add support for alternative mimetype header for vcards Fixes: #1498992
Approved by: Olivier Tilloy

1207. By Ugo Riboni

Add a context menu to each tab in the tab bar, allowing to insert a new tab just after, close or reload the current tab.
Approved by: Riccardo Padovani

1208. By Olivier Tilloy

Fix a couple of autopilot test failures on desktop. Fixes: #1495297, #1499411

1209. By CI Train Bot Account

Releasing 0.23+15.10.20150928-0ubuntu1

1210. By CI Train Bot Account

Resync trunk.

Revision history for this message
Olivier Tilloy (osomon) wrote :

Let’s discuss this proposed implementation at our weekly catchup with design later today.

A side note: "SadWebview.qml" is a confusing name, given that it’s not a webview.

1211. By Ugo Riboni

Extend the clickable area to close a tab on mobile, as taps are less precise and often end up missing it. Fixes: #1500339
Approved by: Olivier Tilloy

1212. By Olivier Tilloy

Use the UA override for www.youtube.com on mobile too. Fixes: #1499394
Approved by: Alexandre Abreu, David Barth

1213. By CI Train Bot Account

Releasing 0.23+15.10.20150929-0ubuntu1

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

Updated according to design's comment; also changed the SadWebview qml name

1214. By Alexandre Abreu

Handle renderer crash in webapp container

1215. By Alexandre Abreu

remove uneeded signal

Revision history for this message
Olivier Tilloy (osomon) wrote :

LGTM.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/app/webcontainer/CMakeLists.txt'
--- src/app/webcontainer/CMakeLists.txt 2015-07-20 14:20:37 +0000
+++ src/app/webcontainer/CMakeLists.txt 2015-09-29 20:15:01 +0000
@@ -44,3 +44,7 @@
44install(FILES ${QML_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app/webcontainer)44install(FILES ${QML_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app/webcontainer)
45install(DIRECTORY actions DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app/webcontainer45install(DIRECTORY actions DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app/webcontainer
46 FILES_MATCHING PATTERN *.qml)46 FILES_MATCHING PATTERN *.qml)
47
48install(DIRECTORY assets
49 DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app/webcontainer
50 FILES_MATCHING PATTERN *.png)
4751
=== modified file 'src/app/webcontainer/PopupWindowOverlay.qml'
--- src/app/webcontainer/PopupWindowOverlay.qml 2015-08-10 15:33:43 +0000
+++ src/app/webcontainer/PopupWindowOverlay.qml 2015-09-29 20:15:01 +0000
@@ -27,6 +27,7 @@
2727
28 property var popupWindowController28 property var popupWindowController
29 property var webContext29 property var webContext
30 property alias currentWebview: popupWebview
30 property alias request: popupWebview.request31 property alias request: popupWebview.request
31 property alias url: popupWebview.url32 property alias url: popupWebview.url
32 33
@@ -194,6 +195,21 @@
194 popupWindowController.handleViewRemoved(popup)195 popupWindowController.handleViewRemoved(popup)
195 }196 }
196 }197 }
198
199 Loader {
200 anchors {
201 fill: popupWebview
202 }
203 active: webProcessMonitor.crashed || (webProcessMonitor.killed && !popupWebview.currentWebview.loading)
204 sourceComponent: SadPage {
205 webview: popupWebview
206 objectName: "overlaySadPage"
207 }
208 WebProcessMonitor {
209 id: webProcessMonitor
210 webview: popupWebview
211 }
212 asynchronous: true
213 }
197 }214 }
198
199}215}
200216
=== added file 'src/app/webcontainer/SadPage.qml'
--- src/app/webcontainer/SadPage.qml 1970-01-01 00:00:00 +0000
+++ src/app/webcontainer/SadPage.qml 2015-09-29 20:15:01 +0000
@@ -0,0 +1,56 @@
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
21
22Rectangle {
23 property var webview
24
25 Column {
26 anchors {
27 fill: parent
28 margins: units.gu(4)
29 }
30 spacing: units.gu(4)
31
32 Image {
33 anchors.horizontalCenter: parent.horizontalCenter
34 source: "assets/tab-error.png"
35 }
36
37 Label {
38 anchors {
39 left: parent.left
40 right: parent.right
41 }
42
43 wrapMode: Text.Wrap
44 horizontalAlignment: Text.AlignHCenter
45 text: webview ? i18n.tr("Oops, something went wrong.") : ""
46 }
47
48 Button {
49 anchors.horizontalCenter: parent.horizontalCenter
50 objectName: "reloadButton"
51 text: i18n.tr("Reload")
52 color: UbuntuColors.green
53 onClicked: webview.reload()
54 }
55 }
56}
057
=== modified file 'src/app/webcontainer/WebApp.qml'
--- src/app/webcontainer/WebApp.qml 2015-08-18 14:18:37 +0000
+++ src/app/webcontainer/WebApp.qml 2015-09-29 20:15:01 +0000
@@ -29,21 +29,21 @@
29 id: webapp29 id: webapp
30 objectName: "webappBrowserView"30 objectName: "webappBrowserView"
3131
32 currentWebview: webview.currentWebview32 currentWebview: containerWebView.currentWebview
3333
34 property alias url: webview.url34 property alias url: containerWebView.url
3535
36 property bool accountSwitcher36 property bool accountSwitcher
3737
38 property string webappModelSearchPath: ""38 property string webappModelSearchPath: ""
3939
40 property var webappUrlPatterns40 property var webappUrlPatterns
41 property alias popupRedirectionUrlPrefixPattern: webview.popupRedirectionUrlPrefixPattern41 property alias popupRedirectionUrlPrefixPattern: containerWebView.popupRedirectionUrlPrefixPattern
42 property alias webviewOverrideFile: webview.webviewOverrideFile42 property alias webviewOverrideFile: containerWebView.webviewOverrideFile
43 property alias blockOpenExternalUrls: webview.blockOpenExternalUrls43 property alias blockOpenExternalUrls: containerWebView.blockOpenExternalUrls
44 property alias localUserAgentOverride: webview.localUserAgentOverride44 property alias localUserAgentOverride: containerWebView.localUserAgentOverride
45 property alias dataPath: webview.dataPath45 property alias dataPath: containerWebView.dataPath
46 property alias runningLocalApplication: webview.runningLocalApplication46 property alias runningLocalApplication: containerWebView.runningLocalApplication
4747
48 property string webappName: ""48 property string webappName: ""
4949
@@ -60,15 +60,15 @@
6060
61 actions: [61 actions: [
62 Actions.Back {62 Actions.Back {
63 enabled: webapp.backForwardButtonsVisible && webview.currentWebview && webview.currentWebview.canGoBack63 enabled: webapp.backForwardButtonsVisible && containerWebView.currentWebview && containerWebView.currentWebview.canGoBack
64 onTriggered: webview.currentWebview.goBack()64 onTriggered: containerWebView.currentWebview.goBack()
65 },65 },
66 Actions.Forward {66 Actions.Forward {
67 enabled: webapp.backForwardButtonsVisible && webview.currentWebview && webview.currentWebview.canGoForward67 enabled: webapp.backForwardButtonsVisible && containerWebView.currentWebview && containerWebView.currentWebview.canGoForward
68 onTriggered: webview.currentWebview.goForward()68 onTriggered: containerWebView.currentWebview.goForward()
69 },69 },
70 Actions.Reload {70 Actions.Reload {
71 onTriggered: webview.currentWebview.reload()71 onTriggered: containerWebView.currentWebview.reload()
72 }72 }
73 ]73 ]
7474
@@ -121,7 +121,7 @@
121 anchors.fill: parent121 anchors.fill: parent
122122
123 WebappContainerWebview {123 WebappContainerWebview {
124 id: webview124 id: containerWebView
125 objectName: "webview"125 objectName: "webview"
126126
127 anchors {127 anchors {
@@ -144,19 +144,39 @@
144 * being explictly defined here.144 * being explictly defined here.
145 */145 */
146 webappName: webapp.webappName === "" ? unityWebapps.name : webapp.webappName146 webappName: webapp.webappName === "" ? unityWebapps.name : webapp.webappName
147
148 Loader {
149 anchors {
150 fill: containerWebView
151 topMargin: (!webapp.chromeless && chromeLoader.item.state == "shown")
152 ? chromeLoader.item.height
153 : 0
154 }
155 active: containerWebView.currentWebview &&
156 (webProcessMonitor.crashed || (webProcessMonitor.killed && !containerWebView.currentWebview.loading))
157 sourceComponent: SadPage {
158 webview: containerWebView.currentWebview
159 objectName: "mainWebviewSadPage"
160 }
161 WebProcessMonitor {
162 id: webProcessMonitor
163 webview: containerWebView.currentWebview
164 }
165 asynchronous: true
166 }
147 }167 }
148168
149 Loader {169 Loader {
150 anchors {170 anchors {
151 fill: webview171 fill: containerWebView
152 topMargin: (!webapp.chromeless && chromeLoader.item.state == "shown") ? chromeLoader.item.height : 0172 topMargin: (!webapp.chromeless && chromeLoader.item.state == "shown") ? chromeLoader.item.height : 0
153 }173 }
154 sourceComponent: ErrorSheet {174 sourceComponent: ErrorSheet {
155 visible: webview.currentWebview && webview.currentWebview.lastLoadFailed175 visible: containerWebView.currentWebview && containerWebView.currentWebview.lastLoadFailed
156 url: webview.currentWebview ? webview.currentWebview.url : ""176 url: containerWebView.currentWebview ? containerWebView.currentWebview.url : ""
157 onRefreshClicked: {177 onRefreshClicked: {
158 if (webview.currentWebview)178 if (containerWebView.currentWebview)
159 webview.currentWebview.reload()179 containerWebView.currentWebview.reload()
160 }180 }
161 }181 }
162 asynchronous: true182 asynchronous: true
@@ -186,7 +206,7 @@
186 right: parent.right206 right: parent.right
187 }207 }
188 height: units.gu(6)208 height: units.gu(6)
189 y: webapp.currentWebview ? webview.currentWebview.locationBarController.offset : 0209 y: webapp.currentWebview ? containerWebView.currentWebview.locationBarController.offset : 0
190210
191 onChooseAccount: webapp.chooseAccount()211 onChooseAccount: webapp.chooseAccount()
192 }212 }
@@ -225,7 +245,7 @@
225 UnityWebApps.UnityWebApps {245 UnityWebApps.UnityWebApps {
226 id: unityWebapps246 id: unityWebapps
227 name: webappName247 name: webappName
228 bindee: webview.currentWebview248 bindee: containerWebView.currentWebview
229 actionsContext: actionManager.globalContext249 actionsContext: actionManager.globalContext
230 model: UnityWebApps.UnityWebappsAppModel { searchPath: webappModelSearchPath }250 model: UnityWebApps.UnityWebappsAppModel { searchPath: webappModelSearchPath }
231 injectExtraUbuntuApis: runningLocalApplication251 injectExtraUbuntuApis: runningLocalApplication
232252
=== added directory 'src/app/webcontainer/assets'
=== added file 'src/app/webcontainer/assets/tab-error@27.png'
233Binary files src/app/webcontainer/assets/tab-error@27.png 1970-01-01 00:00:00 +0000 and src/app/webcontainer/assets/tab-error@27.png 2015-09-29 20:15:01 +0000 differ253Binary files src/app/webcontainer/assets/tab-error@27.png 1970-01-01 00:00:00 +0000 and src/app/webcontainer/assets/tab-error@27.png 2015-09-29 20:15:01 +0000 differ
=== modified file 'tests/autopilot/webapp_container/tests/__init__.py'
--- tests/autopilot/webapp_container/tests/__init__.py 2015-07-28 19:29:58 +0000
+++ tests/autopilot/webapp_container/tests/__init__.py 2015-09-29 20:15:01 +0000
@@ -16,7 +16,9 @@
16""" Autopilot tests for the webapp_container package """16""" Autopilot tests for the webapp_container package """
1717
18import os18import os
19import signal
19import subprocess20import subprocess
21import psutil
2022
21import fixtures23import fixtures
22from autopilot.testcase import AutopilotTestCase24from autopilot.testcase import AutopilotTestCase
@@ -120,6 +122,15 @@
120 webview.url = url122 webview.url = url
121 self.assert_page_eventually_loaded(url)123 self.assert_page_eventually_loaded(url)
122124
125 def kill_web_processes(self, signal=signal.SIGKILL):
126 children = psutil.Process(self.app.pid).children(True)
127 for child in children:
128 if child.name() == 'oxide-renderer':
129 for arg in child.cmdline():
130 if '--type=renderer' in arg:
131 os.kill(child.pid, signal)
132 break
133
123134
124class WebappContainerTestCaseWithLocalContentBase(WebappContainerTestCaseBase):135class WebappContainerTestCaseWithLocalContentBase(WebappContainerTestCaseBase):
125 BASE_URL_SCHEME = 'http://'136 BASE_URL_SCHEME = 'http://'
126137
=== added file 'tests/autopilot/webapp_container/tests/test_sad_tab.py'
--- tests/autopilot/webapp_container/tests/test_sad_tab.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/webapp_container/tests/test_sad_tab.py 2015-09-29 20:15:01 +0000
@@ -0,0 +1,162 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2015 Canonical
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16import signal
17import time
18
19from webapp_container.tests import WebappContainerTestCaseWithLocalContentBase
20
21from testtools.matchers import Equals, Contains, GreaterThan
22from autopilot.matchers import Eventually
23
24import ubuntuuitoolkit as uitk
25
26
27class SadPage(uitk.UbuntuUIToolkitCustomProxyObjectBase):
28 def click_reload_button(self):
29 button = self.select_single("Button", objectName="reloadButton")
30 self.pointing_device.click_object(button)
31
32
33class TestSadTab(WebappContainerTestCaseWithLocalContentBase):
34 def _kill_web_process(self):
35 self.kill_web_processes()
36 time.sleep(1)
37 self.assert_page_eventually_loaded(self.url)
38
39 self.kill_web_processes()
40
41 def _click_href_target_blank(self):
42 webview = self.get_oxide_webview()
43 self.assertThat(webview.url, Contains('/open-close-content'))
44 gr = webview.globalRect
45 self.pointing_device.move(
46 gr.x + gr.width/4,
47 gr.y + gr.height/4)
48 self.pointing_device.click()
49
50 def _click_overlay(self):
51 popup_controller = self.get_popup_controller()
52 new_view_watcher = popup_controller.watch_signal(
53 'newViewCreated(QString)')
54 animation_watcher = popup_controller.watch_signal(
55 'windowOverlayOpenAnimationDone()')
56 animation_signal_emission = animation_watcher.num_emissions
57
58 views = self.get_popup_overlay_views()
59 self.assertThat(len(views), Equals(0))
60
61 self._click_href_target_blank()
62
63 self.assertThat(
64 lambda: new_view_watcher.was_emitted,
65 Eventually(Equals(True)))
66 self.assertThat(
67 lambda: len(self.get_popup_overlay_views()),
68 Eventually(Equals(1)))
69 views = self.get_popup_overlay_views()
70 overlay = views[0]
71 self.assertThat(
72 overlay.select_single(objectName="overlayWebview").url,
73 Contains('/open-close-content'))
74
75 self.assertThat(
76 lambda: animation_watcher.num_emissions,
77 Eventually(GreaterThan(animation_signal_emission)))
78
79 def test_reload_main_webview_killed(self):
80 self.launch_webcontainer_app_with_local_http_server([])
81 self.get_webcontainer_window().visible.wait_for(True)
82
83 self._kill_web_process()
84
85 sad_webview = self.app.wait_select_single(
86 SadPage,
87 objectName="mainWebviewSadPage")
88 sad_webview.click_reload_button()
89 sad_webview.wait_until_destroyed()
90
91 self.assert_page_eventually_loaded(self.url)
92
93 def test_reload_overlay_killed(self):
94 args = []
95 self.launch_webcontainer_app_with_local_http_server(
96 args,
97 '/open-close-content')
98 self.get_webcontainer_window().visible.wait_for(True)
99
100 self._click_overlay()
101
102 self._kill_web_process()
103
104 sad_webview = self.app.wait_select_single(
105 SadPage,
106 objectName="overlaySadPage")
107
108 sad_webview.click_reload_button()
109 sad_webview.wait_until_destroyed()
110
111 views = self.get_popup_overlay_views()
112 overlay = views[0]
113 self.assertThat(
114 lambda: overlay.wait_select_single(
115 objectName="overlayWebview").url,
116 Eventually(Contains('/open-close-content')))
117
118 def _crash_web_process(self):
119 self.kill_web_processes(signal.SIGABRT)
120
121 def test_reload_main_webview_crashed(self):
122 self.launch_webcontainer_app_with_local_http_server([])
123 self.get_webcontainer_window().visible.wait_for(True)
124
125 self._crash_web_process()
126
127 sad_webview = self.app.wait_select_single(
128 SadPage,
129 objectName="mainWebviewSadPage")
130
131 sad_webview.click_reload_button()
132 sad_webview.wait_until_destroyed()
133
134 self.assert_page_eventually_loaded(self.url)
135
136 def test_reload_overlay_crashed(self):
137 args = []
138 self.launch_webcontainer_app_with_local_http_server(
139 args,
140 '/open-close-content')
141 self.get_webcontainer_window().visible.wait_for(True)
142
143 self._click_overlay()
144 self.assertThat(
145 lambda: len(self.get_popup_overlay_views()),
146 Eventually(Equals(1)))
147
148 self._crash_web_process()
149
150 sad_webview = self.app.wait_select_single(
151 SadPage,
152 objectName="overlaySadPage")
153
154 sad_webview.click_reload_button()
155 sad_webview.wait_until_destroyed()
156
157 views = self.get_popup_overlay_views()
158 overlay = views[0]
159 self.assertThat(
160 lambda: overlay.wait_select_single(
161 objectName="overlayWebview").url,
162 Eventually(Contains('/open-close-content')))

Subscribers

People subscribed via source and target branches

to status/vote changes: