Merge lp:~nataliabidart/ubuntu-sso-client/run-that-ui into lp:ubuntu-sso-client

Proposed by Natalia Bidart
Status: Merged
Approved by: Roberto Alsina
Approved revision: 860
Merged at revision: 856
Proposed branch: lp:~nataliabidart/ubuntu-sso-client/run-that-ui
Merge into: lp:ubuntu-sso-client
Prerequisite: lp:~nataliabidart/ubuntu-sso-client/dont-let-it-go
Diff against target: 1277 lines (+293/-450)
12 files modified
ubuntu_sso/__init__.py (+4/-0)
ubuntu_sso/credentials.py (+83/-157)
ubuntu_sso/gtk/gui.py (+3/-13)
ubuntu_sso/gtk/tests/test_gui.py (+4/-4)
ubuntu_sso/main/__init__.py (+19/-12)
ubuntu_sso/main/tests/__init__.py (+8/-3)
ubuntu_sso/main/tests/test_clients.py (+8/-24)
ubuntu_sso/main/tests/test_common.py (+14/-12)
ubuntu_sso/qt/tests/show_gui.py (+2/-2)
ubuntu_sso/tests/__init__.py (+1/-2)
ubuntu_sso/tests/test_credentials.py (+147/-213)
ubuntu_sso/utils/runner/glib.py (+0/-8)
To merge this branch: bzr merge lp:~nataliabidart/ubuntu-sso-client/run-that-ui
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Diego Sarmentero (community) Approve
Review via email: mp+92496@code.launchpad.net

Commit message

