Merge lp:~alecu/ubuntu-sso-client/properly-return-errors into lp:ubuntu-sso-client

Proposed by Alejandro J. Cura
Status: Merged
Approved by: Alejandro J. Cura
Approved revision: 585
Merged at revision: 581
Proposed branch: lp:~alecu/ubuntu-sso-client/properly-return-errors
Merge into: lp:ubuntu-sso-client
Diff against target: 549 lines (+171/-69)
4 files modified
ubuntu_sso/gui.py (+7/-7)
ubuntu_sso/main.py (+46/-33)
ubuntu_sso/tests/test_gui.py (+5/-5)
ubuntu_sso/tests/test_main.py (+113/-24)
To merge this branch: bzr merge lp:~alecu/ubuntu-sso-client/properly-return-errors
Reviewer Review Type Date Requested Status
Natalia Bidart (community) Approve
Rodrigo Moya (community) Approve
Review via email: mp+33362@code.launchpad.net

Commit message

Make all the signals return the errors as dictionaries (LP: #616105).
Credential* signals should return the app_name as well (LP: #621377).

Description of the change

Make all the signals return the errors as dictionaries (LP: #616105).
Credential* signals should return the app_name as well (LP: #621377).

To post a comment you must log in.
Revision history for this message
Rodrigo Moya (rodrigo-moya) :
review: Approve
Revision history for this message
Natalia Bidart (nataliabidart) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ubuntu_sso/gui.py'
2--- ubuntu_sso/gui.py 2010-08-19 20:56:52 +0000
3+++ ubuntu_sso/gui.py 2010-08-23 19:43:39 +0000
4@@ -57,11 +57,11 @@
5 SIG_USER_CANCELATION = 'user-cancelation'
6
7 SIGNAL_ARGUMENTS = [
8- (SIG_LOGIN_FAILED, ()),
9+ (SIG_LOGIN_FAILED, (gobject.TYPE_STRING,)),
10 (SIG_LOGIN_SUCCEEDED, (gobject.TYPE_STRING,)),
11- (SIG_REGISTRATION_FAILED, ()),
12+ (SIG_REGISTRATION_FAILED, (gobject.TYPE_STRING,)),
13 (SIG_REGISTRATION_SUCCEEDED, (gobject.TYPE_STRING,)),
14- (SIG_USER_CANCELATION, ()),
15+ (SIG_USER_CANCELATION, (gobject.TYPE_STRING,)),
16 ]
17
18 for sig, args in SIGNAL_ARGUMENTS:
19@@ -586,7 +586,7 @@
20 self.window.hide()
21
22 if len(args) > 0 and args[0] in self.cancels:
23- self.window.emit(SIG_USER_CANCELATION)
24+ self.window.emit(SIG_USER_CANCELATION, self.app_name)
25 elif len(self._gtk_signal_log) > 0:
26 signal = self._gtk_signal_log[-1][0]
27 args = self._gtk_signal_log[-1][1:]
28@@ -823,7 +823,7 @@
29 args, kwargs)
30 self._set_current_page(self.enter_details_vbox,
31 warning_text=self.UNKNOWN_ERROR)
32- self._gtk_signal_log.append((SIG_REGISTRATION_FAILED,))
33+ self._gtk_signal_log.append((SIG_REGISTRATION_FAILED, self.app_name))
34
35 def on_email_validated(self, app_name, *args, **kwargs):
36 """User email was successfully verified."""
37@@ -838,7 +838,7 @@
38 args, kwargs)
39 self._set_current_page(self.verify_email_vbox,
40 warning_text=self.UNKNOWN_ERROR)
41- self._gtk_signal_log.append((SIG_REGISTRATION_FAILED,))
42+ self._gtk_signal_log.append((SIG_REGISTRATION_FAILED, self.app_name))
43
44 def on_logged_in(self, app_name, *args, **kwargs):
45 """User was successfully logged in."""
46@@ -853,7 +853,7 @@
47 args, kwargs)
48 self._set_current_page(self.login_vbox,
49 warning_text=self.UNKNOWN_ERROR)
50- self._gtk_signal_log.append((SIG_LOGIN_FAILED,))
51+ self._gtk_signal_log.append((SIG_LOGIN_FAILED, self.app_name))
52
53 def on_password_reset_token_sent(self, email, *args, **kwargs):
54 """Password reset token was successfully sent."""
55
56=== modified file 'ubuntu_sso/main.py'
57--- ubuntu_sso/main.py 2010-08-20 18:04:28 +0000
58+++ ubuntu_sso/main.py 2010-08-23 19:43:39 +0000
59@@ -31,6 +31,7 @@
60 import socket
61 import time
62 import threading
63+import traceback
64 import urllib
65 import urllib2
66 import urlparse
67@@ -115,7 +116,7 @@
68 creds = {
69 'consumer_key': "ubuntuone",
70 'consumer_secret': "hammertime",
71- 'name': U1_APP_NAME,
72+ 'token_name': OLD_KEY_NAME,
73 'token': old_creds["oauth_token"],
74 'token_secret': old_creds["oauth_token_secret"],
75 }
76@@ -280,6 +281,14 @@
77 raise NewPasswordError('Received invalid reply: %s' % result)
78
79
80+def except_to_errdict(e):
81+ """Turn an exception into a dictionary to return thru DBus."""
82+ return {
83+ "errtype": type(e).__name__,
84+ "message": "\n".join(str(arg) for arg in e.args),
85+ }
86+
87+
88 def blocking(f, result_cb, error_cb):
89 """Run f in a thread; return or throw an exception thru the callbacks."""
90 def _in_thread():
91@@ -289,7 +298,7 @@
92 except Exception, e:
93 msg = "Exception while running DBus blocking code in a thread."""
94 logger.exception(msg)
95- error_cb(str(e))
96+ error_cb(except_to_errdict(e))
97 threading.Thread(target=_in_thread).start()
98
99
100@@ -315,7 +324,7 @@
101 def CaptchaGenerated(self, result):
102 """Signal thrown after the captcha is generated."""
103
104- @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="s")
105+ @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="a{ss}")
106 def CaptchaGenerationError(self, error):
107 """Signal thrown when there's a problem generating the captcha."""
108
109@@ -333,7 +342,7 @@
110 def UserRegistered(self, result):
111 """Signal thrown when the user is registered."""
112
113- @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="s")
114+ @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="a{ss}")
115 def UserRegistrationError(self, error):
116 """Signal thrown when there's a problem registering the user."""
117
118@@ -352,7 +361,7 @@
119 def LoggedIn(self, result):
120 """Signal thrown when the user is logged in."""
121
122- @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="s")
123+ @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="a{ss}")
124 def LoginError(self, error):
125 """Signal thrown when there is a problem in the login."""
126
127@@ -372,7 +381,7 @@
128 def EmailValidated(self, app_name):
129 """Signal thrown after the email is validated."""
130
131- @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="s")
132+ @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="a{ss}")
133 def EmailValidationError(self, error):
134 """Signal thrown when there's a problem validating the email."""
135
136@@ -392,7 +401,7 @@
137 def PasswordResetTokenSent(self, email):
138 """Signal thrown when the token is succesfully sent."""
139
140- @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="s")
141+ @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="a{ss}")
142 def PasswordResetError(self, error):
143 """Signal thrown when there's a problem sending the token."""
144
145@@ -411,7 +420,7 @@
146 def PasswordChanged(self, email):
147 """Signal thrown when the token is succesfully sent."""
148
149- @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="s")
150+ @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="a{ss}")
151 def PasswordChangeError(self, error):
152 """Signal thrown when there's a problem sending the token."""
153
154@@ -429,16 +438,16 @@
155 class SSOCredentials(dbus.service.Object):
156 """DBus object that gets credentials, and login/registers if needed."""
157
158- @dbus.service.signal(DBUS_IFACE_CRED_NAME, signature="")
159- def AuthorizationDenied(self):
160+ @dbus.service.signal(DBUS_IFACE_CRED_NAME, signature="s")
161+ def AuthorizationDenied(self, app_name):
162 """Signal thrown when the user denies the authorization."""
163
164- @dbus.service.signal(DBUS_IFACE_CRED_NAME, signature="a{ss}")
165- def CredentialsFound(self, app_name):
166+ @dbus.service.signal(DBUS_IFACE_CRED_NAME, signature="sa{ss}")
167+ def CredentialsFound(self, app_name, credentials):
168 """Signal thrown when the credentials are found."""
169
170- @dbus.service.signal(DBUS_IFACE_CRED_NAME, signature="s")
171- def CredentialsError(self, error):
172+ @dbus.service.signal(DBUS_IFACE_CRED_NAME, signature="sss")
173+ def CredentialsError(self, app_name, error_message, detailed_error):
174 """Signal thrown when there is a problem finding the credentials."""
175
176 @dbus.service.method(dbus_interface=DBUS_IFACE_CRED_NAME,
177@@ -455,20 +464,21 @@
178 """Handles the response from the UI dialog."""
179 try:
180 creds = keyring_get_credentials(app_name)
181- self.CredentialsFound(creds)
182- except Exception, e:
183- logger.exception("problem when getting credentials from keyring")
184- self.CredentialsError(str(e))
185+ self.CredentialsFound(app_name, creds)
186+ except Exception:
187+ msg = "Problem getting the credentials from the keyring."
188+ logger.exception(msg)
189+ self.CredentialsError(app_name, msg, traceback.format_exc())
190
191- def _login_error_cb(self, dialog):
192+ def _login_error_cb(self, dialog, app_name):
193 """Handles a problem in the UI."""
194- msg = "misc problem getting the credentials"
195- self.CredentialsError(msg)
196+ msg = "Problem getting the credentials from the keyring."
197+ self.CredentialsError(app_name, msg, "no more info available")
198 logger.error(msg)
199
200- def _login_auth_denied_cb(self, dialog):
201+ def _login_auth_denied_cb(self, dialog, app_name):
202 """The user decides not to allow the registration or login."""
203- self.AuthorizationDenied()
204+ self.AuthorizationDenied(app_name)
205
206 def _show_login_or_register_ui(self, app_name, tc_url, help_text,
207 win_id, login_only=False):
208@@ -483,12 +493,13 @@
209 gui_app.connect(gui.SIG_REGISTRATION_FAILED, self._login_error_cb)
210 gui_app.connect(gui.SIG_USER_CANCELATION,
211 self._login_auth_denied_cb)
212- except Exception, e:
213+ except Exception:
214 msg = '_show_login_or_register_ui failed when calling ' \
215 'gui.UbuntuSSOClientGUI(%r, %r, %r, %r, %r)'
216 logger.exception(msg, app_name, tc_url, help_text,
217 win_id, login_only)
218- self.CredentialsError(str(e))
219+ msg = "Problem opening the Ubuntu SSO user interface."
220+ self.CredentialsError(app_name, msg, traceback.format_exc())
221
222 @dbus.service.method(dbus_interface=DBUS_IFACE_CRED_NAME,
223 in_signature="sssx", out_signature="")
224@@ -512,10 +523,11 @@
225 app_name, terms_and_conditions_url,
226 help_text, window_id)
227 else:
228- self.CredentialsFound(token)
229- except Exception, e:
230- logger.exception("problem while getting the credentials")
231- self.CredentialsError(str(e))
232+ self.CredentialsFound(app_name, token)
233+ except Exception:
234+ msg = "Problem getting the credentials from the keyring."
235+ logger.exception(msg)
236+ self.CredentialsError(app_name, msg, traceback.format_exc())
237
238 def _show_login_only_ui(self, app_name, help_text, win_id):
239 """Shows the UI so the user can login."""
240@@ -541,10 +553,11 @@
241 gobject.idle_add(self._show_login_only_ui, app_name,
242 help_text, window_id)
243 else:
244- self.CredentialsFound(token)
245- except Exception, e:
246- logger.exception("problem while getting the credentials")
247- self.CredentialsError(str(e))
248+ self.CredentialsFound(app_name, token)
249+ except Exception:
250+ msg = "Problem getting the credentials from the keyring."
251+ logger.exception(msg)
252+ self.CredentialsError(app_name, msg, traceback.format_exc())
253
254
255 class LoginProcessor:
256
257=== modified file 'ubuntu_sso/tests/test_gui.py'
258--- ubuntu_sso/tests/test_gui.py 2010-08-19 20:56:52 +0000
259+++ ubuntu_sso/tests/test_gui.py 2010-08-23 19:43:39 +0000
260@@ -1347,15 +1347,15 @@
261 self.ui.connect(sig, self._set_called, sig)
262 widget = getattr(self.ui, name)
263 widget.clicked()
264- self.assertEqual(self._called[sig],
265- (self.ui.window, (), {}), msg % name)
266+ expected_args = (self.ui.window, (APP_NAME,), {})
267+ self.assertEqual(self._called[sig], expected_args, msg % name)
268 self._called = {}
269
270 def test_on_user_registration_error_proper_signal_is_emitted(self):
271 """On UserRegistrationError, 'registration-failed' signal is sent."""
272 self.ui.on_user_registration_error()
273 self.ui.on_close_clicked()
274- self.assertEqual((self.ui.window, (), {}),
275+ self.assertEqual((self.ui.window, (APP_NAME,), {}),
276 self._called[gui.SIG_REGISTRATION_FAILED])
277
278 def test_on_email_validated_proper_signals_is_emitted(self):
279@@ -1369,7 +1369,7 @@
280 """On EmailValidationError, 'registration-failed' signal is sent."""
281 self.ui.on_email_validation_error()
282 self.ui.on_close_clicked()
283- self.assertEqual((self.ui.window, (), {}),
284+ self.assertEqual((self.ui.window, (APP_NAME,), {}),
285 self._called[gui.SIG_REGISTRATION_FAILED])
286
287 def test_on_logged_in_proper_signals_is_emitted(self):
288@@ -1384,7 +1384,7 @@
289 self.click_connect_with_valid_data()
290 self.ui.on_login_error()
291 self.ui.on_close_clicked()
292- self.assertEqual((self.ui.window, (), {}),
293+ self.assertEqual((self.ui.window, (APP_NAME,), {}),
294 self._called[gui.SIG_LOGIN_FAILED])
295
296 def test_registration_successfull_even_if_prior_registration_error(self):
297
298=== modified file 'ubuntu_sso/tests/test_main.py'
299--- ubuntu_sso/tests/test_main.py 2010-08-20 17:33:33 +0000
300+++ ubuntu_sso/tests/test_main.py 2010-08-23 19:43:39 +0000
301@@ -39,7 +39,7 @@
302 InvalidEmailError, InvalidPasswordError, SSOLogin, SSOCredentials,
303 get_token_name, keyring_get_credentials, keyring_store_credentials, logger,
304 LoginProcessor, NewPasswordError, SSOLoginProcessor, RegistrationError,
305- ResetPasswordTokenError, OLD_KEY_NAME, U1_APP_NAME)
306+ ResetPasswordTokenError, OLD_KEY_NAME, U1_APP_NAME, except_to_errdict)
307
308
309 APP_NAME = 'The Coolest App Ever'
310@@ -411,7 +411,7 @@
311 def fake_err_blocking(self, f, cb, eb):
312 """A fake blocking function that fails."""
313 f()
314- eb(BlockingSampleException())
315+ eb(except_to_errdict(BlockingSampleException()))
316
317 def test_creation(self):
318 """Test that the object creation is successful."""
319@@ -457,8 +457,8 @@
320 self.patch(ubuntu_sso.main, "blocking", self.fake_err_blocking)
321 self.mocker.replay()
322
323- def verify(error):
324- self.assertIsInstance(error, BlockingSampleException)
325+ def verify(errdict):
326+ self.assertEqual(errdict["errtype"], "BlockingSampleException")
327 d.callback("Ok")
328
329 client = SSOLogin(self.mockbusname,
330@@ -499,8 +499,8 @@
331 self.patch(ubuntu_sso.main, "blocking", self.fake_err_blocking)
332 self.mocker.replay()
333
334- def verify(error):
335- self.assertIsInstance(error, BlockingSampleException)
336+ def verify(errdict):
337+ self.assertEqual(errdict["errtype"], "BlockingSampleException")
338 d.callback("Ok")
339
340 client = SSOLogin(self.mockbusname,
341@@ -539,8 +539,8 @@
342 self.patch(ubuntu_sso.main, "blocking", self.fake_err_blocking)
343 self.mocker.replay()
344
345- def verify(error):
346- self.assertIsInstance(error, BlockingSampleException)
347+ def verify(errdict):
348+ self.assertEqual(errdict["errtype"], "BlockingSampleException")
349 d.callback("Ok")
350
351 client = SSOLogin(self.mockbusname,
352@@ -581,8 +581,8 @@
353 self.patch(ubuntu_sso.main, "blocking", self.fake_err_blocking)
354 self.mocker.replay()
355
356- def verify(error):
357- self.assertIsInstance(error, BlockingSampleException)
358+ def verify(errdict):
359+ self.assertEqual(errdict["errtype"], "BlockingSampleException")
360 d.callback("Ok")
361
362 client = SSOLogin(self.mockbusname,
363@@ -620,8 +620,8 @@
364 self.patch(ubuntu_sso.main, "blocking", self.fake_err_blocking)
365 self.mocker.replay()
366
367- def verify(error):
368- self.assertIsInstance(error, BlockingSampleException)
369+ def verify(errdict):
370+ self.assertEqual(errdict["errtype"], "BlockingSampleException")
371 d.callback("Ok")
372
373 client = SSOLogin(self.mockbusname,
374@@ -662,8 +662,8 @@
375 self.patch(ubuntu_sso.main, "blocking", self.fake_err_blocking)
376 self.mocker.replay()
377
378- def verify(error):
379- self.assertIsInstance(error, BlockingSampleException)
380+ def verify(errdict):
381+ self.assertEqual(errdict["errtype"], "BlockingSampleException")
382 d.callback("Ok")
383
384 client = SSOLogin(self.mockbusname,
385@@ -676,6 +676,7 @@
386
387 class BlockingFunctionTestCase(TestCase):
388 """Tests for the "blocking" function."""
389+ timeout = 5
390
391 def test_blocking(self):
392 """Test the normal behaviour."""
393@@ -700,8 +701,9 @@
394 def f():
395 raise BlockingSampleException(expected_error_message)
396
397- def verify(error):
398- self.assertEqual(error, expected_error_message)
399+ def verify(errdict):
400+ self.assertEqual(errdict["errtype"], "BlockingSampleException")
401+ self.assertEqual(errdict["message"], expected_error_message)
402 d.callback("Ok")
403
404 blocking(f, d.errback, verify)
405@@ -778,6 +780,8 @@
406 self.assertEqual(new_creds["token"], sample_oauth_token)
407 self.assertIn("token_secret", new_creds)
408 self.assertEqual(new_creds["token_secret"], sample_oauth_secret)
409+ self.assertIn("token_name", new_creds)
410+ self.assertEqual(new_creds["token_name"], OLD_KEY_NAME)
411
412 def test_keyring_get_old_cred_not_found(self):
413 """The method returns None if no old nor new credentials found."""
414@@ -838,8 +842,8 @@
415 expected_creds = TOKEN
416 d = Deferred()
417
418- def verify(result):
419- self.assertEqual(result, expected_creds)
420+ def verify(app_name, credentials):
421+ self.assertEqual(credentials, expected_creds)
422 d.callback("ok")
423
424 kgt = self.mocker.replace("ubuntu_sso.main.keyring_get_credentials")
425@@ -878,8 +882,8 @@
426 expected_error = "Sample Error - not for resale"
427 d = Deferred()
428
429- def verify(result, *a):
430- self.assertEqual(result, expected_error)
431+ def verify(app_name, error_message, detailed_error):
432+ self.assertEqual(app_name, APP_NAME)
433 d.callback("ok")
434
435 kgt = self.mocker.replace("ubuntu_sso.main.keyring_get_credentials")
436@@ -899,8 +903,8 @@
437 expected_creds = TOKEN
438 d = Deferred()
439
440- def verify(result):
441- self.assertEqual(result, expected_creds)
442+ def verify(app_name, credentials):
443+ self.assertEqual(credentials, expected_creds)
444 d.callback("ok")
445
446 kgt = self.mocker.replace("ubuntu_sso.main.keyring_get_credentials")
447@@ -939,8 +943,8 @@
448 expected_error = "Sample Error - not for resale"
449 d = Deferred()
450
451- def verify(result, *a):
452- self.assertEqual(result, expected_error)
453+ def verify(app_name, error_message, detailed_error):
454+ self.assertEqual(app_name, APP_NAME)
455 d.callback("ok")
456
457 kgt = self.mocker.replace("ubuntu_sso.main.keyring_get_credentials")
458@@ -955,6 +959,91 @@
459 client.login_to_get_credentials(*LOGIN_ONLY_ARGS)
460 return d
461
462+ def test_login_error_cb(self):
463+ """The login error callback should throw the signal."""
464+ d = Deferred()
465+
466+ def verify(app_name, error_message, detailed_error):
467+ self.assertEqual(app_name, APP_NAME)
468+ d.callback("ok")
469+
470+ self.mocker.replay()
471+ client = SSOCredentials(self.mocker.mock())
472+ self.patch(client, "CredentialsError", verify)
473+
474+ client._login_error_cb(None, APP_NAME)
475+ return d
476+
477+ def test_show_login_or_register_ui_error(self):
478+ """An error happens when trying to register."""
479+ d = Deferred()
480+ mockgui = self.mocker.replace("ubuntu_sso.gui.UbuntuSSOClientGUI")
481+ mockgui(ARGS)
482+ self.mocker.throw(Exception())
483+ self.mocker.replay()
484+
485+ def verify(app_name, msg, full_error):
486+ self.assertEqual(app_name, APP_NAME)
487+ d.callback("ok")
488+
489+ client = SSOCredentials(self.mocker.mock())
490+ self.patch(client, "CredentialsError", verify)
491+
492+ client._show_login_or_register_ui(APP_NAME, "http:tc_url", "help", 0)
493+ return d
494+
495+ def test_login_success_cb_works(self):
496+ """Check that the right signal is sent."""
497+ expected_creds = TOKEN
498+ d = Deferred()
499+ kgc = self.mocker.replace("ubuntu_sso.main.keyring_get_credentials")
500+ kgc(ARGS)
501+ self.mocker.result(expected_creds)
502+ self.mocker.replay()
503+
504+ def verify(app_name, credentials):
505+ self.assertEqual(credentials, expected_creds)
506+ d.callback("ok")
507+
508+ client = SSOCredentials(self.mocker.mock())
509+ self.patch(client, "CredentialsFound", verify)
510+
511+ client._login_success_cb(None, APP_NAME)
512+ return d
513+
514+ def test_login_success_cb_error(self):
515+ """An error happens when accessing the keyring."""
516+ d = Deferred()
517+ kgc = self.mocker.replace("ubuntu_sso.main.keyring_get_credentials")
518+ kgc(ARGS)
519+ self.mocker.throw(Exception())
520+ self.mocker.replay()
521+
522+ def verify(app_name, msg, full_error):
523+ self.assertEqual(app_name, APP_NAME)
524+ d.callback("ok")
525+
526+ client = SSOCredentials(self.mocker.mock())
527+ self.patch(client, "CredentialsError", verify)
528+
529+ client._login_success_cb(None, APP_NAME)
530+ return d
531+
532+ def test_auth_denied_cb(self):
533+ """When the user decides not to allow the registration or login."""
534+ d = Deferred()
535+ self.mocker.replay()
536+
537+ def verify(app_name):
538+ self.assertEqual(app_name, APP_NAME)
539+ d.callback("ok")
540+
541+ client = SSOCredentials(self.mocker.mock())
542+ self.patch(client, "AuthorizationDenied", verify)
543+
544+ client._login_auth_denied_cb(None, APP_NAME)
545+ return d
546+
547
548 class CredentialsGUITestCase(TestCase):
549 """login_or_register_to_get_credentials opens the proper GUI."""

Subscribers

People subscribed via source and target branches