Merge lp:~nataliabidart/ubuntuone-control-panel/webclient-shutdowns into lp:ubuntuone-control-panel

Proposed by Natalia Bidart
Status: Merged
Approved by: Natalia Bidart
Approved revision: 224
Merged at revision: 228
Proposed branch: lp:~nataliabidart/ubuntuone-control-panel/webclient-shutdowns
Merge into: lp:ubuntuone-control-panel
Diff against target: 228 lines (+192/-1)
3 files modified
ubuntuone/controlpanel/web_client/tests/__init__.py (+19/-0)
ubuntuone/controlpanel/web_client/tests/test_txwebclient.py (+155/-0)
ubuntuone/controlpanel/web_client/txwebclient.py (+18/-1)
To merge this branch: bzr merge lp:~nataliabidart/ubuntuone-control-panel/webclient-shutdowns
Reviewer Review Type Date Requested Status
Alejandro J. Cura (community) Approve
Roberto Alsina (community) Approve
Natalia Bidart Approve
Review via email: mp+75609@code.launchpad.net

Commit message

- Do not throw a webclient error when closing, all credits to alecu (LP: #845105).

To post a comment you must log in.
224. By Natalia Bidart on 2011-09-15

Attaching bug #845105.

Natalia Bidart (nataliabidart) wrote :

This is Alecu's code, and looks great.

review: Approve
Roberto Alsina (ralsina) wrote :

+1

review: Approve
Alejandro J. Cura (alecu) wrote :

All tests pass, and the code looks great :P

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'ubuntuone/controlpanel/web_client/tests'
2=== added file 'ubuntuone/controlpanel/web_client/tests/__init__.py'
3--- ubuntuone/controlpanel/web_client/tests/__init__.py 1970-01-01 00:00:00 +0000
4+++ ubuntuone/controlpanel/web_client/tests/__init__.py 2011-09-15 18:43:24 +0000
5@@ -0,0 +1,19 @@
6+# -*- coding: utf-8 -*-
7+
8+# Authors: Alejandro J. Cura <alecu@canonical.com>
9+#
10+# Copyright 2011 Canonical Ltd.
11+#
12+# This program is free software: you can redistribute it and/or modify it
13+# under the terms of the GNU General Public License version 3, as published
14+# by the Free Software Foundation.
15+#
16+# This program is distributed in the hope that it will be useful, but
17+# WITHOUT ANY WARRANTY; without even the implied warranties of
18+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
19+# PURPOSE. See the GNU General Public License for more details.
20+#
21+# You should have received a copy of the GNU General Public License along
22+# with this program. If not, see <http://www.gnu.org/licenses/>.
23+
24+"""Unit tests for the control panel backend webservice clients."""
25
26=== added file 'ubuntuone/controlpanel/web_client/tests/test_txwebclient.py'
27--- ubuntuone/controlpanel/web_client/tests/test_txwebclient.py 1970-01-01 00:00:00 +0000
28+++ ubuntuone/controlpanel/web_client/tests/test_txwebclient.py 2011-09-15 18:43:24 +0000
29@@ -0,0 +1,155 @@
30+# -*- coding: utf-8 -*-
31+
32+# Authors: Alejandro J. Cura <alecu@canonical.com>
33+#
34+# Copyright 2011 Canonical Ltd.
35+#
36+# This program is free software: you can redistribute it and/or modify it
37+# under the terms of the GNU General Public License version 3, as published
38+# by the Free Software Foundation.
39+#
40+# This program is distributed in the hope that it will be useful, but
41+# WITHOUT ANY WARRANTY; without even the implied warranties of
42+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
43+# PURPOSE. See the GNU General Public License for more details.
44+#
45+# You should have received a copy of the GNU General Public License along
46+# with this program. If not, see <http://www.gnu.org/licenses/>.
47+
48+"""Unit tests for the control panel backend twisted webservice client."""
49+
50+from twisted.application import internet, service
51+from twisted.internet import defer, reactor
52+from twisted.internet.defer import inlineCallbacks
53+from twisted.web import server, resource
54+from ubuntuone.devtools.testcase import skipIfOS
55+
56+from ubuntuone.controlpanel.web_client import txwebclient
57+from ubuntuone.controlpanel.tests import TestCase
58+
59+
60+SAMPLE_KEY = "result"
61+SAMPLE_VALUE = "sample result"
62+SAMPLE_RESOURCE = '{"%s": "%s"}' % (SAMPLE_KEY, SAMPLE_VALUE)
63+SAMPLE_CREDENTIALS = dict(
64+ consumer_key="consumer key",
65+ consumer_secret="consumer secret",
66+ token="the real token",
67+ token_secret="the token secret",
68+)
69+
70+
71+def sample_get_credentials():
72+ """Will return the sample credentials right now."""
73+ return defer.succeed(SAMPLE_CREDENTIALS)
74+
75+
76+class MockResource(resource.Resource):
77+ """A simple web resource."""
78+ isLeaf = True
79+ contents = ""
80+
81+ # pylint: disable=C0103
82+ # t.w.resource methods have freeform cased names
83+
84+ def getChild(self, name, request):
85+ """Get a given child resource."""
86+ if name == '':
87+ return self
88+ return resource.Resource.getChild(self, name, request)
89+
90+ def render_GET(self, request):
91+ """Make a bit of html out of these resource's content."""
92+ return self.contents
93+
94+
95+class MockWebService(object):
96+ """A mock webservice for testing"""
97+
98+ def __init__(self):
99+ """Start up this instance."""
100+ root = resource.Resource()
101+ devices_resource = MockResource()
102+ devices_resource.contents = SAMPLE_RESOURCE
103+ root.putChild("devices", devices_resource)
104+ root.putChild("throwerror", resource.NoResource())
105+ unauthorized = resource.ErrorPage(resource.http.UNAUTHORIZED,
106+ "Unauthrorized", "Unauthrorized")
107+ root.putChild("unauthorized", unauthorized)
108+
109+ site = server.Site(root)
110+ application = service.Application('web')
111+ self.service_collection = service.IServiceCollection(application)
112+ #pylint: disable=E1101
113+ self.tcpserver = internet.TCPServer(0, site)
114+ self.tcpserver.setServiceParent(self.service_collection)
115+ self.service_collection.startService()
116+
117+ def get_url(self):
118+ """Build the url for this mock server."""
119+ #pylint: disable=W0212
120+ port_num = self.tcpserver._port.getHost().port
121+ return "http://localhost:%d/" % port_num
122+
123+ def stop(self):
124+ """Shut it down."""
125+ #pylint: disable=E1101
126+ self.service_collection.stopService()
127+
128+
129+class WebClientTestCase(TestCase):
130+ """Test for the webservice client."""
131+
132+ timeout = 8
133+
134+ def setUp(self):
135+ super(WebClientTestCase, self).setUp()
136+ self.ws = MockWebService()
137+ test_base_url = self.ws.get_url()
138+ self.wc = txwebclient.WebClient(sample_get_credentials, test_base_url)
139+
140+ @inlineCallbacks
141+ def tearDown(self):
142+ super(WebClientTestCase, self).tearDown()
143+ yield self.ws.stop()
144+ self.wc.shutdown()
145+
146+ @inlineCallbacks
147+ def test_get_url(self):
148+ """A method is successfully called in the mock webservice."""
149+ result = yield self.wc.call_api("devices")
150+ self.assertIn(SAMPLE_KEY, result)
151+ self.assertEqual(SAMPLE_VALUE, result[SAMPLE_KEY])
152+
153+ @inlineCallbacks
154+ def test_get_url_error(self):
155+ """The errback is called when there's some error."""
156+ yield self.assertFailure(self.wc.call_api("throwerror"),
157+ txwebclient.WebClientError)
158+
159+ @inlineCallbacks
160+ def test_unauthorized(self):
161+ """Detect when a request failed with UNAUTHORIZED."""
162+ yield self.assertFailure(self.wc.call_api("unauthorized"),
163+ txwebclient.UnauthorizedError)
164+
165+
166+class WebClientShutdownTestCase(TestCase):
167+ """The webclient behaviour during shutdown."""
168+
169+ @skipIfOS('win32', 'Failing on windows, see LP: #851158.')
170+ @inlineCallbacks
171+ def test_shutdown(self):
172+ """The webclient behaves well during shutdown."""
173+ d3 = defer.Deferred()
174+ # pylint: disable=E1101
175+ reactor.callLater(1, d3.callback, None)
176+ ws = MockWebService()
177+ test_base_url = ws.get_url()
178+ wc = txwebclient.WebClient(sample_get_credentials, test_base_url)
179+ d1 = wc.call_api("throwerror")
180+ d2 = ws.stop()
181+ wc.shutdown()
182+ yield d2
183+ yield defer.DeferredList([d1, d3], fireOnOneCallback=True,
184+ fireOnOneErrback=True)
185
186=== modified file 'ubuntuone/controlpanel/web_client/txwebclient.py'
187--- ubuntuone/controlpanel/web_client/txwebclient.py 2011-06-02 13:14:51 +0000
188+++ ubuntuone/controlpanel/web_client/txwebclient.py 2011-09-15 18:43:24 +0000
189@@ -20,6 +20,7 @@
190
191 import simplejson
192
193+from twisted.internet import defer, reactor
194 from twisted.web import client, error, http
195
196 from ubuntuone.controlpanel import WEBSERVICE_BASE_URL
197@@ -39,6 +40,10 @@
198 """Initialize the webclient."""
199 self.base_url = base_url
200 self.get_credentials = get_credentials
201+ self.running = True
202+ # pylint: disable=E1101
203+ self.trigger_id = reactor.addSystemEventTrigger("before", "shutdown",
204+ self.shutdown)
205
206 def _handle_response(self, result):
207 """Handle the response of the webservice call."""
208@@ -74,7 +79,19 @@
209 d = self.get_credentials()
210 d.addErrback(self._handle_error)
211 d.addCallback(self._call_api_with_creds, api_name)
212- return d
213+ d2 = defer.Deferred()
214+ d.addCallback(d2.callback)
215+
216+ def mask_errors_on_shutdown(failure):
217+ """Do not fire the errbacks if we are shutting down."""
218+ if self.running:
219+ d2.errback(failure)
220+
221+ d.addErrback(mask_errors_on_shutdown)
222+ return d2
223
224 def shutdown(self):
225 """End the pending webclient calls."""
226+ self.running = False
227+ # pylint: disable=E1101
228+ reactor.removeSystemEventTrigger(self.trigger_id)

Subscribers

People subscribed via source and target branches