- Execute the UI as a separated process from the sso main thread
  (LP: #919330).

Description of the change

This branch provides the ability to run UIs in a separate process.

To test it IRL in Linux, you should do the following twice (one for the glib spawner, one for the Qt one):

* remove your U1 token
* run the sso service:
  GLib -> U1_DEBUG=True PATH=bin/:$PATH PYTHONPATH=. bin/ubuntu-sso-login
  Qt -> USE_QT_MAINLOOP=True U1_DEBUG=True PATH=bin/:$PATH PYTHONPATH=. bin/ubuntu-sso-login
* open the Ubuntu One Control Panel and login/register/retrieve password/etc (be careful that the sso service will shutdown itself if unused, re run if necessary)
* profit

Please note that we still have to code a fix for bug #930137.

To post a comment you must log in.
858. By Natalia Bidart

Merged updates from dependency branch.

859. By Natalia Bidart

Merged trunk in.

860. By Natalia Bidart

Avoig having double escapes on arguments.

Revision history for this message
Diego Sarmentero (diegosarmentero) wrote :

+1

review: Approve
Revision history for this message
Roberto Alsina (ralsina) wrote :

+1 looks good to me

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ubuntu_sso/__init__.py'
2--- ubuntu_sso/__init__.py 2010-10-07 21:09:01 +0000
3+++ ubuntu_sso/__init__.py 2012-02-10 17:15:32 +0000
4@@ -29,3 +29,7 @@
5 DBUS_CREDENTIALS_IFACE = "com.ubuntu.sso.CredentialsManagement"
6
7 NO_OP = lambda *args, **kwargs: None
8+
9+# return code for UIs
10+USER_SUCCESS = 0
11+USER_CANCELLATION = 10
12
13=== modified file 'ubuntu_sso/credentials.py'
14--- ubuntu_sso/credentials.py 2012-02-09 21:57:15 +0000
15+++ ubuntu_sso/credentials.py 2012-02-10 17:15:32 +0000
16@@ -23,27 +23,22 @@
17 * register
18 * login
19
20-The first three return a Deferred that will be fired when the operation was
21+All the methods return a Deferred that will be fired when the operation was
22 completed.
23
24-The second two use the 'success_cb', 'error_cb' and 'denial_cb' to signal the
25-caller when the credentials were retrieved successfully, when there was an
26-error or when the user denied the access to the application, respectively.
27-
28 For details, please read the Credentials class documentation.
29
30 """
31
32-import sys
33-import traceback
34-
35 from functools import wraps
36
37 from twisted.internet import defer
38
39-from ubuntu_sso import NO_OP
40+from ubuntu_sso import USER_CANCELLATION, USER_SUCCESS
41 from ubuntu_sso.keyring import Keyring
42 from ubuntu_sso.logger import setup_logging
43+from ubuntu_sso.utils import runner
44+
45
46 logger = setup_logging('ubuntu_sso.credentials')
47
48@@ -53,44 +48,19 @@
49 HELP_TEXT_KEY = 'help_text'
50 WINDOW_ID_KEY = 'window_id'
51 PING_URL_KEY = 'ping_url'
52-UI_MODULE_KEY = 'ui_module'
53-UI_CLASS_KEY = 'ui_class'
54-SUCCESS_CB_KEY = 'success_cb'
55-ERROR_CB_KEY = 'error_cb'
56-DENIAL_CB_KEY = 'denial_cb'
57-ERROR_KEY = 'error_message'
58-ERROR_DETAIL_KEY = 'detailed_error'
59-
60-
61-def handle_exceptions(msg):
62- """Handle exceptions using 'msg' as error message."""
63-
64- def middle(f):
65- """Decorate 'f' to catch all errors."""
66-
67- @wraps(f)
68- def inner(self, *a, **kw):
69- """Call 'f' within a try-except block.
70-
71- If any exception occurs, self.error_cb is called and the exception
72- is logged.
73- """
74- result = None
75- try:
76- result = f(self, *a, **kw)
77- except: # pylint: disable=W0702
78- logger.exception('%s (app_name: %s): %s.',
79- f.__name__, self.app_name, msg)
80- logger.error('%s (app_name: %s): Calling error_cb at %r.',
81- f.__name__, self.app_name, self.error_cb)
82- error_dict = {ERROR_KEY: msg,
83- ERROR_DETAIL_KEY: traceback.format_exc()}
84- self.error_cb(error_dict)
85- return result
86-
87- return inner
88-
89- return middle
90+UI_EXECUTABLE_KEY = 'ui_executable'
91+
92+
93+class CredentialsError(Exception):
94+ """Generic credentials error."""
95+
96+
97+class UserCancellationError(CredentialsError):
98+ """The user cancelled the process of authentication."""
99+
100+
101+class UserNotValidatedError(CredentialsError):
102+ """The user is not validated."""
103
104
105 def handle_failures(msg):
106@@ -104,20 +74,17 @@
107 def inner(self, *a, **kw):
108 """Call 'f' within a try-except block.
109
110- If any exception occurs, self.error_cb is called and the exception
111- is logged.
112+ If any exception occurs, the exception is logged and re-raised.
113+
114 """
115 result = None
116 try:
117 result = yield f(self, *a, **kw)
118- except Exception: # pylint: disable=W0703
119+ except:
120 logger.exception('%s (app_name: %s): %s.',
121 f.__name__, self.app_name, msg)
122- logger.error('%s (app_name: %s): Calling error_cb at %r.',
123- f.__name__, self.app_name, self.error_cb)
124- error_dict = {ERROR_KEY: msg,
125- ERROR_DETAIL_KEY: traceback.format_exc()}
126- self.error_cb(error_dict)
127+ raise
128+
129 defer.returnValue(result)
130
131 return inner
132@@ -130,13 +97,12 @@
133
134 def __init__(self, app_name, tc_url=None, help_text='',
135 window_id=0, ping_url=None,
136- ui_module='ubuntu_sso.gtk.gui', ui_class='UbuntuSSOClientGUI',
137- success_cb=NO_OP, error_cb=NO_OP, denial_cb=NO_OP):
138+ ui_executable='ubuntu-sso-login-gtk'):
139 """Return a Credentials management object.
140
141 'app_name' is the application name to be displayed in the GUI.
142
143- 'tc_url' is the URL pointing to Terms & Conditions. If None, no
144+ 'tc_url' is the url pointing to Terms & Conditions. If None, no
145 TOS agreement will be displayed.
146
147 'help_text' is an explanatory text for the end-users, will be shown
148@@ -148,9 +114,9 @@
149 'ping_url' is the url that will be pinged when a user registers/logins
150 successfully. The user email will be attached to 'ping_url'.
151
152- 'success_cb' will be called when the credentials were retrieved
153- successfully. Two params will be passed: the app_name and the
154- credentials per se. The credentials is a dictionary of the form:
155+
156+ When the credentials are retrieved successfully, a dictionary like the
157+ one below is returned:
158
159 {'token': <value>,
160 'token_secret': <value>,
161@@ -158,65 +124,42 @@
162 'consumer_secret': <value>,
163 'name': <the token name, matches "[app_name] @ [host name]">}
164
165- 'error_cb' will be called when the credentials retrieval failed. Two
166- params will be passed: the app_name, and an error dict with 2 keys:
167- the error message (user friendly, not translatable so far), and
168- the detailed error (usually the traceback).
169-
170- 'denial_cb' will be called when the user denied the credentials to the
171- caller. A single param is passed: the app_name.
172-
173 """
174 self.app_name = app_name
175 self.help_text = help_text
176 self.window_id = window_id
177 self.ping_url = ping_url
178 self.tc_url = tc_url
179- self.ui_module = ui_module
180- self.ui_class = ui_class
181- self._success_cb = success_cb
182- self._error_cb = error_cb
183- self.denial_cb = denial_cb
184- self.inner = None # will hold the GUI or SSOLoginRoot instance
185+ self.ui_executable = ui_executable
186
187- @handle_failures(msg='Problem while retrieving credentials')
188 @defer.inlineCallbacks
189- def _login_success_cb(self, app_name, email):
190- """Store credentials when the login/registration succeeded.
191-
192- Return 0 on success, and a non-zero value (or None) on error.
193-
194- """
195- logger.info('Login/registration was successful for app %r, email %r',
196- app_name, email)
197- creds = yield self.find_credentials()
198- if creds is not None:
199- assert len(creds) > 0, 'Creds are empty! This should not happen'
200- self.success_cb(creds)
201- defer.returnValue(0)
202-
203- def _auth_denial_cb(self, app_name):
204- """The user decided not to allow the registration or login."""
205- logger.warning('Login/registration was denied to app %r', app_name)
206- self.denial_cb(app_name)
207-
208- @handle_exceptions(msg='Problem opening the Ubuntu SSO user interface')
209 def _show_ui(self, login_only):
210 """Shows the UI, connect outcome signals."""
211-
212- __import__(self.ui_module)
213- gui = sys.modules[self.ui_module]
214-
215- self.inner = getattr(gui, self.ui_class)(app_name=self.app_name,
216- tc_url=self.tc_url, help_text=self.help_text,
217- ping_url=self.ping_url, window_id=self.window_id,
218- login_only=login_only)
219-
220- self.inner.login_success_callback = self._login_success_cb
221- self.inner.registration_success_callback = self._login_success_cb
222- self.inner.user_cancellation_callback = self._auth_denial_cb
223-
224- @handle_exceptions(msg='Problem logging with email and password.')
225+ args = [str(self.ui_executable)]
226+ for arg in ('app_name', 'help_text', 'ping_url',
227+ 'tc_url', 'window_id'):
228+ value = getattr(self, arg)
229+ if value:
230+ args.append('--%s' % arg)
231+ args.append("%s" % str(value))
232+
233+ if login_only:
234+ args.append('--login_only')
235+
236+ return_code = yield runner.spawn_program(args)
237+ logger.info('_show_ui: received from the ui return code %r.',
238+ return_code)
239+
240+ credentials = None
241+ if return_code == USER_SUCCESS:
242+ credentials = yield self.find_credentials()
243+ elif return_code == USER_CANCELLATION:
244+ raise UserCancellationError()
245+ else:
246+ raise CredentialsError(return_code)
247+
248+ defer.returnValue(credentials)
249+
250 def _do_login(self, email, password):
251 """Login using email/password, connect outcome signals."""
252 from ubuntu_sso.main import SSOLogin
253@@ -234,62 +177,43 @@
254
255 def LoginError(self, app_name, error):
256 """There was an error on login."""
257+ error = CredentialsError(error['errtype'])
258 d.errback(error)
259
260 def UserNotValidated(self, app_name, email):
261 """User is not validated."""
262- d.callback(None)
263+ d.errback(UserNotValidatedError(email))
264
265 # pylint: enable=C0103
266
267- self.inner = SSOLogin(proxy=DummyProxy())
268- self.inner.login(app_name=self.app_name,
269- email=email, password=password)
270-
271- def _success(result):
272- """Check if 'result' is a valid token, and callback properly."""
273- if result is not None:
274- return self._login_success_cb(self.app_name, email)
275- else:
276- error_dict = {
277- 'errtype': 'UserNotValidated',
278- 'message': email,
279- }
280- self._error_cb(self.app_name, error_dict)
281-
282- d.addCallback(_success)
283- d.addErrback(lambda f: self._error_cb(self.app_name, f.value))
284-
285- @handle_failures(msg='Problem while retrieving credentials')
286+ inner = SSOLogin(proxy=DummyProxy())
287+ inner.login(app_name=self.app_name,
288+ email=email, password=password,
289+ ping_url=self.ping_url)
290+
291+ d.addCallback(lambda _: self.find_credentials())
292+ return d
293+
294 @defer.inlineCallbacks
295 def _login_or_register(self, login_only, email=None, password=None):
296- """Get credentials if found else prompt the GUI."""
297+ """Get credentials if found else prompt the GUI.
298+
299+ Will return either the credentials, or will raise UserCancellationError
300+ if the user aborted the operation when the UI was opened.
301+
302+ """
303 logger.info("_login_or_register: login_only=%r email=%r.",
304- login_only, email)
305+ login_only, email)
306 token = yield self.find_credentials()
307- if token is not None and len(token) > 0:
308- self.success_cb(token)
309- elif token == {}:
310+ if not token:
311 if email and password:
312- self._do_login(email, password)
313+ token = yield self._do_login(email, password)
314 else:
315- self._show_ui(login_only)
316- else:
317- # something went wrong with find_credentials, already handled.
318- logger.info('_login_or_register: call to "find_credentials" went '
319- 'wrong, and was already handled.')
320-
321- def error_cb(self, error_dict):
322- """Handle error and notify the caller."""
323- logger.error('Calling error callback at %r (error is %r).',
324- self._error_cb, error_dict)
325- self._error_cb(self.app_name, error_dict)
326-
327- def success_cb(self, creds):
328- """Handle success and notify the caller."""
329- logger.debug('Calling success callback at %r.', self._success_cb)
330- self._success_cb(self.app_name, creds)
331-
332+ token = yield self._show_ui(login_only)
333+
334+ defer.returnValue(token)
335+
336+ @handle_failures(msg='Problem while getting credentials from the keyring')
337 @defer.inlineCallbacks
338 def find_credentials(self):
339 """Get the credentials for 'self.app_name'. Return {} if not there."""
340@@ -298,20 +222,22 @@
341 'result is {}? %s', self.app_name, creds is None)
342 defer.returnValue(creds if creds is not None else {})
343
344- @defer.inlineCallbacks
345+ @handle_failures(msg='Problem while clearing credentials in the keyring')
346 def clear_credentials(self):
347 """Clear the credentials for 'self.app_name'."""
348- yield Keyring().delete_credentials(self.app_name)
349+ return Keyring().delete_credentials(self.app_name)
350
351- @defer.inlineCallbacks
352+ @handle_failures(msg='Problem while storing credentials in the keyring')
353 def store_credentials(self, token):
354 """Store the credentials for 'self.app_name'."""
355- yield Keyring().set_credentials(self.app_name, token)
356+ return Keyring().set_credentials(self.app_name, token)
357
358+ @handle_failures(msg='Problem while performing register')
359 def register(self):
360 """Get credentials if found else prompt the GUI to register."""
361 return self._login_or_register(login_only=False)
362
363+ @handle_failures(msg='Problem while performing login')
364 def login(self, email=None, password=None):
365 """Get credentials if found else prompt the GUI to login.
366
367
368=== modified file 'ubuntu_sso/gtk/gui.py'
369--- ubuntu_sso/gtk/gui.py 2012-02-09 21:57:15 +0000
370+++ ubuntu_sso/gtk/gui.py 2012-02-10 17:15:32 +0000
371@@ -33,6 +33,8 @@
372 from ubuntu_sso import (
373 main,
374 NO_OP,
375+ USER_CANCELLATION,
376+ USER_SUCCESS,
377 utils,
378 )
379 from ubuntu_sso.logger import setup_gui_logging
380@@ -110,9 +112,6 @@
381 HELP_TEXT_COLOR = parse_color("#bfbfbf")
382 WARNING_TEXT_COLOR = parse_color("red")
383
384-USER_CANCELLATION = 10
385-LOGIN_SUCCESS = REGISTRATION_SUCCESS = 0
386-
387
388 def log_call(f):
389 """Decorator to log call funtions."""
390@@ -218,12 +217,6 @@
391 window_id = kwargs.get('window_id', 0)
392 self.close_callback = kwargs.get('close_callback', NO_OP)
393 self.backend = None
394- # the following 3 callbacks will be removed as soon as
395- # the backend stop using them
396- self.login_success_callback = NO_OP
397- self.registration_success_callback = NO_OP
398- self.user_cancellation_callback = NO_OP
399-
400 self.user_email = None
401 self.user_password = None
402
403@@ -726,9 +719,8 @@
404 while Gtk.events_pending():
405 Gtk.main_iteration()
406
407- return_code = LOGIN_SUCCESS
408+ return_code = USER_SUCCESS
409 if not self._done:
410- self.user_cancellation_callback(self.app_name)
411 return_code = USER_CANCELLATION
412 logger.info('Return code will be %r.', return_code)
413
414@@ -1081,7 +1073,6 @@
415 @log_call
416 def on_email_validated(self, app_name, email, *args, **kwargs):
417 """User email was successfully verified."""
418- self.registration_success_callback(self.app_name, email)
419 self.finish_success()
420
421 @log_call
422@@ -1097,7 +1088,6 @@
423 @log_call
424 def on_logged_in(self, app_name, email, *args, **kwargs):
425 """User was successfully logged in."""
426- self.login_success_callback(self.app_name, email)
427 self.finish_success()
428
429 @log_call
430
431=== modified file 'ubuntu_sso/gtk/tests/test_gui.py'
432--- ubuntu_sso/gtk/tests/test_gui.py 2012-02-09 21:57:15 +0000
433+++ ubuntu_sso/gtk/tests/test_gui.py 2012-02-10 17:15:32 +0000
434@@ -2108,7 +2108,7 @@
435 self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL)
436 self.ui.on_close_clicked()
437
438- self.assertEqual(self._called, ((gui.REGISTRATION_SUCCESS,), {}))
439+ self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
440
441 def test_on_email_validation_error_proper_callback_is_called(self):
442 """On EmailValidationError, USER_CANCELLATION is called."""
443@@ -2122,7 +2122,7 @@
444 self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL)
445 self.ui.on_close_clicked()
446
447- self.assertEqual(self._called, ((gui.LOGIN_SUCCESS,), {}))
448+ self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
449
450 def test_on_login_error_proper_callback_is_called(self):
451 """On LoginError, USER_CANCELLATION is called."""
452@@ -2145,7 +2145,7 @@
453 self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL)
454 self.ui.on_close_clicked()
455
456- self.assertEqual(self._called, ((gui.REGISTRATION_SUCCESS,), {}))
457+ self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
458
459 def test_login_success_even_if_prior_login_error(self):
460 """Only one callback is called with the final outcome.
461@@ -2160,7 +2160,7 @@
462 self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL)
463 self.ui.on_close_clicked()
464
465- self.assertEqual(self._called, ((gui.LOGIN_SUCCESS,), {}))
466+ self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
467
468 def test_user_cancelation_even_if_prior_registration_error(self):
469 """Only one callback is called with the final outcome.
470
471=== modified file 'ubuntu_sso/main/__init__.py'
472--- ubuntu_sso/main/__init__.py 2012-02-09 21:17:54 +0000
473+++ ubuntu_sso/main/__init__.py 2012-02-10 17:15:32 +0000
474@@ -29,14 +29,11 @@
475 from ubuntu_sso.account import Account
476 from ubuntu_sso.credentials import (
477 Credentials,
478- DENIAL_CB_KEY,
479- ERROR_CB_KEY,
480 HELP_TEXT_KEY,
481 PING_URL_KEY,
482- SUCCESS_CB_KEY,
483 TC_URL_KEY,
484- UI_CLASS_KEY,
485- UI_MODULE_KEY,
486+ UI_EXECUTABLE_KEY,
487+ UserCancellationError,
488 WINDOW_ID_KEY,
489 )
490 from ubuntu_sso.keyring import get_token_name, Keyring
491@@ -302,15 +299,12 @@
492 self.shutdown_func()
493
494 valid_keys = (HELP_TEXT_KEY, PING_URL_KEY, TC_URL_KEY,
495- UI_CLASS_KEY, UI_MODULE_KEY, WINDOW_ID_KEY)
496+ UI_EXECUTABLE_KEY, WINDOW_ID_KEY)
497
498 def _parse_args(self, args):
499 """Retrieve values from the generic param 'args'."""
500 result = dict(i for i in args.iteritems() if i[0] in self.valid_keys)
501 result[WINDOW_ID_KEY] = int(args.get(WINDOW_ID_KEY, 0))
502- result[SUCCESS_CB_KEY] = self.CredentialsFound
503- result[ERROR_CB_KEY] = self.CredentialsError
504- result[DENIAL_CB_KEY] = self.AuthorizationDenied
505 return result
506
507 @log_call(logger.info)
508@@ -403,6 +397,13 @@
509 d.addCallback(_success_cb)
510 d.addErrback(_error_cb, app_name)
511
512+ def _process_failures(self, failure, app_name):
513+ """Process failure returned by the Credentials module."""
514+ if failure.check(UserCancellationError):
515+ self.AuthorizationDenied(app_name)
516+ else:
517+ self.CredentialsError(app_name, failure.value)
518+
519 def clear_credentials(self, app_name, args):
520 """Clear the credentials for an application.
521
522@@ -439,13 +440,17 @@
523 """Get credentials if found else prompt GUI to register."""
524 self.ref_count += 1
525 obj = Credentials(app_name, **self._parse_args(args))
526- obj.register()
527+ d = obj.register()
528+ d.addCallback(lambda creds: self.CredentialsFound(app_name, creds))
529+ d.addErrback(self._process_failures, app_name)
530
531 def login(self, app_name, args):
532 """Get credentials if found else prompt GUI to login."""
533 self.ref_count += 1
534 obj = Credentials(app_name, **self._parse_args(args))
535- obj.login()
536+ d = obj.login()
537+ d.addCallback(lambda creds: self.CredentialsFound(app_name, creds))
538+ d.addErrback(self._process_failures, app_name)
539
540 def login_email_password(self, app_name, args):
541 """Get credentials if found else try to login.
542@@ -458,7 +463,9 @@
543 email = args.pop('email')
544 password = args.pop('password')
545 obj = Credentials(app_name, **self._parse_args(args))
546- obj.login(email=email, password=password)
547+ d = obj.login(email=email, password=password)
548+ d.addCallback(lambda creds: self.CredentialsFound(app_name, creds))
549+ d.addErrback(self._process_failures, app_name)
550
551
552 # pylint: enable=C0103
553
554=== modified file 'ubuntu_sso/main/tests/__init__.py'
555--- ubuntu_sso/main/tests/__init__.py 2012-01-04 20:30:13 +0000
556+++ ubuntu_sso/main/tests/__init__.py 2012-02-10 17:15:32 +0000
557@@ -38,9 +38,6 @@
558 class FakedCredentials(object):
559 """A very dummy Credentials object."""
560
561- def __init__(self, *a, **kw):
562- self.login = self.register = lambda *a, **kw: None
563-
564 def find_credentials(self, *a, **kw):
565 """Retrieve credentials."""
566 return defer.succeed(TOKEN)
567@@ -52,3 +49,11 @@
568 def store_credentials(self, *a, **kw):
569 """Store credentials."""
570 return defer.succeed(None)
571+
572+ def register(self, *a, **kw):
573+ """Register."""
574+ return defer.succeed(TOKEN)
575+
576+ def login(self, *a, **kw):
577+ """Login."""
578+ return defer.succeed(TOKEN)
579
580=== modified file 'ubuntu_sso/main/tests/test_clients.py'
581--- ubuntu_sso/main/tests/test_clients.py 2012-01-11 13:17:10 +0000
582+++ ubuntu_sso/main/tests/test_clients.py 2012-02-10 17:15:32 +0000
583@@ -259,9 +259,12 @@
584 class CredentialsManagementProxyTestCase(AbstractTestCase):
585 """Tests for the CredentialsManagementProxy DBus interface."""
586
587+ args = dict(foo='bar', fuh='baz')
588+ params = (APP_NAME, args)
589+ success_signal = 'CredentialsFound'
590 error_signal = 'CredentialsError'
591- args = dict(foo='bar', fuh='baz')
592- params = (APP_NAME, args)
593+ backend_result = TOKEN
594+ success_result = (APP_NAME, backend_result)
595
596 @defer.inlineCallbacks
597 def setUp(self):
598@@ -285,9 +288,6 @@
599 """Test the find_credentials method."""
600
601 method = 'find_credentials'
602- success_signal = 'CredentialsFound'
603- backend_result = TOKEN
604- success_result = (APP_NAME, backend_result)
605
606 @skipIfOS('win32', 'find_credentials_sync is only provided in Linux '
607 'due to compatibility issues with old clients.')
608@@ -336,35 +336,19 @@
609 success_result = (APP_NAME,)
610
611
612-class CredentialsManagementOpsTestCase(CredentialsManagementProxyTestCase):
613- """Tests for the CredentialsManagementProxy login/register methods."""
614-
615- success_signal = 'CredentialsFound'
616- success_result = (APP_NAME, TOKEN)
617-
618- def _backend_succeed(self, *args, **kwargs):
619- """Make self.patchable_backend return self.backend_result."""
620- self.sso_service.cred_manager.CredentialsFound(APP_NAME, TOKEN)
621-
622- def _backend_fail(self, *args, **kwargs):
623- """Make self.patchable_backend fail."""
624- self.sso_service.cred_manager.CredentialsError(APP_NAME,
625- dict(errtype='ValueError'))
626-
627-
628-class RegisterTestCase(CredentialsManagementOpsTestCase):
629+class RegisterTestCase(CredentialsManagementProxyTestCase):
630 """Test the register method."""
631
632 method = 'register'
633
634
635-class LoginOnlyTestCase(CredentialsManagementOpsTestCase):
636+class LoginOnlyTestCase(CredentialsManagementProxyTestCase):
637 """Test the login method."""
638
639 method = 'login'
640
641
642-class LoginEmailPasswordTestCase(CredentialsManagementOpsTestCase):
643+class LoginEmailPasswordTestCase(CredentialsManagementProxyTestCase):
644 """Test the login method."""
645
646 method = 'login_email_password'
647
648=== modified file 'ubuntu_sso/main/tests/test_common.py'
649--- ubuntu_sso/main/tests/test_common.py 2012-02-09 21:17:54 +0000
650+++ ubuntu_sso/main/tests/test_common.py 2012-02-10 17:15:32 +0000
651@@ -31,8 +31,7 @@
652 UbuntuSSOService,
653 )
654 from ubuntu_sso.main import (HELP_TEXT_KEY, PING_URL_KEY,
655- TC_URL_KEY, UI_CLASS_KEY, UI_MODULE_KEY, WINDOW_ID_KEY,
656- SUCCESS_CB_KEY, ERROR_CB_KEY, DENIAL_CB_KEY)
657+ TC_URL_KEY, UI_EXECUTABLE_KEY, WINDOW_ID_KEY)
658 from ubuntu_sso.main.tests import FakedCredentials
659 from ubuntu_sso.tests import (APP_NAME, TC_URL, HELP_TEXT, CAPTCHA_ID,
660 CAPTCHA_SOLUTION, EMAIL, EMAIL_TOKEN, NAME, PASSWORD, PING_URL, TOKEN,
661@@ -540,7 +539,7 @@
662 base_args = {
663 HELP_TEXT_KEY: HELP_TEXT, PING_URL_KEY: PING_URL,
664 TC_URL_KEY: TC_URL, WINDOW_ID_KEY: WINDOW_ID,
665- UI_CLASS_KEY: 'SuperUI', UI_MODULE_KEY: 'foo.bar.baz',
666+ UI_EXECUTABLE_KEY: 'super-ui',
667 }
668
669 @defer.inlineCallbacks
670@@ -661,14 +660,19 @@
671
672 def test_register(self):
673 """Keep proper track of ongoing requests."""
674- yield self.assert_refcounter_increased('register')
675+ yield self.assert_refcounter_increased('register',
676+ 'CredentialsFound')
677
678 def test_login(self):
679 """Keep proper track of ongoing requests."""
680- yield self.assert_refcounter_increased('login')
681+ yield self.assert_refcounter_increased('login',
682+ 'CredentialsFound')
683
684 def test_several_requests(self):
685 """Requests can be nested."""
686+ # by patching the CredentialsFound signal, the counter is not decreased
687+ self.patch(self.obj, 'CredentialsFound', lambda *a: None)
688+
689 self.obj.login(APP_NAME, self.args)
690 self.obj.register(APP_NAME, self.args)
691 self.obj.login(APP_NAME, self.args)
692@@ -731,7 +735,6 @@
693 """When ref count reaches 0, queue shutdown op."""
694 self.patch(self.obj, 'timeout_func', self._set_called)
695 self.obj.login(APP_NAME, self.args)
696- self.obj.CredentialsFound(APP_NAME, TOKEN)
697
698 self.assertEqual(self._called,
699 ((TIMEOUT_INTERVAL, self.obj.shutdown), {}))
700@@ -739,6 +742,8 @@
701 def test_on_non_zero_ref_count_do_not_shutdown(self):
702 """If ref count is not 0, do not queue shutdown op."""
703 self.patch(self.obj, 'timeout_func', self._set_called)
704+ # by patching the CredentialsFound signal, the counter is not decreased
705+ self.patch(self.obj, 'CredentialsFound', lambda *a: None)
706 self.obj.login(APP_NAME, self.args)
707
708 self.assertEqual(self._called, False)
709@@ -748,6 +753,8 @@
710
711 def fake_timeout_func(interval, func):
712 """Start a new request when the timer is started."""
713+ # the counter is not decreased
714+ self.patch(self.obj, 'CredentialsFound', lambda *a: None)
715 self.obj.register(APP_NAME, self.args)
716 assert self.obj.ref_count > 0
717 func()
718@@ -756,8 +763,7 @@
719 self.patch(self.obj, 'shutdown_func', self._set_called)
720
721 self.obj.login(APP_NAME, self.args)
722- self.obj.CredentialsFound(APP_NAME, TOKEN)
723- # counter reached 0, timeout_func was called
724+ # counter reached 0, timeout_func was called and register was called
725
726 self.assertEqual(self._called, False, 'shutdown_func was not called')
727
728@@ -773,7 +779,6 @@
729 self.patch(self.obj, 'shutdown_func', self._set_called)
730
731 self.obj.login(APP_NAME, self.args)
732- self.obj.CredentialsFound(APP_NAME, TOKEN)
733 # counter reached 0, timeout_func was called
734
735 self.assertEqual(self._called, ((), {}), 'shutdown_func was called')
736@@ -895,9 +900,6 @@
737 yield super(CredentialsManagementOpsTestCase, self).setUp()
738 self.args = dict((k, str(v)) for k, v in self.base_args.iteritems())
739 self.cred_args = self.base_args.copy()
740- self.cred_args[SUCCESS_CB_KEY] = self.obj.CredentialsFound
741- self.cred_args[ERROR_CB_KEY] = self.obj.CredentialsError
742- self.cred_args[DENIAL_CB_KEY] = self.obj.AuthorizationDenied
743
744 def test_register(self):
745 """The registration is correct."""
746
747=== modified file 'ubuntu_sso/qt/tests/show_gui.py'
748--- ubuntu_sso/qt/tests/show_gui.py 2012-01-26 15:34:16 +0000
749+++ ubuntu_sso/qt/tests/show_gui.py 2012-02-10 17:15:32 +0000
750@@ -33,7 +33,7 @@
751 TC_URL_KEY,
752 HELP_TEXT_KEY,
753 WINDOW_ID_KEY,
754- UI_MODULE_KEY,
755+ UI_EXECUTABLE_KEY,
756 )
757
758
759@@ -58,7 +58,7 @@
760 TC_URL_KEY: 'http://www.google.com',
761 HELP_TEXT_KEY: 'This is a test.',
762 WINDOW_ID_KEY: '0',
763- UI_MODULE_KEY: 'ubuntu_sso.qt.gui',
764+ UI_EXECUTABLE_KEY: 'ubuntu-sso-login-gtk',
765 })
766 print "called ok"
767 yield d
768
769=== modified file 'ubuntu_sso/tests/__init__.py'
770--- ubuntu_sso/tests/__init__.py 2012-01-24 22:26:45 +0000
771+++ ubuntu_sso/tests/__init__.py 2012-02-10 17:15:32 +0000
772@@ -33,8 +33,7 @@
773 CAPTCHA_SOLUTION = u'william Byrd ñandú'
774 EMAIL = u'test@example.com'
775 EMAIL_TOKEN = u'B2Pgtf'
776-GTK_GUI_CLASS = 'UbuntuSSOClientGUI'
777-GTK_GUI_MODULE = 'ubuntu_sso.gtk.gui'
778+GTK_GUI_EXE = 'ubuntu-sso-login-gtk'
779 HELP_TEXT = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed
780 lorem nibh. Suspendisse gravida nulla non nunc suscipit pulvinar tempus ut
781 augue. Morbi consequat, ligula a elementum pretium, dolor nulla tempus metus,
782
783=== modified file 'ubuntu_sso/tests/test_credentials.py'
784--- ubuntu_sso/tests/test_credentials.py 2012-02-09 21:57:15 +0000
785+++ ubuntu_sso/tests/test_credentials.py 2012-02-10 17:15:32 +0000
786@@ -21,12 +21,12 @@
787 from twisted.trial.unittest import TestCase
788 from ubuntuone.devtools.handlers import MementoHandler
789
790+import ubuntu_sso.main
791+
792 from ubuntu_sso import credentials
793-import ubuntu_sso.main
794-from ubuntu_sso.credentials import (APP_NAME_KEY, HELP_TEXT_KEY, NO_OP,
795- PING_URL_KEY, TC_URL_KEY, UI_CLASS_KEY, UI_MODULE_KEY, WINDOW_ID_KEY,
796- ERROR_KEY, ERROR_DETAIL_KEY)
797-from ubuntu_sso.tests import (APP_NAME, EMAIL, GTK_GUI_CLASS, GTK_GUI_MODULE,
798+from ubuntu_sso.credentials import (APP_NAME_KEY, HELP_TEXT_KEY,
799+ PING_URL_KEY, TC_URL_KEY, UI_EXECUTABLE_KEY, WINDOW_ID_KEY)
800+from ubuntu_sso.tests import (APP_NAME, EMAIL, GTK_GUI_EXE,
801 HELP_TEXT, PASSWORD, PING_URL, TC_URL, TOKEN, WINDOW_ID)
802
803
804@@ -42,19 +42,18 @@
805
806 KWARGS = {
807 APP_NAME_KEY: APP_NAME,
808- TC_URL_KEY: TC_URL,
809 HELP_TEXT_KEY: HELP_TEXT,
810 WINDOW_ID_KEY: WINDOW_ID,
811 PING_URL_KEY: PING_URL,
812- UI_MODULE_KEY: 'ubuntu_sso.tests.test_credentials',
813- UI_CLASS_KEY: 'FakedClientGUI',
814+ TC_URL_KEY: TC_URL,
815+ UI_EXECUTABLE_KEY: 'foo-bar-baz',
816 }
817
818 UI_KWARGS = {
819 APP_NAME_KEY: APP_NAME,
820+ HELP_TEXT_KEY: HELP_TEXT,
821 PING_URL_KEY: PING_URL,
822 TC_URL_KEY: TC_URL,
823- HELP_TEXT_KEY: HELP_TEXT,
824 WINDOW_ID_KEY: WINDOW_ID,
825 }
826
827@@ -63,39 +62,17 @@
828 """An error to be used while testing."""
829
830
831-class FailingClient(object):
832- """Fake a failing client."""
833-
834- err_msg = 'A failing class.'
835-
836- def __init__(self, *args, **kwargs):
837- raise SampleMiscException(self.err_msg)
838-
839-
840-class FakedClientGUI(object):
841- """Fake a SSO GUI."""
842-
843- def __init__(self, *args, **kwargs):
844- self.args = args
845- self.kwargs = kwargs
846- self.login_success_callback = None
847- self.registration_success_callback = None
848- self.user_cancellation_callback = None
849-
850-
851 class FakedSSOLogin(object):
852 """Fake a SSOLogin."""
853
854- args = []
855- kwargs = {}
856+ proxy = None
857
858 def __init__(self, proxy):
859 """Nothing."""
860+ FakedSSOLogin.proxy = proxy
861
862 def login(self, *args, **kwargs):
863 """Fake login."""
864- self.args = args
865- self.kwargs = kwargs
866
867
868 class BasicTestCase(TestCase):
869@@ -125,53 +102,12 @@
870 def setUp(self):
871 """Init."""
872 yield super(CredentialsTestCase, self).setUp()
873- self.obj = credentials.Credentials(success_cb=self.success,
874- error_cb=self.error,
875- denial_cb=self.denial,
876- **KWARGS)
877-
878- def success(self, *args, **kwargs):
879- """To be called on success."""
880- self._set_called('success', *args, **kwargs)
881-
882- def error(self, *args, **kwargs):
883- """To be called on error."""
884- self._set_called('error', *args, **kwargs)
885-
886- def denial(self, *args, **kwargs):
887- """To be called on credentials denial."""
888- self._set_called('denial', *args, **kwargs)
889-
890- def assert_error_cb_called(self, msg, detailed_error=None):
891- """Check that self.error_cb was called with proper arguments."""
892- self.assertEqual(len(self._called), 2)
893- self.assertEqual(self._called[0][0], 'error')
894- self.assertEqual(self._called[0][1], APP_NAME)
895- error_dict = self._called[0][2]
896- self.assertEqual(error_dict[ERROR_KEY], msg)
897- if detailed_error is not None:
898- self.assertIn(str(detailed_error), error_dict[ERROR_DETAIL_KEY])
899- else:
900- self.assertNotIn(ERROR_DETAIL_KEY, error_dict)
901- self.assertEqual(self._called[1], {})
902+ self.obj = credentials.Credentials(**KWARGS)
903
904
905 class CredentialsCallbacksTestCase(CredentialsTestCase):
906 """Test suite for the Credentials callbacks."""
907
908- def test_callbacks_are_stored(self):
909- """Creation callbacks are stored."""
910- self.assertEqual(self.obj._success_cb, self.success)
911- self.assertEqual(self.obj._error_cb, self.error)
912- self.assertEqual(self.obj.denial_cb, self.denial)
913-
914- def test_callbacks_default_to_no_op(self):
915- """The callbacks are a no-operation if not given."""
916- self.obj = credentials.Credentials(**KWARGS)
917- self.assertEqual(self.obj._success_cb, NO_OP)
918- self.assertEqual(self.obj._error_cb, NO_OP)
919- self.assertEqual(self.obj.denial_cb, NO_OP)
920-
921 def test_creation_parameters_are_stored(self):
922 """Creation parameters are stored."""
923 for key, value in KWARGS.iteritems():
924@@ -209,78 +145,13 @@
925
926 self.assertEqual(getattr(self.obj, PING_URL_KEY), None)
927
928- def test_ui_class_defaults_to_gtk(self):
929+ def test_ui_executable_defaults_to_gtk(self):
930 """The ui class defaults to gtk."""
931 newkw = KWARGS.copy()
932- newkw.pop(UI_CLASS_KEY)
933- self.obj = credentials.Credentials(**newkw)
934-
935- self.assertEqual(getattr(self.obj, UI_CLASS_KEY), GTK_GUI_CLASS)
936-
937- def test_ui_module_defaults_to_gtk(self):
938- """The ui module defaults to gtk."""
939- newkw = KWARGS.copy()
940- newkw.pop(UI_MODULE_KEY)
941- self.obj = credentials.Credentials(**newkw)
942-
943- self.assertEqual(getattr(self.obj, UI_MODULE_KEY), GTK_GUI_MODULE)
944-
945- def test_success_cb(self):
946- """Success callback calls the caller."""
947- self.obj.gui = None
948- self.obj.success_cb(creds=TOKEN)
949-
950- self.assertEqual(self._called, (('success', APP_NAME, TOKEN), {}),
951- 'caller _success_cb was called.')
952-
953- def test_error_cb(self):
954- """Error callback calls the caller."""
955- error_dict = {'foo': 'bar'}
956- self.obj.error_cb(error_dict=error_dict)
957-
958- self.assertEqual(self._called, (('error', APP_NAME, error_dict), {}),
959- 'caller _error_cb was called.')
960-
961-
962-class CredentialsLoginSuccessTestCase(CredentialsTestCase):
963- """Test suite for the Credentials login success callback."""
964-
965- @defer.inlineCallbacks
966- def test_cred_not_found(self):
967- """On auth success, if cred not found, self.error_cb is called."""
968- self.patch(credentials.Keyring, 'get_credentials',
969- lambda kr, app: defer.succeed(None))
970-
971- result = yield self.obj._login_success_cb(APP_NAME, EMAIL)
972-
973- msg = 'Creds are empty! This should not happen'
974- self.assert_error_cb_called(msg='Problem while retrieving credentials',
975- detailed_error=AssertionError(msg))
976- self.assertEqual(result, None)
977-
978- @defer.inlineCallbacks
979- def test_cred_error(self):
980- """On auth success, if cred failed, self.error_cb is called."""
981- expected_error = SampleMiscException()
982- self.patch(credentials.Keyring, 'get_credentials',
983- lambda kr, app: defer.fail(expected_error))
984-
985- result = yield self.obj._login_success_cb(APP_NAME, EMAIL)
986-
987- msg = 'Problem while retrieving credentials'
988- self.assert_error_cb_called(msg=msg, detailed_error=expected_error)
989- self.assertEqual(result, None)
990- self.assertTrue(self.memento.check_exception(SampleMiscException))
991-
992-
993-class CredentialsAuthDeniedTestCase(CredentialsTestCase):
994- """Test suite for the Credentials auth denied callback."""
995-
996- def test_auth_denial_cb(self):
997- """On auth denied, self.denial_cb is called."""
998- self.obj._auth_denial_cb(app_name=APP_NAME)
999-
1000- self.assertEqual(self._called, (('denial', APP_NAME), {}))
1001+ newkw.pop(UI_EXECUTABLE_KEY)
1002+ self.obj = credentials.Credentials(**newkw)
1003+
1004+ self.assertEqual(getattr(self.obj, UI_EXECUTABLE_KEY), GTK_GUI_EXE)
1005
1006
1007 class FindCredentialsTestCase(CredentialsTestCase):
1008@@ -367,89 +238,128 @@
1009 operation = 'register'
1010 login_only = False
1011 kwargs = {}
1012- inner_class = FakedClientGUI
1013
1014 @defer.inlineCallbacks
1015 def setUp(self):
1016 yield super(RegisterTestCase, self).setUp()
1017- self.inner_kwargs = UI_KWARGS.copy()
1018- self.inner_kwargs['login_only'] = self.login_only
1019+ self.deferred = defer.Deferred()
1020+ self.patch_inner(self.fake_inner)
1021+ self.inner_args = [
1022+ KWARGS[UI_EXECUTABLE_KEY],
1023+ '--app_name', APP_NAME,
1024+ '--help_text', HELP_TEXT,
1025+ '--ping_url', PING_URL,
1026+ '--tc_url', TC_URL,
1027+ '--window_id', str(WINDOW_ID),
1028+ ]
1029+ if self.login_only:
1030+ self.inner_args.append('--login_only')
1031+
1032+ self._next_inner_result = 0
1033+
1034 self.method_call = getattr(self.obj, self.operation)
1035
1036+ def patch_inner(self, f):
1037+ """Patch the inner call."""
1038+ self.patch(credentials.runner, 'spawn_program', f)
1039+
1040+ def fake_inner(self, args):
1041+ """Fake the runner.spawn_program."""
1042+ self.deferred.callback(args)
1043+
1044+ if self._next_inner_result == credentials.USER_SUCCESS:
1045+ # fake that tokens were retrieved from the UI
1046+ self.patch(credentials.Keyring, 'get_credentials',
1047+ lambda kr, app: defer.succeed(TOKEN))
1048+
1049+ return defer.succeed(self._next_inner_result)
1050+
1051+ def fail_inner(self, args):
1052+ """Make the inner call fail."""
1053+ return defer.fail(SampleMiscException(args))
1054+
1055+ def assert_exc_msg_logged(self, exception_class, msg):
1056+ """Check that 'msg' was logged as part as the logger.exception call."""
1057+ for rec in self.memento.records:
1058+ if rec.exc_info and rec.exc_info[0] == exception_class:
1059+ self.assertIn(msg, rec.getMessage())
1060+ break
1061+
1062 @defer.inlineCallbacks
1063 def test_with_existent_token(self):
1064 """The operation returns the credentials if already in keyring."""
1065 self.patch(credentials.Keyring, 'get_credentials',
1066 lambda kr, app: defer.succeed(TOKEN))
1067
1068- yield self.method_call(**self.kwargs)
1069+ result = yield self.method_call(**self.kwargs)
1070
1071- self.assertEqual(self._called, (('success', APP_NAME, TOKEN), {}))
1072+ self.assertEqual(result, TOKEN)
1073+ self.assertFalse(self.deferred.called, 'No program was spawnned.')
1074
1075 @defer.inlineCallbacks
1076- def test_without_existent_token(self):
1077+ def test_without_existent_token_and_return_code_success(self):
1078 """The operation returns the credentials gathered by the inner call."""
1079 self.patch(credentials.Keyring, 'get_credentials',
1080 lambda kr, app: defer.succeed(None))
1081-
1082- yield self.method_call(**self.kwargs)
1083-
1084- self.assertEqual(self.obj.inner.kwargs, self.inner_kwargs)
1085+ self._next_inner_result = credentials.USER_SUCCESS
1086+
1087+ result = yield self.method_call(**self.kwargs)
1088+ self.assertEqual(result, TOKEN)
1089+
1090+ # the ui was opened and proper params were passed
1091+ args = yield self.deferred
1092+ self.assertEqual(self.inner_args, args)
1093+
1094+ @defer.inlineCallbacks
1095+ def test_without_existent_token_and_return_code_cancel(self, exc=None):
1096+ """The operation returns exc if defined, else UserCancellationError."""
1097+ self.patch(credentials.Keyring, 'get_credentials',
1098+ lambda kr, app: defer.succeed(None))
1099+ self._next_inner_result = credentials.USER_CANCELLATION
1100+
1101+ if exc is None:
1102+ exc = credentials.UserCancellationError
1103+ yield self.assertFailure(self.method_call(**self.kwargs), exc)
1104+
1105+ @defer.inlineCallbacks
1106+ def test_without_existent_token_and_return_other(self, result=None):
1107+ """The operation returns CredentialsError with 'result'."""
1108+ self.patch(credentials.Keyring, 'get_credentials',
1109+ lambda kr, app: defer.succeed(None))
1110+ self._next_inner_result = credentials.USER_CANCELLATION * 2 # other
1111+
1112+ exc = yield self.assertFailure(self.method_call(**self.kwargs),
1113+ credentials.CredentialsError)
1114+ if result is None:
1115+ result = self._next_inner_result
1116+ self.assertEqual(exc.args, (result,))
1117
1118 @defer.inlineCallbacks
1119 def test_with_exception_on_credentials(self):
1120 """The operation calls the error callback if a exception occurs."""
1121- expected_error = SampleMiscException()
1122 self.patch(credentials.Keyring, 'get_credentials',
1123- lambda kr, app: defer.fail(expected_error))
1124-
1125- yield self.method_call(**self.kwargs)
1126-
1127- msg = 'Problem while retrieving credentials'
1128- self.assert_error_cb_called(msg=msg, detailed_error=expected_error)
1129+ lambda kr, app: defer.fail(SampleMiscException()))
1130+
1131+ yield self.assertFailure(self.method_call(**self.kwargs),
1132+ SampleMiscException)
1133+
1134 self.assertTrue(self.memento.check_exception(SampleMiscException))
1135+ msg = 'Problem while getting credentials from the keyring'
1136+ self.assert_exc_msg_logged(SampleMiscException, msg)
1137
1138 @defer.inlineCallbacks
1139- def test_with_exception_on_inner_call(self, msg=None):
1140+ def test_with_exception_on_inner_call(self):
1141 """The operation calls the error callback if a exception occurs."""
1142 self.patch(credentials.Keyring, 'get_credentials',
1143 lambda kr, app: defer.succeed(None))
1144- self.obj.ui_class = 'FailingClient'
1145-
1146- yield self.method_call(**self.kwargs)
1147-
1148- if msg is None:
1149- msg = 'Problem opening the Ubuntu SSO user interface'
1150- self.assert_error_cb_called(msg=msg,
1151- detailed_error=SampleMiscException(FailingClient.err_msg))
1152- self.assertTrue(self.memento.check_exception(SampleMiscException,
1153- FailingClient.err_msg))
1154-
1155- @defer.inlineCallbacks
1156- def test_connects_inner_signals(self):
1157- """Inner callbacks are properly connected."""
1158- self.patch(credentials.Keyring, 'get_credentials',
1159- lambda kr, app: defer.succeed(None))
1160- yield self.method_call(**self.kwargs)
1161-
1162- self.assertEqual(self.obj.inner.login_success_callback,
1163- self.obj._login_success_cb)
1164- self.assertEqual(self.obj.inner.registration_success_callback,
1165- self.obj._login_success_cb)
1166- self.assertEqual(self.obj.inner.user_cancellation_callback,
1167- self.obj._auth_denial_cb)
1168-
1169- @defer.inlineCallbacks
1170- def test_inner_object_is_created(self):
1171- """The inner object is created and stored."""
1172- self.patch(credentials.Keyring, 'get_credentials',
1173- lambda kr, app: defer.succeed(None))
1174-
1175- yield self.method_call(**self.kwargs)
1176-
1177- self.assertIsInstance(self.obj.inner, self.inner_class)
1178- self.assertEqual(self.obj.inner.args, ())
1179- self.assertEqual(self.obj.inner.kwargs, self.inner_kwargs)
1180+ self.patch_inner(self.fail_inner)
1181+
1182+ yield self.assertFailure(self.method_call(**self.kwargs),
1183+ SampleMiscException)
1184+
1185+ self.assertTrue(self.memento.check_exception(SampleMiscException))
1186+ msg = 'Problem while performing %s' % self.operation
1187+ self.assert_exc_msg_logged(SampleMiscException, msg)
1188
1189
1190 class LoginTestCase(RegisterTestCase):
1191@@ -465,22 +375,46 @@
1192 operation = 'login'
1193 login_only = True
1194 kwargs = {'email': EMAIL, 'password': PASSWORD}
1195- inner_class = FakedSSOLogin
1196
1197 @defer.inlineCallbacks
1198 def setUp(self):
1199 yield super(LoginEmailPasswordTestCase, self).setUp()
1200- self.inner_kwargs = self.kwargs.copy()
1201- self.inner_kwargs[APP_NAME_KEY] = APP_NAME
1202 self.patch(ubuntu_sso.main, 'SSOLogin', FakedSSOLogin)
1203-
1204- def test_with_exception_on_inner_call(self, msg=None):
1205- """The operation calls the error callback if a exception occurs."""
1206- self.patch(ubuntu_sso.main, 'SSOLogin', FailingClient)
1207- msg = 'Problem logging with email and password.'
1208- return super(LoginEmailPasswordTestCase,
1209- self).test_with_exception_on_inner_call(msg=msg)
1210-
1211- def test_connects_inner_signals(self):
1212- """Inner callbacks are properly connected."""
1213- # there is no inner callbacks for the SSOLoginRoot object
1214+ self.patch_inner(self.fake_inner)
1215+ self.inner_args = dict(app_name=APP_NAME,
1216+ email=EMAIL, password=PASSWORD,
1217+ ping_url=PING_URL)
1218+
1219+ def patch_inner(self, f):
1220+ """Patch the inner call."""
1221+ self.patch(FakedSSOLogin, 'login', f)
1222+
1223+ def fake_inner(self, **kwargs):
1224+ """Fake the runner.spawn_program."""
1225+ self.deferred.callback(kwargs)
1226+
1227+ if self._next_inner_result == credentials.USER_SUCCESS:
1228+ # fake that tokens were retrieved from the UI
1229+ self.patch(credentials.Keyring, 'get_credentials',
1230+ lambda kr, app: defer.succeed(TOKEN))
1231+ FakedSSOLogin.proxy.LoggedIn(APP_NAME, EMAIL)
1232+ elif self._next_inner_result == credentials.USER_CANCELLATION:
1233+ FakedSSOLogin.proxy.UserNotValidated(APP_NAME, EMAIL)
1234+ else:
1235+ FakedSSOLogin.proxy.LoginError(APP_NAME, {'errtype': 'foo'})
1236+
1237+ def fail_inner(self, **kwargs):
1238+ """Make the inner call fail."""
1239+ raise SampleMiscException(kwargs)
1240+
1241+ def test_without_existent_token_and_return_code_cancel(self, exc=None):
1242+ """The operation returns UserNotValidatedError."""
1243+ exc = credentials.UserNotValidatedError
1244+ return super(LoginEmailPasswordTestCase, self).\
1245+ test_without_existent_token_and_return_code_cancel(exc=exc)
1246+
1247+ def test_without_existent_token_and_return_other(self, result=None):
1248+ """The operation returns CredentialsError with 'result'."""
1249+ result = 'foo'
1250+ return super(LoginEmailPasswordTestCase, self).\
1251+ test_without_existent_token_and_return_other(result=result)
1252
1253=== modified file 'ubuntu_sso/utils/runner/glib.py'
1254--- ubuntu_sso/utils/runner/glib.py 2012-02-10 14:05:09 +0000
1255+++ ubuntu_sso/utils/runner/glib.py 2012-02-10 17:15:32 +0000
1256@@ -19,11 +19,6 @@
1257 import os
1258
1259 # pylint: disable=E0611,F0401
1260-try:
1261- from shlex import quote
1262-except ImportError:
1263- from pipes import quote
1264-
1265 from gi.repository import GLib
1266 # pylint: enable=E0611,F0401
1267
1268@@ -66,9 +61,6 @@
1269 msg = 'GError is: code %r, message %r' % (gerror.code, gerror.message)
1270 error_handler(msg=msg, failed_to_start=failed_to_start)
1271
1272- # escape arguments
1273- args = [quote(a) for a in args]
1274-
1275 flags = GLib.SpawnFlags.DO_NOT_REAP_CHILD | \
1276 GLib.SpawnFlags.SEARCH_PATH | \
1277 GLib.SpawnFlags.STDOUT_TO_DEV_NULL | \

Subscribers

People subscribed via source and target branches