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

Proposed by Alejandro J. Cura
Status: Rejected
Rejected by: Alejandro J. Cura
Proposed branch: lp:~alecu/ubuntuone-control-panel/webclient-shutdowns
Merge into: lp:ubuntuone-control-panel
Diff against target: 226 lines (+190/-1)
3 files modified
ubuntuone/controlpanel/web_client/tests/__init__.py (+19/-0)
ubuntuone/controlpanel/web_client/tests/test_txwebclient.py (+153/-0)
ubuntuone/controlpanel/web_client/txwebclient.py (+18/-1)
To merge this branch: bzr merge lp:~alecu/ubuntuone-control-panel/webclient-shutdowns
Reviewer Review Type Date Requested Status
Natalia Bidart (community) Needs Fixing
Review via email: mp+74708@code.launchpad.net

Commit message

- Do not throw a webclient error when closing (LP: #845105).

Description of the change

Do not throw a webclient error when closing (LP: #845105)

To post a comment you must log in.
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

The branch looks good, but I'm getting this in windows:

===============================================================================
[ERROR]
Traceback (most recent call last):
Failure: twisted.trial.util.DirtyReactorAggregateError: Reactor was unclean.
DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug)
<DelayedCall 0x5dad710 [29.004999876s] called=0 cancelled=0 Client.failIfNotConn
ected(TimeoutError('',))>

ubuntuone.controlpanel.web_client.tests.test_txwebclient.WebClientShutdownTestCa
se.test_shutdown
===============================================================================
[ERROR]
Traceback (most recent call last):
Failure: twisted.trial.util.DirtyReactorAggregateError: Reactor was unclean.
Selectables:
<<class 'twisted.internet.tcp.Client'> to ('localhost', 50832) at 5dac6d0>

ubuntuone.controlpanel.web_client.tests.test_txwebclient.WebClientShutdownTestCa
se.test_shutdown
-------------------------------------------------------------------------------

As far as I can see, if the test finished because d2 was fired, the deferred d3 leaves the reactor unclean with the callLater thing added.

review: Needs Fixing
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

It works great IRL!!!

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Unmerged revisions

Preview Diff

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

Subscribers

People subscribed via source and target branches