Merge lp:~nataliabidart/ubuntu/precise/ubuntu-sso-client/ubuntu-sso-client-2.99.2 into lp:ubuntu/precise/ubuntu-sso-client
- Precise (12.04)
- ubuntu-sso-client-2.99.2
- Merge into precise
Proposed by
Natalia Bidart
Status: | Merged |
---|---|
Merged at revision: | 42 |
Proposed branch: | lp:~nataliabidart/ubuntu/precise/ubuntu-sso-client/ubuntu-sso-client-2.99.2 |
Merge into: | lp:ubuntu/precise/ubuntu-sso-client |
Diff against target: |
9351 lines (+4205/-3711) 42 files modified
PKG-INFO (+1/-1) debian/changelog (+7/-0) debian/watch (+1/-1) setup.py (+1/-1) ubuntu_sso/account.py (+11/-14) ubuntu_sso/credentials.py (+61/-25) ubuntu_sso/logger.py (+20/-0) ubuntu_sso/main/__init__.py (+257/-111) ubuntu_sso/main/linux.py (+181/-164) ubuntu_sso/main/tests/__init__.py (+37/-0) ubuntu_sso/main/tests/test_clients.py (+373/-0) ubuntu_sso/main/tests/test_common.py (+911/-155) ubuntu_sso/main/tests/test_linux.py (+0/-1275) ubuntu_sso/main/tests/test_windows.py (+18/-926) ubuntu_sso/main/windows.py (+185/-663) ubuntu_sso/networkstate/__init__.py (+8/-0) ubuntu_sso/networkstate/linux.py (+24/-0) ubuntu_sso/networkstate/tests/test_linux.py (+137/-2) ubuntu_sso/networkstate/tests/test_windows.py (+64/-0) ubuntu_sso/networkstate/windows.py (+13/-5) ubuntu_sso/qt/controllers.py (+12/-3) ubuntu_sso/qt/tests/__init__.py (+7/-4) ubuntu_sso/qt/tests/login_u_p.py (+37/-29) ubuntu_sso/qt/tests/show_gui.py (+36/-20) ubuntu_sso/qt/tests/test_controllers.py (+0/-2) ubuntu_sso/tests/__init__.py (+41/-0) ubuntu_sso/tests/test_account.py (+17/-3) ubuntu_sso/tests/test_credentials.py (+11/-14) ubuntu_sso/utils/ipc.py (+361/-0) ubuntu_sso/utils/tests/test_common.py (+264/-0) ubuntu_sso/utils/tests/test_ipc.py (+505/-0) ubuntu_sso/utils/tests/test_oauth_headers.py (+0/-260) ubuntu_sso/utils/tests/test_txsecrets.py (+22/-0) ubuntu_sso/utils/webclient/common.py (+16/-4) ubuntu_sso/utils/webclient/gsettings.py (+63/-0) ubuntu_sso/utils/webclient/libsoup.py (+32/-4) ubuntu_sso/utils/webclient/qtnetwork.py (+36/-6) ubuntu_sso/utils/webclient/restful.py (+52/-0) ubuntu_sso/utils/webclient/tests/test_gsettings.py (+131/-0) ubuntu_sso/utils/webclient/tests/test_restful.py (+148/-0) ubuntu_sso/utils/webclient/tests/test_webclient.py (+96/-16) ubuntu_sso/utils/webclient/txweb.py (+8/-3) |
To merge this branch: | bzr merge lp:~nataliabidart/ubuntu/precise/ubuntu-sso-client/ubuntu-sso-client-2.99.2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sebastien Bacher | Approve | ||
Review via email: mp+88926@code.launchpad.net |
Commit message
* New upstream release.
* debian/watch: updated to latest active milestone.
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'PKG-INFO' |
2 | --- PKG-INFO 2012-01-03 19:02:32 +0000 |
3 | +++ PKG-INFO 2012-01-17 19:42:46 +0000 |
4 | @@ -1,6 +1,6 @@ |
5 | Metadata-Version: 1.1 |
6 | Name: ubuntu-sso-client |
7 | -Version: 2.99.1 |
8 | +Version: 2.99.2 |
9 | Summary: Ubuntu Single Sign-On client |
10 | Home-page: https://launchpad.net/ubuntu-sso-client |
11 | Author: Natalia Bidart |
12 | |
13 | === modified file 'debian/changelog' |
14 | --- debian/changelog 2012-01-03 20:13:45 +0000 |
15 | +++ debian/changelog 2012-01-17 19:42:46 +0000 |
16 | @@ -1,3 +1,10 @@ |
17 | +ubuntu-sso-client (2.99.2-0ubuntu1) UNRELEASED; urgency=low |
18 | + |
19 | + * New upstream release. |
20 | + * debian/watch: updated to latest active milestone. |
21 | + |
22 | + -- Natalia Bidart (nessita) <nataliabidart@gmail.com> Tue, 17 Jan 2012 16:05:02 -0300 |
23 | + |
24 | ubuntu-sso-client (2.99.1-0ubuntu1) precise; urgency=low |
25 | |
26 | * New upstream release: |
27 | |
28 | === modified file 'debian/watch' |
29 | --- debian/watch 2012-01-03 19:01:50 +0000 |
30 | +++ debian/watch 2012-01-17 19:42:46 +0000 |
31 | @@ -1,2 +1,2 @@ |
32 | version=3 |
33 | -http://launchpad.net/ubuntu-sso-client/stable-3-0/2.99.1/ .*/ubuntu-sso-client-([0-9.]+)\.tar\.gz |
34 | +http://launchpad.net/ubuntu-sso-client/stable-3-0/2.99.2/ .*/ubuntu-sso-client-([0-9.]+)\.tar\.gz |
35 | |
36 | === modified file 'setup.py' |
37 | --- setup.py 2012-01-03 19:02:32 +0000 |
38 | +++ setup.py 2012-01-17 19:42:46 +0000 |
39 | @@ -364,7 +364,7 @@ |
40 | |
41 | DistUtilsExtra.auto.setup( |
42 | name='ubuntu-sso-client', |
43 | - version='2.99.1', |
44 | + version='2.99.2', |
45 | license='GPL v3', |
46 | author='Natalia Bidart', |
47 | author_email='natalia.bidart@canonical.com', |
48 | |
49 | === modified file 'ubuntu_sso/account.py' |
50 | --- ubuntu_sso/account.py 2011-12-20 17:33:13 +0000 |
51 | +++ ubuntu_sso/account.py 2012-01-17 19:42:46 +0000 |
52 | @@ -96,15 +96,12 @@ |
53 | class Account(object): |
54 | """Login and register users using the Ubuntu Single Sign On service.""" |
55 | |
56 | - def __init__(self, sso_service_class=None): |
57 | + def __init__(self, service_url=None): |
58 | """Create a new SSO Account manager.""" |
59 | - if sso_service_class is None: |
60 | - self.sso_service_class = ServiceRoot |
61 | + if service_url is not None: |
62 | + self.service_url = service_url |
63 | else: |
64 | - self.sso_service_class = sso_service_class |
65 | - |
66 | - self.service_url = os.environ.get('USSOC_SERVICE_URL', SERVICE_URL) |
67 | - |
68 | + self.service_url = os.environ.get('USSOC_SERVICE_URL', SERVICE_URL) |
69 | logger.info('Created a new SSO access layer for service url %r', |
70 | self.service_url) |
71 | |
72 | @@ -134,7 +131,7 @@ |
73 | """Generate a captcha using the SSO service.""" |
74 | logger.debug('generate_captcha: requesting captcha, filename: %r', |
75 | filename) |
76 | - sso_service = self.sso_service_class(None, self.service_url) |
77 | + sso_service = ServiceRoot(None, self.service_url) |
78 | captcha = sso_service.captchas.new() |
79 | |
80 | # download captcha and save to 'filename' |
81 | @@ -156,7 +153,7 @@ |
82 | logger.debug('register_user: email: %r password: <hidden>, ' |
83 | 'displayname: %r, captcha_id: %r, captcha_solution: %r', |
84 | email, displayname, captcha_id, captcha_solution) |
85 | - sso_service = self.sso_service_class(None, self.service_url) |
86 | + sso_service = ServiceRoot(None, self.service_url) |
87 | if not self._valid_email(email): |
88 | logger.error('register_user: InvalidEmailError for email: %r', |
89 | email) |
90 | @@ -185,7 +182,7 @@ |
91 | logger.debug('login: email: %r password: <hidden>, token_name: %r', |
92 | email, token_name) |
93 | basic = BasicHttpAuthorizer(email, password) |
94 | - sso_service = self.sso_service_class(basic, self.service_url) |
95 | + sso_service = ServiceRoot(basic, self.service_url) |
96 | service = sso_service.authentications.authenticate |
97 | |
98 | try: |
99 | @@ -209,7 +206,7 @@ |
100 | token['consumer_key'], |
101 | token['consumer_secret'], |
102 | oauth_token) |
103 | - sso_service = self.sso_service_class(authorizer, self.service_url) |
104 | + sso_service = ServiceRoot(authorizer, self.service_url) |
105 | |
106 | me_info = sso_service.accounts.me() |
107 | key = 'preferred_email' |
108 | @@ -232,7 +229,7 @@ |
109 | token['consumer_key'], |
110 | token['consumer_secret'], |
111 | oauth_token) |
112 | - sso_service = self.sso_service_class(authorizer, self.service_url) |
113 | + sso_service = ServiceRoot(authorizer, self.service_url) |
114 | result = sso_service.accounts.validate_email(email_token=email_token) |
115 | logger.info('validate_email: email: %r result: %r', email, result) |
116 | if 'errors' in result: |
117 | @@ -245,7 +242,7 @@ |
118 | |
119 | def request_password_reset_token(self, email): |
120 | """Request a token to reset the password for the account 'email'.""" |
121 | - sso_service = self.sso_service_class(None, self.service_url) |
122 | + sso_service = ServiceRoot(None, self.service_url) |
123 | service = sso_service.registrations.request_password_reset_token |
124 | try: |
125 | result = service(email=email) |
126 | @@ -266,7 +263,7 @@ |
127 | 'request_password_reset_token'. |
128 | |
129 | """ |
130 | - sso_service = self.sso_service_class(None, self.service_url) |
131 | + sso_service = ServiceRoot(None, self.service_url) |
132 | service = sso_service.registrations.set_new_password |
133 | try: |
134 | result = service(email=email, token=token, |
135 | |
136 | === modified file 'ubuntu_sso/credentials.py' |
137 | --- ubuntu_sso/credentials.py 2012-01-03 19:02:32 +0000 |
138 | +++ ubuntu_sso/credentials.py 2012-01-17 19:42:46 +0000 |
139 | @@ -44,7 +44,6 @@ |
140 | from functools import wraps |
141 | |
142 | from twisted.internet import defer |
143 | -from twisted.internet.defer import inlineCallbacks, returnValue |
144 | |
145 | from ubuntu_sso import NO_OP, utils |
146 | from ubuntu_sso.keyring import Keyring |
147 | @@ -105,7 +104,7 @@ |
148 | """Decorate 'f' to catch all errors.""" |
149 | |
150 | @wraps(f) |
151 | - @inlineCallbacks |
152 | + @defer.inlineCallbacks |
153 | def inner(self, *a, **kw): |
154 | """Call 'f' within a try-except block. |
155 | |
156 | @@ -123,7 +122,7 @@ |
157 | error_dict = {ERROR_KEY: msg, |
158 | ERROR_DETAIL_KEY: traceback.format_exc()} |
159 | self.error_cb(error_dict) |
160 | - returnValue(result) |
161 | + defer.returnValue(result) |
162 | |
163 | return inner |
164 | |
165 | @@ -185,7 +184,7 @@ |
166 | self.inner = None # will hold the GUI or SSOLoginRoot instance |
167 | |
168 | @handle_failures(msg='Problem while retrieving credentials') |
169 | - @inlineCallbacks |
170 | + @defer.inlineCallbacks |
171 | def _login_success_cb(self, app_name, email): |
172 | """Store credentials when the login/registration succeeded. |
173 | |
174 | @@ -209,7 +208,7 @@ |
175 | return |
176 | |
177 | self.success_cb(creds) |
178 | - returnValue(0) |
179 | + defer.returnValue(0) |
180 | |
181 | def _auth_denial_cb(self, app_name): |
182 | """The user decided not to allow the registration or login.""" |
183 | @@ -265,16 +264,49 @@ |
184 | @handle_exceptions(msg='Problem logging with email and password.') |
185 | def _do_login(self, email, password): |
186 | """Login using email/password, connect outcome signals.""" |
187 | - from ubuntu_sso.main import SSOLoginRoot |
188 | - self.inner = SSOLoginRoot() |
189 | - self.inner.login(app_name=self.app_name, email=email, |
190 | - password=password, |
191 | - result_cb=self._login_success_cb, |
192 | - error_cb=self._error_cb, |
193 | - not_validated_cb=self._error_cb) |
194 | + from ubuntu_sso.main import SSOLogin |
195 | + |
196 | + d = defer.Deferred() |
197 | + |
198 | + class DummyProxy(object): |
199 | + """A temporary proxy to handle non-traditional login.""" |
200 | + |
201 | + # pylint: disable=C0103 |
202 | + |
203 | + def LoggedIn(self, app_name, result): |
204 | + """User was logged in.""" |
205 | + d.callback(result) |
206 | + |
207 | + def LoginError(self, app_name, error): |
208 | + """There was an error on login.""" |
209 | + d.errback(error) |
210 | + |
211 | + def UserNotValidated(self, app_name, email): |
212 | + """User is not validated.""" |
213 | + d.callback(None) |
214 | + |
215 | + # pylint: enable=C0103 |
216 | + |
217 | + self.inner = SSOLogin(proxy=DummyProxy()) |
218 | + self.inner.login(app_name=self.app_name, |
219 | + email=email, password=password) |
220 | + |
221 | + def _success(result): |
222 | + """Check if 'result' is a valid token, and callback properly.""" |
223 | + if result is not None: |
224 | + return self._login_success_cb(self.app_name, email) |
225 | + else: |
226 | + error_dict = { |
227 | + 'errtype': 'UserNotValidated', |
228 | + 'message': email, |
229 | + } |
230 | + self._error_cb(self.app_name, error_dict) |
231 | + |
232 | + d.addCallback(_success) |
233 | + d.addErrback(lambda f: self._error_cb(self.app_name, f.value)) |
234 | |
235 | @handle_failures(msg='Problem while retrieving credentials') |
236 | - @inlineCallbacks |
237 | + @defer.inlineCallbacks |
238 | def _login_or_register(self, login_only, email=None, password=None): |
239 | """Get credentials if found else prompt the GUI.""" |
240 | logger.info("_login_or_register: login_only=%r email=%r.", |
241 | @@ -303,20 +335,20 @@ |
242 | logger.debug('Calling success callback at %r.', self._success_cb) |
243 | self._success_cb(self.app_name, creds) |
244 | |
245 | - @inlineCallbacks |
246 | + @defer.inlineCallbacks |
247 | def find_credentials(self): |
248 | """Get the credentials for 'self.app_name'. Return {} if not there.""" |
249 | creds = yield Keyring().get_credentials(self.app_name) |
250 | logger.info('find_credentials: self.app_name %r, ' |
251 | 'result is {}? %s', self.app_name, creds is None) |
252 | - returnValue(creds if creds is not None else {}) |
253 | + defer.returnValue(creds if creds is not None else {}) |
254 | |
255 | - @inlineCallbacks |
256 | + @defer.inlineCallbacks |
257 | def clear_credentials(self): |
258 | """Clear the credentials for 'self.app_name'.""" |
259 | yield Keyring().delete_credentials(self.app_name) |
260 | |
261 | - @inlineCallbacks |
262 | + @defer.inlineCallbacks |
263 | def store_credentials(self, token): |
264 | """Store the credentials for 'self.app_name'.""" |
265 | yield Keyring().set_credentials(self.app_name, token) |
266 | @@ -325,11 +357,15 @@ |
267 | """Get credentials if found else prompt the GUI to register.""" |
268 | return self._login_or_register(login_only=False) |
269 | |
270 | - def login(self): |
271 | - """Get credentials if found else prompt the GUI to login.""" |
272 | - return self._login_or_register(login_only=True) |
273 | - |
274 | - def login_email_password(self, email, password): |
275 | - """Get credentials if found else login using email and password.""" |
276 | - return self._login_or_register(login_only=True, |
277 | - email=email, password=password) |
278 | + def login(self, email=None, password=None): |
279 | + """Get credentials if found else prompt the GUI to login. |
280 | + |
281 | + if 'email' and 'password' are given, do not prompt the user and use |
282 | + that to retrieve a token. |
283 | + |
284 | + """ |
285 | + if email is None or password is None: |
286 | + return self._login_or_register(login_only=True) |
287 | + else: |
288 | + return self._login_or_register(login_only=True, |
289 | + email=email, password=password) |
290 | |
291 | === modified file 'ubuntu_sso/logger.py' |
292 | --- ubuntu_sso/logger.py 2011-12-20 17:33:13 +0000 |
293 | +++ ubuntu_sso/logger.py 2012-01-17 19:42:46 +0000 |
294 | @@ -25,6 +25,7 @@ |
295 | import os |
296 | import sys |
297 | |
298 | +from functools import wraps |
299 | from logging.handlers import RotatingFileHandler |
300 | |
301 | from ubuntu_sso.xdg_base_directory import unicode_path, xdg_cache_home |
302 | @@ -61,3 +62,22 @@ |
303 | logger.addHandler(debug_handler) |
304 | |
305 | return logger |
306 | + |
307 | + |
308 | +def log_call(log_func): |
309 | + """Decorator to log, using 'log_func', calls to functions.""" |
310 | + |
311 | + def middle(f): |
312 | + """Return a function that will act as 'f' but will log the call.""" |
313 | + |
314 | + @wraps(f) |
315 | + def inner(instance, *a, **kw): |
316 | + """Call 'f(*a, **kw)' and return its result. Log that call.""" |
317 | + log_func('%r: emitting %r with args %r and kwargs %r', |
318 | + instance.__class__.__name__, f.__name__, a, kw) |
319 | + result = f(instance, *a, **kw) |
320 | + return result |
321 | + |
322 | + return inner |
323 | + |
324 | + return middle |
325 | |
326 | === modified file 'ubuntu_sso/main/__init__.py' |
327 | --- ubuntu_sso/main/__init__.py 2011-12-20 17:33:13 +0000 |
328 | +++ ubuntu_sso/main/__init__.py 2012-01-17 19:42:46 +0000 |
329 | @@ -1,9 +1,5 @@ |
330 | # -*- coding: utf-8 -*- |
331 | # |
332 | -# Author: Natalia Bidart <natalia.bidart@canonical.com> |
333 | -# Author: Alejandro J. Cura <alecu@canonical.com> |
334 | -# Author: Manuel de la Pena <manuel@canonical.com> |
335 | -# |
336 | # Copyright 2011 Canonical Ltd. |
337 | # |
338 | # This program is free software: you can redistribute it and/or modify it |
339 | @@ -17,10 +13,18 @@ |
340 | # |
341 | # You should have received a copy of the GNU General Public License along |
342 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
343 | -"""Main object implementations.""" |
344 | +"""Single Sign On client main module. |
345 | + |
346 | +Provides a utility which accepts requests to the Ubuntu Single Sign On |
347 | +service. The OAuth process is handled, including adding the OAuth access token |
348 | +to the local keyring. |
349 | + |
350 | +""" |
351 | |
352 | import sys |
353 | |
354 | +from twisted.internet import defer |
355 | + |
356 | from ubuntu_sso.account import Account |
357 | from ubuntu_sso.credentials import ( |
358 | Credentials, |
359 | @@ -35,16 +39,30 @@ |
360 | WINDOW_ID_KEY, |
361 | ) |
362 | from ubuntu_sso.keyring import get_token_name, Keyring |
363 | -from ubuntu_sso.logger import setup_logging |
364 | +from ubuntu_sso.logger import setup_logging, log_call |
365 | |
366 | |
367 | logger = setup_logging("ubuntu_sso.main") |
368 | U1_PING_URL = "https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/" |
369 | TIMEOUT_INTERVAL = 10000 # 10 seconds |
370 | |
371 | +# pylint: disable=C0103 |
372 | + |
373 | +if sys.platform == 'win32': |
374 | + from ubuntu_sso.main import windows |
375 | + source = windows |
376 | + TIMEOUT_INTERVAL = 10000000000 # forever (hack) |
377 | +else: |
378 | + from ubuntu_sso.main import linux |
379 | + source = linux |
380 | + |
381 | +UbuntuSSOProxy = source.UbuntuSSOProxy |
382 | +get_sso_client = source.get_sso_client |
383 | +thread_execute = source.blocking |
384 | + |
385 | |
386 | def except_to_errdict(e): |
387 | - """Turn an exception into a dictionary to return thru DBus.""" |
388 | + """Turn an exception into a dictionary to return thru IPC.""" |
389 | result = { |
390 | "errtype": e.__class__.__name__, |
391 | } |
392 | @@ -58,35 +76,71 @@ |
393 | return result |
394 | |
395 | |
396 | -class SSOLoginRoot(object): |
397 | +class SSOLogin(object): |
398 | """Login thru the Single Sign On service.""" |
399 | |
400 | - def __init__(self, sso_login_processor_class=Account, |
401 | - sso_service_class=None): |
402 | + def __init__(self, proxy): |
403 | """Initiate the Login object.""" |
404 | - self.sso_login_processor_class = sso_login_processor_class |
405 | - self.processor = self.sso_login_processor_class( |
406 | - sso_service_class=sso_service_class) |
407 | - |
408 | - def generate_captcha(self, app_name, filename, result_cb, |
409 | - error_cb): |
410 | + self.processor = Account() |
411 | + self.proxy = proxy |
412 | + |
413 | + @log_call(logger.debug) |
414 | + def CaptchaGenerated(self, app_name, result): |
415 | + """Signal thrown after the captcha is generated.""" |
416 | + self.proxy.CaptchaGenerated(app_name, result) |
417 | + |
418 | + @log_call(logger.debug) |
419 | + def CaptchaGenerationError(self, app_name, error): |
420 | + """Signal thrown when there's a problem generating the captcha.""" |
421 | + error_dict = except_to_errdict(error) |
422 | + self.proxy.CaptchaGenerationError(app_name, error_dict) |
423 | + |
424 | + def generate_captcha(self, app_name, filename): |
425 | """Call the matching method in the processor.""" |
426 | def f(): |
427 | """Inner function that will be run in a thread.""" |
428 | return self.processor.generate_captcha(filename) |
429 | - thread_execute(f, app_name, result_cb, error_cb) |
430 | + thread_execute(f, app_name, |
431 | + self.CaptchaGenerated, self.CaptchaGenerationError) |
432 | + |
433 | + @log_call(logger.debug) |
434 | + def UserRegistered(self, app_name, result): |
435 | + """Signal thrown when the user is registered.""" |
436 | + self.proxy.UserRegistered(app_name, result) |
437 | + |
438 | + @log_call(logger.debug) |
439 | + def UserRegistrationError(self, app_name, error): |
440 | + """Signal thrown when there's a problem registering the user.""" |
441 | + error_dict = except_to_errdict(error) |
442 | + self.proxy.UserRegistrationError(app_name, error_dict) |
443 | |
444 | def register_user(self, app_name, email, password, name, captcha_id, |
445 | - captcha_solution, result_cb, error_cb): |
446 | + captcha_solution): |
447 | """Call the matching method in the processor.""" |
448 | def f(): |
449 | """Inner function that will be run in a thread.""" |
450 | return self.processor.register_user(email, password, name, |
451 | captcha_id, captcha_solution) |
452 | - thread_execute(f, app_name, result_cb, error_cb) |
453 | - |
454 | - def login(self, app_name, email, password, result_cb, |
455 | - error_cb, not_validated_cb): |
456 | + thread_execute(f, app_name, |
457 | + self.UserRegistered, self.UserRegistrationError) |
458 | + |
459 | + @log_call(logger.debug) |
460 | + def LoggedIn(self, app_name, result): |
461 | + """Signal thrown when the user is logged in.""" |
462 | + self.proxy.LoggedIn(app_name, result) |
463 | + |
464 | + @log_call(logger.debug) |
465 | + def LoginError(self, app_name, error): |
466 | + """Signal thrown when there is a problem in the login.""" |
467 | + error_dict = except_to_errdict(error) |
468 | + self.proxy.LoginError(app_name, error_dict) |
469 | + |
470 | + @log_call(logger.debug) |
471 | + def UserNotValidated(self, app_name, email): |
472 | + """Signal thrown when the user is not validated.""" |
473 | + self.proxy.UserNotValidated(app_name, email) |
474 | + |
475 | + def login(self, app_name, email, password): |
476 | """Call the matching method in the processor.""" |
477 | def f(): |
478 | """Inner function that will be run in a thread.""" |
479 | @@ -103,18 +157,25 @@ |
480 | is_validated = self.processor.is_validated(credentials) |
481 | logger.debug('user is validated? %r.', is_validated) |
482 | if is_validated: |
483 | - # pylint: disable=E1101 |
484 | d = Keyring().set_credentials(app_name, credentials) |
485 | - d.addCallback(lambda _: result_cb(app_name, email)) |
486 | - d.addErrback(lambda failure: \ |
487 | - error_cb(app_name, |
488 | - except_to_errdict(failure.value))) |
489 | + d.addCallback(lambda _: self.LoggedIn(app_name, email)) |
490 | + d.addErrback(lambda f: self.LoginError(app_name, f.value)) |
491 | else: |
492 | - not_validated_cb(app_name, email) |
493 | - thread_execute(f, app_name, success_cb, error_cb) |
494 | - |
495 | - def validate_email(self, app_name, email, password, email_token, |
496 | - result_cb, error_cb): |
497 | + self.UserNotValidated(app_name, email) |
498 | + thread_execute(f, app_name, success_cb, self.LoginError) |
499 | + |
500 | + @log_call(logger.debug) |
501 | + def EmailValidated(self, app_name, result): |
502 | + """Signal thrown after the email is validated.""" |
503 | + self.proxy.EmailValidated(app_name, result) |
504 | + |
505 | + @log_call(logger.debug) |
506 | + def EmailValidationError(self, app_name, error): |
507 | + """Signal thrown when there's a problem validating the email.""" |
508 | + error_dict = except_to_errdict(error) |
509 | + self.proxy.EmailValidationError(app_name, error_dict) |
510 | + |
511 | + def validate_email(self, app_name, email, password, email_token): |
512 | """Call the matching method in the processor.""" |
513 | |
514 | def f(): |
515 | @@ -126,33 +187,54 @@ |
516 | |
517 | def success_cb(app_name, credentials): |
518 | """Validation finished successfully.""" |
519 | - # pylint: disable=E1101 |
520 | d = Keyring().set_credentials(app_name, credentials) |
521 | - d.addCallback(lambda _: result_cb(app_name, email)) |
522 | - failure_cb = lambda f: error_cb(app_name, f.value) |
523 | + d.addCallback(lambda _: self.EmailValidated(app_name, email)) |
524 | + failure_cb = lambda f: self.EmailValidationError(app_name, f.value) |
525 | d.addErrback(failure_cb) |
526 | |
527 | - thread_execute(f, app_name, success_cb, error_cb) |
528 | - |
529 | - def request_password_reset_token(self, app_name, email, |
530 | - result_cb, error_cb): |
531 | + thread_execute(f, app_name, success_cb, self.EmailValidationError) |
532 | + |
533 | + @log_call(logger.debug) |
534 | + def PasswordResetTokenSent(self, app_name, result): |
535 | + """Signal thrown when the token is succesfully sent.""" |
536 | + self.proxy.PasswordResetTokenSent(app_name, result) |
537 | + |
538 | + @log_call(logger.debug) |
539 | + def PasswordResetError(self, app_name, error): |
540 | + """Signal thrown when there's a problem sending the token.""" |
541 | + error_dict = except_to_errdict(error) |
542 | + self.proxy.PasswordResetError(app_name, error_dict) |
543 | + |
544 | + def request_password_reset_token(self, app_name, email): |
545 | """Call the matching method in the processor.""" |
546 | def f(): |
547 | """Inner function that will be run in a thread.""" |
548 | return self.processor.request_password_reset_token(email) |
549 | - thread_execute(f, app_name, result_cb, error_cb) |
550 | - |
551 | - def set_new_password(self, app_name, email, token, new_password, |
552 | - result_cb, error_cb): |
553 | + thread_execute(f, app_name, |
554 | + self.PasswordResetTokenSent, self.PasswordResetError) |
555 | + |
556 | + @log_call(logger.debug) |
557 | + def PasswordChanged(self, app_name, result): |
558 | + """Signal thrown when the token is succesfully sent.""" |
559 | + self.proxy.PasswordChanged(app_name, result) |
560 | + |
561 | + @log_call(logger.debug) |
562 | + def PasswordChangeError(self, app_name, error): |
563 | + """Signal thrown when there's a problem sending the token.""" |
564 | + error_dict = except_to_errdict(error) |
565 | + self.proxy.PasswordChangeError(app_name, error_dict) |
566 | + |
567 | + def set_new_password(self, app_name, email, token, new_password): |
568 | """Call the matching method in the processor.""" |
569 | def f(): |
570 | """Inner function that will be run in a thread.""" |
571 | return self.processor.set_new_password(email, token, |
572 | new_password) |
573 | - thread_execute(f, app_name, result_cb, error_cb) |
574 | - |
575 | - |
576 | -class CredentialsManagementRoot(object): |
577 | + thread_execute(f, app_name, |
578 | + self.PasswordChanged, self.PasswordChangeError) |
579 | + |
580 | + |
581 | +class CredentialsManagement(object): |
582 | """Object that manages credentials. |
583 | |
584 | Every exposed method in this class requires one mandatory argument: |
585 | @@ -178,27 +260,12 @@ |
586 | |
587 | """ |
588 | |
589 | - def __init__(self, timeout_func, shutdown_func, found_cb, error_cb, |
590 | - denied_cb, *args, **kwargs): |
591 | - """Create a new instance. |
592 | - |
593 | - - 'found_cb' is a callback that will be executed when the credentials |
594 | - were found. |
595 | - |
596 | - - 'error_cb' is a callback that will be executed when there was an |
597 | - error getting the credentials. |
598 | - |
599 | - - 'denied_cb' is a callback that will be executed when the user denied |
600 | - the use of the crendetials. |
601 | - |
602 | - """ |
603 | - super(CredentialsManagementRoot, self).__init__(*args, **kwargs) |
604 | + def __init__(self, timeout_func, shutdown_func, proxy): |
605 | + super(CredentialsManagement, self).__init__() |
606 | self._ref_count = 0 |
607 | self.timeout_func = timeout_func |
608 | self.shutdown_func = shutdown_func |
609 | - self.found_cb = found_cb |
610 | - self.error_cb = error_cb |
611 | - self.denied_cb = denied_cb |
612 | + self.proxy = proxy |
613 | |
614 | def _get_ref_count(self): |
615 | """Get value of ref_count.""" |
616 | @@ -236,12 +303,54 @@ |
617 | """Retrieve values from the generic param 'args'.""" |
618 | result = dict(i for i in args.iteritems() if i[0] in self.valid_keys) |
619 | result[WINDOW_ID_KEY] = int(args.get(WINDOW_ID_KEY, 0)) |
620 | - result[SUCCESS_CB_KEY] = self.found_cb |
621 | - result[ERROR_CB_KEY] = self.error_cb |
622 | - result[DENIAL_CB_KEY] = self.denied_cb |
623 | + result[SUCCESS_CB_KEY] = self.CredentialsFound |
624 | + result[ERROR_CB_KEY] = self.CredentialsError |
625 | + result[DENIAL_CB_KEY] = self.AuthorizationDenied |
626 | return result |
627 | |
628 | - def find_credentials(self, app_name, args, success_cb, error_cb): |
629 | + @log_call(logger.info) |
630 | + def AuthorizationDenied(self, app_name): |
631 | + """Signal thrown when the user denies the authorization.""" |
632 | + self.ref_count -= 1 |
633 | + self.proxy.AuthorizationDenied(app_name) |
634 | + |
635 | + # do not use log_call decorator since we should not log credentials |
636 | + def CredentialsFound(self, app_name, credentials): |
637 | + """Signal thrown when the credentials are found.""" |
638 | + self.ref_count -= 1 |
639 | + logger.info('%s: emitting CredentialsFound with app_name "%s".', |
640 | + self.__class__.__name__, app_name) |
641 | + self.proxy.CredentialsFound(app_name, credentials) |
642 | + |
643 | + @log_call(logger.info) |
644 | + def CredentialsNotFound(self, app_name): |
645 | + """Signal thrown when the credentials are not found.""" |
646 | + self.ref_count -= 1 |
647 | + self.proxy.CredentialsNotFound(app_name) |
648 | + |
649 | + @log_call(logger.info) |
650 | + def CredentialsCleared(self, app_name): |
651 | + """Signal thrown when the credentials were cleared.""" |
652 | + self.ref_count -= 1 |
653 | + self.proxy.CredentialsCleared(app_name) |
654 | + |
655 | + @log_call(logger.info) |
656 | + def CredentialsStored(self, app_name): |
657 | + """Signal thrown when the credentials were cleared.""" |
658 | + self.ref_count -= 1 |
659 | + self.proxy.CredentialsStored(app_name) |
660 | + |
661 | + @log_call(logger.error) |
662 | + def CredentialsError(self, app_name, error): |
663 | + """Signal thrown when there is a problem getting the credentials.""" |
664 | + self.ref_count -= 1 |
665 | + if isinstance(error, dict): |
666 | + error_dict = error |
667 | + else: |
668 | + error_dict = except_to_errdict(error) |
669 | + self.proxy.CredentialsError(app_name, error_dict) |
670 | + |
671 | + def find_credentials(self, app_name, args, success_cb=None, error_cb=None): |
672 | """Look for the credentials for an application. |
673 | |
674 | - 'app_name': the name of the application which credentials are |
675 | @@ -249,21 +358,47 @@ |
676 | |
677 | - 'args' is a dictionary, currently not used. |
678 | |
679 | - - 'success_cb' is a callback that will be execute if the operation was |
680 | + - 'success_cb', if not None, will be executed if the operation was |
681 | a success. |
682 | |
683 | - - 'error_cb' is a callback that will be executed if the operation had |
684 | + - 'error_cb', if not None, will be executed if the operation had |
685 | an error. |
686 | |
687 | """ |
688 | + def _analize_creds(credentials): |
689 | + """Find credentials and notify using signals.""" |
690 | + if credentials is not None and len(credentials) > 0: |
691 | + self.CredentialsFound(app_name, credentials) |
692 | + else: |
693 | + self.CredentialsNotFound(app_name) |
694 | + |
695 | + def _tweaked_success_cb(creds): |
696 | + """Decrease ref counter and call 'success_cb'.""" |
697 | + self.ref_count -= 1 |
698 | + success_cb(creds) |
699 | + |
700 | + if success_cb is None: |
701 | + _success_cb = _analize_creds |
702 | + else: |
703 | + _success_cb = _tweaked_success_cb |
704 | + |
705 | + def _tweaked_error_cb(error, app): |
706 | + """Decrease ref counter and call 'error_cb', modifying the dict.""" |
707 | + self.ref_count -= 1 |
708 | + error_cb(except_to_errdict(error.value)) |
709 | + |
710 | + if error_cb is None: |
711 | + _error_cb = lambda f, _: self.CredentialsError(app_name, f.value) |
712 | + else: |
713 | + _error_cb = _tweaked_error_cb |
714 | + |
715 | self.ref_count += 1 |
716 | obj = Credentials(app_name) |
717 | d = obj.find_credentials() |
718 | - # pylint: disable=E1101 |
719 | - d.addCallback(success_cb) |
720 | - d.addErrback(error_cb, app_name) |
721 | + d.addCallback(_success_cb) |
722 | + d.addErrback(_error_cb, app_name) |
723 | |
724 | - def clear_credentials(self, app_name, args, success_cb, error_cb): |
725 | + def clear_credentials(self, app_name, args): |
726 | """Clear the credentials for an application. |
727 | |
728 | - 'app_name': the name of the application which credentials are |
729 | @@ -271,21 +406,14 @@ |
730 | |
731 | - 'args' is a dictionary, currently not used. |
732 | |
733 | - - 'success_cb' is a callback that will be execute if the operation was |
734 | - a success. |
735 | - |
736 | - - 'error_cb' is a callback that will be executed if the operation had |
737 | - an error. |
738 | - |
739 | """ |
740 | self.ref_count += 1 |
741 | obj = Credentials(app_name) |
742 | d = obj.clear_credentials() |
743 | - # pylint: disable=E1101 |
744 | - d.addCallback(success_cb) |
745 | - d.addErrback(error_cb, app_name) |
746 | + d.addCallback(lambda _: self.CredentialsCleared(app_name)) |
747 | + d.addErrback(lambda f: self.CredentialsError(app_name, f.value)) |
748 | |
749 | - def store_credentials(self, app_name, args, success_cb, error_cb): |
750 | + def store_credentials(self, app_name, args): |
751 | """Store the token for an application. |
752 | |
753 | - 'app_name': the name of the application which credentials are |
754 | @@ -295,18 +423,12 @@ |
755 | the following mandatory keys: 'token', 'token_key', 'consumer_key', |
756 | 'consumer_secret'. |
757 | |
758 | - - 'success_cb' is a callback that will be execute if the operation was |
759 | - a success. |
760 | - |
761 | - - 'error_cb' is a callback that will be executed if the operation had |
762 | - an error. |
763 | """ |
764 | self.ref_count += 1 |
765 | obj = Credentials(app_name) |
766 | d = obj.store_credentials(args) |
767 | - # pylint: disable=E1101 |
768 | - d.addCallback(success_cb) |
769 | - d.addErrback(error_cb, app_name) |
770 | + d.addCallback(lambda _: self.CredentialsStored(app_name)) |
771 | + d.addErrback(lambda f: self.CredentialsError(app_name, f.value)) |
772 | |
773 | def register(self, app_name, args): |
774 | """Get credentials if found else prompt GUI to register.""" |
775 | @@ -331,23 +453,47 @@ |
776 | email = args.pop('email') |
777 | password = args.pop('password') |
778 | obj = Credentials(app_name, **self._parse_args(args)) |
779 | - obj.login_email_password(email=email, password=password) |
780 | - |
781 | - |
782 | -# pylint: disable=C0103 |
783 | - |
784 | -if sys.platform == 'win32': |
785 | - from ubuntu_sso.main import windows |
786 | - source = windows |
787 | - TIMEOUT_INTERVAL = 10000000000 # forever |
788 | -else: |
789 | - from ubuntu_sso.main import linux |
790 | - source = linux |
791 | - |
792 | -CredentialsManagement = source.CredentialsManagement |
793 | -get_sso_login_backend = source.get_sso_login_backend |
794 | -main = source.main |
795 | -SSOLogin = source.SSOLogin |
796 | -thread_execute = source.blocking |
797 | + obj.login(email=email, password=password) |
798 | + |
799 | |
800 | # pylint: enable=C0103 |
801 | + |
802 | +class UbuntuSSOService(object): |
803 | + """Manager that exposes the diff referenceable objects.""" |
804 | + |
805 | + def __init__(self): |
806 | + self.proxy = UbuntuSSOProxy(self) |
807 | + self.sso_login = None |
808 | + self.cred_manager = None |
809 | + |
810 | + @defer.inlineCallbacks |
811 | + def start(self): |
812 | + """Start the service.""" |
813 | + logger.debug('Starting up Ubuntu SSO service...') |
814 | + try: |
815 | + yield self.proxy.start() |
816 | + except: |
817 | + logger.exception('Can not start Ubuntu SSO service:') |
818 | + raise |
819 | + else: |
820 | + logger.info('Ubuntu SSO service started.') |
821 | + |
822 | + self.sso_login = SSOLogin(proxy=self.proxy.sso_login) |
823 | + self.cred_manager = CredentialsManagement( |
824 | + timeout_func=source.timeout_func, |
825 | + shutdown_func=source.shutdown_func, |
826 | + proxy=self.proxy.cred_manager) |
827 | + |
828 | + def shutdown(self): |
829 | + """Shutdown the service.""" |
830 | + return self.proxy.shutdown() |
831 | + |
832 | + |
833 | +def main(): |
834 | + """Run the backend service.""" |
835 | + logger.info('Setting up Ubuntu SSO service.') |
836 | + source.start_setup() |
837 | + service = UbuntuSSOService() |
838 | + d = service.start() |
839 | + d.addBoth(source.finish_setup) |
840 | + source.main() |
841 | |
842 | === modified file 'ubuntu_sso/main/linux.py' |
843 | --- ubuntu_sso/main/linux.py 2011-12-20 17:33:13 +0000 |
844 | +++ ubuntu_sso/main/linux.py 2012-01-17 19:42:46 +0000 |
845 | @@ -13,23 +13,26 @@ |
846 | # |
847 | # You should have received a copy of the GNU General Public License along |
848 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
849 | -"""Single Sign On login handler. |
850 | - |
851 | -An utility which accepts requests for Ubuntu Single Sign On login over D-Bus. |
852 | - |
853 | -The OAuth process is handled, including adding the OAuth access token to the |
854 | -local keyring. |
855 | +"""Main module implementation specific for linux. |
856 | + |
857 | +This module should never import from the multiplatform one (main/__init__.py), |
858 | +but the other way around. Likewise, this module should *not* have any logic |
859 | +regarding error processing or decision making about when to send a given |
860 | +signal. |
861 | + |
862 | +Also, most of the logging is being made in the main module to avoid |
863 | +duplication between the different platform implementations. |
864 | |
865 | """ |
866 | |
867 | import threading |
868 | import signal |
869 | -import sys |
870 | |
871 | import dbus.mainloop.glib |
872 | import dbus.service |
873 | import gtk |
874 | |
875 | +from twisted.internet import defer |
876 | |
877 | from ubuntu_sso import ( |
878 | DBUS_ACCOUNT_PATH, |
879 | @@ -39,13 +42,7 @@ |
880 | DBUS_IFACE_USER_NAME, |
881 | NO_OP, |
882 | ) |
883 | -from ubuntu_sso.account import Account |
884 | from ubuntu_sso.logger import setup_logging |
885 | -from ubuntu_sso.main import ( |
886 | - CredentialsManagementRoot, |
887 | - SSOLoginRoot, |
888 | - except_to_errdict, |
889 | -) |
890 | |
891 | |
892 | # Disable the invalid name warning, as we have a lot of DBus style names |
893 | @@ -62,162 +59,124 @@ |
894 | try: |
895 | result_cb(app_name, f()) |
896 | except Exception, e: # pylint: disable=W0703 |
897 | - msg = "Exception while running DBus blocking code in a thread:" |
898 | + msg = "Exception while running blocking code in a thread:" |
899 | logger.exception(msg) |
900 | - error_cb(app_name, except_to_errdict(e)) |
901 | + error_cb(app_name, e) |
902 | threading.Thread(target=_in_thread).start() |
903 | |
904 | |
905 | -class SSOLogin(dbus.service.Object): |
906 | +class SSOLoginProxy(dbus.service.Object): |
907 | """Login thru the Single Sign On service.""" |
908 | |
909 | # Operator not preceded by a space (fails with dbus decorators) |
910 | # pylint: disable=C0322 |
911 | |
912 | - def __init__(self, bus_name, object_path=DBUS_ACCOUNT_PATH, |
913 | - sso_login_processor_class=Account, |
914 | - sso_service_class=None): |
915 | + def __init__(self, root, *args, **kwargs): |
916 | """Initiate the Login object.""" |
917 | - dbus.service.Object.__init__(self, object_path=object_path, |
918 | - bus_name=bus_name) |
919 | - self.root = SSOLoginRoot(sso_login_processor_class, sso_service_class) |
920 | + super(SSOLoginProxy, self).__init__(*args, **kwargs) |
921 | + self.root = root |
922 | |
923 | # generate_capcha signals |
924 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="ss") |
925 | def CaptchaGenerated(self, app_name, result): |
926 | """Signal thrown after the captcha is generated.""" |
927 | - logger.debug('SSOLogin: emitting CaptchaGenerated with app_name "%s" ' |
928 | - 'and result %r', app_name, result) |
929 | |
930 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="sa{ss}") |
931 | def CaptchaGenerationError(self, app_name, error): |
932 | """Signal thrown when there's a problem generating the captcha.""" |
933 | - logger.debug('SSOLogin: emitting CaptchaGenerationError with ' |
934 | - 'app_name "%s" and error %r', app_name, error) |
935 | |
936 | @dbus.service.method(dbus_interface=DBUS_IFACE_USER_NAME, |
937 | in_signature='ss') |
938 | def generate_captcha(self, app_name, filename): |
939 | """Call the matching method in the processor.""" |
940 | - self.root.generate_captcha(app_name, filename, |
941 | - self.CaptchaGenerated, |
942 | - self.CaptchaGenerationError) |
943 | + self.root.sso_login.generate_captcha(app_name, filename) |
944 | |
945 | # register_user signals |
946 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="ss") |
947 | def UserRegistered(self, app_name, result): |
948 | """Signal thrown when the user is registered.""" |
949 | - logger.debug('SSOLogin: emitting UserRegistered with app_name "%s" ' |
950 | - 'and result %r', app_name, result) |
951 | |
952 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="sa{ss}") |
953 | def UserRegistrationError(self, app_name, error): |
954 | """Signal thrown when there's a problem registering the user.""" |
955 | - logger.debug('SSOLogin: emitting UserRegistrationError with ' |
956 | - 'app_name "%s" and error %r', app_name, error) |
957 | |
958 | @dbus.service.method(dbus_interface=DBUS_IFACE_USER_NAME, |
959 | in_signature='ssssss') |
960 | def register_user(self, app_name, email, password, name, |
961 | captcha_id, captcha_solution): |
962 | """Call the matching method in the processor.""" |
963 | - self.root.register_user(app_name, email, password, name, captcha_id, |
964 | - captcha_solution, |
965 | - self.UserRegistered, |
966 | - self.UserRegistrationError) |
967 | + self.root.sso_login.register_user(app_name, email, password, name, |
968 | + captcha_id, captcha_solution) |
969 | |
970 | # login signals |
971 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="ss") |
972 | def LoggedIn(self, app_name, result): |
973 | """Signal thrown when the user is logged in.""" |
974 | - logger.debug('SSOLogin: emitting LoggedIn with app_name "%s" ' |
975 | - 'and result %r', app_name, result) |
976 | |
977 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="sa{ss}") |
978 | def LoginError(self, app_name, error): |
979 | """Signal thrown when there is a problem in the login.""" |
980 | - logger.debug('SSOLogin: emitting LoginError with ' |
981 | - 'app_name "%s" and error %r', app_name, error) |
982 | |
983 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="ss") |
984 | def UserNotValidated(self, app_name, result): |
985 | """Signal thrown when the user is not validated.""" |
986 | - logger.debug('SSOLogin: emitting UserNotValidated with app_name "%s" ' |
987 | - 'and result %r', app_name, result) |
988 | |
989 | @dbus.service.method(dbus_interface=DBUS_IFACE_USER_NAME, |
990 | in_signature='sss') |
991 | def login(self, app_name, email, password): |
992 | """Call the matching method in the processor.""" |
993 | - self.root.login(app_name, email, password, self.LoggedIn, |
994 | - self.LoginError, self.UserNotValidated) |
995 | + self.root.sso_login.login(app_name, email, password) |
996 | |
997 | # validate_email signals |
998 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="ss") |
999 | def EmailValidated(self, app_name, result): |
1000 | """Signal thrown after the email is validated.""" |
1001 | - logger.debug('SSOLogin: emitting EmailValidated with app_name "%s" ' |
1002 | - 'and result %r', app_name, result) |
1003 | |
1004 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="sa{ss}") |
1005 | def EmailValidationError(self, app_name, error): |
1006 | """Signal thrown when there's a problem validating the email.""" |
1007 | - logger.debug('SSOLogin: emitting EmailValidationError with ' |
1008 | - 'app_name "%s" and error %r', app_name, error) |
1009 | |
1010 | @dbus.service.method(dbus_interface=DBUS_IFACE_USER_NAME, |
1011 | in_signature='ssss') |
1012 | def validate_email(self, app_name, email, password, email_token): |
1013 | """Call the matching method in the processor.""" |
1014 | - self.root.validate_email(app_name, email, password, email_token, |
1015 | - self.EmailValidated, |
1016 | - self.EmailValidationError) |
1017 | + self.root.sso_login.validate_email(app_name, |
1018 | + email, password, email_token) |
1019 | |
1020 | # request_password_reset_token signals |
1021 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="ss") |
1022 | def PasswordResetTokenSent(self, app_name, result): |
1023 | """Signal thrown when the token is succesfully sent.""" |
1024 | - logger.debug('SSOLogin: emitting PasswordResetTokenSent with app_name ' |
1025 | - '"%s" and result %r', app_name, result) |
1026 | |
1027 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="sa{ss}") |
1028 | def PasswordResetError(self, app_name, error): |
1029 | """Signal thrown when there's a problem sending the token.""" |
1030 | - logger.debug('SSOLogin: emitting PasswordResetError with ' |
1031 | - 'app_name "%s" and error %r', app_name, error) |
1032 | |
1033 | @dbus.service.method(dbus_interface=DBUS_IFACE_USER_NAME, |
1034 | in_signature='ss') |
1035 | def request_password_reset_token(self, app_name, email): |
1036 | """Call the matching method in the processor.""" |
1037 | - self.root.request_password_reset_token(app_name, email, |
1038 | - self.PasswordResetTokenSent, |
1039 | - self.PasswordResetError) |
1040 | + self.root.sso_login.request_password_reset_token(app_name, email) |
1041 | |
1042 | # set_new_password signals |
1043 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="ss") |
1044 | def PasswordChanged(self, app_name, result): |
1045 | """Signal thrown when the token is succesfully sent.""" |
1046 | - logger.debug('SSOLogin: emitting PasswordChanged with app_name "%s" ' |
1047 | - 'and result %r', app_name, result) |
1048 | |
1049 | @dbus.service.signal(DBUS_IFACE_USER_NAME, signature="sa{ss}") |
1050 | def PasswordChangeError(self, app_name, error): |
1051 | """Signal thrown when there's a problem sending the token.""" |
1052 | - logger.debug('SSOLogin: emitting PasswordChangeError with ' |
1053 | - 'app_name "%s" and error %r', app_name, error) |
1054 | |
1055 | @dbus.service.method(dbus_interface=DBUS_IFACE_USER_NAME, |
1056 | in_signature='ssss') |
1057 | def set_new_password(self, app_name, email, token, new_password): |
1058 | """Call the matching method in the processor.""" |
1059 | - self.root.set_new_password(app_name, email, token, new_password, |
1060 | - self.PasswordChanged, |
1061 | - self.PasswordChangeError) |
1062 | - |
1063 | - |
1064 | -class CredentialsManagement(dbus.service.Object): |
1065 | - """DBus object that manages credentials. |
1066 | + self.root.sso_login.set_new_password(app_name, |
1067 | + email, token, new_password) |
1068 | + |
1069 | + |
1070 | +class CredentialsManagementProxy(dbus.service.Object): |
1071 | + """Object that manages credentials. |
1072 | |
1073 | Every exposed method in this class requires one mandatory argument: |
1074 | |
1075 | @@ -242,67 +201,36 @@ |
1076 | |
1077 | """ |
1078 | |
1079 | - def __init__(self, timeout_func, shutdown_func, *args, **kwargs): |
1080 | - super(CredentialsManagement, self).__init__(*args, **kwargs) |
1081 | - self.root = CredentialsManagementRoot(timeout_func, shutdown_func, |
1082 | - self.CredentialsFound, |
1083 | - self.CredentialsError, |
1084 | - self.AuthorizationDenied) |
1085 | + def __init__(self, root, *args, **kwargs): |
1086 | + super(CredentialsManagementProxy, self).__init__(*args, **kwargs) |
1087 | + self.root = root |
1088 | |
1089 | # Operator not preceded by a space (fails with dbus decorators) |
1090 | # pylint: disable=C0322 |
1091 | |
1092 | - def _process_failure(self, failure, app_name): |
1093 | - """Process the 'failure' and emit CredentialsError.""" |
1094 | - self.CredentialsError(app_name, except_to_errdict(failure.value)) |
1095 | - |
1096 | - def shutdown(self): |
1097 | - """If no ongoing requests, call self.shutdown_func.""" |
1098 | - logger.debug('shutdown!, ref_count is %r.', self.root.ref_count) |
1099 | - self.root.shutdown() |
1100 | - |
1101 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') |
1102 | def AuthorizationDenied(self, app_name): |
1103 | """Signal thrown when the user denies the authorization.""" |
1104 | - self.root.ref_count -= 1 |
1105 | - logger.info('%s: emitting AuthorizationDenied with app_name "%s".', |
1106 | - self.__class__.__name__, app_name) |
1107 | |
1108 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='sa{ss}') |
1109 | def CredentialsFound(self, app_name, credentials): |
1110 | """Signal thrown when the credentials are found.""" |
1111 | - self.root.ref_count -= 1 |
1112 | - logger.info('%s: emitting CredentialsFound with app_name "%s".', |
1113 | - self.__class__.__name__, app_name) |
1114 | |
1115 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') |
1116 | def CredentialsNotFound(self, app_name): |
1117 | """Signal thrown when the credentials are not found.""" |
1118 | - self.root.ref_count -= 1 |
1119 | - logger.info('%s: emitting CredentialsNotFound with app_name "%s".', |
1120 | - self.__class__.__name__, app_name) |
1121 | |
1122 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') |
1123 | def CredentialsCleared(self, app_name): |
1124 | """Signal thrown when the credentials were cleared.""" |
1125 | - self.root.ref_count -= 1 |
1126 | - logger.info('%s: emitting CredentialsCleared with app_name "%s".', |
1127 | - self.__class__.__name__, app_name) |
1128 | |
1129 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') |
1130 | def CredentialsStored(self, app_name): |
1131 | """Signal thrown when the credentials were cleared.""" |
1132 | - self.root.ref_count -= 1 |
1133 | - logger.info('%s: emitting CredentialsStored with app_name "%s".', |
1134 | - self.__class__.__name__, app_name) |
1135 | |
1136 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='sa{ss}') |
1137 | def CredentialsError(self, app_name, error_dict): |
1138 | """Signal thrown when there is a problem getting the credentials.""" |
1139 | - self.root.ref_count -= 1 |
1140 | - logger.error('%s: emitting CredentialsError with app_name "%s" and ' |
1141 | - 'error_dict %r.', self.__class__.__name__, app_name, |
1142 | - error_dict) |
1143 | |
1144 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, |
1145 | in_signature='sa{ss}', out_signature='') |
1146 | @@ -315,16 +243,7 @@ |
1147 | - 'args' is a dictionary, currently not used. |
1148 | |
1149 | """ |
1150 | - |
1151 | - def success_cb(credentials): |
1152 | - """Find credentials and notify using signals.""" |
1153 | - if credentials is not None and len(credentials) > 0: |
1154 | - self.CredentialsFound(app_name, credentials) |
1155 | - else: |
1156 | - self.CredentialsNotFound(app_name) |
1157 | - |
1158 | - self.root.find_credentials(app_name, args, success_cb, |
1159 | - self._process_failure) |
1160 | + self.root.cred_manager.find_credentials(app_name, args) |
1161 | |
1162 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, |
1163 | in_signature="sa{ss}", out_signature="a{ss}", |
1164 | @@ -337,20 +256,13 @@ |
1165 | |
1166 | """ |
1167 | |
1168 | - def decrease_counter_success(credentials): |
1169 | - """Call 'reply_handler' and decrease the root ref counter.""" |
1170 | - reply_handler(credentials) |
1171 | - self.root.ref_count -= 1 |
1172 | - |
1173 | - def decrease_counter_error(failure, app_name): |
1174 | - """Call 'error_handler' and decrease the root ref counter.""" |
1175 | - error_dict = except_to_errdict(failure.value) |
1176 | - error_handler(dbus.service.DBusException(error_dict)) |
1177 | - self.root.ref_count -= 1 |
1178 | - |
1179 | - self.root.find_credentials(app_name, args, |
1180 | - success_cb=decrease_counter_success, |
1181 | - error_cb=decrease_counter_error) |
1182 | + def _drop_dict(error_dict): |
1183 | + """Call 'error_handler' properly.""" |
1184 | + error_handler(dbus.service.DBusException(error_dict['errtype'])) |
1185 | + |
1186 | + self.root.cred_manager.find_credentials(app_name, args, |
1187 | + success_cb=reply_handler, |
1188 | + error_cb=_drop_dict) |
1189 | |
1190 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, |
1191 | in_signature='sa{ss}', out_signature='') |
1192 | @@ -363,9 +275,7 @@ |
1193 | - 'args' is a dictionary, currently not used. |
1194 | |
1195 | """ |
1196 | - self.root.clear_credentials(app_name, args, |
1197 | - lambda _: self.CredentialsCleared(app_name), |
1198 | - self._process_failure) |
1199 | + self.root.cred_manager.clear_credentials(app_name, args) |
1200 | |
1201 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, |
1202 | in_signature='sa{ss}', out_signature='') |
1203 | @@ -380,21 +290,19 @@ |
1204 | 'consumer_secret'. |
1205 | |
1206 | """ |
1207 | - self.root.store_credentials(app_name, args, |
1208 | - lambda _: self.CredentialsStored(app_name), |
1209 | - self._process_failure) |
1210 | + self.root.cred_manager.store_credentials(app_name, args) |
1211 | |
1212 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, |
1213 | in_signature='sa{ss}', out_signature='') |
1214 | def register(self, app_name, args): |
1215 | """Get credentials if found else prompt GUI to register.""" |
1216 | - self.root.register(app_name, args) |
1217 | + self.root.cred_manager.register(app_name, args) |
1218 | |
1219 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, |
1220 | in_signature='sa{ss}', out_signature='') |
1221 | def login(self, app_name, args): |
1222 | """Get credentials if found else prompt GUI to login.""" |
1223 | - self.root.login(app_name, args) |
1224 | + self.root.cred_manager.login(app_name, args) |
1225 | |
1226 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, |
1227 | in_signature='sa{ss}', out_signature='') |
1228 | @@ -406,12 +314,121 @@ |
1229 | returned trough the CredentialsFound signal. |
1230 | |
1231 | """ |
1232 | - self.root.login_email_password(app_name, args) |
1233 | - |
1234 | - |
1235 | -def get_sso_login_backend(): |
1236 | - """Get the backend for the Login service.""" |
1237 | - raise NotImplementedError() |
1238 | + self.root.cred_manager.login_email_password(app_name, args) |
1239 | + |
1240 | + |
1241 | +class UbuntuSSOProxy(object): |
1242 | + """Object that exposes the diff referenceable objects.""" |
1243 | + |
1244 | + def __init__(self, root): |
1245 | + self.root = root |
1246 | + self.bus = dbus.SessionBus() |
1247 | + self.sso_login = None |
1248 | + self.cred_manager = None |
1249 | + |
1250 | + def start(self): |
1251 | + """Start listening, nothing async to be done in this platform.""" |
1252 | + # Register DBus service for making sure we run only one instance |
1253 | + name = self.bus.request_name(DBUS_BUS_NAME, |
1254 | + dbus.bus.NAME_FLAG_DO_NOT_QUEUE) |
1255 | + if name == dbus.bus.REQUEST_NAME_REPLY_EXISTS: |
1256 | + raise AlreadyStartedError() |
1257 | + |
1258 | + bus_name = dbus.service.BusName(DBUS_BUS_NAME, bus=self.bus) |
1259 | + self.sso_login = SSOLoginProxy(self.root, |
1260 | + bus_name=bus_name, |
1261 | + object_path=DBUS_ACCOUNT_PATH) |
1262 | + self.cred_manager = CredentialsManagementProxy(self.root, |
1263 | + bus_name=bus_name, |
1264 | + object_path=DBUS_CREDENTIALS_PATH) |
1265 | + |
1266 | + return defer.succeed(None) |
1267 | + |
1268 | + def shutdown(self): |
1269 | + """Shutdown the service.""" |
1270 | + self.sso_login.remove_from_connection() |
1271 | + self.cred_manager.remove_from_connection() |
1272 | + self.bus.release_name(DBUS_BUS_NAME) |
1273 | + return defer.succeed(None) |
1274 | + |
1275 | + |
1276 | +# ============================== client classes ============================== |
1277 | + |
1278 | + |
1279 | +class RemoteClient(object): |
1280 | + """Client that can perform calls to remote DBus object.""" |
1281 | + |
1282 | + bus_name = None |
1283 | + path = None |
1284 | + interface = None |
1285 | + |
1286 | + def __init__(self): |
1287 | + self.bus = dbus.SessionBus() |
1288 | + obj = self.bus.get_object(bus_name=self.bus_name, |
1289 | + object_path=self.path, |
1290 | + follow_name_owner_changes=True) |
1291 | + self.dbus_iface = dbus.Interface(obj, dbus_interface=self.interface) |
1292 | + self.dbus_iface.call_method = self.call_method |
1293 | + self.dbus_iface.disconnect_from_signal = lambda _, sig: sig.remove() |
1294 | + |
1295 | + def call_method(self, method_name, *args, **kwargs): |
1296 | + """Call asynchronously 'method_name(*args)'. |
1297 | + |
1298 | + Return a deferred that will be fired when the call finishes. |
1299 | + |
1300 | + """ |
1301 | + d = defer.Deferred() |
1302 | + |
1303 | + reply_handler = kwargs.get('reply_handler', None) |
1304 | + if reply_handler is not None: |
1305 | + d.addCallback(lambda a: reply_handler(*a)) |
1306 | + |
1307 | + error_handler = kwargs.get('error_handler', None) |
1308 | + if error_handler is not None: |
1309 | + d.addErrback(lambda f: error_handler(f.value)) |
1310 | + |
1311 | + self.bus.call_async( |
1312 | + bus_name=self.bus_name, object_path=self.path, |
1313 | + dbus_interface=self.interface, method=method_name, |
1314 | + signature=None, args=args, |
1315 | + reply_handler=lambda *a: d.callback(a), |
1316 | + error_handler=d.errback) |
1317 | + |
1318 | + return d |
1319 | + |
1320 | + |
1321 | +class SSOLoginClient(RemoteClient): |
1322 | + """Access the UserManagement DBus interface.""" |
1323 | + |
1324 | + bus_name = DBUS_BUS_NAME |
1325 | + path = DBUS_ACCOUNT_PATH |
1326 | + interface = DBUS_IFACE_USER_NAME |
1327 | + |
1328 | + |
1329 | +class CredentialsManagementClient(RemoteClient): |
1330 | + """Access the CredentialsManagement DBus interface.""" |
1331 | + |
1332 | + bus_name = DBUS_BUS_NAME |
1333 | + path = DBUS_CREDENTIALS_PATH |
1334 | + interface = DBUS_CREDENTIALS_IFACE |
1335 | + |
1336 | + |
1337 | +class UbuntuSSOClient(object): |
1338 | + """Base client that provides remote access to the sso API.""" |
1339 | + |
1340 | + def __init__(self): |
1341 | + self.sso_login = SSOLoginClient().dbus_iface |
1342 | + self.cred_manager = CredentialsManagementClient().dbus_iface |
1343 | + |
1344 | + def disconnect(self): |
1345 | + """No need to disconnect DBus proxy objects.""" |
1346 | + return defer.succeed(None) |
1347 | + |
1348 | + |
1349 | +def get_sso_client(): |
1350 | + """Get a client to access the SSO service.""" |
1351 | + result = UbuntuSSOClient() |
1352 | + return defer.succeed(result) |
1353 | |
1354 | |
1355 | def sighup_handler(*a, **kw): |
1356 | @@ -422,32 +439,32 @@ |
1357 | # |
1358 | # gtk.main_quit and the logger methods are safe to be called from any |
1359 | # thread. Just don't call other random stuff here. |
1360 | - logger.info("Stoping Ubuntu SSO login manager since SIGHUP was received.") |
1361 | + logger.info("Stoping Ubuntu SSO service since SIGHUP was received.") |
1362 | gtk.main_quit() |
1363 | |
1364 | |
1365 | -def main(): |
1366 | - """Run the backend service.""" |
1367 | +class AlreadyStartedError(Exception): |
1368 | + """The backend service has already been started.""" |
1369 | + |
1370 | + |
1371 | +timeout_func = gtk.timeout_add |
1372 | +shutdown_func = gtk.main_quit |
1373 | + |
1374 | + |
1375 | +def start_setup(): |
1376 | + """Setup the env to run the service.""" |
1377 | dbus.mainloop.glib.threads_init() |
1378 | gtk.gdk.threads_init() |
1379 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) |
1380 | |
1381 | - bus = dbus.SessionBus() |
1382 | - # Register DBus service for making sure we run only one instance |
1383 | - name = bus.request_name(DBUS_BUS_NAME, |
1384 | - dbus.bus.NAME_FLAG_DO_NOT_QUEUE) |
1385 | - if name == dbus.bus.REQUEST_NAME_REPLY_EXISTS: |
1386 | - logger.error("Ubuntu SSO login manager already running, quitting.") |
1387 | - sys.exit(0) |
1388 | - |
1389 | - logger.debug("Hooking up SIGHUP with handler %r.", sighup_handler) |
1390 | - signal.signal(signal.SIGHUP, sighup_handler) |
1391 | - |
1392 | - logger.info("Starting Ubuntu SSO login manager for bus %r.", DBUS_BUS_NAME) |
1393 | - bus_name = dbus.service.BusName(DBUS_BUS_NAME, bus=dbus.SessionBus()) |
1394 | - SSOLogin(bus_name, object_path=DBUS_ACCOUNT_PATH) |
1395 | - CredentialsManagement(timeout_func=gtk.timeout_add, |
1396 | - shutdown_func=gtk.main_quit, |
1397 | - bus_name=bus_name, object_path=DBUS_CREDENTIALS_PATH) |
1398 | - |
1399 | - gtk.main() |
1400 | + |
1401 | +def finish_setup(result): |
1402 | + """Run the specific mainloop only if no failure ocurred.""" |
1403 | + if result is None: # no failure ocurred, start the service |
1404 | + logger.debug("Hooking up SIGHUP with handler %r.", sighup_handler) |
1405 | + signal.signal(signal.SIGHUP, sighup_handler) |
1406 | + gtk.main() |
1407 | + |
1408 | + |
1409 | +def main(): |
1410 | + """Run the specific mainloop.""" |
1411 | |
1412 | === modified file 'ubuntu_sso/main/tests/__init__.py' |
1413 | --- ubuntu_sso/main/tests/__init__.py 2011-03-22 23:29:20 +0000 |
1414 | +++ ubuntu_sso/main/tests/__init__.py 2012-01-17 19:42:46 +0000 |
1415 | @@ -15,3 +15,40 @@ |
1416 | # You should have received a copy of the GNU General Public License along |
1417 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
1418 | """Test the different main implementations.""" |
1419 | + |
1420 | +import sys |
1421 | + |
1422 | +from twisted.internet import defer |
1423 | + |
1424 | +from ubuntu_sso.tests import TOKEN |
1425 | + |
1426 | +# Invalid name "BaseTestCase" |
1427 | +# pylint: disable=C0103 |
1428 | + |
1429 | +if sys.platform == 'win32': |
1430 | + from ubuntu_sso.utils.tests.test_ipc import BaseIPCTestCase |
1431 | + BaseTestCase = BaseIPCTestCase |
1432 | +else: |
1433 | + from ubuntuone.devtools.testcases.dbus import DBusTestCase |
1434 | + BaseTestCase = DBusTestCase |
1435 | + |
1436 | +# pylint: enable=C0103 |
1437 | + |
1438 | + |
1439 | +class FakedCredentials(object): |
1440 | + """A very dummy Credentials object.""" |
1441 | + |
1442 | + def __init__(self, *a, **kw): |
1443 | + self.login = self.register = lambda *a, **kw: None |
1444 | + |
1445 | + def find_credentials(self, *a, **kw): |
1446 | + """Retrieve credentials.""" |
1447 | + return defer.succeed(TOKEN) |
1448 | + |
1449 | + def clear_credentials(self, *a, **kw): |
1450 | + """Clear credentials.""" |
1451 | + return defer.succeed(None) |
1452 | + |
1453 | + def store_credentials(self, *a, **kw): |
1454 | + """Store credentials.""" |
1455 | + return defer.succeed(None) |
1456 | |
1457 | === added file 'ubuntu_sso/main/tests/test_clients.py' |
1458 | --- ubuntu_sso/main/tests/test_clients.py 1970-01-01 00:00:00 +0000 |
1459 | +++ ubuntu_sso/main/tests/test_clients.py 2012-01-17 19:42:46 +0000 |
1460 | @@ -0,0 +1,373 @@ |
1461 | +# -*- coding: utf-8 -*- |
1462 | +# |
1463 | +# Copyright 2012 Canonical Ltd. |
1464 | +# |
1465 | +# This program is free software: you can redistribute it and/or modify it |
1466 | +# under the terms of the GNU General Public License version 3, as published |
1467 | +# by the Free Software Foundation. |
1468 | +# |
1469 | +# This program is distributed in the hope that it will be useful, but |
1470 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1471 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1472 | +# PURPOSE. See the GNU General Public License for more details. |
1473 | +# |
1474 | +# You should have received a copy of the GNU General Public License along |
1475 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1476 | +"""Tests for the main SSO client code.""" |
1477 | + |
1478 | +from twisted.internet import defer |
1479 | +from ubuntuone.devtools.testcases import skipIfOS |
1480 | + |
1481 | +from ubuntu_sso import main |
1482 | +from ubuntu_sso.tests import ( |
1483 | + APP_NAME, |
1484 | + CAPTCHA_ID, |
1485 | + CAPTCHA_SOLUTION, |
1486 | + EMAIL, |
1487 | + EMAIL_TOKEN, |
1488 | + NAME, |
1489 | + PASSWORD, |
1490 | + TOKEN, |
1491 | +) |
1492 | +from ubuntu_sso.main.tests import BaseTestCase, FakedCredentials |
1493 | + |
1494 | +FILENAME = 'sample filename' |
1495 | + |
1496 | + |
1497 | +class FakedKeyring(object): |
1498 | + """A faked Keyring object.""" |
1499 | + |
1500 | + _keys = {} |
1501 | + |
1502 | + def get_credentials(self, app_name): |
1503 | + """Return the credentials for app_name.""" |
1504 | + return defer.succeed(self._keys.get(app_name, {})) |
1505 | + |
1506 | + def delete_credentials(self, app_name): |
1507 | + """Delete the credentials for app_name.""" |
1508 | + self._keys.pop(app_name, None) |
1509 | + return defer.succeed(None) |
1510 | + |
1511 | + def set_credentials(self, app_name, token): |
1512 | + """Store the credentials for app_name.""" |
1513 | + self._keys[app_name] = token |
1514 | + return defer.succeed(None) |
1515 | + |
1516 | + |
1517 | +class AbstractTestCase(BaseTestCase): |
1518 | + """The base test case with platform specific support.""" |
1519 | + |
1520 | + timeout = 2 |
1521 | + method = None |
1522 | + backend_method = method |
1523 | + params = () |
1524 | + success_signal = None |
1525 | + backend_result = None |
1526 | + success_result = None |
1527 | + error_signal = None |
1528 | + |
1529 | + @defer.inlineCallbacks |
1530 | + def setUp(self): |
1531 | + yield super(AbstractTestCase, self).setUp() |
1532 | + self.keyring = FakedKeyring() |
1533 | + self.patch(main, 'Keyring', lambda: self.keyring) |
1534 | + |
1535 | + # avoid putting stuff in the mainloops |
1536 | + self.patch(main.source, 'timeout_func', lambda *a: None) |
1537 | + self.patch(main.source, 'shutdown_func', lambda *a: None) |
1538 | + |
1539 | + self.sso_service = main.UbuntuSSOService() |
1540 | + yield self.sso_service.start() |
1541 | + self.addCleanup(self.sso_service.shutdown) |
1542 | + |
1543 | + self.sso_client = yield main.get_sso_client() |
1544 | + self.addCleanup(self.sso_client.disconnect) |
1545 | + |
1546 | + self.client = self.patchable_backend = None |
1547 | + |
1548 | + if self.backend_method is None: |
1549 | + self.backend_method = self.method |
1550 | + |
1551 | + def _backend_succeed(self, *args, **kwargs): |
1552 | + """Make self.patchable_backend return self.backend_result.""" |
1553 | + return self.backend_result |
1554 | + |
1555 | + def _backend_fail(self, *args, **kwargs): |
1556 | + """Make self.patchable_backend raise an exception.""" |
1557 | + raise ValueError((args, kwargs)) |
1558 | + |
1559 | + @defer.inlineCallbacks |
1560 | + def assert_method_correct(self, success_signal, error_signal, |
1561 | + patched_backend_method, expected_result=None): |
1562 | + """Calling 'self.method' works ok. |
1563 | + |
1564 | + Check that 'success_signal' is emitted, and make the test fail if |
1565 | + error_signal is received. |
1566 | + |
1567 | + The self.patchable_backend will be patched with |
1568 | + 'patched_backend_method'. |
1569 | + |
1570 | + """ |
1571 | + if self.method is None: |
1572 | + defer.returnValue(None) |
1573 | + |
1574 | + d = defer.Deferred() |
1575 | + |
1576 | + cb = lambda *a: d.callback(a) |
1577 | + match = self.client.connect_to_signal(success_signal, cb) |
1578 | + self.addCleanup(self.client.disconnect_from_signal, |
1579 | + success_signal, match) |
1580 | + |
1581 | + eb = lambda *a: d.errback(AssertionError(a)) |
1582 | + match = self.client.connect_to_signal(error_signal, eb) |
1583 | + self.addCleanup(self.client.disconnect_from_signal, |
1584 | + error_signal, match) |
1585 | + |
1586 | + self.patch(self.patchable_backend, self.backend_method, |
1587 | + patched_backend_method) |
1588 | + |
1589 | + yield self.client.call_method(self.method, *self.params) |
1590 | + |
1591 | + result = yield d |
1592 | + self.assertEqual(expected_result, result) |
1593 | + |
1594 | + def test_success(self): |
1595 | + """Test that the 'method' works ok.""" |
1596 | + success_signal = self.success_signal |
1597 | + error_signal = self.error_signal |
1598 | + patched_backend_method = self._backend_succeed |
1599 | + expected_result = self.success_result |
1600 | + |
1601 | + return self.assert_method_correct(success_signal, error_signal, |
1602 | + patched_backend_method, expected_result) |
1603 | + |
1604 | + def test_error(self): |
1605 | + """Test that the 'method' fails as expected.""" |
1606 | + success_signal = self.error_signal |
1607 | + error_signal = self.success_signal |
1608 | + patched_backend_method = self._backend_fail |
1609 | + expected_result = (APP_NAME, dict(errtype='ValueError')) |
1610 | + |
1611 | + return self.assert_method_correct(success_signal, error_signal, |
1612 | + patched_backend_method, expected_result) |
1613 | + |
1614 | + |
1615 | +class SSOLoginProxyTestCase(AbstractTestCase): |
1616 | + """Test the SSOLoginProxy interface.""" |
1617 | + |
1618 | + @defer.inlineCallbacks |
1619 | + def setUp(self): |
1620 | + yield super(SSOLoginProxyTestCase, self).setUp() |
1621 | + self.client = self.sso_client.sso_login |
1622 | + self.patchable_backend = self.sso_service.sso_login.processor |
1623 | + |
1624 | + |
1625 | +class GenerateCaptchaTestCase(SSOLoginProxyTestCase): |
1626 | + """Test the generate_captcha method.""" |
1627 | + |
1628 | + method = 'generate_captcha' |
1629 | + params = (APP_NAME, FILENAME) |
1630 | + success_signal = 'CaptchaGenerated' |
1631 | + error_signal = 'CaptchaGenerationError' |
1632 | + backend_result = 'a captcha id' |
1633 | + success_result = (APP_NAME, backend_result) |
1634 | + |
1635 | + |
1636 | +class RegisterUserTestCase(SSOLoginProxyTestCase): |
1637 | + """Test the register_user method.""" |
1638 | + |
1639 | + method = 'register_user' |
1640 | + params = (APP_NAME, EMAIL, PASSWORD, NAME, CAPTCHA_ID, CAPTCHA_SOLUTION) |
1641 | + success_signal = 'UserRegistered' |
1642 | + error_signal = 'UserRegistrationError' |
1643 | + backend_result = EMAIL |
1644 | + success_result = (APP_NAME, backend_result) |
1645 | + |
1646 | + |
1647 | +class LoginTestCase(SSOLoginProxyTestCase): |
1648 | + """Test the login method.""" |
1649 | + |
1650 | + method = 'login' |
1651 | + params = (APP_NAME, EMAIL, PASSWORD) |
1652 | + success_signal = 'LoggedIn' |
1653 | + error_signal = 'LoginError' |
1654 | + backend_result = TOKEN |
1655 | + success_result = (APP_NAME, EMAIL) |
1656 | + |
1657 | + @defer.inlineCallbacks |
1658 | + def test_success(self): |
1659 | + """Test that the 'method' works ok when the user is validated.""" |
1660 | + self.patch(self.patchable_backend, 'is_validated', lambda _: True) |
1661 | + |
1662 | + yield super(LoginTestCase, self).test_success() |
1663 | + |
1664 | + expected_credentials = yield self.keyring.get_credentials(APP_NAME) |
1665 | + self.assertEqual(expected_credentials, TOKEN) |
1666 | + |
1667 | + def test_not_validated(self): |
1668 | + """Test that the 'method' works ok when the user is not validated.""" |
1669 | + self.patch(self.patchable_backend, 'is_validated', lambda _: False) |
1670 | + self.patch(self, 'success_signal', 'UserNotValidated') |
1671 | + |
1672 | + return super(LoginTestCase, self).test_success() |
1673 | + |
1674 | + def test_error_when_setting_credentials(self): |
1675 | + """The 'error_signal' is emitted when credentials can't be set.""" |
1676 | + self.patch(self.patchable_backend, 'is_validated', lambda _: True) |
1677 | + exc = TypeError('foo') |
1678 | + self.patch(self.keyring, 'set_credentials', lambda *a: defer.fail(exc)) |
1679 | + patched_backend_method = lambda *a, **kw: self.backend_result |
1680 | + expected_result = (APP_NAME, dict(errtype='TypeError', message='foo')) |
1681 | + |
1682 | + return self.assert_method_correct('LoginError', 'LoggedIn', |
1683 | + patched_backend_method, expected_result) |
1684 | + |
1685 | + |
1686 | +class ValidateEmailTestCase(SSOLoginProxyTestCase): |
1687 | + """Test the validate_email method.""" |
1688 | + |
1689 | + method = 'validate_email' |
1690 | + params = (APP_NAME, EMAIL, PASSWORD, EMAIL_TOKEN) |
1691 | + success_signal = 'EmailValidated' |
1692 | + error_signal = 'EmailValidationError' |
1693 | + backend_result = TOKEN |
1694 | + success_result = (APP_NAME, EMAIL) |
1695 | + |
1696 | + |
1697 | +class RequestPasswordResetTokenTestCase(SSOLoginProxyTestCase): |
1698 | + """Test the request_password_reset_token method.""" |
1699 | + |
1700 | + method = 'request_password_reset_token' |
1701 | + params = (APP_NAME, EMAIL) |
1702 | + success_signal = 'PasswordResetTokenSent' |
1703 | + error_signal = 'PasswordResetError' |
1704 | + backend_result = EMAIL |
1705 | + success_result = (APP_NAME, backend_result) |
1706 | + |
1707 | + |
1708 | +class SetNewPasswordTestCase(SSOLoginProxyTestCase): |
1709 | + """Test the set_new_password method.""" |
1710 | + |
1711 | + method = 'set_new_password' |
1712 | + params = (APP_NAME, EMAIL, EMAIL_TOKEN, PASSWORD) |
1713 | + success_signal = 'PasswordChanged' |
1714 | + error_signal = 'PasswordChangeError' |
1715 | + backend_result = EMAIL |
1716 | + success_result = (APP_NAME, backend_result) |
1717 | + |
1718 | + |
1719 | +class CredentialsManagementProxyTestCase(AbstractTestCase): |
1720 | + """Tests for the CredentialsManagementProxy DBus interface.""" |
1721 | + |
1722 | + error_signal = 'CredentialsError' |
1723 | + args = dict(foo='bar', fuh='baz') |
1724 | + params = (APP_NAME, args) |
1725 | + |
1726 | + @defer.inlineCallbacks |
1727 | + def setUp(self): |
1728 | + yield super(CredentialsManagementProxyTestCase, self).setUp() |
1729 | + self.credentials = FakedCredentials() |
1730 | + self.patch(main, 'Credentials', lambda *a, **kw: self.credentials) |
1731 | + |
1732 | + self.client = self.sso_client.cred_manager |
1733 | + self.patchable_backend = self.credentials |
1734 | + |
1735 | + def _backend_succeed(self, *args, **kwargs): |
1736 | + """Make self.patchable_backend return self.backend_result.""" |
1737 | + return defer.succeed(self.backend_result) |
1738 | + |
1739 | + def _backend_fail(self, *args, **kwargs): |
1740 | + """Make self.patchable_backend return a failed deferred.""" |
1741 | + return defer.fail(ValueError((args, kwargs))) |
1742 | + |
1743 | + |
1744 | +class FindCredentialsTestCase(CredentialsManagementProxyTestCase): |
1745 | + """Test the find_credentials method.""" |
1746 | + |
1747 | + method = 'find_credentials' |
1748 | + success_signal = 'CredentialsFound' |
1749 | + backend_result = TOKEN |
1750 | + success_result = (APP_NAME, backend_result) |
1751 | + |
1752 | + @skipIfOS('win32', 'find_credentials_sync is only provided in Linux ' |
1753 | + 'due to compatibility issues with old clients.') |
1754 | + @defer.inlineCallbacks |
1755 | + def test_find_credentials_sync(self): |
1756 | + """The credentials are asked and returned in a sync call.""" |
1757 | + d = defer.Deferred() |
1758 | + |
1759 | + self.client.call_method('find_credentials_sync', |
1760 | + APP_NAME, self.args, |
1761 | + reply_handler=d.callback, |
1762 | + error_handler=d.errback) |
1763 | + creds = yield d |
1764 | + self.assertEqual(creds, TOKEN) |
1765 | + |
1766 | + @skipIfOS('win32', 'find_credentials_sync is only provided in Linux ' |
1767 | + 'due to compatibility issues with old clients.') |
1768 | + @defer.inlineCallbacks |
1769 | + def test_find_credentials_sync_error(self): |
1770 | + """If find_credentials_sync fails, error_handler is called.""" |
1771 | + self.patch(self.credentials, 'find_credentials', self._backend_fail) |
1772 | + d = defer.Deferred() |
1773 | + |
1774 | + self.client.call_method('find_credentials_sync', |
1775 | + APP_NAME, self.args, |
1776 | + reply_handler=d.errback, |
1777 | + error_handler=d.callback) |
1778 | + error = yield d |
1779 | + error = error.args[0] |
1780 | + self.assertEqual(error, 'ValueError') |
1781 | + |
1782 | + |
1783 | +class ClearCredentialsTestCase(CredentialsManagementProxyTestCase): |
1784 | + """Test the clear_credentials method.""" |
1785 | + |
1786 | + method = 'clear_credentials' |
1787 | + success_signal = 'CredentialsCleared' |
1788 | + success_result = (APP_NAME,) |
1789 | + |
1790 | + |
1791 | +class StoreCredentialsTestCase(CredentialsManagementProxyTestCase): |
1792 | + """Test the store_credentials method.""" |
1793 | + |
1794 | + method = 'store_credentials' |
1795 | + success_signal = 'CredentialsStored' |
1796 | + success_result = (APP_NAME,) |
1797 | + |
1798 | + |
1799 | +class CredentialsManagementOpsTestCase(CredentialsManagementProxyTestCase): |
1800 | + """Tests for the CredentialsManagementProxy login/register methods.""" |
1801 | + |
1802 | + success_signal = 'CredentialsFound' |
1803 | + success_result = (APP_NAME, TOKEN) |
1804 | + |
1805 | + def _backend_succeed(self, *args, **kwargs): |
1806 | + """Make self.patchable_backend return self.backend_result.""" |
1807 | + self.sso_service.cred_manager.CredentialsFound(APP_NAME, TOKEN) |
1808 | + |
1809 | + def _backend_fail(self, *args, **kwargs): |
1810 | + """Make self.patchable_backend fail.""" |
1811 | + self.sso_service.cred_manager.CredentialsError(APP_NAME, |
1812 | + dict(errtype='ValueError')) |
1813 | + |
1814 | + |
1815 | +class RegisterTestCase(CredentialsManagementOpsTestCase): |
1816 | + """Test the register method.""" |
1817 | + |
1818 | + method = 'register' |
1819 | + |
1820 | + |
1821 | +class LoginOnlyTestCase(CredentialsManagementOpsTestCase): |
1822 | + """Test the login method.""" |
1823 | + |
1824 | + method = 'login' |
1825 | + |
1826 | + |
1827 | +class LoginEmailPasswordTestCase(CredentialsManagementOpsTestCase): |
1828 | + """Test the login method.""" |
1829 | + |
1830 | + method = 'login_email_password' |
1831 | + backend_method = 'login' |
1832 | + args = dict(email=EMAIL, password=PASSWORD) |
1833 | + params = (APP_NAME, args) |
1834 | |
1835 | === modified file 'ubuntu_sso/main/tests/test_common.py' |
1836 | --- ubuntu_sso/main/tests/test_common.py 2011-12-20 17:33:13 +0000 |
1837 | +++ ubuntu_sso/main/tests/test_common.py 2012-01-17 19:42:46 +0000 |
1838 | @@ -1,12 +1,6 @@ |
1839 | # -*- coding: utf-8 -*- |
1840 | # |
1841 | -# test_main - tests for ubuntu_sso.main |
1842 | -# |
1843 | -# Author: Natalia Bidart <natalia.bidart@canonical.com> |
1844 | -# Author: Alejandro J. Cura <alecu@canonical.com> |
1845 | -# Author: Manuel de la Pena <manuel@canonical.com> |
1846 | -# |
1847 | -# Copyright 2009-2010 Canonical Ltd. |
1848 | +# Copyright 2009-2011 Canonical Ltd. |
1849 | # |
1850 | # This program is free software: you can redistribute it and/or modify it |
1851 | # under the terms of the GNU General Public License version 3, as published |
1852 | @@ -19,161 +13,923 @@ |
1853 | # |
1854 | # You should have received a copy of the GNU General Public License along |
1855 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
1856 | -"""Tests share by diff platforms.""" |
1857 | - |
1858 | -from unittest import TestCase |
1859 | - |
1860 | -from mocker import MockerTestCase, MATCH |
1861 | - |
1862 | +"""Tests for the main SSO client code.""" |
1863 | + |
1864 | +import logging |
1865 | + |
1866 | +from twisted.internet import defer |
1867 | +from ubuntuone.devtools.handlers import MementoHandler |
1868 | + |
1869 | +from ubuntu_sso import main |
1870 | from ubuntu_sso.main import ( |
1871 | CredentialsManagement, |
1872 | + except_to_errdict, |
1873 | SSOLogin, |
1874 | + thread_execute, |
1875 | + TIMEOUT_INTERVAL, |
1876 | + UbuntuSSOService, |
1877 | ) |
1878 | - |
1879 | - |
1880 | -class SSOLoginMockedTestCase(MockerTestCase): |
1881 | - """Test that the call are relied correctly.""" |
1882 | - |
1883 | - def setUp(self): |
1884 | - """Setup tests.""" |
1885 | - super(SSOLoginMockedTestCase, self).setUp() |
1886 | - self.root = self.mocker.mock() |
1887 | - mockbusname = self.mocker.mock() |
1888 | - mockbus = self.mocker.mock() |
1889 | - mockbusname.get_bus() |
1890 | - self.mocker.result(mockbus) |
1891 | - self.login = SSOLogin(mockbus) |
1892 | - self.login.root = self.root |
1893 | - self.mocker.reset() |
1894 | - |
1895 | - def test_generate_captcha(self): |
1896 | - """Test that the call is relayed.""" |
1897 | - app_name = 'app' |
1898 | - filename = 'file' |
1899 | - self.root.generate_captcha(app_name, filename, |
1900 | - MATCH(callable), MATCH(callable)) |
1901 | - self.mocker.replay() |
1902 | - self.login.generate_captcha(app_name, filename) |
1903 | - |
1904 | - def test_register_user(self): |
1905 | - """Test that the call is relayed.""" |
1906 | - app_name = 'app' |
1907 | - email = 'email' |
1908 | - password = 'pwd' |
1909 | - name = 'display name' |
1910 | - captcha_id = 'id' |
1911 | - captcha_solution = 'hello' |
1912 | - self.root.register_user(app_name, email, password, name, captcha_id, |
1913 | - captcha_solution, |
1914 | - MATCH(callable), MATCH(callable)) |
1915 | - self.mocker.replay() |
1916 | - self.login.register_user(app_name, email, password, name, captcha_id, |
1917 | - captcha_solution) |
1918 | - |
1919 | - def test_login(self): |
1920 | - """Test that the call is relayed.""" |
1921 | - app_name = 'app' |
1922 | - email = 'email' |
1923 | - password = 'password' |
1924 | - self.root.login(app_name, email, password, |
1925 | - MATCH(callable), MATCH(callable), |
1926 | - MATCH(callable)) |
1927 | - self.mocker.mock() |
1928 | - self.mocker.replay() |
1929 | - self.login.login(app_name, email, password) |
1930 | - |
1931 | - def test_validate_email(self): |
1932 | - """Test that the call is relayed.""" |
1933 | - app_name = 'app' |
1934 | - email = 'email' |
1935 | - password = 'passwrd' |
1936 | - email_token = 'token' |
1937 | - self.root.validate_email(app_name, email, password, email_token, |
1938 | - MATCH(callable), |
1939 | - MATCH(callable)) |
1940 | - self.mocker.replay() |
1941 | - self.login.validate_email(app_name, email, password, email_token) |
1942 | - |
1943 | - def test_request_password_reset_token(self): |
1944 | - """Test that the call is relayed.""" |
1945 | - app_name = 'app' |
1946 | - email = 'email' |
1947 | - self.root.request_password_reset_token(app_name, email, |
1948 | - MATCH(callable), |
1949 | - MATCH(callable)) |
1950 | - self.mocker.replay() |
1951 | - self.login.request_password_reset_token(app_name, email) |
1952 | - |
1953 | - def test_set_new_password(self): |
1954 | - """Test that the call is relayed.""" |
1955 | - app_name = 'app' |
1956 | - email = 'email' |
1957 | - token = 'token' |
1958 | - new_password = 'new' |
1959 | - self.root.set_new_password(app_name, email, token, new_password, |
1960 | - MATCH(callable), |
1961 | - MATCH(callable)) |
1962 | - self.mocker.replay() |
1963 | - self.login.set_new_password(app_name, email, token, new_password) |
1964 | - |
1965 | - |
1966 | -class CredentialsManagementMockedTestCase(MockerTestCase, TestCase): |
1967 | - """Test that the call are relied correctly.""" |
1968 | - |
1969 | - def setUp(self): |
1970 | - """Setup tests.""" |
1971 | - super(CredentialsManagementMockedTestCase, self).setUp() |
1972 | - self.root = self.mocker.mock() |
1973 | - self.cred = CredentialsManagement(None, None) |
1974 | - self.cred.root = self.root |
1975 | - |
1976 | +from ubuntu_sso.main import (HELP_TEXT_KEY, PING_URL_KEY, |
1977 | + TC_URL_KEY, UI_CLASS_KEY, UI_MODULE_KEY, WINDOW_ID_KEY, |
1978 | + SUCCESS_CB_KEY, ERROR_CB_KEY, DENIAL_CB_KEY) |
1979 | +from ubuntu_sso.main.tests import FakedCredentials |
1980 | +from ubuntu_sso.tests import (APP_NAME, TC_URL, HELP_TEXT, CAPTCHA_ID, |
1981 | + CAPTCHA_SOLUTION, EMAIL, EMAIL_TOKEN, NAME, PASSWORD, PING_URL, TOKEN, |
1982 | + WINDOW_ID, Recorder, TestCase) |
1983 | + |
1984 | + |
1985 | +# Access to a protected member 'yyy' of a client class |
1986 | +# pylint: disable=W0212 |
1987 | + |
1988 | + |
1989 | +class SampleException(Exception): |
1990 | + """The exception that will be thrown by the fake thread_execute.""" |
1991 | + |
1992 | + |
1993 | +def fake_ok_thread_execute(f, app, cb, eb): |
1994 | + """A fake thread_execute function that succeeds.""" |
1995 | + cb(app, f()) |
1996 | + |
1997 | + |
1998 | +def fake_err_thread_execute(f, app, cb, eb): |
1999 | + """A fake thread_execute function that fails.""" |
2000 | + try: |
2001 | + f() |
2002 | + except Exception, e: # pylint: disable=W0703 |
2003 | + eb(app, except_to_errdict(e)) |
2004 | + else: |
2005 | + eb(app, except_to_errdict(SampleException())) |
2006 | + |
2007 | + |
2008 | +class FakedProxy(Recorder): |
2009 | + """A faked multiplatform proxy.""" |
2010 | + |
2011 | + |
2012 | +class FakedAccount(Recorder): |
2013 | + """A faked Account processor.""" |
2014 | + |
2015 | + |
2016 | +class FakedCredentialsFactory(Recorder): |
2017 | + """A very dummy Credentials object.""" |
2018 | + |
2019 | + credentials = FakedCredentials() |
2020 | + |
2021 | + # pylint: disable=C0103 |
2022 | + |
2023 | + def Credentials(self, *a, **kw): |
2024 | + """Return always the same Credentials instance.""" |
2025 | + return self.credentials |
2026 | + |
2027 | + # pylint: enable=C0103 |
2028 | + |
2029 | + |
2030 | +class TestExceptToErrdictException(Exception): |
2031 | + """A dummy exception for the following testcase.""" |
2032 | + |
2033 | + |
2034 | +class ExceptToErrdictTestCase(TestCase): |
2035 | + """Tests for the except_to_errdict function.""" |
2036 | + |
2037 | + def test_first_arg_is_dict(self): |
2038 | + """If the first arg is a dict, use it as the base dict.""" |
2039 | + sample_dict = { |
2040 | + "errorcode1": "error message 1", |
2041 | + "errorcode2": "error message 2", |
2042 | + "errorcode3": "error message 3", |
2043 | + } |
2044 | + e = TestExceptToErrdictException(sample_dict) |
2045 | + result = except_to_errdict(e) |
2046 | + |
2047 | + self.assertEqual(result["errtype"], e.__class__.__name__) |
2048 | + for k in sample_dict.keys(): |
2049 | + self.assertIn(k, result) |
2050 | + self.assertEqual(result[k], sample_dict[k]) |
2051 | + |
2052 | + def test_first_arg_is_str(self): |
2053 | + """If the first arg is a str, use it as the message.""" |
2054 | + sample_string = "a sample string" |
2055 | + e = TestExceptToErrdictException(sample_string) |
2056 | + result = except_to_errdict(e) |
2057 | + self.assertEqual(result["errtype"], e.__class__.__name__) |
2058 | + self.assertEqual(result["message"], sample_string) |
2059 | + |
2060 | + def test_first_arg_is_unicode(self): |
2061 | + """If the first arg is a unicode, use it as the message.""" |
2062 | + sample_string = u"a sample string" |
2063 | + e = TestExceptToErrdictException(sample_string) |
2064 | + result = except_to_errdict(e) |
2065 | + self.assertEqual(result["errtype"], e.__class__.__name__) |
2066 | + self.assertEqual(result["message"], sample_string) |
2067 | + |
2068 | + def test_no_args_at_all(self): |
2069 | + """If there are no args, use the class docstring.""" |
2070 | + e = TestExceptToErrdictException() |
2071 | + result = except_to_errdict(e) |
2072 | + self.assertEqual(result["errtype"], e.__class__.__name__) |
2073 | + self.assertEqual(result["message"], e.__class__.__doc__) |
2074 | + |
2075 | + def test_some_other_thing_as_first_arg(self): |
2076 | + """If first arg is not basestring nor dict, then repr all args.""" |
2077 | + sample_args = (None, u"unicode2\ufffd", "errorcode3") |
2078 | + e = TestExceptToErrdictException(*sample_args) |
2079 | + result = except_to_errdict(e) |
2080 | + self.assertEqual(result["errtype"], e.__class__.__name__) |
2081 | + |
2082 | + |
2083 | +class BaseTestCase(TestCase): |
2084 | + """Base test case.""" |
2085 | + |
2086 | + timeout = 2 |
2087 | + |
2088 | + @defer.inlineCallbacks |
2089 | + def setUp(self): |
2090 | + yield super(BaseTestCase, self).setUp() |
2091 | + self.proxy = FakedProxy() |
2092 | + |
2093 | + def assert_recorder_called(self, fake, method, *args, **kwargs): |
2094 | + """Check that 'fake.method(*args, **kwargs)' was called.""" |
2095 | + self.assertEqual(fake._called[method], [(args, kwargs)]) |
2096 | + |
2097 | + |
2098 | +class SSOLoginTestCase(BaseTestCase): |
2099 | + """Test the SSOLogin class.""" |
2100 | + |
2101 | + @defer.inlineCallbacks |
2102 | + def setUp(self): |
2103 | + yield super(SSOLoginTestCase, self).setUp() |
2104 | + |
2105 | + def ksc(keyring, k, val): |
2106 | + """Assert over token and app_name.""" |
2107 | + self.assertEqual(k, APP_NAME) |
2108 | + self.assertEqual(val, TOKEN) |
2109 | + self.keyring_was_set = True |
2110 | + self.keyring_values = k, val |
2111 | + return defer.succeed(None) |
2112 | + |
2113 | + self.patch(main.Keyring, "set_credentials", ksc) |
2114 | + self.patch(main, 'Account', FakedAccount) |
2115 | + self.patch(main, "thread_execute", fake_ok_thread_execute) |
2116 | + self.keyring_was_set = False |
2117 | + self.keyring_values = None |
2118 | + |
2119 | + self.obj = SSOLogin(self.proxy) |
2120 | + |
2121 | + def test_creation(self): |
2122 | + """Test that the object creation is successful.""" |
2123 | + self.assertIsInstance(self.obj.processor, main.Account) |
2124 | + self.assertTrue(self.obj.proxy is self.proxy) |
2125 | + |
2126 | + @defer.inlineCallbacks |
2127 | + def test_generate_captcha(self): |
2128 | + """Test that the captcha method works ok.""" |
2129 | + d = defer.Deferred() |
2130 | + filename = "sample filename" |
2131 | + expected_result = "expected result" |
2132 | + |
2133 | + self.patch(self.obj, "CaptchaGenerated", lambda *a: d.callback(a)) |
2134 | + self.patch(self.obj, "CaptchaGenerationError", d.errback) |
2135 | + |
2136 | + self.obj.processor._next_result = expected_result |
2137 | + self.obj.generate_captcha(APP_NAME, filename) |
2138 | + |
2139 | + app_name, result = yield d |
2140 | + self.assertEqual(result, expected_result) |
2141 | + self.assertEqual(app_name, APP_NAME) |
2142 | + self.assert_recorder_called(self.obj.processor, 'generate_captcha', |
2143 | + filename) |
2144 | + |
2145 | + @defer.inlineCallbacks |
2146 | + def test_register_user(self): |
2147 | + """Test that the register_user method works ok.""" |
2148 | + d = defer.Deferred() |
2149 | + expected_result = "expected result" |
2150 | + |
2151 | + self.patch(self.obj, "UserRegistered", lambda *a: d.callback(a)) |
2152 | + self.patch(self.obj, "UserRegistrationError", d.errback) |
2153 | + |
2154 | + self.obj.processor._next_result = expected_result |
2155 | + self.obj.register_user(APP_NAME, EMAIL, PASSWORD, NAME, CAPTCHA_ID, |
2156 | + CAPTCHA_SOLUTION) |
2157 | + |
2158 | + app_name, result = yield d |
2159 | + self.assertEqual(result, expected_result) |
2160 | + self.assertEqual(app_name, APP_NAME) |
2161 | + self.assert_recorder_called(self.obj.processor, 'register_user', |
2162 | + EMAIL, PASSWORD, NAME, CAPTCHA_ID, CAPTCHA_SOLUTION) |
2163 | + |
2164 | + @defer.inlineCallbacks |
2165 | + def test_login(self): |
2166 | + """Test that the login method works ok.""" |
2167 | + d = defer.Deferred() |
2168 | + |
2169 | + self.patch(self.obj, "LoggedIn", lambda *a: d.callback(a)) |
2170 | + self.patch(self.obj, "LoginError", d.errback) |
2171 | + self.patch(self.obj, "UserNotValidated", d.errback) |
2172 | + |
2173 | + self.obj.processor._next_result = TOKEN |
2174 | + self.obj.login(APP_NAME, EMAIL, PASSWORD) |
2175 | + |
2176 | + app_name, result = yield d |
2177 | + self.assertEqual(result, EMAIL) |
2178 | + self.assertEqual(app_name, APP_NAME) |
2179 | + self.assertTrue(self.keyring_was_set, "The keyring should be set") |
2180 | + self.assert_recorder_called(self.obj.processor, 'login', |
2181 | + EMAIL, PASSWORD, main.get_token_name(APP_NAME)) |
2182 | + |
2183 | + @defer.inlineCallbacks |
2184 | + def test_validate_email(self): |
2185 | + """Test that the validate_email method works ok.""" |
2186 | + d = defer.Deferred() |
2187 | + |
2188 | + self.patch(self.obj, "EmailValidated", lambda *a: d.callback(a)) |
2189 | + self.patch(self.obj, "EmailValidationError", d.errback) |
2190 | + |
2191 | + self.obj.processor._next_result = TOKEN |
2192 | + self.obj.validate_email(APP_NAME, EMAIL, PASSWORD, EMAIL_TOKEN) |
2193 | + |
2194 | + app_name, result = yield d |
2195 | + self.assertEqual(result, EMAIL) |
2196 | + self.assertEqual(app_name, APP_NAME) |
2197 | + self.assertTrue(self.keyring_was_set, "The keyring should be set") |
2198 | + self.assert_recorder_called(self.obj.processor, 'validate_email', |
2199 | + EMAIL, PASSWORD, EMAIL_TOKEN, main.get_token_name(APP_NAME)) |
2200 | + |
2201 | + @defer.inlineCallbacks |
2202 | + def test_request_password_reset_token(self): |
2203 | + """Test that the request_password_reset_token method works ok.""" |
2204 | + d = defer.Deferred() |
2205 | + |
2206 | + self.patch(self.obj, "PasswordResetTokenSent", |
2207 | + lambda *a: d.callback(a)) |
2208 | + self.patch(self.obj, "PasswordResetError", d.errback) |
2209 | + |
2210 | + self.obj.processor._next_result = EMAIL |
2211 | + self.obj.request_password_reset_token(APP_NAME, EMAIL) |
2212 | + |
2213 | + app_name, result = yield d |
2214 | + self.assertEqual(result, EMAIL) |
2215 | + self.assertEqual(app_name, APP_NAME) |
2216 | + self.assert_recorder_called(self.obj.processor, |
2217 | + 'request_password_reset_token', EMAIL) |
2218 | + |
2219 | + @defer.inlineCallbacks |
2220 | + def test_set_new_password(self): |
2221 | + """Test that the set_new_password method works ok.""" |
2222 | + d = defer.Deferred() |
2223 | + |
2224 | + self.patch(self.obj, "PasswordChanged", lambda *a: d.callback(a)) |
2225 | + self.patch(self.obj, "PasswordChangeError", d.errback) |
2226 | + |
2227 | + self.obj.processor._next_result = EMAIL |
2228 | + self.obj.set_new_password(APP_NAME, EMAIL, EMAIL_TOKEN, PASSWORD) |
2229 | + |
2230 | + app_name, result = yield d |
2231 | + self.assertEqual(result, EMAIL) |
2232 | + self.assertEqual(app_name, APP_NAME) |
2233 | + self.assert_recorder_called(self.obj.processor, |
2234 | + 'set_new_password', EMAIL, EMAIL_TOKEN, PASSWORD) |
2235 | + |
2236 | + |
2237 | +class SSOLoginWithErrorTestCase(SSOLoginTestCase): |
2238 | + """Test the SSOLogin class.""" |
2239 | + |
2240 | + @defer.inlineCallbacks |
2241 | + def setUp(self): |
2242 | + yield super(SSOLoginWithErrorTestCase, self).setUp() |
2243 | + self.patch(main, "thread_execute", fake_err_thread_execute) |
2244 | + |
2245 | + @defer.inlineCallbacks |
2246 | + def test_generate_captcha(self): |
2247 | + """Test that the captcha method fails as expected.""" |
2248 | + d = defer.Deferred() |
2249 | + filename = "sample filename" |
2250 | + |
2251 | + self.patch(self.obj, "CaptchaGenerated", d.errback) |
2252 | + self.patch(self.obj, "CaptchaGenerationError", |
2253 | + lambda *a: d.callback(a)) |
2254 | + self.obj.generate_captcha(APP_NAME, filename) |
2255 | + |
2256 | + app_name, errdict = yield d |
2257 | + self.assertEqual(errdict["errtype"], "SampleException") |
2258 | + self.assertEqual(app_name, APP_NAME) |
2259 | + |
2260 | + @defer.inlineCallbacks |
2261 | + def test_register_user(self): |
2262 | + """Test that the register_user method fails as expected.""" |
2263 | + d = defer.Deferred() |
2264 | + |
2265 | + self.patch(self.obj, "UserRegistered", d.errback) |
2266 | + self.patch(self.obj, "UserRegistrationError", lambda *a: d.callback(a)) |
2267 | + self.obj.register_user(APP_NAME, EMAIL, PASSWORD, NAME, CAPTCHA_ID, |
2268 | + CAPTCHA_SOLUTION) |
2269 | + |
2270 | + app_name, errdict = yield d |
2271 | + self.assertEqual(errdict["errtype"], "SampleException") |
2272 | + self.assertEqual(app_name, APP_NAME) |
2273 | + |
2274 | + @defer.inlineCallbacks |
2275 | + def test_login(self): |
2276 | + """The login method fails as expected when get_token_name fails.""" |
2277 | + d = defer.Deferred() |
2278 | + |
2279 | + def fake_gtn(*args): |
2280 | + """A fake get_token_name that fails.""" |
2281 | + raise SampleException() |
2282 | + |
2283 | + self.patch(main, "get_token_name", fake_gtn) |
2284 | + self.patch(self.obj, "LoggedIn", d.errback) |
2285 | + self.patch(self.obj, "LoginError", lambda *a: d.callback(a)) |
2286 | + self.patch(self.obj, "UserNotValidated", d.errback) |
2287 | + self.obj.login(APP_NAME, EMAIL, PASSWORD) |
2288 | + |
2289 | + app_name, errdict = yield d |
2290 | + self.assertEqual(app_name, APP_NAME) |
2291 | + self.assertEqual(errdict["errtype"], "SampleException") |
2292 | + self.assertFalse(self.keyring_was_set, "Keyring should not be set") |
2293 | + |
2294 | + @defer.inlineCallbacks |
2295 | + def test_login_set_credentials(self): |
2296 | + """The login method fails as expected when set_credentials fails.""" |
2297 | + d = defer.Deferred() |
2298 | + |
2299 | + def fake_set_creds(*args): |
2300 | + """A fake Keyring.set_credentials that fails.""" |
2301 | + return defer.fail(SampleException()) |
2302 | + |
2303 | + self.patch(main.Keyring, "set_credentials", fake_set_creds) |
2304 | + fail = lambda app, res: d.errback((app, res)) |
2305 | + self.patch(self.obj, "LoggedIn", fail) |
2306 | + self.patch(self.obj, "LoginError", lambda *a: d.callback(a)) |
2307 | + self.patch(self.obj, "UserNotValidated", fail) |
2308 | + self.obj.login(APP_NAME, EMAIL, PASSWORD) |
2309 | + |
2310 | + app_name, errdict = yield d |
2311 | + self.assertEqual(app_name, APP_NAME) |
2312 | + self.assertEqual(errdict["errtype"], "SampleException") |
2313 | + self.assertFalse(self.keyring_was_set, "Keyring should not be set") |
2314 | + |
2315 | + @defer.inlineCallbacks |
2316 | + def test_validate_email(self): |
2317 | + """Test that the validate_email method fails as expected.""" |
2318 | + d = defer.Deferred() |
2319 | + |
2320 | + def fake_gtn(*args): |
2321 | + """A fake get_token_name that fails.""" |
2322 | + raise SampleException() |
2323 | + |
2324 | + self.patch(main, "get_token_name", fake_gtn) |
2325 | + |
2326 | + self.patch(self.obj, "EmailValidated", d.errback) |
2327 | + self.patch(self.obj, "EmailValidationError", lambda *a: d.callback(a)) |
2328 | + self.obj.validate_email(APP_NAME, EMAIL, PASSWORD, EMAIL_TOKEN) |
2329 | + |
2330 | + app_name, errdict = yield d |
2331 | + self.assertEqual(app_name, APP_NAME) |
2332 | + self.assertEqual(errdict["errtype"], "SampleException") |
2333 | + self.assertFalse(self.keyring_was_set, "Keyring should not be set") |
2334 | + |
2335 | + @defer.inlineCallbacks |
2336 | + def test_request_password_reset_token(self): |
2337 | + """Test the request_password_reset_token method fails as expected.""" |
2338 | + d = defer.Deferred() |
2339 | + |
2340 | + self.patch(self.obj, "PasswordResetTokenSent", d.errback) |
2341 | + self.patch(self.obj, "PasswordResetError", lambda *a: d.callback(a)) |
2342 | + self.obj.request_password_reset_token(APP_NAME, EMAIL) |
2343 | + |
2344 | + app_name, errdict = yield d |
2345 | + self.assertEqual(errdict["errtype"], "SampleException") |
2346 | + self.assertEqual(app_name, APP_NAME) |
2347 | + |
2348 | + @defer.inlineCallbacks |
2349 | + def test_set_new_password(self): |
2350 | + """Test that the set_new_password method fails as expected.""" |
2351 | + d = defer.Deferred() |
2352 | + |
2353 | + self.patch(self.obj, "PasswordChanged", d.errback) |
2354 | + self.patch(self.obj, "PasswordChangeError", lambda *a: d.callback(a)) |
2355 | + self.obj.set_new_password(APP_NAME, EMAIL, EMAIL_TOKEN, PASSWORD) |
2356 | + |
2357 | + app_name, errdict = yield d |
2358 | + self.assertEqual(errdict["errtype"], "SampleException") |
2359 | + self.assertEqual(app_name, APP_NAME) |
2360 | + |
2361 | + |
2362 | +class BlockingFunctionTestCase(TestCase): |
2363 | + """Tests for the "thread_execute" function.""" |
2364 | + |
2365 | + timeout = 5 |
2366 | + |
2367 | + @defer.inlineCallbacks |
2368 | + def test_thread_execute(self): |
2369 | + """Test the normal behaviour.""" |
2370 | + d = defer.Deferred() |
2371 | + expected_result = "expected result" |
2372 | + |
2373 | + def f(): |
2374 | + """No failure.""" |
2375 | + return expected_result |
2376 | + |
2377 | + thread_execute(f, APP_NAME, lambda *a: d.callback(a), d.errback) |
2378 | + |
2379 | + app_name, result = yield d |
2380 | + |
2381 | + self.assertEqual(result, expected_result) |
2382 | + self.assertEqual(app_name, APP_NAME) |
2383 | + |
2384 | + @defer.inlineCallbacks |
2385 | + def test_thread_execute_error(self): |
2386 | + """Test the behaviour when an Exception is raised.""" |
2387 | + d = defer.Deferred() |
2388 | + expected_error_message = "expected error message" |
2389 | + expected_exc = SampleException(expected_error_message) |
2390 | + |
2391 | + def f(): |
2392 | + """Failure.""" |
2393 | + raise expected_exc |
2394 | + |
2395 | + thread_execute(f, APP_NAME, d.errback, lambda *a: d.callback(a)) |
2396 | + |
2397 | + app_name, error = yield d |
2398 | + |
2399 | + self.assertEqual(app_name, APP_NAME) |
2400 | + self.assertEqual(error, expected_exc) |
2401 | + |
2402 | + |
2403 | +class CredentialsManagementTestCase(BaseTestCase): |
2404 | + """Tests for the CredentialsManagement DBus interface.""" |
2405 | + |
2406 | + base_args = { |
2407 | + HELP_TEXT_KEY: HELP_TEXT, PING_URL_KEY: PING_URL, |
2408 | + TC_URL_KEY: TC_URL, WINDOW_ID_KEY: WINDOW_ID, |
2409 | + UI_CLASS_KEY: 'SuperUI', UI_MODULE_KEY: 'foo.bar.baz', |
2410 | + } |
2411 | + |
2412 | + @defer.inlineCallbacks |
2413 | + def setUp(self): |
2414 | + yield super(CredentialsManagementTestCase, self).setUp() |
2415 | + |
2416 | + self.factory = FakedCredentialsFactory() |
2417 | + self.patch(main, 'Credentials', self.factory.Credentials) |
2418 | + self.obj = CredentialsManagement(timeout_func=lambda *a: None, |
2419 | + shutdown_func=lambda *a: None, |
2420 | + proxy=self.proxy) |
2421 | + self.args = {} |
2422 | + self.cred_args = {} |
2423 | + |
2424 | + self.memento = MementoHandler() |
2425 | + self.memento.setLevel(logging.DEBUG) |
2426 | + main.logger.addHandler(self.memento) |
2427 | + self.addCleanup(main.logger.removeHandler, self.memento) |
2428 | + |
2429 | + |
2430 | +class CredentialsManagementRefCountingTestCase(CredentialsManagementTestCase): |
2431 | + """Tests for the CredentialsManagement ref counting.""" |
2432 | + |
2433 | + @defer.inlineCallbacks |
2434 | + def assert_refcounter_increased(self, method_name, signal_name=None): |
2435 | + """Assert that calling 'method_name' increases the ref counter.""" |
2436 | + if signal_name is not None: |
2437 | + d = defer.Deferred() |
2438 | + self.patch(self.obj, signal_name, lambda *a: d.callback(a)) |
2439 | + else: |
2440 | + d = defer.succeed(None) |
2441 | + |
2442 | + getattr(self.obj, method_name)(APP_NAME, self.args) |
2443 | + |
2444 | + yield d |
2445 | + self.assertEqual(self.obj.ref_count, 1) |
2446 | + |
2447 | + def assert_refcounter_decreased(self, signal_name, *a, **kw): |
2448 | + """Assert that calling 'signal_name' decreases the ref counter.""" |
2449 | + self.obj.ref_count = 3 |
2450 | + |
2451 | + getattr(self.obj, signal_name)(*a, **kw) |
2452 | + |
2453 | + self.assertEqual(self.obj.ref_count, 2) |
2454 | + |
2455 | + def assert_refcounter_negative(self, signal_name, *a, **kw): |
2456 | + """Assert that calling 'signal_name' decreases the ref counter. |
2457 | + |
2458 | + If decreased value is negative, assert that a warning log was made. |
2459 | + |
2460 | + """ |
2461 | + self.obj._ref_count = -3 # overwrite internal to force a negative |
2462 | + |
2463 | + getattr(self.obj, signal_name)(*a, **kw) |
2464 | + |
2465 | + self.assertEqual(self.obj.ref_count, 0) |
2466 | + msg = 'Attempting to decrease ref_count to a negative value (-4).' |
2467 | + self.assertTrue(self.memento.check_warning(msg)) |
2468 | + |
2469 | + def test_ref_counting(self): |
2470 | + """Ref counting is in place.""" |
2471 | + self.assertEqual(self.obj.ref_count, 0) |
2472 | + |
2473 | + @defer.inlineCallbacks |
2474 | def test_find_credentials(self): |
2475 | - """Test that the call is relayed.""" |
2476 | - app_name = 'app' |
2477 | - args = 'args' |
2478 | - self.root.find_credentials(app_name, args, MATCH(callable), |
2479 | - MATCH(callable)) |
2480 | - self.mocker.replay() |
2481 | - self.cred.find_credentials(app_name, args) |
2482 | - |
2483 | + """Keep proper track of ongoing requests.""" |
2484 | + yield self.assert_refcounter_increased('find_credentials', |
2485 | + 'CredentialsFound') |
2486 | + |
2487 | + @defer.inlineCallbacks |
2488 | + def test_find_credentials_with_success_cb(self): |
2489 | + """Keep proper track of ongoing requests.""" |
2490 | + d = defer.Deferred() |
2491 | + counter = [] |
2492 | + |
2493 | + def in_the_middle(): |
2494 | + """Store the ref_count value.""" |
2495 | + counter.append(self.obj.ref_count) |
2496 | + return defer.succeed(TOKEN) |
2497 | + |
2498 | + self.patch(self.factory.credentials, 'find_credentials', in_the_middle) |
2499 | + self.obj.find_credentials(APP_NAME, self.args, |
2500 | + success_cb=d.callback, error_cb=d.errback) |
2501 | + yield d |
2502 | + self.assertEqual(counter, [1]) |
2503 | + self.assertEqual(self.obj.ref_count, 0) |
2504 | + |
2505 | + @defer.inlineCallbacks |
2506 | + def test_find_credentials_with_error_cb(self): |
2507 | + """Keep proper track of ongoing requests.""" |
2508 | + d = defer.Deferred() |
2509 | + counter = [] |
2510 | + |
2511 | + def in_the_middle(): |
2512 | + """Store the ref_count value.""" |
2513 | + counter.append(self.obj.ref_count) |
2514 | + return defer.fail('foo') |
2515 | + |
2516 | + self.patch(self.factory.credentials, 'find_credentials', in_the_middle) |
2517 | + self.obj.find_credentials(APP_NAME, self.args, |
2518 | + success_cb=d.errback, error_cb=d.callback) |
2519 | + |
2520 | + yield d |
2521 | + self.assertEqual(counter, [1]) |
2522 | + self.assertEqual(self.obj.ref_count, 0) |
2523 | + |
2524 | + @defer.inlineCallbacks |
2525 | def test_clear_credentials(self): |
2526 | - """Test that the call is relayed.""" |
2527 | - app_name = 'app' |
2528 | - args = 'args' |
2529 | - self.root.clear_credentials(app_name, args, MATCH(callable), |
2530 | - MATCH(callable)) |
2531 | - self.mocker.replay() |
2532 | - self.cred.clear_credentials(app_name, args) |
2533 | + """Keep proper track of ongoing requests.""" |
2534 | + yield self.assert_refcounter_increased('clear_credentials', |
2535 | + 'CredentialsCleared') |
2536 | |
2537 | + @defer.inlineCallbacks |
2538 | def test_store_credentials(self): |
2539 | - """Test that the call is relayed.""" |
2540 | - app_name = 'app' |
2541 | - args = 'args' |
2542 | - self.root.store_credentials(app_name, args, MATCH(callable), |
2543 | - MATCH(callable)) |
2544 | - self.mocker.replay() |
2545 | - self.cred.store_credentials(app_name, args) |
2546 | - |
2547 | - def test_register(self): |
2548 | - """Test that the call is relayed.""" |
2549 | - app_name = 'app' |
2550 | - args = 'args' |
2551 | - self.root.register(app_name, args) |
2552 | - self.mocker.replay() |
2553 | - self.cred.register(app_name, args) |
2554 | - |
2555 | - def test_login(self): |
2556 | - """Test that the call is relayed.""" |
2557 | - app_name = 'app' |
2558 | - args = 'args' |
2559 | - self.root.login(app_name, args) |
2560 | - self.mocker.replay() |
2561 | - self.cred.login(app_name, args) |
2562 | + """Keep proper track of ongoing requests.""" |
2563 | + yield self.assert_refcounter_increased('store_credentials', |
2564 | + 'CredentialsStored') |
2565 | + |
2566 | + def test_register(self): |
2567 | + """Keep proper track of ongoing requests.""" |
2568 | + yield self.assert_refcounter_increased('register') |
2569 | + |
2570 | + def test_login(self): |
2571 | + """Keep proper track of ongoing requests.""" |
2572 | + yield self.assert_refcounter_increased('login') |
2573 | + |
2574 | + def test_several_requests(self): |
2575 | + """Requests can be nested.""" |
2576 | + self.obj.login(APP_NAME, self.args) |
2577 | + self.obj.register(APP_NAME, self.args) |
2578 | + self.obj.login(APP_NAME, self.args) |
2579 | + self.obj.register(APP_NAME, self.args) |
2580 | + self.obj.register(APP_NAME, self.args) |
2581 | + |
2582 | + self.assertEqual(self.obj.ref_count, 5) |
2583 | + |
2584 | + def test_credentials_found(self): |
2585 | + """Ref counter is decreased when a signal is sent.""" |
2586 | + self.assert_refcounter_decreased('CredentialsFound', APP_NAME, TOKEN) |
2587 | + |
2588 | + def test_credentials_not_found(self): |
2589 | + """Ref counter is decreased when a signal is sent.""" |
2590 | + self.assert_refcounter_decreased('CredentialsNotFound', APP_NAME) |
2591 | + |
2592 | + def test_credentials_cleared(self): |
2593 | + """Ref counter is decreased when a signal is sent.""" |
2594 | + self.assert_refcounter_decreased('CredentialsCleared', APP_NAME) |
2595 | + |
2596 | + def test_credentials_stored(self): |
2597 | + """Ref counter is decreased when a signal is sent.""" |
2598 | + self.assert_refcounter_decreased('CredentialsStored', APP_NAME) |
2599 | + |
2600 | + def test_credentials_error(self): |
2601 | + """Ref counter is decreased when a signal is sent.""" |
2602 | + self.assert_refcounter_decreased('CredentialsError', APP_NAME, |
2603 | + SampleException('test')) |
2604 | + |
2605 | + def test_authorization_denied(self): |
2606 | + """Ref counter is decreased when a signal is sent.""" |
2607 | + self.assert_refcounter_decreased('AuthorizationDenied', APP_NAME) |
2608 | + |
2609 | + def test_credentials_found_when_ref_count_is_not_positive(self): |
2610 | + """Ref counter is decreased when a signal is sent.""" |
2611 | + self.assert_refcounter_negative('CredentialsFound', APP_NAME, TOKEN) |
2612 | + |
2613 | + def test_credentials_not_found_when_ref_count_is_not_positive(self): |
2614 | + """Ref counter is decreased when a signal is sent.""" |
2615 | + self.assert_refcounter_negative('CredentialsNotFound', APP_NAME) |
2616 | + |
2617 | + def test_credentials_cleared_when_ref_count_is_not_positive(self): |
2618 | + """Ref counter is decreased when a signal is sent.""" |
2619 | + self.assert_refcounter_negative('CredentialsCleared', APP_NAME) |
2620 | + |
2621 | + def test_credentials_stored_when_ref_count_is_not_positive(self): |
2622 | + """Ref counter is decreased when a signal is sent.""" |
2623 | + self.assert_refcounter_negative('CredentialsStored', APP_NAME) |
2624 | + |
2625 | + def test_credentials_error_when_ref_count_is_not_positive(self): |
2626 | + """Ref counter is decreased when a signal is sent.""" |
2627 | + self.assert_refcounter_negative('CredentialsError', APP_NAME, |
2628 | + SampleException('test')) |
2629 | + |
2630 | + def test_autorization_denied_when_ref_count_is_not_positive(self): |
2631 | + """Ref counter is decreased when a signal is sent.""" |
2632 | + self.assert_refcounter_negative('AuthorizationDenied', APP_NAME) |
2633 | + |
2634 | + def test_on_zero_ref_count_shutdown(self): |
2635 | + """When ref count reaches 0, queue shutdown op.""" |
2636 | + self.patch(self.obj, 'timeout_func', self._set_called) |
2637 | + self.obj.login(APP_NAME, self.args) |
2638 | + self.obj.CredentialsFound(APP_NAME, TOKEN) |
2639 | + |
2640 | + self.assertEqual(self._called, |
2641 | + ((TIMEOUT_INTERVAL, self.obj.shutdown), {})) |
2642 | + |
2643 | + def test_on_non_zero_ref_count_do_not_shutdown(self): |
2644 | + """If ref count is not 0, do not queue shutdown op.""" |
2645 | + self.patch(self.obj, 'timeout_func', self._set_called) |
2646 | + self.obj.login(APP_NAME, self.args) |
2647 | + |
2648 | + self.assertEqual(self._called, False) |
2649 | + |
2650 | + def test_on_non_zero_ref_count_after_zero_do_not_shutdown(self): |
2651 | + """If the shutdown was queued, do not quit if counter is not zero.""" |
2652 | + |
2653 | + def fake_timeout_func(interval, func): |
2654 | + """Start a new request when the timer is started.""" |
2655 | + self.obj.register(APP_NAME, self.args) |
2656 | + assert self.obj.ref_count > 0 |
2657 | + func() |
2658 | + |
2659 | + self.patch(self.obj, 'timeout_func', fake_timeout_func) |
2660 | + self.patch(self.obj, 'shutdown_func', self._set_called) |
2661 | + |
2662 | + self.obj.login(APP_NAME, self.args) |
2663 | + self.obj.CredentialsFound(APP_NAME, TOKEN) |
2664 | + # counter reached 0, timeout_func was called |
2665 | + |
2666 | + self.assertEqual(self._called, False, 'shutdown_func was not called') |
2667 | + |
2668 | + def test_zero_ref_count_after_zero_do_shutdown(self): |
2669 | + """If the shutdown was queued, do quit if counter is zero.""" |
2670 | + |
2671 | + def fake_timeout_func(interval, func): |
2672 | + """Start a new request when the timer is started.""" |
2673 | + assert self.obj.ref_count == 0 |
2674 | + func() |
2675 | + |
2676 | + self.patch(self.obj, 'timeout_func', fake_timeout_func) |
2677 | + self.patch(self.obj, 'shutdown_func', self._set_called) |
2678 | + |
2679 | + self.obj.login(APP_NAME, self.args) |
2680 | + self.obj.CredentialsFound(APP_NAME, TOKEN) |
2681 | + # counter reached 0, timeout_func was called |
2682 | + |
2683 | + self.assertEqual(self._called, ((), {}), 'shutdown_func was called') |
2684 | + |
2685 | + |
2686 | +class CredentialsManagementClearTestCase(CredentialsManagementTestCase): |
2687 | + """Tests for the CredentialsManagement clear method.""" |
2688 | + |
2689 | + method = 'clear_credentials' |
2690 | + success_signal = 'CredentialsCleared' |
2691 | + success_result = (APP_NAME,) |
2692 | + others_should_errback = [] |
2693 | + |
2694 | + @defer.inlineCallbacks |
2695 | + def setUp(self): |
2696 | + yield super(CredentialsManagementClearTestCase, self).setUp() |
2697 | + self.call_method = getattr(self.obj, self.method) |
2698 | + |
2699 | + def test_backend_called(self): |
2700 | + """The credentials backend is properly called.""" |
2701 | + self.call_method(APP_NAME, self.args) |
2702 | + self.assert_recorder_called(self.factory, 'Credentials', APP_NAME) |
2703 | + |
2704 | + @defer.inlineCallbacks |
2705 | + def test_does_not_block(self): |
2706 | + """Calling 'method' does not block but return thru signals.""" |
2707 | + d = defer.Deferred() |
2708 | + |
2709 | + self.patch(self.obj, self.success_signal, lambda *a: d.callback(a)) |
2710 | + self.patch(self.obj, 'CredentialsError', |
2711 | + lambda *a: d.errback(SampleException(a))) |
2712 | + for signal in self.others_should_errback: |
2713 | + self.patch(self.obj, signal, |
2714 | + lambda *a: d.errback(AssertionError(a))) |
2715 | + |
2716 | + self.call_method(APP_NAME, self.args) |
2717 | + |
2718 | + result = yield d |
2719 | + self.assertEqual(result, self.success_result) |
2720 | + |
2721 | + @defer.inlineCallbacks |
2722 | + def test_handles_error(self): |
2723 | + """If calling the backend fails, CredentialsError is sent.""" |
2724 | + d = defer.Deferred() |
2725 | + |
2726 | + self.patch(self.obj, self.success_signal, d.errback) |
2727 | + self.patch(self.obj, 'CredentialsError', lambda *a: d.callback(a)) |
2728 | + |
2729 | + exc = SampleException('baz') |
2730 | + self.patch(self.factory.credentials, self.method, |
2731 | + lambda *a: defer.fail(exc)) |
2732 | + self.call_method(APP_NAME, self.args) |
2733 | + |
2734 | + app_name, error = yield d |
2735 | + self.assertEqual(error, exc) |
2736 | + self.assertEqual(app_name, APP_NAME) |
2737 | + |
2738 | + |
2739 | +class CredentialsManagementStoreTestCase(CredentialsManagementClearTestCase): |
2740 | + """Tests for the CredentialsManagement store method.""" |
2741 | + |
2742 | + method = 'store_credentials' |
2743 | + success_signal = 'CredentialsStored' |
2744 | + |
2745 | + |
2746 | +class CredentialsManagementFindTestCase(CredentialsManagementClearTestCase): |
2747 | + """Tests for the CredentialsManagement find method.""" |
2748 | + |
2749 | + method = 'find_credentials' |
2750 | + success_signal = 'CredentialsFound' |
2751 | + success_result = (APP_NAME, TOKEN) |
2752 | + others_should_errback = ['CredentialsNotFound'] |
2753 | + |
2754 | + @defer.inlineCallbacks |
2755 | + def test_find_credentials_with_success_cb(self): |
2756 | + """The credentials are asked and returned in a thread_execute call.""" |
2757 | + d = defer.Deferred() |
2758 | + |
2759 | + self.obj.find_credentials(APP_NAME, self.args, |
2760 | + success_cb=d.callback, error_cb=d.errback) |
2761 | + |
2762 | + creds = yield d |
2763 | + expected = yield self.factory.credentials.find_credentials() |
2764 | + self.assertEqual(creds, expected) |
2765 | + self.assert_recorder_called(self.factory, 'Credentials', APP_NAME) |
2766 | + |
2767 | + @defer.inlineCallbacks |
2768 | + def test_find_credentials_with_error_cb(self): |
2769 | + """If find_credentials fails, error_cb is called.""" |
2770 | + d = defer.Deferred() |
2771 | + |
2772 | + self.patch(self.factory.credentials, 'find_credentials', |
2773 | + lambda *a: defer.fail(SampleException('baz'))) |
2774 | + self.obj.find_credentials(APP_NAME, self.args, |
2775 | + success_cb=d.errback, error_cb=d.callback) |
2776 | + |
2777 | + errdict = yield d |
2778 | + self.assertEqual(errdict["errtype"], "SampleException") |
2779 | + self.assert_recorder_called(self.factory, 'Credentials', APP_NAME) |
2780 | + |
2781 | + |
2782 | +class CredentialsManagementNotFindTestCase(CredentialsManagementFindTestCase): |
2783 | + """Tests for the CredentialsManagement find method.""" |
2784 | + |
2785 | + success_signal = 'CredentialsNotFound' |
2786 | + success_result = (APP_NAME,) |
2787 | + others_should_errback = ['CredentialsFound'] |
2788 | + |
2789 | + @defer.inlineCallbacks |
2790 | + def setUp(self): |
2791 | + yield super(CredentialsManagementNotFindTestCase, self).setUp() |
2792 | + self.call_method = getattr(self.obj, self.method) |
2793 | + self.patch(self.factory.credentials, self.method, |
2794 | + lambda: defer.succeed({})) |
2795 | + |
2796 | + |
2797 | +class CredentialsManagementOpsTestCase(CredentialsManagementTestCase): |
2798 | + """Tests for the CredentialsManagement login/register methods.""" |
2799 | + |
2800 | + @defer.inlineCallbacks |
2801 | + def setUp(self): |
2802 | + yield super(CredentialsManagementOpsTestCase, self).setUp() |
2803 | + self.args = dict((k, str(v)) for k, v in self.base_args.iteritems()) |
2804 | + self.cred_args = self.base_args.copy() |
2805 | + self.cred_args[SUCCESS_CB_KEY] = self.obj.CredentialsFound |
2806 | + self.cred_args[ERROR_CB_KEY] = self.obj.CredentialsError |
2807 | + self.cred_args[DENIAL_CB_KEY] = self.obj.AuthorizationDenied |
2808 | + |
2809 | + def test_register(self): |
2810 | + """The registration is correct.""" |
2811 | + self.obj.register(APP_NAME, self.args) |
2812 | + self.assert_recorder_called(self.factory, 'Credentials', |
2813 | + APP_NAME, **self.cred_args) |
2814 | + |
2815 | + def test_login(self): |
2816 | + """The login is correct.""" |
2817 | + self.obj.login(APP_NAME, self.args) |
2818 | + self.assert_recorder_called(self.factory, 'Credentials', |
2819 | + APP_NAME, **self.cred_args) |
2820 | |
2821 | def test_login_email_password(self): |
2822 | - """Test that the call is relayed.""" |
2823 | - app_name = 'app' |
2824 | - args = 'args' |
2825 | - self.root.login_email_password(app_name, args) |
2826 | - self.mocker.replay() |
2827 | - self.cred.login_email_password(app_name, args) |
2828 | + """The login_email_password is correct.""" |
2829 | + self.args['email'] = EMAIL |
2830 | + self.args['password'] = PASSWORD |
2831 | + self.obj.login_email_password(APP_NAME, self.args) |
2832 | + self.assert_recorder_called(self.factory, 'Credentials', |
2833 | + APP_NAME, **self.cred_args) |
2834 | + |
2835 | + |
2836 | +class CredentialsManagementParamsTestCase(CredentialsManagementOpsTestCase): |
2837 | + """Tests for the CredentialsManagement extra parameters handling.""" |
2838 | + |
2839 | + @defer.inlineCallbacks |
2840 | + def setUp(self): |
2841 | + yield super(CredentialsManagementParamsTestCase, self).setUp() |
2842 | + self.args['dummy'] = 'nothing useful' |
2843 | + |
2844 | + |
2845 | +class CredentialsManagementSignalsTestCase(CredentialsManagementTestCase): |
2846 | + """Tests for the CredentialsManagement DBus signals.""" |
2847 | + |
2848 | + def test_credentials_found(self): |
2849 | + """The CredentialsFound signal.""" |
2850 | + self.obj.CredentialsFound(APP_NAME, TOKEN) |
2851 | + msgs = (self.obj.__class__.__name__, |
2852 | + self.obj.CredentialsFound.__name__, APP_NAME) |
2853 | + self.assertTrue(self.memento.check_info(*msgs)) |
2854 | + |
2855 | + msg = 'credentials must not be logged (found %r in log).' |
2856 | + for val in TOKEN.itervalues(): |
2857 | + self.assertFalse(self.memento.check_info(val), msg % val) |
2858 | + |
2859 | + def test_credentials_not_found(self): |
2860 | + """The CredentialsNotFound signal.""" |
2861 | + self.obj.CredentialsNotFound(APP_NAME) |
2862 | + msgs = (self.obj.__class__.__name__, |
2863 | + self.obj.CredentialsNotFound.__name__, APP_NAME) |
2864 | + self.assertTrue(self.memento.check_info(*msgs)) |
2865 | + |
2866 | + def test_credentials_cleared(self): |
2867 | + """The CredentialsCleared signal.""" |
2868 | + self.obj.CredentialsCleared(APP_NAME) |
2869 | + msgs = (self.obj.__class__.__name__, |
2870 | + self.obj.CredentialsCleared.__name__, APP_NAME) |
2871 | + self.assertTrue(self.memento.check_info(*msgs)) |
2872 | + |
2873 | + def test_credentials_stored(self): |
2874 | + """The CredentialsStored signal.""" |
2875 | + self.obj.CredentialsStored(APP_NAME) |
2876 | + msgs = (self.obj.__class__.__name__, |
2877 | + self.obj.CredentialsStored.__name__, APP_NAME) |
2878 | + self.assertTrue(self.memento.check_info(*msgs)) |
2879 | + |
2880 | + def test_credentials_error(self): |
2881 | + """The CredentialsError signal.""" |
2882 | + error = {'error_message': 'failed!', 'detailed error': 'yadda yadda'} |
2883 | + self.obj.CredentialsError(APP_NAME, error) |
2884 | + msgs = (self.obj.__class__.__name__, |
2885 | + self.obj.CredentialsError.__name__, |
2886 | + APP_NAME, str(error)) |
2887 | + self.assertTrue(self.memento.check_error(*msgs)) |
2888 | + |
2889 | + def test_authorization_denied(self): |
2890 | + """The AuthorizationDenied signal.""" |
2891 | + self.obj.AuthorizationDenied(APP_NAME) |
2892 | + msgs = (self.obj.__class__.__name__, |
2893 | + self.obj.AuthorizationDenied.__name__, APP_NAME) |
2894 | + self.assertTrue(self.memento.check_info(*msgs)) |
2895 | + |
2896 | + |
2897 | +class UbuntuSSOServiceTestCase(BaseTestCase): |
2898 | + """Test suite for the UbuntuSSOService class.""" |
2899 | + |
2900 | + @defer.inlineCallbacks |
2901 | + def setUp(self): |
2902 | + yield super(UbuntuSSOServiceTestCase, self).setUp() |
2903 | + self.proxy.sso_login = object() |
2904 | + self.proxy.cred_manager = object() |
2905 | + self.params = [] |
2906 | + self.patch(main, 'UbuntuSSOProxy', |
2907 | + lambda _: self.params.append(_) or self.proxy) |
2908 | + self.obj = UbuntuSSOService() |
2909 | + yield self.obj.start() |
2910 | + |
2911 | + def test_creation(self): |
2912 | + """Creation paremeter is properly used.""" |
2913 | + self.assertEqual(self.params, [self.obj]) |
2914 | + |
2915 | + def test_sso_login(self): |
2916 | + """Attributes has the expected value.""" |
2917 | + self.assertIsInstance(self.obj.sso_login, SSOLogin) |
2918 | + self.assertTrue(self.obj.sso_login.proxy is self.proxy.sso_login) |
2919 | + |
2920 | + def test_cred_manager(self): |
2921 | + """Attributes has the expected value.""" |
2922 | + self.assertIsInstance(self.obj.cred_manager, CredentialsManagement) |
2923 | + self.assertTrue(self.obj.cred_manager.proxy is self.proxy.cred_manager) |
2924 | |
2925 | === removed file 'ubuntu_sso/main/tests/test_linux.py' |
2926 | --- ubuntu_sso/main/tests/test_linux.py 2011-12-20 17:33:13 +0000 |
2927 | +++ ubuntu_sso/main/tests/test_linux.py 1970-01-01 00:00:00 +0000 |
2928 | @@ -1,1275 +0,0 @@ |
2929 | -# -*- coding: utf-8 -*- |
2930 | -# |
2931 | -# test_main - tests for ubuntu_sso.main |
2932 | -# |
2933 | -# Author: Natalia Bidart <natalia.bidart@canonical.com> |
2934 | -# Author: Alejandro J. Cura <alecu@canonical.com> |
2935 | -# |
2936 | -# Copyright 2009-2010 Canonical Ltd. |
2937 | -# |
2938 | -# This program is free software: you can redistribute it and/or modify it |
2939 | -# under the terms of the GNU General Public License version 3, as published |
2940 | -# by the Free Software Foundation. |
2941 | -# |
2942 | -# This program is distributed in the hope that it will be useful, but |
2943 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
2944 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2945 | -# PURPOSE. See the GNU General Public License for more details. |
2946 | -# |
2947 | -# You should have received a copy of the GNU General Public License along |
2948 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
2949 | -"""Tests for the main SSO client code.""" |
2950 | - |
2951 | -import logging |
2952 | - |
2953 | -from mocker import Mocker, ARGS, KWARGS |
2954 | -from twisted.internet import defer |
2955 | -from ubuntuone.devtools.handlers import MementoHandler |
2956 | - |
2957 | -import ubuntu_sso.keyring |
2958 | -import ubuntu_sso.main |
2959 | -import ubuntu_sso.main.linux |
2960 | - |
2961 | -from ubuntu_sso import DBUS_CREDENTIALS_IFACE |
2962 | -from ubuntu_sso.main import ( |
2963 | - except_to_errdict, |
2964 | - CredentialsManagement, |
2965 | - SSOLogin, |
2966 | - TIMEOUT_INTERVAL, |
2967 | -) |
2968 | -from ubuntu_sso.main.linux import blocking |
2969 | -from ubuntu_sso.main import (HELP_TEXT_KEY, PING_URL_KEY, |
2970 | - TC_URL_KEY, UI_CLASS_KEY, UI_MODULE_KEY, WINDOW_ID_KEY, |
2971 | - SUCCESS_CB_KEY, ERROR_CB_KEY, DENIAL_CB_KEY) |
2972 | -from ubuntu_sso.tests import (APP_NAME, TC_URL, HELP_TEXT, CAPTCHA_ID, |
2973 | - CAPTCHA_SOLUTION, EMAIL, EMAIL_TOKEN, NAME, PASSWORD, PING_URL, TOKEN, |
2974 | - TOKEN_NAME, WINDOW_ID, TestCase) |
2975 | - |
2976 | - |
2977 | -# Access to a protected member 'yyy' of a client class |
2978 | -# pylint: disable=W0212 |
2979 | - |
2980 | - |
2981 | -class BlockingSampleException(Exception): |
2982 | - """The exception that will be thrown by the fake blocking.""" |
2983 | - |
2984 | - |
2985 | -def fake_ok_blocking(f, app, cb, eb): |
2986 | - """A fake blocking function that succeeds.""" |
2987 | - cb(app, f()) |
2988 | - |
2989 | - |
2990 | -def fake_err_blocking(f, app, cb, eb): |
2991 | - """A fake blocking function that fails.""" |
2992 | - try: |
2993 | - f() |
2994 | - except Exception, e: # pylint: disable=W0703 |
2995 | - eb(app, except_to_errdict(e)) |
2996 | - else: |
2997 | - eb(app, except_to_errdict(BlockingSampleException())) |
2998 | - |
2999 | - |
3000 | -class SsoDbusTestCase(TestCase): |
3001 | - """Test the SSOLogin DBus interface.""" |
3002 | - |
3003 | - timeout = 2 |
3004 | - |
3005 | - @defer.inlineCallbacks |
3006 | - def setUp(self): |
3007 | - """Create the mocking bus.""" |
3008 | - yield super(SsoDbusTestCase, self).setUp() |
3009 | - self.mocker = Mocker() |
3010 | - self.mockbusname = self.mocker.mock() |
3011 | - mockbus = self.mocker.mock() |
3012 | - self.mockbusname.get_bus() |
3013 | - self.mocker.result(mockbus) |
3014 | - mockbus._register_object_path(ARGS) |
3015 | - self.mockprocessorclass = None |
3016 | - |
3017 | - def ksc(keyring, k, val): |
3018 | - """Assert over token and app_name.""" |
3019 | - self.assertEqual(k, APP_NAME) |
3020 | - self.assertEqual(val, TOKEN) |
3021 | - self.keyring_was_set = True |
3022 | - self.keyring_values = k, val |
3023 | - return defer.succeed(None) |
3024 | - |
3025 | - self.patch(ubuntu_sso.main.Keyring, "set_credentials", ksc) |
3026 | - self.keyring_was_set = False |
3027 | - self.keyring_values = None |
3028 | - |
3029 | - @defer.inlineCallbacks |
3030 | - def tearDown(self): |
3031 | - """Verify the mocking bus and shut it down.""" |
3032 | - self.mocker.verify() |
3033 | - self.mocker.restore() |
3034 | - yield super(SsoDbusTestCase, self).tearDown() |
3035 | - |
3036 | - def test_creation(self): |
3037 | - """Test that the object creation is successful.""" |
3038 | - self.mocker.replay() |
3039 | - SSOLogin(self.mockbusname) |
3040 | - |
3041 | - def create_mock_processor(self): |
3042 | - """Create a mock processor from a dummy processor class.""" |
3043 | - self.mockprocessorclass = self.mocker.mock() |
3044 | - mockprocessor = self.mocker.mock() |
3045 | - self.mockprocessorclass(ARGS, KWARGS) |
3046 | - self.mocker.result(mockprocessor) |
3047 | - return mockprocessor |
3048 | - |
3049 | - def test_generate_captcha(self): |
3050 | - """Test that the captcha method works ok.""" |
3051 | - d = defer.Deferred() |
3052 | - filename = "sample filename" |
3053 | - expected_result = "expected result" |
3054 | - self.create_mock_processor().generate_captcha(filename) |
3055 | - self.mocker.result(expected_result) |
3056 | - self.patch(ubuntu_sso.main.linux, "blocking", fake_ok_blocking) |
3057 | - self.mocker.replay() |
3058 | - |
3059 | - def verify(app_name, result): |
3060 | - """The actual test.""" |
3061 | - self.assertEqual(result, expected_result) |
3062 | - self.assertEqual(app_name, APP_NAME) |
3063 | - d.callback(result) |
3064 | - |
3065 | - client = SSOLogin(self.mockbusname, |
3066 | - sso_login_processor_class=self.mockprocessorclass) |
3067 | - self.patch(client, "CaptchaGenerated", verify) |
3068 | - self.patch(client, "CaptchaGenerationError", d.errback) |
3069 | - client.generate_captcha(APP_NAME, filename) |
3070 | - return d |
3071 | - |
3072 | - def test_generate_captcha_error(self): |
3073 | - """Test that the captcha method fails as expected.""" |
3074 | - d = defer.Deferred() |
3075 | - filename = "sample filename" |
3076 | - expected_result = "expected result" |
3077 | - self.create_mock_processor().generate_captcha(filename) |
3078 | - self.mocker.result(expected_result) |
3079 | - self.patch(ubuntu_sso.main, "thread_execute", fake_err_blocking) |
3080 | - self.mocker.replay() |
3081 | - |
3082 | - def verify(app_name, errdict): |
3083 | - """The actual test.""" |
3084 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
3085 | - self.assertEqual(app_name, APP_NAME) |
3086 | - d.callback("Ok") |
3087 | - |
3088 | - client = SSOLogin(self.mockbusname, |
3089 | - sso_login_processor_class=self.mockprocessorclass) |
3090 | - self.patch(client, "CaptchaGenerated", d.errback) |
3091 | - self.patch(client, "CaptchaGenerationError", verify) |
3092 | - client.generate_captcha(APP_NAME, filename) |
3093 | - return d |
3094 | - |
3095 | - def test_register_user(self): |
3096 | - """Test that the register_user method works ok.""" |
3097 | - d = defer.Deferred() |
3098 | - expected_result = "expected result" |
3099 | - self.create_mock_processor().register_user(EMAIL, PASSWORD, NAME, |
3100 | - CAPTCHA_ID, CAPTCHA_SOLUTION) |
3101 | - self.mocker.result(expected_result) |
3102 | - self.patch(ubuntu_sso.main.linux, "blocking", fake_ok_blocking) |
3103 | - self.mocker.replay() |
3104 | - |
3105 | - def verify(app_name, result): |
3106 | - """The actual test.""" |
3107 | - self.assertEqual(result, expected_result) |
3108 | - self.assertEqual(app_name, APP_NAME) |
3109 | - d.callback(result) |
3110 | - |
3111 | - client = SSOLogin(self.mockbusname, |
3112 | - sso_login_processor_class=self.mockprocessorclass) |
3113 | - self.patch(client, "UserRegistered", verify) |
3114 | - self.patch(client, "UserRegistrationError", d.errback) |
3115 | - client.register_user(APP_NAME, EMAIL, PASSWORD, NAME, CAPTCHA_ID, |
3116 | - CAPTCHA_SOLUTION) |
3117 | - return d |
3118 | - |
3119 | - def test_register_user_error(self): |
3120 | - """Test that the register_user method fails as expected.""" |
3121 | - d = defer.Deferred() |
3122 | - expected_result = "expected result" |
3123 | - self.create_mock_processor().register_user(EMAIL, PASSWORD, NAME, |
3124 | - CAPTCHA_ID, CAPTCHA_SOLUTION) |
3125 | - self.mocker.result(expected_result) |
3126 | - self.patch(ubuntu_sso.main, "thread_execute", fake_err_blocking) |
3127 | - self.mocker.replay() |
3128 | - |
3129 | - def verify(app_name, errdict): |
3130 | - """The actual test.""" |
3131 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
3132 | - self.assertEqual(app_name, APP_NAME) |
3133 | - d.callback("Ok") |
3134 | - |
3135 | - client = SSOLogin(self.mockbusname, |
3136 | - sso_login_processor_class=self.mockprocessorclass) |
3137 | - self.patch(client, "UserRegistered", d.errback) |
3138 | - self.patch(client, "UserRegistrationError", verify) |
3139 | - client.register_user(APP_NAME, EMAIL, PASSWORD, NAME, CAPTCHA_ID, |
3140 | - CAPTCHA_SOLUTION) |
3141 | - return d |
3142 | - |
3143 | - def test_login(self): |
3144 | - """Test that the login method works ok.""" |
3145 | - d = defer.Deferred() |
3146 | - processor = self.create_mock_processor() |
3147 | - processor.login(EMAIL, PASSWORD, TOKEN_NAME) |
3148 | - self.mocker.result(TOKEN) |
3149 | - processor.is_validated(TOKEN) |
3150 | - self.mocker.result(True) |
3151 | - self.patch(ubuntu_sso.main.linux, "blocking", fake_ok_blocking) |
3152 | - self.mocker.replay() |
3153 | - |
3154 | - def verify(app_name, result): |
3155 | - """The actual test.""" |
3156 | - self.assertEqual(result, EMAIL) |
3157 | - self.assertEqual(app_name, APP_NAME) |
3158 | - self.assertTrue(self.keyring_was_set, "The keyring should be set") |
3159 | - d.callback(result) |
3160 | - |
3161 | - client = SSOLogin(self.mockbusname, |
3162 | - sso_login_processor_class=self.mockprocessorclass) |
3163 | - self.patch(client, "LoggedIn", verify) |
3164 | - self.patch(client, "LoginError", d.errback) |
3165 | - self.patch(client, "UserNotValidated", d.errback) |
3166 | - client.login(APP_NAME, EMAIL, PASSWORD) |
3167 | - return d |
3168 | - |
3169 | - def test_login_user_not_validated(self): |
3170 | - """Test that the login sends EmailNotValidated signal.""" |
3171 | - d = defer.Deferred() |
3172 | - processor = self.create_mock_processor() |
3173 | - processor.login(EMAIL, PASSWORD, TOKEN_NAME) |
3174 | - self.mocker.result(TOKEN) |
3175 | - processor.is_validated(TOKEN) |
3176 | - self.mocker.result(False) |
3177 | - self.patch(ubuntu_sso.main.linux, "blocking", fake_ok_blocking) |
3178 | - self.mocker.replay() |
3179 | - |
3180 | - def verify(app_name, email): |
3181 | - """The actual test.""" |
3182 | - self.assertEqual(app_name, APP_NAME) |
3183 | - self.assertEqual(email, EMAIL) |
3184 | - self.assertFalse(self.keyring_was_set, "Keyring should not be set") |
3185 | - d.callback("Ok") |
3186 | - |
3187 | - client = SSOLogin(self.mockbusname, |
3188 | - sso_login_processor_class=self.mockprocessorclass) |
3189 | - self.patch(client, "LoggedIn", d.errback) |
3190 | - self.patch(client, "LoginError", d.errback) |
3191 | - self.patch(client, "UserNotValidated", verify) |
3192 | - client.login(APP_NAME, EMAIL, PASSWORD) |
3193 | - return d |
3194 | - |
3195 | - def test_login_error_get_token_name(self): |
3196 | - """The login method fails as expected when get_token_name fails.""" |
3197 | - d = defer.Deferred() |
3198 | - self.create_mock_processor() |
3199 | - self.patch(ubuntu_sso.main.linux, "blocking", fake_err_blocking) |
3200 | - |
3201 | - def fake_gtn(*args): |
3202 | - """A fake get_token_name that fails.""" |
3203 | - raise BlockingSampleException() |
3204 | - |
3205 | - self.patch(ubuntu_sso.main, "get_token_name", fake_gtn) |
3206 | - self.mocker.replay() |
3207 | - |
3208 | - def verify(app_name, errdict): |
3209 | - """The actual test.""" |
3210 | - self.assertEqual(app_name, APP_NAME) |
3211 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
3212 | - self.assertFalse(self.keyring_was_set, "Keyring should not be set") |
3213 | - d.callback("Ok") |
3214 | - |
3215 | - client = SSOLogin(self.mockbusname, |
3216 | - sso_login_processor_class=self.mockprocessorclass) |
3217 | - self.patch(client, "LoggedIn", d.errback) |
3218 | - self.patch(client, "LoginError", verify) |
3219 | - self.patch(client, "UserNotValidated", d.errback) |
3220 | - client.login(APP_NAME, EMAIL, PASSWORD) |
3221 | - return d |
3222 | - |
3223 | - def test_login_error_set_credentials(self): |
3224 | - """The login method fails as expected when set_credentials fails.""" |
3225 | - d = defer.Deferred() |
3226 | - processor = self.create_mock_processor() |
3227 | - processor.login(EMAIL, PASSWORD, TOKEN_NAME) |
3228 | - self.mocker.result(TOKEN) |
3229 | - processor.is_validated(TOKEN) |
3230 | - self.mocker.result(True) |
3231 | - |
3232 | - self.patch(ubuntu_sso.main.linux, "blocking", fake_ok_blocking) |
3233 | - |
3234 | - def fake_set_creds(*args): |
3235 | - """A fake Keyring.set_credentials that fails.""" |
3236 | - return defer.fail(BlockingSampleException()) |
3237 | - |
3238 | - self.patch(ubuntu_sso.main.Keyring, "set_credentials", fake_set_creds) |
3239 | - self.mocker.replay() |
3240 | - |
3241 | - def verify(app_name, errdict): |
3242 | - """The actual test.""" |
3243 | - self.assertEqual(app_name, APP_NAME) |
3244 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
3245 | - self.assertFalse(self.keyring_was_set, "Keyring should not be set") |
3246 | - d.callback("Ok") |
3247 | - |
3248 | - client = SSOLogin(self.mockbusname, |
3249 | - sso_login_processor_class=self.mockprocessorclass) |
3250 | - fail = lambda app, res: d.errback((app, res)) |
3251 | - self.patch(client, "LoggedIn", fail) |
3252 | - self.patch(client, "LoginError", verify) |
3253 | - self.patch(client, "UserNotValidated", fail) |
3254 | - client.login(APP_NAME, EMAIL, PASSWORD) |
3255 | - return d |
3256 | - |
3257 | - def test_validate_email(self): |
3258 | - """Test that the validate_email method works ok.""" |
3259 | - d = defer.Deferred() |
3260 | - self.create_mock_processor().validate_email(EMAIL, PASSWORD, |
3261 | - EMAIL_TOKEN, TOKEN_NAME) |
3262 | - self.mocker.result(TOKEN) |
3263 | - self.patch(ubuntu_sso.main.linux, "blocking", fake_ok_blocking) |
3264 | - self.mocker.replay() |
3265 | - |
3266 | - def verify(app_name, result): |
3267 | - """The actual test.""" |
3268 | - self.assertEqual(result, EMAIL) |
3269 | - self.assertEqual(app_name, APP_NAME) |
3270 | - self.assertTrue(self.keyring_was_set, "The keyring should be set") |
3271 | - d.callback(result) |
3272 | - |
3273 | - client = SSOLogin(self.mockbusname, |
3274 | - sso_login_processor_class=self.mockprocessorclass) |
3275 | - self.patch(client, "EmailValidated", verify) |
3276 | - self.patch(client, "EmailValidationError", d.errback) |
3277 | - client.validate_email(APP_NAME, EMAIL, PASSWORD, EMAIL_TOKEN) |
3278 | - return d |
3279 | - |
3280 | - def test_validate_email_error(self): |
3281 | - """Test that the validate_email method fails as expected.""" |
3282 | - d = defer.Deferred() |
3283 | - self.create_mock_processor() |
3284 | - self.patch(ubuntu_sso.main.linux, "blocking", fake_err_blocking) |
3285 | - |
3286 | - def fake_gtn(*args): |
3287 | - """A fake get_token_name that fails.""" |
3288 | - raise BlockingSampleException() |
3289 | - |
3290 | - self.patch(ubuntu_sso.main, "get_token_name", fake_gtn) |
3291 | - self.mocker.replay() |
3292 | - |
3293 | - def verify(app_name, errdict): |
3294 | - """The actual test.""" |
3295 | - self.assertEqual(app_name, APP_NAME) |
3296 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
3297 | - self.assertFalse(self.keyring_was_set, "Keyring should not be set") |
3298 | - d.callback("Ok") |
3299 | - |
3300 | - client = SSOLogin(self.mockbusname, |
3301 | - sso_login_processor_class=self.mockprocessorclass) |
3302 | - self.patch(client, "EmailValidated", d.errback) |
3303 | - self.patch(client, "EmailValidationError", verify) |
3304 | - client.validate_email(APP_NAME, EMAIL, PASSWORD, EMAIL_TOKEN) |
3305 | - return d |
3306 | - |
3307 | - def test_request_password_reset_token(self): |
3308 | - """Test that the request_password_reset_token method works ok.""" |
3309 | - d = defer.Deferred() |
3310 | - processor = self.create_mock_processor() |
3311 | - processor.request_password_reset_token(EMAIL) |
3312 | - self.patch(ubuntu_sso.main, "thread_execute", fake_ok_blocking) |
3313 | - self.mocker.result(EMAIL) |
3314 | - self.mocker.replay() |
3315 | - |
3316 | - def verify(app_name, result): |
3317 | - """The actual test.""" |
3318 | - self.assertEqual(result, EMAIL) |
3319 | - self.assertEqual(app_name, APP_NAME) |
3320 | - d.callback(result) |
3321 | - |
3322 | - client = SSOLogin(self.mockbusname, |
3323 | - sso_login_processor_class=self.mockprocessorclass) |
3324 | - self.patch(client, "PasswordResetTokenSent", verify) |
3325 | - self.patch(client, "PasswordResetError", d.errback) |
3326 | - client.request_password_reset_token(APP_NAME, EMAIL) |
3327 | - return d |
3328 | - |
3329 | - def test_request_password_reset_token_error(self): |
3330 | - """Test the request_password_reset_token method fails as expected.""" |
3331 | - d = defer.Deferred() |
3332 | - |
3333 | - self.create_mock_processor().request_password_reset_token(EMAIL) |
3334 | - self.mocker.result(EMAIL) |
3335 | - self.patch(ubuntu_sso.main, "thread_execute", fake_err_blocking) |
3336 | - self.mocker.replay() |
3337 | - |
3338 | - def verify(app_name, errdict): |
3339 | - """The actual test.""" |
3340 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
3341 | - self.assertEqual(app_name, APP_NAME) |
3342 | - d.callback("Ok") |
3343 | - |
3344 | - client = SSOLogin(self.mockbusname, |
3345 | - sso_login_processor_class=self.mockprocessorclass) |
3346 | - self.patch(client, "PasswordResetTokenSent", d.errback) |
3347 | - self.patch(client, "PasswordResetError", verify) |
3348 | - client.request_password_reset_token(APP_NAME, EMAIL) |
3349 | - return d |
3350 | - |
3351 | - def test_set_new_password(self): |
3352 | - """Test that the set_new_password method works ok.""" |
3353 | - d = defer.Deferred() |
3354 | - self.create_mock_processor().set_new_password(EMAIL, EMAIL_TOKEN, |
3355 | - PASSWORD) |
3356 | - self.mocker.result(EMAIL) |
3357 | - self.patch(ubuntu_sso.main.linux, "blocking", fake_ok_blocking) |
3358 | - self.mocker.replay() |
3359 | - |
3360 | - def verify(app_name, result): |
3361 | - """The actual test.""" |
3362 | - self.assertEqual(result, EMAIL) |
3363 | - self.assertEqual(app_name, APP_NAME) |
3364 | - d.callback(result) |
3365 | - |
3366 | - client = SSOLogin(self.mockbusname, |
3367 | - sso_login_processor_class=self.mockprocessorclass) |
3368 | - self.patch(client, "PasswordChanged", verify) |
3369 | - self.patch(client, "PasswordChangeError", d.errback) |
3370 | - client.set_new_password(APP_NAME, EMAIL, EMAIL_TOKEN, PASSWORD) |
3371 | - return d |
3372 | - |
3373 | - def test_set_new_password_error(self): |
3374 | - """Test that the set_new_password method fails as expected.""" |
3375 | - d = defer.Deferred() |
3376 | - expected_result = "expected result" |
3377 | - |
3378 | - self.create_mock_processor().set_new_password(EMAIL, EMAIL_TOKEN, |
3379 | - PASSWORD) |
3380 | - self.mocker.result(expected_result) |
3381 | - self.patch(ubuntu_sso.main, "thread_execute", fake_err_blocking) |
3382 | - self.mocker.replay() |
3383 | - |
3384 | - def verify(app_name, errdict): |
3385 | - """The actual test.""" |
3386 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
3387 | - self.assertEqual(app_name, APP_NAME) |
3388 | - d.callback("Ok") |
3389 | - |
3390 | - client = SSOLogin(self.mockbusname, |
3391 | - sso_login_processor_class=self.mockprocessorclass) |
3392 | - self.patch(client, "PasswordChanged", d.errback) |
3393 | - self.patch(client, "PasswordChangeError", verify) |
3394 | - client.set_new_password(APP_NAME, EMAIL, EMAIL_TOKEN, PASSWORD) |
3395 | - return d |
3396 | - |
3397 | - |
3398 | -class BlockingFunctionTestCase(TestCase): |
3399 | - """Tests for the "blocking" function.""" |
3400 | - |
3401 | - timeout = 5 |
3402 | - |
3403 | - def test_blocking(self): |
3404 | - """Test the normal behaviour.""" |
3405 | - d = defer.Deferred() |
3406 | - expected_result = "expected result" |
3407 | - |
3408 | - def f(): |
3409 | - """No failure.""" |
3410 | - return expected_result |
3411 | - |
3412 | - def verify(app_name, result): |
3413 | - """The actual test.""" |
3414 | - self.assertEqual(result, expected_result) |
3415 | - self.assertEqual(app_name, APP_NAME) |
3416 | - d.callback(result) |
3417 | - |
3418 | - blocking(f, APP_NAME, verify, d.errback) |
3419 | - return d |
3420 | - |
3421 | - def test_blocking_error(self): |
3422 | - """Test the behaviour when an Exception is raised.""" |
3423 | - d = defer.Deferred() |
3424 | - expected_error_message = "expected error message" |
3425 | - |
3426 | - def f(): |
3427 | - """Failure.""" |
3428 | - raise BlockingSampleException(expected_error_message) |
3429 | - |
3430 | - def verify(app_name, errdict): |
3431 | - """The actual test.""" |
3432 | - self.assertEqual(app_name, APP_NAME) |
3433 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
3434 | - self.assertEqual(errdict["message"], expected_error_message) |
3435 | - d.callback("Ok") |
3436 | - |
3437 | - blocking(f, APP_NAME, d.errback, verify) |
3438 | - return d |
3439 | - |
3440 | - |
3441 | -class TestExceptToErrdictException(Exception): |
3442 | - """A dummy exception for the following testcase.""" |
3443 | - |
3444 | - |
3445 | -class ExceptToErrdictTestCase(TestCase): |
3446 | - """Tests for the except_to_errdict function.""" |
3447 | - |
3448 | - def test_first_arg_is_dict(self): |
3449 | - """If the first arg is a dict, use it as the base dict.""" |
3450 | - sample_dict = { |
3451 | - "errorcode1": "error message 1", |
3452 | - "errorcode2": "error message 2", |
3453 | - "errorcode3": "error message 3", |
3454 | - } |
3455 | - e = TestExceptToErrdictException(sample_dict) |
3456 | - result = except_to_errdict(e) |
3457 | - |
3458 | - self.assertEqual(result["errtype"], e.__class__.__name__) |
3459 | - for k in sample_dict.keys(): |
3460 | - self.assertIn(k, result) |
3461 | - self.assertEqual(result[k], sample_dict[k]) |
3462 | - |
3463 | - def test_first_arg_is_str(self): |
3464 | - """If the first arg is a str, use it as the message.""" |
3465 | - sample_string = "a sample string" |
3466 | - e = TestExceptToErrdictException(sample_string) |
3467 | - result = except_to_errdict(e) |
3468 | - self.assertEqual(result["errtype"], e.__class__.__name__) |
3469 | - self.assertEqual(result["message"], sample_string) |
3470 | - |
3471 | - def test_first_arg_is_unicode(self): |
3472 | - """If the first arg is a unicode, use it as the message.""" |
3473 | - sample_string = u"a sample string" |
3474 | - e = TestExceptToErrdictException(sample_string) |
3475 | - result = except_to_errdict(e) |
3476 | - self.assertEqual(result["errtype"], e.__class__.__name__) |
3477 | - self.assertEqual(result["message"], sample_string) |
3478 | - |
3479 | - def test_no_args_at_all(self): |
3480 | - """If there are no args, use the class docstring.""" |
3481 | - e = TestExceptToErrdictException() |
3482 | - result = except_to_errdict(e) |
3483 | - self.assertEqual(result["errtype"], e.__class__.__name__) |
3484 | - self.assertEqual(result["message"], e.__class__.__doc__) |
3485 | - |
3486 | - def test_some_other_thing_as_first_arg(self): |
3487 | - """If first arg is not basestring nor dict, then repr all args.""" |
3488 | - sample_args = (None, u"unicode2\ufffd", "errorcode3") |
3489 | - e = TestExceptToErrdictException(*sample_args) |
3490 | - result = except_to_errdict(e) |
3491 | - self.assertEqual(result["errtype"], e.__class__.__name__) |
3492 | - |
3493 | - |
3494 | -class CredentialsManagementTestCase(TestCase): |
3495 | - """Tests for the CredentialsManagement DBus interface.""" |
3496 | - |
3497 | - timeout = 2 |
3498 | - base_args = {HELP_TEXT_KEY: HELP_TEXT, PING_URL_KEY: PING_URL, |
3499 | - TC_URL_KEY: TC_URL, WINDOW_ID_KEY: WINDOW_ID, |
3500 | - UI_CLASS_KEY: 'SuperUI', UI_MODULE_KEY: 'foo.bar.baz', |
3501 | - } |
3502 | - |
3503 | - @defer.inlineCallbacks |
3504 | - def setUp(self): |
3505 | - yield super(CredentialsManagementTestCase, self).setUp() |
3506 | - |
3507 | - self.mocker = Mocker() |
3508 | - self.client = CredentialsManagement(timeout_func=lambda *a: None, |
3509 | - shutdown_func=lambda *a: None) |
3510 | - self.args = {} |
3511 | - self.cred_args = {} |
3512 | - |
3513 | - self.memento = MementoHandler() |
3514 | - self.memento.setLevel(logging.DEBUG) |
3515 | - ubuntu_sso.main.logger.addHandler(self.memento) |
3516 | - self.addCleanup(ubuntu_sso.main.logger.removeHandler, self.memento) |
3517 | - |
3518 | - @defer.inlineCallbacks |
3519 | - def tearDown(self): |
3520 | - """Verify the mocking stuff and shut it down.""" |
3521 | - self.mocker.verify() |
3522 | - self.mocker.restore() |
3523 | - yield super(CredentialsManagementTestCase, self).tearDown() |
3524 | - |
3525 | - def assert_dbus_method_correct(self, method, out_signature=''): |
3526 | - """Check that 'method' is a dbus method with proper signatures.""" |
3527 | - self.assertTrue(method._dbus_is_method) |
3528 | - self.assertEqual(method._dbus_interface, DBUS_CREDENTIALS_IFACE) |
3529 | - self.assertEqual(method._dbus_in_signature, 'sa{ss}') |
3530 | - self.assertEqual(method._dbus_out_signature, out_signature) |
3531 | - |
3532 | - def create_mock_backend(self): |
3533 | - """Create a mock backend.""" |
3534 | - mock_class = self.mocker.replace("ubuntu_sso.credentials.Credentials") |
3535 | - mock_class(APP_NAME, **self.cred_args) |
3536 | - creds_obj = self.mocker.mock() |
3537 | - self.mocker.result(creds_obj) |
3538 | - |
3539 | - return creds_obj |
3540 | - |
3541 | - def test_is_dbus_object(self): |
3542 | - """CredentialsManagement is a Dbus object.""" |
3543 | - self.assertIsInstance(self.client, |
3544 | - ubuntu_sso.main.linux.dbus.service.Object) |
3545 | - |
3546 | - |
3547 | -class FakeCredentials(object): |
3548 | - """A very dummy Credentials object.""" |
3549 | - |
3550 | - def __init__(self, *a, **kw): |
3551 | - self.clear_credentials = lambda *a: defer.succeed(None) |
3552 | - self.store_credentials = lambda *a: defer.succeed(None) |
3553 | - self.login = self.register = lambda *a: None |
3554 | - |
3555 | - def find_credentials(self, *a, **kw): |
3556 | - """Retrieve credentials.""" |
3557 | - return defer.succeed(TOKEN) |
3558 | - |
3559 | - |
3560 | -class CredentialsManagementRefCountingTestCase(CredentialsManagementTestCase): |
3561 | - """Tests for the CredentialsManagement ref counting.""" |
3562 | - |
3563 | - @defer.inlineCallbacks |
3564 | - def setUp(self): |
3565 | - yield super(CredentialsManagementRefCountingTestCase, self).setUp() |
3566 | - self.patch(ubuntu_sso.main, 'Credentials', FakeCredentials) |
3567 | - |
3568 | - def test_ref_counting(self): |
3569 | - """Ref counting is in place.""" |
3570 | - self.assertEqual(self.client.root.ref_count, 0) |
3571 | - |
3572 | - def test_find_credentials(self): |
3573 | - """Keep proper track of on going requests.""" |
3574 | - d = defer.Deferred() |
3575 | - |
3576 | - def verify(*args): |
3577 | - """Make the check.""" |
3578 | - self.assertEqual(self.client.root.ref_count, 1) |
3579 | - d.callback(True) |
3580 | - |
3581 | - self.patch(self.client, 'CredentialsFound', verify) |
3582 | - self.client.find_credentials(APP_NAME, self.args) |
3583 | - |
3584 | - return d |
3585 | - |
3586 | - @defer.inlineCallbacks |
3587 | - def test_find_credentials_sync(self): |
3588 | - """Keep proper track of on going requests.""" |
3589 | - d = defer.Deferred() |
3590 | - |
3591 | - def verify(*args): |
3592 | - """Make the check.""" |
3593 | - self.assertEqual(self.client.root.ref_count, 1) |
3594 | - d.callback(True) |
3595 | - |
3596 | - self.client.find_credentials_sync(APP_NAME, self.args, |
3597 | - reply_handler=verify, |
3598 | - error_handler=d.errback) |
3599 | - yield d |
3600 | - self.assertEqual(self.client.root.ref_count, 0) |
3601 | - |
3602 | - @defer.inlineCallbacks |
3603 | - def test_find_credentials_sync_error(self): |
3604 | - """Keep proper track of on going requests.""" |
3605 | - d = defer.Deferred() |
3606 | - |
3607 | - def verify(*args): |
3608 | - """Make the check.""" |
3609 | - self.assertEqual(self.client.root.ref_count, 1) |
3610 | - d.callback(True) |
3611 | - |
3612 | - self.patch(ubuntu_sso.main.Credentials, 'find_credentials', |
3613 | - lambda *a: defer.fail('foo')) |
3614 | - self.client.find_credentials_sync(APP_NAME, self.args, |
3615 | - reply_handler=d.errback, |
3616 | - error_handler=verify) |
3617 | - |
3618 | - yield d |
3619 | - self.assertEqual(self.client.root.ref_count, 0) |
3620 | - |
3621 | - def test_clear_credentials(self): |
3622 | - """Keep proper track of on going requests.""" |
3623 | - d = defer.Deferred() |
3624 | - |
3625 | - def verify(*args): |
3626 | - """Make the check.""" |
3627 | - self.assertEqual(self.client.root.ref_count, 1) |
3628 | - d.callback(True) |
3629 | - |
3630 | - self.patch(self.client, 'CredentialsCleared', verify) |
3631 | - self.client.clear_credentials(APP_NAME, self.args) |
3632 | - |
3633 | - return d |
3634 | - |
3635 | - def test_store_credentials(self): |
3636 | - """Keep proper track of on going requests.""" |
3637 | - d = defer.Deferred() |
3638 | - |
3639 | - def verify(*args): |
3640 | - """Make the check.""" |
3641 | - self.assertEqual(self.client.root.ref_count, 1) |
3642 | - d.callback(True) |
3643 | - |
3644 | - self.patch(self.client, 'CredentialsStored', verify) |
3645 | - self.client.store_credentials(APP_NAME, self.args) |
3646 | - |
3647 | - return d |
3648 | - |
3649 | - def test_register(self): |
3650 | - """Keep proper track of on going requests.""" |
3651 | - self.client.register(APP_NAME, self.args) |
3652 | - |
3653 | - self.assertEqual(self.client.root.ref_count, 1) |
3654 | - |
3655 | - def test_login(self): |
3656 | - """Keep proper track of on going requests.""" |
3657 | - self.client.login(APP_NAME, self.args) |
3658 | - |
3659 | - self.assertEqual(self.client.root.ref_count, 1) |
3660 | - |
3661 | - def test_several_requests(self): |
3662 | - """Requests can be nested.""" |
3663 | - self.client.login(APP_NAME, self.args) |
3664 | - self.client.register(APP_NAME, self.args) |
3665 | - self.client.login(APP_NAME, self.args) |
3666 | - self.client.register(APP_NAME, self.args) |
3667 | - self.client.register(APP_NAME, self.args) |
3668 | - |
3669 | - self.assertEqual(self.client.root.ref_count, 5) |
3670 | - |
3671 | - def test_credentials_found(self): |
3672 | - """Ref counter is decreased when a signal is sent.""" |
3673 | - self.client.root.ref_count = 3 |
3674 | - self.client.CredentialsFound(APP_NAME, TOKEN) |
3675 | - |
3676 | - self.assertEqual(self.client.root.ref_count, 2) |
3677 | - |
3678 | - def test_credentials_not_found(self): |
3679 | - """Ref counter is decreased when a signal is sent.""" |
3680 | - self.client.root.ref_count = 3 |
3681 | - self.client.CredentialsNotFound(APP_NAME) |
3682 | - |
3683 | - self.assertEqual(self.client.root.ref_count, 2) |
3684 | - |
3685 | - def test_credentials_cleared(self): |
3686 | - """Ref counter is decreased when a signal is sent.""" |
3687 | - self.client.root.ref_count = 3 |
3688 | - self.client.CredentialsCleared(APP_NAME) |
3689 | - |
3690 | - self.assertEqual(self.client.root.ref_count, 2) |
3691 | - |
3692 | - def test_credentials_stored(self): |
3693 | - """Ref counter is decreased when a signal is sent.""" |
3694 | - self.client.root.ref_count = 3 |
3695 | - self.client.CredentialsStored(APP_NAME) |
3696 | - |
3697 | - self.assertEqual(self.client.root.ref_count, 2) |
3698 | - |
3699 | - def test_credentials_error(self): |
3700 | - """Ref counter is decreased when a signal is sent.""" |
3701 | - self.client.root.ref_count = 3 |
3702 | - self.client.CredentialsError(APP_NAME, {'error_type': 'test'}) |
3703 | - |
3704 | - self.assertEqual(self.client.root.ref_count, 2) |
3705 | - |
3706 | - def test_authorization_denied(self): |
3707 | - """Ref counter is decreased when a signal is sent.""" |
3708 | - self.client.root.ref_count = 3 |
3709 | - self.client.AuthorizationDenied(APP_NAME) |
3710 | - |
3711 | - self.assertEqual(self.client.root.ref_count, 2) |
3712 | - |
3713 | - def test_credentials_found_when_ref_count_is_not_positive(self): |
3714 | - """Ref counter is decreased when a signal is sent.""" |
3715 | - self.client.root._ref_count = -3 |
3716 | - self.client.CredentialsFound(APP_NAME, TOKEN) |
3717 | - |
3718 | - self.assertEqual(self.client.root.ref_count, 0) |
3719 | - msg = 'Attempting to decrease ref_count to a negative value (-4).' |
3720 | - self.assertTrue(self.memento.check_warning(msg)) |
3721 | - |
3722 | - def test_credentials_not_found_when_ref_count_is_not_positive(self): |
3723 | - """Ref counter is decreased when a signal is sent.""" |
3724 | - self.client.root._ref_count = -3 |
3725 | - self.client.CredentialsNotFound(APP_NAME) |
3726 | - |
3727 | - self.assertEqual(self.client.root.ref_count, 0) |
3728 | - msg = 'Attempting to decrease ref_count to a negative value (-4).' |
3729 | - self.assertTrue(self.memento.check_warning(msg)) |
3730 | - |
3731 | - def test_credentials_cleared_when_ref_count_is_not_positive(self): |
3732 | - """Ref counter is decreased when a signal is sent.""" |
3733 | - self.client.root._ref_count = -3 |
3734 | - self.client.CredentialsCleared(APP_NAME) |
3735 | - |
3736 | - self.assertEqual(self.client.root.ref_count, 0) |
3737 | - msg = 'Attempting to decrease ref_count to a negative value (-4).' |
3738 | - self.assertTrue(self.memento.check_warning(msg)) |
3739 | - |
3740 | - def test_credentials_stored_when_ref_count_is_not_positive(self): |
3741 | - """Ref counter is decreased when a signal is sent.""" |
3742 | - self.client.root._ref_count = -3 |
3743 | - self.client.CredentialsStored(APP_NAME) |
3744 | - |
3745 | - self.assertEqual(self.client.root.ref_count, 0) |
3746 | - msg = 'Attempting to decrease ref_count to a negative value (-4).' |
3747 | - self.assertTrue(self.memento.check_warning(msg)) |
3748 | - |
3749 | - def test_credentials_error_when_ref_count_is_not_positive(self): |
3750 | - """Ref counter is decreased when a signal is sent.""" |
3751 | - self.client.root._ref_count = -3 |
3752 | - self.client.CredentialsError(APP_NAME, {'error_type': 'test'}) |
3753 | - |
3754 | - self.assertEqual(self.client.root.ref_count, 0) |
3755 | - msg = 'Attempting to decrease ref_count to a negative value (-4).' |
3756 | - self.assertTrue(self.memento.check_warning(msg)) |
3757 | - |
3758 | - def test_autorization_denied_when_ref_count_is_not_positive(self): |
3759 | - """Ref counter is decreased when a signal is sent.""" |
3760 | - self.client.root._ref_count = -3 |
3761 | - self.client.AuthorizationDenied(APP_NAME) |
3762 | - |
3763 | - self.assertEqual(self.client.root.ref_count, 0) |
3764 | - msg = 'Attempting to decrease ref_count to a negative value (-4).' |
3765 | - self.assertTrue(self.memento.check_warning(msg)) |
3766 | - |
3767 | - def test_on_zero_ref_count_shutdown(self): |
3768 | - """When ref count reaches 0, queue shutdown op.""" |
3769 | - self.patch(self.client.root, 'timeout_func', self._set_called) |
3770 | - self.client.login(APP_NAME, self.args) |
3771 | - self.client.CredentialsFound(APP_NAME, TOKEN) |
3772 | - |
3773 | - self.assertEqual(self._called, |
3774 | - ((TIMEOUT_INTERVAL, self.client.root.shutdown), {})) |
3775 | - |
3776 | - def test_on_non_zero_ref_count_do_not_shutdown(self): |
3777 | - """If ref count is not 0, do not queue shutdown op.""" |
3778 | - self.patch(self.client.root, 'timeout_func', self._set_called) |
3779 | - self.client.login(APP_NAME, self.args) |
3780 | - |
3781 | - self.assertEqual(self._called, False) |
3782 | - |
3783 | - def test_on_non_zero_ref_count_after_zero_do_not_shutdown(self): |
3784 | - """If the shutdown was queued, do not quit if counter is not zero.""" |
3785 | - |
3786 | - def fake_timeout_func(interval, func): |
3787 | - """Start a new request when the timer is started.""" |
3788 | - self.client.register(APP_NAME, self.args) |
3789 | - assert self.client.root.ref_count > 0 |
3790 | - func() |
3791 | - |
3792 | - self.patch(self.client.root, 'timeout_func', fake_timeout_func) |
3793 | - self.patch(self.client.root, 'shutdown_func', self._set_called) |
3794 | - |
3795 | - self.client.login(APP_NAME, self.args) |
3796 | - self.client.CredentialsFound(APP_NAME, TOKEN) |
3797 | - # counter reached 0, timeout_func was called |
3798 | - |
3799 | - self.assertEqual(self._called, False, 'shutdown_func was not called') |
3800 | - |
3801 | - def test_zero_ref_count_after_zero_do_shutdown(self): |
3802 | - """If the shutdown was queued, do quit if counter is zero.""" |
3803 | - |
3804 | - def fake_timeout_func(interval, func): |
3805 | - """Start a new request when the timer is started.""" |
3806 | - assert self.client.root.ref_count == 0 |
3807 | - func() |
3808 | - |
3809 | - self.patch(self.client.root, 'timeout_func', fake_timeout_func) |
3810 | - self.patch(self.client.root, 'shutdown_func', self._set_called) |
3811 | - |
3812 | - self.client.login(APP_NAME, self.args) |
3813 | - self.client.CredentialsFound(APP_NAME, TOKEN) |
3814 | - # counter reached 0, timeout_func was called |
3815 | - |
3816 | - self.assertEqual(self._called, ((), {}), 'shutdown_func was called') |
3817 | - |
3818 | - |
3819 | -class CredentialsManagementFindTestCase(CredentialsManagementTestCase): |
3820 | - """Tests for the CredentialsManagement find method.""" |
3821 | - |
3822 | - def test_find_credentials(self): |
3823 | - """The credentials are asked and returned in signals.""" |
3824 | - self.create_mock_backend().find_credentials() |
3825 | - self.mocker.result(defer.succeed(None)) |
3826 | - self.mocker.replay() |
3827 | - |
3828 | - self.client.find_credentials(APP_NAME, self.args) |
3829 | - self.assert_dbus_method_correct(self.client.find_credentials) |
3830 | - |
3831 | - def test_find_credentials_does_not_block_when_found(self): |
3832 | - """Calling find_credentials does not block but return thru signals. |
3833 | - |
3834 | - If the creds are found, CredentialsFound is emitted. |
3835 | - |
3836 | - """ |
3837 | - d = defer.Deferred() |
3838 | - |
3839 | - def verify(app_name, creds): |
3840 | - """The actual test.""" |
3841 | - try: |
3842 | - self.assertEqual(app_name, APP_NAME) |
3843 | - self.assertEqual(creds, TOKEN) |
3844 | - except Exception, e: # pylint: disable=W0703 |
3845 | - d.errback(e) |
3846 | - else: |
3847 | - d.callback(creds) |
3848 | - |
3849 | - self.patch(self.client, 'CredentialsFound', verify) |
3850 | - self.patch(self.client, 'CredentialsNotFound', d.errback) |
3851 | - |
3852 | - self.create_mock_backend().find_credentials() |
3853 | - self.mocker.result(defer.succeed(TOKEN)) |
3854 | - self.mocker.replay() |
3855 | - |
3856 | - self.client.find_credentials(APP_NAME, self.args) |
3857 | - return d |
3858 | - |
3859 | - def test_find_credentials_does_not_block_when_not_found(self): |
3860 | - """Calling find_credentials does not block but return thru signals. |
3861 | - |
3862 | - If the creds are not found, CredentialsNotFound is emitted. |
3863 | - |
3864 | - """ |
3865 | - d = defer.Deferred() |
3866 | - |
3867 | - def verify(app_name): |
3868 | - """The actual test.""" |
3869 | - try: |
3870 | - self.assertEqual(app_name, APP_NAME) |
3871 | - except Exception, e: # pylint: disable=W0703 |
3872 | - d.errback(e) |
3873 | - else: |
3874 | - d.callback(app_name) |
3875 | - |
3876 | - self.patch(self.client, 'CredentialsFound', |
3877 | - lambda app, creds: d.errback(app)) |
3878 | - self.patch(self.client, 'CredentialsNotFound', verify) |
3879 | - |
3880 | - self.create_mock_backend().find_credentials() |
3881 | - self.mocker.result(defer.succeed({})) |
3882 | - self.mocker.replay() |
3883 | - |
3884 | - self.client.find_credentials(APP_NAME, self.args) |
3885 | - return d |
3886 | - |
3887 | - def test_find_credentials_error(self): |
3888 | - """If find_credentials fails, CredentialsError is sent.""" |
3889 | - d = defer.Deferred() |
3890 | - |
3891 | - def verify(app_name, errdict): |
3892 | - """The actual test.""" |
3893 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
3894 | - self.assertEqual(app_name, APP_NAME) |
3895 | - d.callback("Ok") |
3896 | - |
3897 | - self.patch(self.client, 'CredentialsFound', |
3898 | - lambda app, creds: d.errback(app)) |
3899 | - self.patch(self.client, 'CredentialsNotFound', d.errback) |
3900 | - self.patch(self.client, 'CredentialsError', verify) |
3901 | - |
3902 | - self.create_mock_backend().find_credentials() |
3903 | - self.mocker.result(defer.fail(BlockingSampleException())) |
3904 | - self.mocker.replay() |
3905 | - |
3906 | - self.client.find_credentials(APP_NAME, self.args) |
3907 | - return d |
3908 | - |
3909 | - def test_find_credentials_sync(self): |
3910 | - """The credentials are asked and returned in a blocking call.""" |
3911 | - d = defer.Deferred() |
3912 | - |
3913 | - def verify(creds): |
3914 | - """The actual test.""" |
3915 | - try: |
3916 | - self.assertEqual(creds, TOKEN) |
3917 | - except Exception, e: # pylint: disable=W0703 |
3918 | - d.errback(e) |
3919 | - else: |
3920 | - d.callback(creds) |
3921 | - |
3922 | - self.create_mock_backend().find_credentials() |
3923 | - self.mocker.result(defer.succeed(TOKEN)) |
3924 | - self.mocker.replay() |
3925 | - |
3926 | - self.client.find_credentials_sync(APP_NAME, self.args, |
3927 | - reply_handler=verify, |
3928 | - error_handler=d.errback) |
3929 | - self.assert_dbus_method_correct(self.client.find_credentials_sync, |
3930 | - out_signature='a{ss}') |
3931 | - return d |
3932 | - |
3933 | - def test_find_credentials_sync_error(self): |
3934 | - """If find_credentials_sync fails, error_handler is called.""" |
3935 | - d = defer.Deferred() |
3936 | - |
3937 | - def verify(error): |
3938 | - """The actual test.""" |
3939 | - try: |
3940 | - errdict = error.args[0] |
3941 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
3942 | - except Exception, e: # pylint: disable=W0703 |
3943 | - d.errback(e) |
3944 | - else: |
3945 | - d.callback("Ok") |
3946 | - |
3947 | - self.create_mock_backend().find_credentials() |
3948 | - self.mocker.result(defer.fail(BlockingSampleException())) |
3949 | - self.mocker.replay() |
3950 | - |
3951 | - self.client.find_credentials_sync(APP_NAME, self.args, |
3952 | - reply_handler=d.errback, |
3953 | - error_handler=verify) |
3954 | - return d |
3955 | - |
3956 | - |
3957 | -class CredentialsManagementClearTestCase(CredentialsManagementTestCase): |
3958 | - """Tests for the CredentialsManagement clear method.""" |
3959 | - |
3960 | - def test_clear_credentials(self): |
3961 | - """The credentials are removed.""" |
3962 | - self.create_mock_backend().clear_credentials() |
3963 | - self.mocker.result(defer.succeed(APP_NAME)) |
3964 | - self.mocker.replay() |
3965 | - |
3966 | - self.client.clear_credentials(APP_NAME, self.args) |
3967 | - self.assert_dbus_method_correct(self.client.clear_credentials) |
3968 | - |
3969 | - def test_clear_credentials_does_not_block(self): |
3970 | - """Calling clear_credentials does not block but return thru signals.""" |
3971 | - d = defer.Deferred() |
3972 | - |
3973 | - def verify(app_name): |
3974 | - """The actual test.""" |
3975 | - try: |
3976 | - self.assertEqual(app_name, APP_NAME) |
3977 | - except Exception, e: # pylint: disable=W0703 |
3978 | - d.errback(e) |
3979 | - else: |
3980 | - d.callback(app_name) |
3981 | - |
3982 | - self.patch(self.client, 'CredentialsCleared', verify) |
3983 | - self.patch(self.client, 'CredentialsError', |
3984 | - lambda app, err: d.errback(app)) |
3985 | - |
3986 | - self.create_mock_backend().clear_credentials() |
3987 | - self.mocker.result(defer.succeed(APP_NAME)) |
3988 | - self.mocker.replay() |
3989 | - |
3990 | - self.client.clear_credentials(APP_NAME, self.args) |
3991 | - return d |
3992 | - |
3993 | - def test_clear_credentials_error(self): |
3994 | - """If clear_credentials fails, CredentialsError is sent.""" |
3995 | - d = defer.Deferred() |
3996 | - |
3997 | - def verify(app_name, errdict): |
3998 | - """The actual test.""" |
3999 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
4000 | - self.assertEqual(app_name, APP_NAME) |
4001 | - d.callback("Ok") |
4002 | - |
4003 | - self.patch(self.client, 'CredentialsCleared', d.errback) |
4004 | - self.patch(self.client, 'CredentialsError', verify) |
4005 | - |
4006 | - self.create_mock_backend().clear_credentials() |
4007 | - self.mocker.result(defer.fail(BlockingSampleException())) |
4008 | - self.mocker.replay() |
4009 | - |
4010 | - self.client.clear_credentials(APP_NAME, self.args) |
4011 | - return d |
4012 | - |
4013 | - |
4014 | -class CredentialsManagementStoreTestCase(CredentialsManagementTestCase): |
4015 | - """Tests for the CredentialsManagement store method.""" |
4016 | - |
4017 | - def test_store_credentials(self): |
4018 | - """The credentials are stored and the outcome is a signal.""" |
4019 | - self.create_mock_backend().store_credentials(TOKEN) |
4020 | - self.mocker.result(defer.succeed(APP_NAME)) |
4021 | - self.mocker.replay() |
4022 | - |
4023 | - self.client.store_credentials(APP_NAME, TOKEN) |
4024 | - self.assert_dbus_method_correct(self.client.store_credentials) |
4025 | - |
4026 | - def test_store_credentials_does_not_block(self): |
4027 | - """Calling store_credentials does not block but return thru signals. |
4028 | - |
4029 | - If the creds are stored, CredentialsStored is emitted. |
4030 | - |
4031 | - """ |
4032 | - d = defer.Deferred() |
4033 | - |
4034 | - def verify(app_name): |
4035 | - """The actual test.""" |
4036 | - try: |
4037 | - self.assertEqual(app_name, APP_NAME) |
4038 | - except Exception, e: # pylint: disable=W0703 |
4039 | - d.errback(e) |
4040 | - else: |
4041 | - d.callback(app_name) |
4042 | - |
4043 | - self.patch(self.client, 'CredentialsStored', verify) |
4044 | - self.patch(self.client, 'CredentialsError', |
4045 | - lambda app, err: d.errback(app)) |
4046 | - |
4047 | - self.create_mock_backend().store_credentials(TOKEN) |
4048 | - self.mocker.result(defer.succeed(APP_NAME)) |
4049 | - self.mocker.replay() |
4050 | - |
4051 | - self.client.store_credentials(APP_NAME, TOKEN) |
4052 | - return d |
4053 | - |
4054 | - def test_store_credentials_error(self): |
4055 | - """If store_credentials fails, CredentialsError is sent.""" |
4056 | - d = defer.Deferred() |
4057 | - |
4058 | - def verify(app_name, errdict): |
4059 | - """The actual test.""" |
4060 | - self.assertEqual(errdict["errtype"], "BlockingSampleException") |
4061 | - self.assertEqual(app_name, APP_NAME) |
4062 | - d.callback("Ok") |
4063 | - |
4064 | - self.patch(self.client, 'CredentialsStored', d.errback) |
4065 | - self.patch(self.client, 'CredentialsError', verify) |
4066 | - |
4067 | - self.create_mock_backend().store_credentials(TOKEN) |
4068 | - self.mocker.result(defer.fail(BlockingSampleException())) |
4069 | - self.mocker.replay() |
4070 | - |
4071 | - self.client.store_credentials(APP_NAME, TOKEN) |
4072 | - return d |
4073 | - |
4074 | - |
4075 | -class CredentialsManagementOpsTestCase(CredentialsManagementTestCase): |
4076 | - """Tests for the CredentialsManagement login/register methods.""" |
4077 | - |
4078 | - @defer.inlineCallbacks |
4079 | - def setUp(self): |
4080 | - yield super(CredentialsManagementOpsTestCase, self).setUp() |
4081 | - self.args = dict((k, str(v)) for k, v in self.base_args.iteritems()) |
4082 | - self.cred_args = self.base_args.copy() |
4083 | - self.cred_args[SUCCESS_CB_KEY] = self.client.CredentialsFound |
4084 | - self.cred_args[ERROR_CB_KEY] = self.client.CredentialsError |
4085 | - self.cred_args[DENIAL_CB_KEY] = self.client.AuthorizationDenied |
4086 | - |
4087 | - def test_register(self): |
4088 | - """The registration is correct.""" |
4089 | - self.create_mock_backend().register() |
4090 | - self.mocker.replay() |
4091 | - |
4092 | - self.client.register(APP_NAME, self.args) |
4093 | - self.assert_dbus_method_correct(self.client.register) |
4094 | - |
4095 | - def test_login(self): |
4096 | - """The login is correct.""" |
4097 | - self.create_mock_backend().login() |
4098 | - self.mocker.replay() |
4099 | - |
4100 | - self.client.login(APP_NAME, self.args) |
4101 | - self.assert_dbus_method_correct(self.client.login) |
4102 | - |
4103 | - def test_login_email_password(self): |
4104 | - """The login_email_password is correct.""" |
4105 | - self.create_mock_backend().login_email_password(email=EMAIL, |
4106 | - password=PASSWORD) |
4107 | - self.mocker.replay() |
4108 | - |
4109 | - self.args['email'] = EMAIL |
4110 | - self.args['password'] = PASSWORD |
4111 | - self.client.login_email_password(APP_NAME, self.args) |
4112 | - self.assert_dbus_method_correct(self.client.login_email_password) |
4113 | - |
4114 | - |
4115 | -class CredentialsManagementParamsTestCase(CredentialsManagementOpsTestCase): |
4116 | - """Tests for the CredentialsManagement extra parameters handling.""" |
4117 | - |
4118 | - @defer.inlineCallbacks |
4119 | - def setUp(self): |
4120 | - yield super(CredentialsManagementParamsTestCase, self).setUp() |
4121 | - self.args['dummy'] = 'nothing useful' |
4122 | - |
4123 | - |
4124 | -class CredentialsManagementSignalsTestCase(TestCase): |
4125 | - """Tests for the CredentialsManagement DBus signals.""" |
4126 | - |
4127 | - @defer.inlineCallbacks |
4128 | - def setUp(self): |
4129 | - """Set up.""" |
4130 | - yield super(CredentialsManagementSignalsTestCase, self).setUp() |
4131 | - self.client = CredentialsManagement(timeout_func=lambda *a: None, |
4132 | - shutdown_func=lambda *a: None) |
4133 | - |
4134 | - self.memento = MementoHandler() |
4135 | - self.memento.setLevel(logging.DEBUG) |
4136 | - ubuntu_sso.main.linux.logger.addHandler(self.memento) |
4137 | - self.addCleanup(ubuntu_sso.main.linux.logger.removeHandler, |
4138 | - self.memento) |
4139 | - |
4140 | - def assert_dbus_signal_correct(self, signal, signature): |
4141 | - """Check that 'signal' is a dbus signal with proper 'signature'.""" |
4142 | - self.assertTrue(signal._dbus_is_signal) |
4143 | - self.assertEqual(signal._dbus_interface, DBUS_CREDENTIALS_IFACE) |
4144 | - self.assertEqual(signal._dbus_signature, signature) |
4145 | - |
4146 | - def test_credentials_found(self): |
4147 | - """The CredentialsFound signal.""" |
4148 | - self.client.CredentialsFound(APP_NAME, TOKEN) |
4149 | - msgs = (self.client.__class__.__name__, |
4150 | - self.client.CredentialsFound.__name__, APP_NAME) |
4151 | - self.assertTrue(self.memento.check_info(*msgs)) |
4152 | - |
4153 | - msg = 'credentials must not be logged (found %r in log).' |
4154 | - for val in TOKEN.itervalues(): |
4155 | - self.assertFalse(self.memento.check_info(val), msg % val) |
4156 | - |
4157 | - self.assert_dbus_signal_correct(self.client.CredentialsFound, 'sa{ss}') |
4158 | - |
4159 | - def test_credentials_not_found(self): |
4160 | - """The CredentialsNotFound signal.""" |
4161 | - self.client.CredentialsNotFound(APP_NAME) |
4162 | - msgs = (self.client.__class__.__name__, |
4163 | - self.client.CredentialsNotFound.__name__, APP_NAME) |
4164 | - self.assertTrue(self.memento.check_info(*msgs)) |
4165 | - self.assert_dbus_signal_correct(self.client.CredentialsNotFound, 's') |
4166 | - |
4167 | - def test_credentials_cleared(self): |
4168 | - """The CredentialsCleared signal.""" |
4169 | - self.client.CredentialsCleared(APP_NAME) |
4170 | - msgs = (self.client.__class__.__name__, |
4171 | - self.client.CredentialsCleared.__name__, APP_NAME) |
4172 | - self.assertTrue(self.memento.check_info(*msgs)) |
4173 | - |
4174 | - self.assert_dbus_signal_correct(self.client.CredentialsCleared, 's') |
4175 | - |
4176 | - def test_credentials_stored(self): |
4177 | - """The CredentialsStored signal.""" |
4178 | - self.client.CredentialsStored(APP_NAME) |
4179 | - msgs = (self.client.__class__.__name__, |
4180 | - self.client.CredentialsStored.__name__, APP_NAME) |
4181 | - self.assertTrue(self.memento.check_info(*msgs)) |
4182 | - |
4183 | - self.assert_dbus_signal_correct(self.client.CredentialsStored, 's') |
4184 | - |
4185 | - def test_credentials_error(self): |
4186 | - """The CredentialsError signal.""" |
4187 | - error = {'error_message': 'failed!', 'detailed error': 'yadda yadda'} |
4188 | - self.client.CredentialsError(APP_NAME, error) |
4189 | - msgs = (self.client.__class__.__name__, |
4190 | - self.client.CredentialsError.__name__, |
4191 | - APP_NAME, str(error)) |
4192 | - self.assertTrue(self.memento.check_error(*msgs)) |
4193 | - |
4194 | - self.assert_dbus_signal_correct(self.client.CredentialsError, 'sa{ss}') |
4195 | - |
4196 | - def test_authorization_denied(self): |
4197 | - """The AuthorizationDenied signal.""" |
4198 | - self.client.AuthorizationDenied(APP_NAME) |
4199 | - msgs = (self.client.__class__.__name__, |
4200 | - self.client.AuthorizationDenied.__name__, APP_NAME) |
4201 | - self.assertTrue(self.memento.check_info(*msgs)) |
4202 | - |
4203 | - self.assert_dbus_signal_correct(self.client.AuthorizationDenied, 's') |
4204 | |
4205 | === modified file 'ubuntu_sso/main/tests/test_windows.py' |
4206 | --- ubuntu_sso/main/tests/test_windows.py 2011-12-20 17:33:13 +0000 |
4207 | +++ ubuntu_sso/main/tests/test_windows.py 2012-01-17 19:42:46 +0000 |
4208 | @@ -1,6 +1,4 @@ |
4209 | # -*- coding: utf-8 -*- |
4210 | -# Authors: Manuel de la Pena <manuel@canonical.com> |
4211 | -# Alejandro J. Cura <alecu@canonical.com> |
4212 | # |
4213 | # Copyright 2011 Canonical Ltd. |
4214 | # |
4215 | @@ -15,932 +13,16 @@ |
4216 | # |
4217 | # You should have received a copy of the GNU General Public License along |
4218 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
4219 | -"""Windows tests.""" |
4220 | +"""Windows specific tests for the main module.""" |
4221 | |
4222 | # pylint: disable=F0401 |
4223 | from _winreg import REG_SZ |
4224 | |
4225 | -from mocker import MATCH, Mocker, MockerTestCase |
4226 | - |
4227 | -from twisted.internet import defer, reactor |
4228 | -from twisted.trial.unittest import TestCase |
4229 | -from twisted.spread.pb import ( |
4230 | - DeadReferenceError, |
4231 | - PBClientFactory, |
4232 | - PBServerFactory, |
4233 | - Broker, |
4234 | -) |
4235 | -from ubuntu_sso import main |
4236 | from ubuntu_sso.main import windows |
4237 | -from ubuntu_sso.main.windows import ( |
4238 | - signal, |
4239 | - CredentialsManagement, |
4240 | - CredentialsManagementClient, |
4241 | - LOCALHOST, |
4242 | - SignalBroadcaster, |
4243 | - SSOLogin, |
4244 | - SSOLoginClient, |
4245 | - UbuntuSSORoot, |
4246 | - UbuntuSSOClient, |
4247 | - get_sso_pb_port, |
4248 | -) |
4249 | - |
4250 | -# because we are using twisted we have java like names C0103 and |
4251 | -# the issues that mocker brings with it like W0104 |
4252 | -# pylint: disable=C0103,W0104,E1101,W0201 |
4253 | - |
4254 | - |
4255 | -class SaveProtocolServerFactory(PBServerFactory): |
4256 | - """A PBServerFactory that saves the latest connected client.""" |
4257 | - |
4258 | - protocolInstance = None |
4259 | - |
4260 | - def clientConnectionMade(self, protocol): |
4261 | - """Keep track of the given protocol.""" |
4262 | - self.protocolInstance = protocol |
4263 | - |
4264 | - |
4265 | -class SaveClientFactory(PBClientFactory): |
4266 | - """Client Factory that knows when we disconnected.""" |
4267 | - |
4268 | - def __init__(self, connected_d, disconnected_d): |
4269 | - """Create a new instance.""" |
4270 | - PBClientFactory.__init__(self) |
4271 | - self.connected_d = connected_d |
4272 | - self.disconnected_d = disconnected_d |
4273 | - |
4274 | - def clientConnectionMade(self, broker): |
4275 | - """Connection made.""" |
4276 | - PBClientFactory.clientConnectionMade(self, broker) |
4277 | - self.connected_d.callback(True) |
4278 | - |
4279 | - def clientConnectionLost(self, connector, reason, reconnecting=0): |
4280 | - """Connection lost.""" |
4281 | - self.disconnected_d.callback(True) |
4282 | - |
4283 | - |
4284 | -class ServerProtocol(Broker): |
4285 | - """Server protocol that allows us to clean the tests.""" |
4286 | - |
4287 | - def connectionLost(self, *a): |
4288 | - self.factory.onConnectionLost.callback(self) |
4289 | - |
4290 | - |
4291 | -class ConnectedTestCase(TestCase): |
4292 | - """Base test case with a client and a server.""" |
4293 | - |
4294 | - @defer.inlineCallbacks |
4295 | - def setUp(self): |
4296 | - """Set up for the tests.""" |
4297 | - yield super(ConnectedTestCase, self).setUp() |
4298 | - self.server_disconnected = defer.Deferred() |
4299 | - self.client_disconnected = defer.Deferred() |
4300 | - self.listener = None |
4301 | - self.connector = None |
4302 | - self.server_factory = None |
4303 | - self.client_factory = None |
4304 | - |
4305 | - def setup_client_server(self, sso_root): |
4306 | - """Set tests.""" |
4307 | - port = get_sso_pb_port() |
4308 | - self.listener = self._listen_server(sso_root, self.server_disconnected, |
4309 | - port) |
4310 | - connected = defer.Deferred() |
4311 | - self.connector = self._connect_client(connected, |
4312 | - self.client_disconnected, port) |
4313 | - self.addCleanup(self.teardown_client_server) |
4314 | - return connected |
4315 | - |
4316 | - def _listen_server(self, sso_root, d, port): |
4317 | - """Start listenting.""" |
4318 | - self.server_factory = SaveProtocolServerFactory(sso_root) |
4319 | - self.server_factory.onConnectionLost = d |
4320 | - self.server_factory.protocol = ServerProtocol |
4321 | - return reactor.listenTCP(port, self.server_factory) |
4322 | - |
4323 | - def _connect_client(self, d1, d2, port): |
4324 | - """Connect client.""" |
4325 | - self.client_factory = SaveClientFactory(d1, d2) |
4326 | - return reactor.connectTCP(LOCALHOST, port, self.client_factory) |
4327 | - |
4328 | - def teardown_client_server(self): |
4329 | - """Clean resources.""" |
4330 | - self.connector.disconnect() |
4331 | - d = defer.maybeDeferred(self.listener.stopListening) |
4332 | - return defer.gatherResults([d, self.client_disconnected, |
4333 | - self.server_disconnected]) |
4334 | - |
4335 | - |
4336 | -class FakeDecoratedObject(object): |
4337 | - """An object that has decorators.""" |
4338 | - |
4339 | - def __init__(self): |
4340 | - """Create a new instance.""" |
4341 | - super(FakeDecoratedObject, self).__init__() |
4342 | - |
4343 | - @signal |
4344 | - def on_no_args(self): |
4345 | - """Get no args passwed.""" |
4346 | - |
4347 | - @signal |
4348 | - def on_just_args(self, *args): |
4349 | - """Just get args.""" |
4350 | - |
4351 | - @signal |
4352 | - def on_just_kwargs(self, **kwargs): |
4353 | - """Just get kwargs.""" |
4354 | - |
4355 | - @signal |
4356 | - def on_both_args(self, *args, **kwargs): |
4357 | - """Both args.""" |
4358 | - |
4359 | - |
4360 | -class TestException(Exception): |
4361 | - """A test exception.""" |
4362 | - |
4363 | - @classmethod |
4364 | - def fail(cls, *args): |
4365 | - """Raise this exception.""" |
4366 | - raise cls(*args) |
4367 | - |
4368 | - |
4369 | -# pylint: disable=W0201 |
4370 | -class SignalTestCase(MockerTestCase): |
4371 | - """Test the signal decorator.""" |
4372 | - |
4373 | - @defer.inlineCallbacks |
4374 | - def setUp(self): |
4375 | - yield super(SignalTestCase, self).setUp() |
4376 | - self.fake_object = FakeDecoratedObject() |
4377 | - self.cb = self.mocker.mock() |
4378 | - |
4379 | - def test_no_args(self): |
4380 | - """Test when the cb should have no args.""" |
4381 | - self.fake_object.on_no_args_cb = self.cb |
4382 | - self.cb() |
4383 | - self.mocker.replay() |
4384 | - self.fake_object.on_no_args() |
4385 | - |
4386 | - def test_just_args(self): |
4387 | - """Test when the cb just has *args""" |
4388 | - first = 'first' |
4389 | - second = 'second' |
4390 | - self.fake_object.on_just_args_cb = self.cb |
4391 | - self.cb(first, second) |
4392 | - self.mocker.replay() |
4393 | - self.fake_object.on_just_args(first, second) |
4394 | - |
4395 | - def test_just_kwargs(self): |
4396 | - """Test when the cb just has kwargs.""" |
4397 | - first = 'first' |
4398 | - second = 'second' |
4399 | - self.fake_object.on_just_kwargs_cb = self.cb |
4400 | - self.cb(first=first, second=second) |
4401 | - self.mocker.replay() |
4402 | - self.fake_object.on_just_kwargs(first=first, second=second) |
4403 | - |
4404 | - def test_just_kwargs_empty(self): |
4405 | - """Test when the cb just has kwargs.""" |
4406 | - self.fake_object.on_just_kwargs_cb = self.cb |
4407 | - self.cb() |
4408 | - self.mocker.replay() |
4409 | - self.fake_object.on_just_kwargs() |
4410 | - |
4411 | - def test_both_args(self): |
4412 | - """Test with args and kwargs.""" |
4413 | - first = 'first' |
4414 | - second = 'second' |
4415 | - self.fake_object.on_both_args_cb = self.cb |
4416 | - self.cb(first, second, first=first, second=second) |
4417 | - self.mocker.replay() |
4418 | - self.fake_object.on_both_args(first, second, first=first, |
4419 | - second=second) |
4420 | - |
4421 | - def test_both_args_no_kwargs(self): |
4422 | - """Test with args and kwargs.""" |
4423 | - first = 'first' |
4424 | - second = 'second' |
4425 | - self.fake_object.on_both_args_cb = self.cb |
4426 | - self.cb(first, second) |
4427 | - self.mocker.replay() |
4428 | - self.fake_object.on_both_args(first, second) |
4429 | - |
4430 | - def test_both_args_no_args(self): |
4431 | - """Test with args and kwargs.""" |
4432 | - first = 'first' |
4433 | - second = 'second' |
4434 | - self.fake_object.on_both_args_cb = self.cb |
4435 | - self.cb(first=first, second=second) |
4436 | - self.mocker.replay() |
4437 | - self.fake_object.on_both_args(first=first, second=second) |
4438 | -# pylint: enable=W0201 |
4439 | - |
4440 | - |
4441 | -class FakeDeadRemoteClient(object): |
4442 | - """A fake dead remote client.""" |
4443 | - |
4444 | - def callRemote(self, signal_name, *args, **kwargs): |
4445 | - """Fails with DeadReferenceError.""" |
4446 | - raise DeadReferenceError("Calling Stale Broker") |
4447 | - |
4448 | - |
4449 | -class FakeAliveRemoteClient(object): |
4450 | - """A fake alive remote client.""" |
4451 | - |
4452 | - def __init__(self): |
4453 | - self.called = False |
4454 | - |
4455 | - def callRemote(self, signal_name, *args, **kwargs): |
4456 | - """Returns a succeed.""" |
4457 | - self.called = True |
4458 | - return defer.succeed(None) |
4459 | - |
4460 | - |
4461 | -class SignalBroadcasterTestCase(TestCase): |
4462 | - """Test the SignalBroadcaster class.""" |
4463 | - |
4464 | - def test_emit_signal_dead_reference(self): |
4465 | - """Test dead reference while emiting the signal.""" |
4466 | - fake_remote_client = FakeDeadRemoteClient() |
4467 | - sb = SignalBroadcaster() |
4468 | - sb.remote_register_to_signals(fake_remote_client) |
4469 | - self.assertIn(fake_remote_client, sb.clients) |
4470 | - sb.emit_signal("sample_signal") |
4471 | - self.assertNotIn(fake_remote_client, sb.clients) |
4472 | - |
4473 | - def test_emit_signal_some_dead_some_not(self): |
4474 | - """Test a clean reference after a dead one.""" |
4475 | - fake_dead_remote = FakeDeadRemoteClient() |
4476 | - fake_alive_remote = FakeAliveRemoteClient() |
4477 | - sb = SignalBroadcaster() |
4478 | - sb.remote_register_to_signals(fake_dead_remote) |
4479 | - sb.remote_register_to_signals(fake_alive_remote) |
4480 | - sb.emit_signal("sample_signal") |
4481 | - self.assertTrue(fake_alive_remote.called, "The alive must be called.") |
4482 | - |
4483 | - |
4484 | -class SignalHandlingTestCase(TestCase): |
4485 | - """Base for test suites that deal with IPC signal handling.""" |
4486 | - |
4487 | - timeout = 3 |
4488 | - signal_names = [] |
4489 | - first_signal = None |
4490 | - |
4491 | - def create_handler(self, d): |
4492 | - """Create a handler in a new namespace.""" |
4493 | - return lambda *args: d.callback(args) |
4494 | - |
4495 | - def install_handlers(self, client): |
4496 | - """Install the signal handlers.""" |
4497 | - signal_handlers = [] |
4498 | - |
4499 | - for signal_name in self.signal_names: |
4500 | - d = defer.Deferred() |
4501 | - handler = self.create_handler(d) |
4502 | - handler_name = "on_%s_cb" % signal_name |
4503 | - setattr(client, handler_name, handler) |
4504 | - signal_handlers.append(d) |
4505 | - self.first_signal = defer.DeferredList(signal_handlers, |
4506 | - fireOnOneCallback=True, |
4507 | - fireOnOneErrback=True) |
4508 | - |
4509 | - @defer.inlineCallbacks |
4510 | - def assert_fired(self, name, *args): |
4511 | - """Assert that the given signal was fired.""" |
4512 | - signal_args, signal_index = yield self.first_signal |
4513 | - self.assertEqual(args, signal_args[:len(args)]) |
4514 | - self.assertEqual(name, self.signal_names[signal_index]) |
4515 | - |
4516 | - |
4517 | -class SSOLoginTestCase(ConnectedTestCase, SignalHandlingTestCase): |
4518 | - """Test the login class.""" |
4519 | - |
4520 | - signal_names = [ |
4521 | - 'captcha_generated', |
4522 | - 'captcha_generation_error', |
4523 | - 'user_registered', |
4524 | - 'user_registration_error', |
4525 | - 'logged_in', |
4526 | - 'login_error', |
4527 | - 'user_not_validated', |
4528 | - 'email_validated', |
4529 | - 'email_validation_error', |
4530 | - 'password_reset_token_sent', |
4531 | - 'password_reset_error', |
4532 | - 'password_changed', |
4533 | - 'password_change_error', |
4534 | - ] |
4535 | - |
4536 | - @defer.inlineCallbacks |
4537 | - def setUp(self): |
4538 | - """Setup tests.""" |
4539 | - yield super(SSOLoginTestCase, self).setUp() |
4540 | - self.mocker = Mocker() |
4541 | - self.root = self.mocker.mock() |
4542 | - self.login = SSOLogin(None) |
4543 | - # start pb |
4544 | - self.sso_root = UbuntuSSORoot(sso_login=self.login) |
4545 | - # pylint: disable=E1101 |
4546 | - yield self.setup_client_server(self.sso_root) |
4547 | - self.client = yield self._get_client() |
4548 | - # pylint: enable=E1101 |
4549 | - |
4550 | - @defer.inlineCallbacks |
4551 | - def _get_client(self): |
4552 | - """Get the client.""" |
4553 | - # request the remote object and create a client |
4554 | - root = yield self.client_factory.getRootObject() |
4555 | - remote = yield root.callRemote('get_sso_login') |
4556 | - client = SSOLoginClient(remote) |
4557 | - yield client.register_to_signals() |
4558 | - self.addCleanup(client.unregister_to_signals) |
4559 | - |
4560 | - self.install_handlers(client) |
4561 | - defer.returnValue(client) |
4562 | - |
4563 | - @defer.inlineCallbacks |
4564 | - def test_emit_captcha_generated(self): |
4565 | - """Test that the cb was called.""" |
4566 | - app_name = 'app' |
4567 | - result = 'result' |
4568 | - |
4569 | - self.login.emit_captcha_generated(app_name, result) |
4570 | - yield self.assert_fired("captcha_generated", app_name, result) |
4571 | - |
4572 | - @defer.inlineCallbacks |
4573 | - def test_emit_captcha_generation_error(self): |
4574 | - """Test that the cb was called.""" |
4575 | - app_name = 'app' |
4576 | - filename = 'file' |
4577 | - |
4578 | - self.patch(self.login.root.processor, "generate_captcha", |
4579 | - TestException.fail) |
4580 | - self.login.generate_captcha(app_name, filename) |
4581 | - yield self.assert_fired("captcha_generation_error", app_name) |
4582 | - |
4583 | - @defer.inlineCallbacks |
4584 | - def test_generate_captcha(self): |
4585 | - """Test the call from the client.""" |
4586 | - app_name = 'app' |
4587 | - filename = 'file' |
4588 | - self.login.root = self.root |
4589 | - |
4590 | - self.root.generate_captcha(app_name, filename, |
4591 | - self.login.emit_captcha_generated, |
4592 | - self.login.emit_captcha_generation_error) |
4593 | - self.mocker.replay() |
4594 | - yield self.client.generate_captcha(app_name, filename) |
4595 | - yield self.client.unregister_to_signals() |
4596 | - self.mocker.verify() |
4597 | - |
4598 | - @defer.inlineCallbacks |
4599 | - def test_emit_user_registered(self): |
4600 | - """Test that the cb was called.""" |
4601 | - app_name = 'app' |
4602 | - result = 'result' |
4603 | - |
4604 | - self.login.emit_user_registered(app_name, result) |
4605 | - yield self.assert_fired("user_registered", app_name, result) |
4606 | - |
4607 | - @defer.inlineCallbacks |
4608 | - def test_emit_user_registration_error(self): |
4609 | - """Test that the cb was called.""" |
4610 | - app_name = 'app' |
4611 | - |
4612 | - self.patch(self.login.root.processor, "register_user", |
4613 | - TestException.fail) |
4614 | - self.login.register_user(app_name, "email", "password", "name", |
4615 | - "captcha_id", "captcha_solution") |
4616 | - yield self.assert_fired("user_registration_error", app_name) |
4617 | - |
4618 | - @defer.inlineCallbacks |
4619 | - def test_register_user(self): |
4620 | - """Test the call from the client.""" |
4621 | - app_name = 'app' |
4622 | - email = 'email' |
4623 | - password = 'password' |
4624 | - displayname = 'name' |
4625 | - captcha_id = 'captcha_id' |
4626 | - captcha_solution = 'captcha_solution' |
4627 | - self.login.root = self.root |
4628 | - |
4629 | - self.root.register_user(app_name, email, password, displayname, |
4630 | - captcha_id, captcha_solution, |
4631 | - self.login.emit_user_registered, |
4632 | - self.login.emit_user_registration_error) |
4633 | - self.mocker.replay() |
4634 | - yield self.client.register_user(app_name, email, password, displayname, |
4635 | - captcha_id, captcha_solution) |
4636 | - yield self.client.unregister_to_signals() |
4637 | - self.mocker.verify() |
4638 | - |
4639 | - @defer.inlineCallbacks |
4640 | - def test_emit_logged_in(self): |
4641 | - """Test that the cb was called.""" |
4642 | - app_name = 'app' |
4643 | - result = 'result' |
4644 | - |
4645 | - self.login.emit_logged_in(app_name, result) |
4646 | - yield self.assert_fired("logged_in", app_name) |
4647 | - |
4648 | - @defer.inlineCallbacks |
4649 | - def test_emit_login_error(self): |
4650 | - """Test that the db was called.""" |
4651 | - app_name = 'app' |
4652 | - |
4653 | - self.patch(main, "get_token_name", lambda _: None) |
4654 | - self.patch(self.login.root.processor, "login", |
4655 | - TestException.fail) |
4656 | - self.login.login(app_name, "email", "password") |
4657 | - yield self.assert_fired("login_error", app_name) |
4658 | - |
4659 | - @defer.inlineCallbacks |
4660 | - def test_emit_user_not_validated(self): |
4661 | - """Test that the cb was called.""" |
4662 | - app_name = 'app' |
4663 | - result = 'result' |
4664 | - |
4665 | - self.login.emit_user_not_validated(app_name, result) |
4666 | - yield self.assert_fired("user_not_validated", app_name) |
4667 | - |
4668 | - @defer.inlineCallbacks |
4669 | - def test_login(self): |
4670 | - """Test the call from the client.""" |
4671 | - app_name = 'app' |
4672 | - email = 'email' |
4673 | - password = 'password' |
4674 | - self.login.root = self.root |
4675 | - |
4676 | - self.root.login(app_name, email, password, |
4677 | - self.login.emit_logged_in, |
4678 | - self.login.emit_login_error, |
4679 | - self.login.emit_user_not_validated) |
4680 | - self.mocker.replay() |
4681 | - yield self.client.login(app_name, email, password) |
4682 | - yield self.client.unregister_to_signals() |
4683 | - self.mocker.verify() |
4684 | - |
4685 | - @defer.inlineCallbacks |
4686 | - def test_emit_email_validated(self): |
4687 | - """Test the cb was called.""" |
4688 | - app_name = 'app' |
4689 | - result = 'result' |
4690 | - |
4691 | - self.login.emit_email_validated(app_name, result) |
4692 | - yield self.assert_fired("email_validated", app_name) |
4693 | - |
4694 | - @defer.inlineCallbacks |
4695 | - def test_emit_email_validation_error(self): |
4696 | - """Test the cb was called.""" |
4697 | - app_name = 'app' |
4698 | - |
4699 | - self.patch(main, "get_token_name", lambda _: None) |
4700 | - self.patch(self.login.root.processor, "validate_email", |
4701 | - TestException.fail) |
4702 | - self.login.validate_email(app_name, "email", "password", "token") |
4703 | - yield self.assert_fired("email_validation_error", app_name) |
4704 | - |
4705 | - @defer.inlineCallbacks |
4706 | - def test_validate_email(self): |
4707 | - """Test the client calll.""" |
4708 | - app_name = 'app' |
4709 | - email = 'email' |
4710 | - password = 'password' |
4711 | - email_token = 'token' |
4712 | - self.login.root = self.root |
4713 | - |
4714 | - self.root.validate_email(app_name, email, password, email_token, |
4715 | - self.login.emit_email_validated, |
4716 | - self.login.emit_email_validation_error) |
4717 | - self.mocker.replay() |
4718 | - yield self.client.validate_email(app_name, email, password, |
4719 | - email_token) |
4720 | - yield self.client.unregister_to_signals() |
4721 | - self.mocker.verify() |
4722 | - |
4723 | - @defer.inlineCallbacks |
4724 | - def test_emit_password_reset_token_sent(self): |
4725 | - """Test the cb was called.""" |
4726 | - app_name = 'app' |
4727 | - result = 'result' |
4728 | - |
4729 | - self.login.emit_password_reset_token_sent(app_name, result) |
4730 | - yield self.assert_fired("password_reset_token_sent", app_name) |
4731 | - |
4732 | - @defer.inlineCallbacks |
4733 | - def test_emit_password_reset_error(self): |
4734 | - """Test the cb was called.""" |
4735 | - app_name = 'app' |
4736 | - |
4737 | - self.patch(self.login.root.processor, "request_password_reset_token", |
4738 | - TestException.fail) |
4739 | - self.login.request_password_reset_token(app_name, "email") |
4740 | - yield self.assert_fired("password_reset_error", app_name) |
4741 | - |
4742 | - @defer.inlineCallbacks |
4743 | - def test_request_password_reset_token(self): |
4744 | - """Test the client call.""" |
4745 | - app_name = 'app' |
4746 | - email = 'email' |
4747 | - self.login.root = self.root |
4748 | - |
4749 | - self.root.request_password_reset_token(app_name, email, |
4750 | - self.login.emit_password_reset_token_sent, |
4751 | - self.login.emit_password_reset_error) |
4752 | - self.mocker.replay() |
4753 | - self.client.request_password_reset_token(app_name, email) |
4754 | - yield self.client.unregister_to_signals() |
4755 | - self.mocker.verify() |
4756 | - |
4757 | - @defer.inlineCallbacks |
4758 | - def test_emit_password_changed(self): |
4759 | - """Test the cb was called.""" |
4760 | - app_name = 'app' |
4761 | - result = 'result' |
4762 | - |
4763 | - self.login.emit_password_changed(app_name, result) |
4764 | - yield self.assert_fired("password_changed", app_name) |
4765 | - |
4766 | - @defer.inlineCallbacks |
4767 | - def test_emit_password_change_error(self): |
4768 | - """Test the cb was called.""" |
4769 | - app_name = 'app' |
4770 | - |
4771 | - self.patch(self.login.root.processor, "set_new_password", |
4772 | - TestException.fail) |
4773 | - self.login.set_new_password(app_name, "email", "token", "password") |
4774 | - yield self.assert_fired("password_change_error", app_name) |
4775 | - |
4776 | - @defer.inlineCallbacks |
4777 | - def test_set_new_password(self): |
4778 | - """Test the client call.""" |
4779 | - app_name = 'app' |
4780 | - email = 'email' |
4781 | - token = 'token' |
4782 | - new_password = 'password' |
4783 | - self.login.root = self.root |
4784 | - |
4785 | - self.root.set_new_password(app_name, email, token, new_password, |
4786 | - self.login.emit_password_changed, |
4787 | - self.login.emit_password_change_error) |
4788 | - self.mocker.replay() |
4789 | - yield self.client.set_new_password(app_name, email, token, |
4790 | - new_password) |
4791 | - yield self.client.unregister_to_signals() |
4792 | - self.mocker.verify() |
4793 | - |
4794 | - |
4795 | -class CredentialsManagementTestCase(ConnectedTestCase, TestCase): |
4796 | - """Test the management class.""" |
4797 | - |
4798 | - @defer.inlineCallbacks |
4799 | - def setUp(self): |
4800 | - """Set up tests.""" |
4801 | - yield super(CredentialsManagementTestCase, self).setUp() |
4802 | - self.mocker = Mocker() |
4803 | - self.root = self.mocker.mock() |
4804 | - self.except_to_errdict = self.mocker.replace( |
4805 | - 'ubuntu_sso.main.except_to_errdict') |
4806 | - self.creds = CredentialsManagement(None, None) |
4807 | - self.creds.root = self.root |
4808 | - # start pb |
4809 | - self.sso_root = UbuntuSSORoot(cred_manager=self.creds) |
4810 | - # pylint: disable=E1101 |
4811 | - yield self.setup_client_server(self.sso_root) |
4812 | - self.client = yield self._get_client() |
4813 | - # pylint: enable=E1101 |
4814 | - |
4815 | - @defer.inlineCallbacks |
4816 | - def _get_client(self): |
4817 | - """Get the client.""" |
4818 | - # request the remote object and create a client |
4819 | - root = yield self.client_factory.getRootObject() |
4820 | - remote = yield root.callRemote('get_cred_manager') |
4821 | - client = CredentialsManagementClient(remote) |
4822 | - yield client.register_to_signals() |
4823 | - self.addCleanup(client.unregister_to_signals) |
4824 | - # set the cb |
4825 | - for signal_name in ['on_authorization_denied_cb', |
4826 | - 'on_credentials_found_cb', |
4827 | - 'on_credentials_not_found_cb', |
4828 | - 'on_credentials_cleared_cb', |
4829 | - 'on_credentials_stored_cb', |
4830 | - 'on_credentials_error_cb']: |
4831 | - setattr(client, signal_name, self.mocker.mock()) |
4832 | - defer.returnValue(client) |
4833 | - |
4834 | - @defer.inlineCallbacks |
4835 | - def test_shutdown(self): |
4836 | - """Test that root is called.""" |
4837 | - # pylint: disable=W0104 |
4838 | - self.root.ref_count |
4839 | - # pylint: enable=W0104 |
4840 | - self.mocker.result(1) |
4841 | - self.root.shutdown() |
4842 | - self.mocker.replay() |
4843 | - yield self.client.shutdown() |
4844 | - yield self.client.unregister_to_signals() |
4845 | - |
4846 | - @defer.inlineCallbacks |
4847 | - def test_emit_authorization_denied(self): |
4848 | - """Test the callback is called.""" |
4849 | - app_name = 'app' |
4850 | - |
4851 | - # pylint: disable=W0104 |
4852 | - self.root.ref_count |
4853 | - # pylint: enable=W0104 |
4854 | - self.mocker.result(1) |
4855 | - self.root.ref_count = 0 |
4856 | - self.client.on_authorization_denied_cb(app_name) |
4857 | - self.mocker.replay() |
4858 | - self.creds.emit_authorization_denied(app_name) |
4859 | - yield self.client.unregister_to_signals() |
4860 | - self.mocker.verify() |
4861 | - |
4862 | - @defer.inlineCallbacks |
4863 | - def test_emit_credentials_found(self): |
4864 | - """Test the callback is called.""" |
4865 | - app_name = 'app' |
4866 | - creds = 'creds' |
4867 | - |
4868 | - # pylint: disable=W0104 |
4869 | - self.root.ref_count |
4870 | - # pylint: enable=W0104 |
4871 | - self.mocker.result(1) |
4872 | - self.root.ref_count = 0 |
4873 | - self.client.on_credentials_found_cb(app_name, creds) |
4874 | - self.mocker.replay() |
4875 | - self.creds.emit_credentials_found(app_name, creds) |
4876 | - yield self.client.unregister_to_signals() |
4877 | - self.mocker.verify() |
4878 | - |
4879 | - @defer.inlineCallbacks |
4880 | - def test_emit_credentials_not_found(self): |
4881 | - """Test the callback is called.""" |
4882 | - app_name = 'app' |
4883 | - |
4884 | - # pylint: disable=W0104 |
4885 | - self.root.ref_count |
4886 | - # pylint: enable=W0104 |
4887 | - self.mocker.result(1) |
4888 | - self.root.ref_count = 0 |
4889 | - self.client.on_credentials_not_found_cb(app_name) |
4890 | - self.mocker.replay() |
4891 | - self.creds.emit_credentials_not_found(app_name) |
4892 | - yield self.client.unregister_to_signals() |
4893 | - self.mocker.verify() |
4894 | - |
4895 | - @defer.inlineCallbacks |
4896 | - def test_emit_credentials_cleared(self): |
4897 | - """Test the callback is called.""" |
4898 | - app_name = 'app' |
4899 | - |
4900 | - # pylint: disable=W0104 |
4901 | - self.root.ref_count |
4902 | - # pylint: enable=W0104 |
4903 | - self.mocker.result(1) |
4904 | - self.root.ref_count = 0 |
4905 | - self.client.on_credentials_cleared_cb(app_name) |
4906 | - self.mocker.replay() |
4907 | - self.creds.emit_credentials_cleared(app_name) |
4908 | - yield self.client.unregister_to_signals() |
4909 | - self.mocker.verify() |
4910 | - |
4911 | - @defer.inlineCallbacks |
4912 | - def test_emit_credentials_stored(self): |
4913 | - """Test the callback is called.""" |
4914 | - app_name = 'app' |
4915 | - |
4916 | - # pylint: disable=W0104 |
4917 | - self.root.ref_count |
4918 | - # pylint: enable=W0104 |
4919 | - self.mocker.result(1) |
4920 | - self.root.ref_count = 0 |
4921 | - self.client.on_credentials_stored_cb(app_name) |
4922 | - self.mocker.replay() |
4923 | - self.creds.emit_credentials_stored(app_name) |
4924 | - yield self.client.unregister_to_signals() |
4925 | - self.mocker.verify() |
4926 | - |
4927 | - @defer.inlineCallbacks |
4928 | - def test_emit_credentials_error(self): |
4929 | - """Test the callback is called.""" |
4930 | - app_name = 'app' |
4931 | - raised_error = 'error' |
4932 | - |
4933 | - # pylint: disable=W0104 |
4934 | - self.root.ref_count |
4935 | - # pylint: enable=W0104 |
4936 | - self.mocker.result(1) |
4937 | - self.root.ref_count = 0 |
4938 | - self.client.on_credentials_error_cb(app_name, raised_error) |
4939 | - self.mocker.replay() |
4940 | - self.creds.emit_credentials_error(app_name, raised_error) |
4941 | - yield self.client.unregister_to_signals() |
4942 | - self.mocker.verify() |
4943 | - |
4944 | - @defer.inlineCallbacks |
4945 | - def test_find_credentials(self): |
4946 | - """Test that root is called.""" |
4947 | - app_name = 'app' |
4948 | - args = 'args' |
4949 | - |
4950 | - # pylint: disable=W0212 |
4951 | - self.root.find_credentials(app_name, args, MATCH(callable), |
4952 | - self.creds._process_failure) |
4953 | - # pylint: enable=W0212 |
4954 | - self.root.shutdown() |
4955 | - yield self.client.find_credentials(app_name, args) |
4956 | - yield self.client.unregister_to_signals() |
4957 | - |
4958 | - @defer.inlineCallbacks |
4959 | - def test_clear_credentials(self): |
4960 | - """Test that root is called.""" |
4961 | - app_name = 'app' |
4962 | - args = 'args' |
4963 | - |
4964 | - # pylint: disable=W0212 |
4965 | - self.root.clear_credentials(app_name, args, MATCH(callable), |
4966 | - self.creds._process_failure) |
4967 | - # pylint: enable=W0212 |
4968 | - self.mocker.replay() |
4969 | - yield self.client.clear_credentials(app_name, args) |
4970 | - yield self.client.unregister_to_signals() |
4971 | - |
4972 | - @defer.inlineCallbacks |
4973 | - def test_store_credentials(self): |
4974 | - """Test that root is called.""" |
4975 | - app_name = 'app' |
4976 | - args = 'args' |
4977 | - |
4978 | - # pylint: disable=W0212 |
4979 | - self.root.store_credentials(app_name, args, MATCH(callable), |
4980 | - self.creds._process_failure) |
4981 | - # pylint: enable=W0212 |
4982 | - self.mocker.replay() |
4983 | - yield self.client.store_credentials(app_name, args) |
4984 | - yield self.client.unregister_to_signals() |
4985 | - |
4986 | - @defer.inlineCallbacks |
4987 | - def test_register(self): |
4988 | - """Test that root is called.""" |
4989 | - app_name = 'app' |
4990 | - args = 'args' |
4991 | - |
4992 | - self.root.register(app_name, args) |
4993 | - self.mocker.replay() |
4994 | - yield self.client.register(app_name, args) |
4995 | - yield self.client.unregister_to_signals() |
4996 | - |
4997 | - @defer.inlineCallbacks |
4998 | - def test_login(self): |
4999 | - """Test that root is called.""" |
5000 | - app_name = 'app' |
The diff has been truncated for viewing.
Thank you for your work there