Merge lp:~nataliabidart/ubuntuone-client/login-email-password-for-everyone into lp:ubuntuone-client
- login-email-password-for-everyone
- Merge into trunk
Proposed by
Natalia Bidart
Status: | Merged |
---|---|
Approved by: | Natalia Bidart |
Approved revision: | 1122 |
Merged at revision: | 1117 |
Proposed branch: | lp:~nataliabidart/ubuntuone-client/login-email-password-for-everyone |
Merge into: | lp:ubuntuone-client |
Diff against target: |
1262 lines (+647/-296) 7 files modified
contrib/login_email_password.py (+19/-8) tests/platform/linux/test_credentials.py (+15/-30) tests/platform/test_credentials.py (+391/-111) tests/platform/windows/test_credentials.py (+95/-16) ubuntuone/platform/credentials/__init__.py (+76/-49) ubuntuone/platform/credentials/linux.py (+11/-70) ubuntuone/platform/credentials/windows.py (+40/-12) |
To merge this branch: | bzr merge lp:~nataliabidart/ubuntuone-client/login-email-password-for-everyone |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alejandro J. Cura (community) | ran tests | Approve | |
Manuel de la Peña (community) | Approve | ||
Review via email: mp+72735@code.launchpad.net |
Description of the change
You can test this on both linux and windows by running:
PYTHONPATH=. contrib/
You will be prompted by email and password, and the result will be printed in the terminal.
In windows, please be sure to have latest ussoc service running and in the PYTHONPATH.
To post a comment you must log in.
- 1119. By Natalia Bidart
-
Typo.
Revision history for this message
Alejandro J. Cura (alecu) wrote : | # |
review:
Needs Fixing
(just eyeballed the code)
- 1120. By Natalia Bidart
-
Merged trunk in.
- 1121. By Natalia Bidart
-
Fixes from review.
Revision history for this message
Manuel de la Peña (mandel) wrote : | # |
Looks good to me.
review:
Approve
- 1122. By Natalia Bidart
-
Merged trunk in.
Revision history for this message
Alejandro J. Cura (alecu) wrote : | # |
Looks great!
review:
Approve
(ran tests)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'contrib/login_email_password.py' (properties changed: -x to +x) |
2 | --- contrib/login_email_password.py 2011-07-29 17:57:25 +0000 |
3 | +++ contrib/login_email_password.py 2011-08-26 17:23:37 +0000 |
4 | @@ -16,6 +16,12 @@ |
5 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
6 | """Script that shows the qt gui.""" |
7 | |
8 | +import sys |
9 | + |
10 | +if sys.platform != 'win32': |
11 | + from twisted.internet import glib2reactor |
12 | + glib2reactor.install() |
13 | + |
14 | # pylint: disable=F0401, E1101 |
15 | from twisted.internet import reactor |
16 | from twisted.internet.defer import inlineCallbacks |
17 | @@ -23,18 +29,23 @@ |
18 | |
19 | |
20 | @inlineCallbacks |
21 | -def main(): |
22 | +def main(email='whomever@canonical.com', password='whatever'): |
23 | """Perform a client request to be logged in.""" |
24 | credtool = CredentialsManagementTool() |
25 | - |
26 | - creds = yield credtool.login_email_password( |
27 | - email='whomever@canonical.com', |
28 | - password='whatever', |
29 | - ) |
30 | - print "creds found", creds |
31 | + print 'Trying to get credentials for email:', email |
32 | + try: |
33 | + creds = yield credtool.login_email_password(email=email, |
34 | + password=password) |
35 | + print "creds found!", creds |
36 | + except Exception, e: |
37 | + print "creds error!", e |
38 | reactor.stop() |
39 | |
40 | |
41 | if __name__ == '__main__': |
42 | - main() |
43 | + print 'Enter email:' |
44 | + email = raw_input() |
45 | + print 'Enter password:' |
46 | + password = raw_input() |
47 | + main(email=email, password=password) |
48 | reactor.run() |
49 | |
50 | === modified file 'tests/platform/linux/test_credentials.py' |
51 | --- tests/platform/linux/test_credentials.py 2011-08-16 13:44:20 +0000 |
52 | +++ tests/platform/linux/test_credentials.py 2011-08-26 17:23:37 +0000 |
53 | @@ -885,12 +885,9 @@ |
54 | """Find credentials and error.""" |
55 | FakedSSOService.error_dict = {'failure': 'really'} |
56 | |
57 | - try: |
58 | - yield self.client.find_credentials() |
59 | - except CredentialsError, e: |
60 | - self.assertEqual(e[0], FakedSSOService.error_dict) |
61 | - else: |
62 | - self.fail('Must not succeed!') |
63 | + e = yield self.assertFailure(self.client.find_credentials(), |
64 | + CredentialsError) |
65 | + self.assertEqual(e[0], FakedSSOService.error_dict) |
66 | |
67 | @inlineCallbacks |
68 | def test_clear_credentials(self): |
69 | @@ -907,12 +904,9 @@ |
70 | """Clear credentials and error.""" |
71 | FakedSSOService.error_dict = {'failure': 'really'} |
72 | |
73 | - try: |
74 | - yield self.client.clear_credentials() |
75 | - except CredentialsError, e: |
76 | - self.assertEqual(e[0], FakedSSOService.error_dict) |
77 | - else: |
78 | - self.fail('Must not succeed!') |
79 | + e = yield self.assertFailure(self.client.clear_credentials(), |
80 | + CredentialsError) |
81 | + self.assertEqual(e[0], FakedSSOService.error_dict) |
82 | |
83 | @inlineCallbacks |
84 | def test_store_credentials(self): |
85 | @@ -929,12 +923,9 @@ |
86 | """Store credentials and error.""" |
87 | FakedSSOService.error_dict = {'failure': 'really'} |
88 | |
89 | - try: |
90 | - yield self.client.store_credentials({'test': 'me'}) |
91 | - except CredentialsError, e: |
92 | - self.assertEqual(e[0], FakedSSOService.error_dict) |
93 | - else: |
94 | - self.fail('Must not succeed!') |
95 | + e = yield self.assertFailure(self.client.store_credentials({'0': '1'}), |
96 | + CredentialsError) |
97 | + self.assertEqual(e[0], FakedSSOService.error_dict) |
98 | |
99 | @inlineCallbacks |
100 | def test_register(self): |
101 | @@ -956,12 +947,9 @@ |
102 | """Register and error.""" |
103 | FakedSSOService.error_dict = {'failure': 'really'} |
104 | |
105 | - try: |
106 | - yield self.client.register() |
107 | - except CredentialsError, e: |
108 | - self.assertEqual(e[0], FakedSSOService.error_dict) |
109 | - else: |
110 | - self.fail('Must not succeed!') |
111 | + e = yield self.assertFailure(self.client.register(), |
112 | + CredentialsError) |
113 | + self.assertEqual(e[0], FakedSSOService.error_dict) |
114 | |
115 | @inlineCallbacks |
116 | def test_login(self): |
117 | @@ -983,9 +971,6 @@ |
118 | """Login and error.""" |
119 | FakedSSOService.error_dict = {'failure': 'really'} |
120 | |
121 | - try: |
122 | - yield self.client.login() |
123 | - except CredentialsError, e: |
124 | - self.assertEqual(e[0], FakedSSOService.error_dict) |
125 | - else: |
126 | - self.fail('Must not succeed!') |
127 | + e = yield self.assertFailure(self.client.login(), |
128 | + CredentialsError) |
129 | + self.assertEqual(e[0], FakedSSOService.error_dict) |
130 | |
131 | === modified file 'tests/platform/test_credentials.py' |
132 | --- tests/platform/test_credentials.py 2011-08-18 13:13:37 +0000 |
133 | +++ tests/platform/test_credentials.py 2011-08-26 17:23:37 +0000 |
134 | @@ -22,127 +22,407 @@ |
135 | import urllib |
136 | import urlparse |
137 | |
138 | -from mocker import MockerTestCase, MATCH |
139 | +from collections import defaultdict |
140 | +from functools import wraps |
141 | + |
142 | from twisted.internet import defer |
143 | from twisted.trial.unittest import TestCase |
144 | |
145 | from ubuntuone import clientdefs |
146 | from ubuntuone.platform.credentials import ( |
147 | BASE_PING_URL, |
148 | + CredentialsError, |
149 | CredentialsManagementTool, |
150 | + NO_OP, |
151 | PING_URL, |
152 | platform_data, |
153 | ) |
154 | - |
155 | - |
156 | -class TestCredentialsManagementTool(MockerTestCase): |
157 | - """Test the credentials management tool mocking the proxy.""" |
158 | - |
159 | - def setUp(self): |
160 | - """Set the diff tests.""" |
161 | - super(TestCredentialsManagementTool, self).setUp() |
162 | - self.get_cred_proxy = self.mocker.mock() |
163 | - self.proxy = self.mocker.mock() |
164 | - self.management_tool = CredentialsManagementTool() |
165 | - self.management_tool.get_creds_proxy = self.get_cred_proxy |
166 | - |
167 | - def test_find_credentials(self): |
168 | - """Test that we do ask for the credentials correctly.""" |
169 | - signals = ['creds_found', 'creds_not_found', 'creds_erro'] |
170 | - self.get_cred_proxy() |
171 | - self.mocker.result(self.proxy) |
172 | - self.proxy.register_to_credentials_found(MATCH(callable)) |
173 | - self.mocker.result(signals[0]) |
174 | - self.proxy.register_to_credentials_not_found(MATCH(callable)) |
175 | - self.mocker.result(signals[1]) |
176 | - self.proxy.register_to_credentials_error(MATCH(callable)) |
177 | - self.mocker.result(signals[2]) |
178 | - self.proxy.find_credentials(reply_handler=MATCH(callable), |
179 | - error_handler=MATCH(callable)) |
180 | - self.mocker.replay() |
181 | - return self.management_tool.find_credentials() |
182 | - |
183 | - def test_clear_credentials(self): |
184 | - """Test that we clear the credentials correctly.""" |
185 | - signals = ['creds_cleared', 'creds_error'] |
186 | - self.get_cred_proxy() |
187 | - self.mocker.result(self.proxy) |
188 | - self.proxy.register_to_credentials_cleared(MATCH(callable)) |
189 | - self.mocker.result(signals[0]) |
190 | - self.proxy.register_to_credentials_error(MATCH(callable)) |
191 | - self.mocker.result(signals[1]) |
192 | - self.proxy.clear_credentials(reply_handler=MATCH(callable), |
193 | - error_handler=MATCH(callable)) |
194 | - self.mocker.replay() |
195 | - return self.management_tool.clear_credentials() |
196 | - |
197 | - def test_store_credentials(self): |
198 | - """Test that we store the credentials correctly.""" |
199 | - token = 'token' |
200 | - signals = ['creds_stored','creds_error'] |
201 | - self.get_cred_proxy() |
202 | - self.mocker.result(self.proxy) |
203 | - self.proxy.register_to_credentials_stored(MATCH(callable)) |
204 | - self.mocker.result(signals[0]) |
205 | - self.proxy.register_to_credentials_error(MATCH(callable)) |
206 | - self.mocker.result(signals[1]) |
207 | - self.proxy.store_credentials(token, reply_handler=MATCH(callable), |
208 | - error_handler=MATCH(callable)) |
209 | - self.mocker.replay() |
210 | - return self.management_tool.store_credentials(token) |
211 | - |
212 | - def test_register(self): |
213 | - """Test that we correctly register.""" |
214 | - window_id = 10 |
215 | - window_id_dict = dict(window_id=str(window_id)) |
216 | - signals = ['creds_found', 'creds_denied', 'creds_error'] |
217 | - self.get_cred_proxy() |
218 | - self.mocker.result(self.proxy) |
219 | - self.proxy.register_to_credentials_found(MATCH(callable)) |
220 | - self.mocker.result(signals[0]) |
221 | - self.proxy.register_to_authorization_denied(MATCH(callable)) |
222 | - self.mocker.result(signals[1]) |
223 | - self.proxy.register_to_credentials_error(MATCH(callable)) |
224 | - self.mocker.result(signals[2]) |
225 | - self.proxy.register(window_id_dict, reply_handler=MATCH(callable), |
226 | - error_handler=MATCH(callable)) |
227 | - self.mocker.replay() |
228 | - return self.management_tool.register(window_id=window_id) |
229 | - |
230 | - def test_login_email_password(self): |
231 | - """Test that we login correctly.""" |
232 | - email = 'email' |
233 | - password = 'password' |
234 | - arg_dict = dict(email=email, password=password) |
235 | - signals = ['creds_found', 'creds_denied', 'creds_error'] |
236 | - self.get_cred_proxy() |
237 | - self.mocker.result(self.proxy) |
238 | - self.proxy.register_to_credentials_found(MATCH(callable)) |
239 | - self.mocker.result(signals[0]) |
240 | - self.proxy.register_to_credentials_error(MATCH(callable)) |
241 | - self.mocker.result(signals[1]) |
242 | - self.proxy.login_email_password(arg_dict, reply_handler=MATCH(callable), |
243 | - error_handler=MATCH(callable)) |
244 | - self.mocker.replay() |
245 | - return self.management_tool.login_email_password(email=email, |
246 | - password=password) |
247 | - |
248 | - def test_cleanup_but_no_remove(self): |
249 | - """The cleanup method works on handlers that have no remove method.""" |
250 | - self.management_tool._cleanup_signals = ["test signal 1", "test sig 2"] |
251 | - self.management_tool.cleanup(None) |
252 | - |
253 | - |
254 | -class TestDeferredCredentialsManagementTool(TestCredentialsManagementTool): |
255 | - """Test the credentials management tool mocking the proxy in a deferred.""" |
256 | - |
257 | - def setUp(self): |
258 | - """Set the diff tests.""" |
259 | - super(TestDeferredCredentialsManagementTool, self).setUp() |
260 | - real_get_cred_proxy = self.mocker.mock() |
261 | - self.get_cred_proxy = lambda: defer.succeed(real_get_cred_proxy()) |
262 | - self.management_tool = CredentialsManagementTool() |
263 | - self.management_tool.get_creds_proxy = self.get_cred_proxy |
264 | +from contrib.testing.testcase import FAKED_CREDENTIALS |
265 | + |
266 | + |
267 | +class FakedSignal(object): |
268 | + """A faked signal.""" |
269 | + |
270 | + def __init__(self, name, callback): |
271 | + self.name = name |
272 | + self.callback = callback |
273 | + self.removed = False |
274 | + self.remove = lambda: setattr(self, 'removed', True) |
275 | + |
276 | + |
277 | +class FakedProxy(object): |
278 | + """Fake a CredentialsManagement proxy.""" |
279 | + |
280 | + error_dict = None |
281 | + error_handler = None |
282 | + |
283 | + def __init__(self, *args, **kwargs): |
284 | + self._credentials = None |
285 | + self._args = None |
286 | + self._kwargs = None |
287 | + self._signals = [] |
288 | + self._receivers = defaultdict(list) |
289 | + self._called = defaultdict(list) |
290 | + |
291 | + def connect_to_signal(self, signal_name, callback): |
292 | + """Keep track of connected signals.""" |
293 | + self._receivers[signal_name].append(callback) |
294 | + result = FakedSignal(signal_name, callback) |
295 | + self._signals.append(result) |
296 | + return result |
297 | + |
298 | + def maybe_emit_error(f): |
299 | + """Decorator to fake a CredentialsError signal.""" |
300 | + |
301 | + @wraps(f) |
302 | + def inner(self, *args, **kwargs): |
303 | + """Fake a CredentialsError signal.""" |
304 | + if self.error_dict is None and self.error_handler is None: |
305 | + f(self, *args, **kwargs) |
306 | + |
307 | + reply_handler = kwargs.pop('reply_handler', NO_OP) |
308 | + error_handler = kwargs.pop('error_handler', NO_OP) |
309 | + if self.error_handler is not None: |
310 | + error_handler(self.error_handler) |
311 | + else: |
312 | + reply_handler() |
313 | + |
314 | + if self.error_dict is not None: |
315 | + self.CredentialsError(self.error_dict) |
316 | + |
317 | + return inner |
318 | + |
319 | + def record_call(f): |
320 | + """Decorator to record calls to 'f'.""" |
321 | + |
322 | + @wraps(f) |
323 | + def inner(self, *a, **kw): |
324 | + """Record the call to 'f' and call it.""" |
325 | + self._called[f.__name__].append((a, kw)) |
326 | + return f(self, *a, **kw) |
327 | + |
328 | + return inner |
329 | + |
330 | + def emit_signal(f): |
331 | + """Decorator to emit a signal.""" |
332 | + |
333 | + @wraps(f) |
334 | + def inner(self, *args, **kwargs): |
335 | + """Emit the signal.""" |
336 | + for cb in self._receivers[f.__name__]: |
337 | + cb(*args, **kwargs) |
338 | + |
339 | + return inner |
340 | + |
341 | + @emit_signal |
342 | + def AuthorizationDenied(self): |
343 | + """Signal thrown when the user denies the authorization.""" |
344 | + |
345 | + @emit_signal |
346 | + def CredentialsFound(self, credentials): |
347 | + """Signal thrown when the credentials are found.""" |
348 | + |
349 | + @emit_signal |
350 | + def CredentialsNotFound(self): |
351 | + """Signal thrown when the credentials are not found.""" |
352 | + |
353 | + @emit_signal |
354 | + def CredentialsCleared(self): |
355 | + """Signal thrown when the credentials were cleared.""" |
356 | + |
357 | + @emit_signal |
358 | + def CredentialsStored(self): |
359 | + """Signal thrown when the credentials were stored.""" |
360 | + |
361 | + @emit_signal |
362 | + def CredentialsError(self, error_dict): |
363 | + """Signal thrown when there is a problem getting the credentials.""" |
364 | + |
365 | + @record_call |
366 | + @maybe_emit_error |
367 | + def find_credentials(self, reply_handler=NO_OP, error_handler=NO_OP): |
368 | + """Look for the credentials for an application.""" |
369 | + if self._credentials is not None: |
370 | + self.CredentialsFound(self._credentials) |
371 | + else: |
372 | + self.CredentialsNotFound() |
373 | + |
374 | + @record_call |
375 | + @maybe_emit_error |
376 | + def clear_credentials(self, reply_handler=NO_OP, error_handler=NO_OP): |
377 | + """Clear the credentials for an application.""" |
378 | + self._credentials = None |
379 | + self.CredentialsCleared() |
380 | + |
381 | + @record_call |
382 | + @maybe_emit_error |
383 | + def store_credentials(self, credentials, |
384 | + reply_handler=NO_OP, error_handler=NO_OP): |
385 | + """Store the token for an application.""" |
386 | + self._credentials = credentials |
387 | + self.CredentialsStored() |
388 | + |
389 | + @record_call |
390 | + @maybe_emit_error |
391 | + def register(self, dict_arg, |
392 | + reply_handler=NO_OP, error_handler=NO_OP): |
393 | + """Get credentials if found else prompt GUI to register.""" |
394 | + creds = self._credentials |
395 | + if creds is not None and len(creds) > 0: |
396 | + self.CredentialsFound(creds) |
397 | + elif creds == {}: |
398 | + # fake an AuthorizationDenied |
399 | + self.AuthorizationDenied() |
400 | + elif creds is None: |
401 | + # fake the adding of the credentials |
402 | + self._credentials = FAKED_CREDENTIALS |
403 | + self.CredentialsFound(FAKED_CREDENTIALS) |
404 | + |
405 | + @record_call |
406 | + @maybe_emit_error |
407 | + def login(self, dict_arg, |
408 | + reply_handler=NO_OP, error_handler=NO_OP): |
409 | + """Get credentials if found else prompt GUI to login.""" |
410 | + self.register(dict_arg, reply_handler, error_handler) |
411 | + |
412 | + @record_call |
413 | + @maybe_emit_error |
414 | + def login_email_password(self, dict_arg, |
415 | + reply_handler=NO_OP, error_handler=NO_OP): |
416 | + """Fake login_email_password.""" |
417 | + self.register(dict_arg, reply_handler, error_handler) |
418 | + |
419 | + |
420 | +class FakedPlatformSource(object): |
421 | + """Faked the platform source.""" |
422 | + |
423 | + def get_creds_proxy(self): |
424 | + """Return a new faked proxy every time, so we can test proxy caching.""" |
425 | + return FakedProxy() |
426 | + |
427 | + |
428 | +class CredentialsManagementToolTestCase(TestCase): |
429 | + """Test case for the object that manages Ubuntu One credentials.""" |
430 | + |
431 | + timeout = 3 |
432 | + error_dict = None |
433 | + error_handler = None |
434 | + |
435 | + @defer.inlineCallbacks |
436 | + def setUp(self): |
437 | + yield super(CredentialsManagementToolTestCase, self).setUp() |
438 | + self.cred_tool = CredentialsManagementTool() |
439 | + self.patch(self.cred_tool, 'get_platform_source', FakedPlatformSource) |
440 | + self.proxy = yield self.cred_tool.get_creds_proxy() |
441 | + self.proxy.error_dict = self.error_dict |
442 | + self.proxy.error_handler = self.error_handler |
443 | + |
444 | + self.window_id_arg = {'window_id': '803'} |
445 | + self.email_password_arg = {'email': 'foo@bar.com', 'password': 'yadda'} |
446 | + |
447 | + @defer.inlineCallbacks |
448 | + def test_proxy_is_reused(self): |
449 | + """The inner proxy is re-used.""" |
450 | + proxy1 = yield self.cred_tool.get_creds_proxy() |
451 | + proxy2 = yield self.cred_tool.get_creds_proxy() |
452 | + self.assertIs(proxy1, proxy2) |
453 | + |
454 | + |
455 | +class ArgsTestCase(CredentialsManagementToolTestCase): |
456 | + """Test case to check that proper arguments are passed to SSO backend.""" |
457 | + |
458 | + @defer.inlineCallbacks |
459 | + def assert_method_called(self, method_name, *args, **kwargs): |
460 | + """Test that 'method_name' was called once with 'args' and 'kwargs.""" |
461 | + self.assertIn(method_name, self.proxy._called) |
462 | + |
463 | + calls = self.proxy._called[method_name] |
464 | + msg = '%s must be called only once (got %s instead).' |
465 | + self.assertEqual(len(calls), 1, msg % (method_name, len(calls))) |
466 | + |
467 | + actual_args, actual_kwargs = calls[0] |
468 | + self.assertEqual(args, actual_args) |
469 | + |
470 | + reply_handler = actual_kwargs.pop('reply_handler', None) |
471 | + self.assertIsNotNone(reply_handler, 'Must provide a reply_handler') |
472 | + d = defer.Deferred() |
473 | + reply_handler(deferred=d) |
474 | + yield d |
475 | + self.assertTrue(d.called) |
476 | + |
477 | + error_handler = actual_kwargs.pop('error_handler', None) |
478 | + self.assertIsNotNone(error_handler, 'Must provide a error_handler') |
479 | + d = defer.Deferred() |
480 | + error_handler(error='foo', deferred=d) |
481 | + e = yield self.assertFailure(d, CredentialsError) |
482 | + self.assertEqual(e.message, 'foo') |
483 | + |
484 | + self.assertEqual(kwargs, actual_kwargs) |
485 | + |
486 | + @defer.inlineCallbacks |
487 | + def test_find_credentials(self): |
488 | + """The find_credentials method calls proper method.""" |
489 | + yield self.cred_tool.find_credentials() |
490 | + |
491 | + self.assert_method_called('find_credentials') |
492 | + |
493 | + @defer.inlineCallbacks |
494 | + def test_clear_credentials(self): |
495 | + """The clear_credentials method calls proper method.""" |
496 | + yield self.cred_tool.clear_credentials() |
497 | + |
498 | + self.assert_method_called('clear_credentials') |
499 | + |
500 | + @defer.inlineCallbacks |
501 | + def test_store_credentials(self): |
502 | + """The store_credentials method calls proper method.""" |
503 | + yield self.cred_tool.store_credentials(FAKED_CREDENTIALS) |
504 | + |
505 | + self.assert_method_called('store_credentials', FAKED_CREDENTIALS) |
506 | + |
507 | + @defer.inlineCallbacks |
508 | + def test_register(self): |
509 | + """The register method calls proper method.""" |
510 | + yield self.cred_tool.register(**self.window_id_arg) |
511 | + |
512 | + self.assert_method_called('register', self.window_id_arg) |
513 | + |
514 | + @defer.inlineCallbacks |
515 | + def test_login(self): |
516 | + """The login method calls proper method.""" |
517 | + yield self.cred_tool.login(**self.window_id_arg) |
518 | + |
519 | + self.assert_method_called('login', self.window_id_arg) |
520 | + |
521 | + @defer.inlineCallbacks |
522 | + def test_login_email_password(self): |
523 | + """The login method calls proper method.""" |
524 | + yield self.cred_tool.login_email_password(**self.email_password_arg) |
525 | + |
526 | + self.assert_method_called('login_email_password', |
527 | + self.email_password_arg) |
528 | + |
529 | + |
530 | +class NoErrorWithCredsTestCase(CredentialsManagementToolTestCase): |
531 | + """Test case when there was no error, and credentials are present.""" |
532 | + |
533 | + token = {'test': 'me'} |
534 | + |
535 | + @defer.inlineCallbacks |
536 | + def do_test(self, method, expected=None, **kwargs): |
537 | + """Perform the test itself.""" |
538 | + if self.token is not None: |
539 | + self.proxy.store_credentials(self.token) |
540 | + else: |
541 | + yield self.proxy.clear_credentials() |
542 | + actual = yield method(**kwargs) |
543 | + self.assertEqual(expected, actual) |
544 | + |
545 | + @defer.inlineCallbacks |
546 | + def test_find_credentials(self): |
547 | + """The find_credentials method calls proper method.""" |
548 | + yield self.do_test(self.cred_tool.find_credentials, self.token) |
549 | + |
550 | + @defer.inlineCallbacks |
551 | + def test_clear_credentials(self): |
552 | + """The clear_credentials method calls proper method.""" |
553 | + yield self.do_test(self.cred_tool.clear_credentials, None) |
554 | + |
555 | + @defer.inlineCallbacks |
556 | + def test_store_credentials(self): |
557 | + """The store_credentials method calls proper method.""" |
558 | + yield self.do_test(self.cred_tool.store_credentials, None, |
559 | + token=FAKED_CREDENTIALS) |
560 | + |
561 | + @defer.inlineCallbacks |
562 | + def test_register(self): |
563 | + """The register method calls proper method.""" |
564 | + yield self.do_test(self.cred_tool.register, self.token, |
565 | + **self.window_id_arg) |
566 | + |
567 | + @defer.inlineCallbacks |
568 | + def test_login(self): |
569 | + """The login method calls proper method.""" |
570 | + yield self.do_test(self.cred_tool.login, self.token, |
571 | + **self.window_id_arg) |
572 | + |
573 | + @defer.inlineCallbacks |
574 | + def test_login_email_password(self): |
575 | + """The login_email_password method calls proper method.""" |
576 | + yield self.do_test(self.cred_tool.login_email_password, self.token, |
577 | + **self.email_password_arg) |
578 | + |
579 | + |
580 | +class NoErrorNoCredsTestCase(NoErrorWithCredsTestCase): |
581 | + """Test case when there was no error, and credentials are not present.""" |
582 | + |
583 | + token = None |
584 | + |
585 | + @defer.inlineCallbacks |
586 | + def test_find_credentials(self): |
587 | + """The find_credentials method calls proper method.""" |
588 | + yield self.do_test(self.cred_tool.find_credentials, {}) |
589 | + |
590 | + @defer.inlineCallbacks |
591 | + def test_register(self): |
592 | + """The register method calls proper method.""" |
593 | + yield self.do_test(self.cred_tool.register, FAKED_CREDENTIALS, |
594 | + **self.window_id_arg) |
595 | + |
596 | + @defer.inlineCallbacks |
597 | + def test_register_authorization_denied(self): |
598 | + """The register method calls proper method.""" |
599 | + self.token = {} |
600 | + yield self.do_test(self.cred_tool.register, None, |
601 | + **self.window_id_arg) |
602 | + |
603 | + @defer.inlineCallbacks |
604 | + def test_login(self): |
605 | + """The login method calls proper method.""" |
606 | + yield self.do_test(self.cred_tool.login, FAKED_CREDENTIALS, |
607 | + **self.window_id_arg) |
608 | + |
609 | + @defer.inlineCallbacks |
610 | + def test_login_authorization_denied(self): |
611 | + """The login method calls proper method.""" |
612 | + self.token = {} |
613 | + yield self.do_test(self.cred_tool.login, None, **self.window_id_arg) |
614 | + |
615 | + @defer.inlineCallbacks |
616 | + def test_login_email_password(self): |
617 | + """The login_email_password method calls proper method.""" |
618 | + yield self.do_test(self.cred_tool.login_email_password, |
619 | + FAKED_CREDENTIALS, **self.email_password_arg) |
620 | + |
621 | + |
622 | +class WithCredentialsErrorTestCase(NoErrorNoCredsTestCase): |
623 | + """Test case when there was a CredentialsError sent from the proxy.""" |
624 | + |
625 | + error_dict = expected = {'error_type': 'Test'} |
626 | + |
627 | + @defer.inlineCallbacks |
628 | + def do_test(self, method, expected=None, **kwargs): |
629 | + """Perform the test itself.""" |
630 | + exc = yield self.assertFailure(method(**kwargs), Exception) |
631 | + self.assertIsInstance(exc, CredentialsError) |
632 | + self.assertEqual(self.expected, exc.args[0]) |
633 | + |
634 | + |
635 | +class WithErrorHandlerCalledTestCase(WithCredentialsErrorTestCase): |
636 | + """Test case when the error handler was called.""" |
637 | + |
638 | + error_dict = None |
639 | + error_handler = expected = {'error_type': 'Another Test'} |
640 | + |
641 | + |
642 | +class SignalsRemovedTestCase(NoErrorWithCredsTestCase): |
643 | + |
644 | + @defer.inlineCallbacks |
645 | + def do_test(self, method, expected=None, **kwargs): |
646 | + """Perform the test itself.""" |
647 | + yield method(**kwargs) |
648 | + for signal in self.proxy._signals: |
649 | + self.assertTrue(signal.removed) |
650 | |
651 | |
652 | class PingURLPlatformDetails(TestCase): |
653 | |
654 | === modified file 'tests/platform/windows/test_credentials.py' |
655 | --- tests/platform/windows/test_credentials.py 2011-08-16 15:43:52 +0000 |
656 | +++ tests/platform/windows/test_credentials.py 2011-08-26 17:23:37 +0000 |
657 | @@ -20,6 +20,8 @@ |
658 | from twisted.internet import defer |
659 | from twisted.trial.unittest import TestCase |
660 | |
661 | +from contrib.testing.testcase import FAKED_CREDENTIALS |
662 | +from ubuntuone.platform.credentials import APP_NAME |
663 | from ubuntuone.platform.credentials.windows import ( |
664 | CredentialsManagement, |
665 | RemovableSignal, |
666 | @@ -27,9 +29,7 @@ |
667 | |
668 | TEST_APP_NAME = "test application" |
669 | TEST_ERROR_DICT = {} |
670 | -TEST_CREDENTIALS = { |
671 | - "token": "1234token", |
672 | -} |
673 | +TEST_CREDENTIALS = FAKED_CREDENTIALS |
674 | |
675 | |
676 | class FakeSSOProxy(object): |
677 | @@ -77,11 +77,15 @@ |
678 | return defer.succeed(None) |
679 | |
680 | def register(self, app_name, options): |
681 | - """Store the U1 credentials.""" |
682 | + """Register.""" |
683 | return defer.succeed(None) |
684 | |
685 | def login(self, app_name, options): |
686 | - """Store the U1 credentials.""" |
687 | + """Login.""" |
688 | + return defer.succeed(None) |
689 | + |
690 | + def login_email_password(self, app_name, options): |
691 | + """Login using email and password.""" |
692 | return defer.succeed(None) |
693 | |
694 | |
695 | @@ -92,13 +96,27 @@ |
696 | """Initialize this fake instance.""" |
697 | self.proxy = FakeSSOProxy() |
698 | |
699 | + def test_creation(self): |
700 | + """When creating, bind properly to self.proxy.""" |
701 | + rs = RemovableSignal(self.proxy, "test", lambda *a: None) |
702 | + self.assertIs(self.proxy.test, rs) |
703 | + |
704 | def test_dunder_callable(self): |
705 | """__call__ works as expected.""" |
706 | sample_store = [] |
707 | - test_cb = lambda app_name, creds: sample_store.append(creds) |
708 | - rs = RemovableSignal(self.proxy, "on_credentials_found_cb", test_cb) |
709 | - rs(TEST_APP_NAME, TEST_CREDENTIALS) |
710 | - self.assertEqual(sample_store[0], TEST_CREDENTIALS) |
711 | + expected = object() |
712 | + test_cb = lambda res: sample_store.append(res) |
713 | + rs = RemovableSignal(self.proxy, "on_credentials_found_cb", test_cb) |
714 | + rs(APP_NAME, expected) |
715 | + self.assertEqual(sample_store, [expected]) |
716 | + |
717 | + def test_dunder_filters_other_apps(self): |
718 | + """__call__ filters by app_name.""" |
719 | + sample_store = [] |
720 | + test_cb = lambda res: sample_store.append(res) |
721 | + rs = RemovableSignal(self.proxy, "on_credentials_found_cb", test_cb) |
722 | + rs('other app name', object()) |
723 | + self.assertEqual(sample_store, []) |
724 | |
725 | def test_remove(self): |
726 | """The signal has a .remove that removes the callback.""" |
727 | @@ -114,12 +132,22 @@ |
728 | """Tests for CredentialsManagement.""" |
729 | |
730 | timeout = 5 |
731 | + app_name = APP_NAME |
732 | |
733 | def setUp(self): |
734 | """Initialize these tests.""" |
735 | + self._called = False |
736 | self.proxy = FakeSSOProxy() |
737 | self.cm = CredentialsManagement(self.proxy) |
738 | |
739 | + def _set_called(self, *args, **kwargs): |
740 | + """Helper to keep track calls.""" |
741 | + self._called = (args, kwargs) |
742 | + |
743 | + def assert_callback_called(self, expected): |
744 | + """Test that _called helper holds 'expected'.""" |
745 | + self.assertEqual(self._called, expected) |
746 | + |
747 | def test_find_credentials(self): |
748 | """Test the find_credentials method.""" |
749 | d = defer.Deferred() |
750 | @@ -161,17 +189,50 @@ |
751 | self.cm.login({}, reply_handler=ok, error_handler=error) |
752 | return d |
753 | |
754 | + def test_login_email_password(self): |
755 | + """Test the login_email_password method.""" |
756 | + d = defer.Deferred() |
757 | + ok = lambda: d.callback("ok") |
758 | + error = lambda *args: d.errback(args) |
759 | + self.cm.login_email_password({'email': 'foo', 'password': 'bar'}, |
760 | + reply_handler=ok, error_handler=error) |
761 | + return d |
762 | + |
763 | def test_register_to_credentials_found(self): |
764 | """Test the register_to_credentials_found method.""" |
765 | - cb = lambda creds: self.assertEqual(creds, TEST_CREDENTIALS) |
766 | - other_cb = self.cm.register_to_credentials_found(cb) |
767 | - other_cb(TEST_APP_NAME, TEST_CREDENTIALS) |
768 | + signal = self.cm.register_to_credentials_found(self._set_called) |
769 | + signal(self.app_name, TEST_CREDENTIALS) |
770 | + self.assert_callback_called(((TEST_CREDENTIALS,), {})) |
771 | |
772 | def test_register_to_credentials_not_found(self): |
773 | """Test the register_to_credentials_not_found method.""" |
774 | - cb = lambda: None |
775 | - other_cb = self.cm.register_to_credentials_not_found(cb) |
776 | - other_cb(TEST_APP_NAME) |
777 | + signal = self.cm.register_to_credentials_not_found(self._set_called) |
778 | + signal(self.app_name) |
779 | + self.assert_callback_called(((), {})) |
780 | + |
781 | + def test_register_to_credentials_stored(self): |
782 | + """Test the register_to_credentials_stored method.""" |
783 | + signal = self.cm.register_to_credentials_stored(self._set_called) |
784 | + signal(self.app_name) |
785 | + self.assert_callback_called(((), {})) |
786 | + |
787 | + def test_register_to_credentials_cleared(self): |
788 | + """Test the register_to_credentials_cleared method.""" |
789 | + signal = self.cm.register_to_credentials_cleared(self._set_called) |
790 | + signal(self.app_name) |
791 | + self.assert_callback_called(((), {})) |
792 | + |
793 | + def test_register_to_credentials_error(self): |
794 | + """Test the register_to_credentials_error method.""" |
795 | + signal = self.cm.register_to_credentials_error(self._set_called) |
796 | + signal(self.app_name) |
797 | + self.assert_callback_called(((), {})) |
798 | + |
799 | + def test_register_to_authorization_denied(self): |
800 | + """Test the register_to_authorization_denied method.""" |
801 | + signal = self.cm.register_to_authorization_denied(self._set_called) |
802 | + signal(self.app_name, TEST_ERROR_DICT) |
803 | + self.assert_callback_called(((TEST_ERROR_DICT,), {})) |
804 | |
805 | def _verify_not_called_twice(self, signal_name, *args): |
806 | """Test that the callback is not called twice.""" |
807 | @@ -199,7 +260,7 @@ |
808 | |
809 | def test_not_called_twice_credentials_found(self): |
810 | """Test that on_credentials_found is not called twice.""" |
811 | - self._verify_not_called_twice("credentials_found", TEST_APP_NAME, |
812 | + self._verify_not_called_twice("credentials_found", self.app_name, |
813 | TEST_CREDENTIALS) |
814 | |
815 | def test_not_called_twice_credentials_not_found(self): |
816 | @@ -213,3 +274,21 @@ |
817 | def test_not_called_twice_credentials_error(self): |
818 | """Test that on_credentials_error is not called twice.""" |
819 | self._verify_not_called_twice("credentials_error", TEST_ERROR_DICT) |
820 | + |
821 | + def test_connect_to_signal(self): |
822 | + """The connect_to_signal method is correct.""" |
823 | + for signal_name in self.cm._SIGNAL_TO_CALLBACK_MAPPING: |
824 | + match = self.cm.connect_to_signal(signal_name, self._set_called) |
825 | + expected = object() |
826 | + match(APP_NAME, expected) |
827 | + self.assertEqual(self._called, ((expected,), {})) |
828 | + |
829 | + |
830 | +class CredentialsManagementOtherAppNameTestCase(CredentialsManagementTestCase): |
831 | + """Tests for CredentialsManagement when the app name differs.""" |
832 | + |
833 | + app_name = 'other app name' |
834 | + |
835 | + def assert_callback_called(self, expected): |
836 | + """Test that _called helper does not hold 'expected'.""" |
837 | + self.assertEqual(self._called, False) |
838 | |
839 | === modified file 'ubuntuone/platform/credentials/__init__.py' |
840 | --- ubuntuone/platform/credentials/__init__.py 2011-08-18 15:30:53 +0000 |
841 | +++ ubuntuone/platform/credentials/__init__.py 2011-08-26 17:23:37 +0000 |
842 | @@ -25,6 +25,8 @@ |
843 | import urllib |
844 | import sys |
845 | |
846 | +from functools import partial |
847 | + |
848 | from twisted.internet import defer |
849 | |
850 | from ubuntuone import clientdefs |
851 | @@ -83,6 +85,15 @@ |
852 | |
853 | def __init__(self): |
854 | self._cleanup_signals = [] |
855 | + self._proxy = None |
856 | + |
857 | + def callback(self, result, deferred): |
858 | + """Fire 'deferred' with success, sending 'result' as result.""" |
859 | + deferred.callback(result) |
860 | + |
861 | + def errback(self, error, deferred): |
862 | + """Fire 'deferred' with error sending a CredentialsError.""" |
863 | + deferred.errback(CredentialsError(error)) |
864 | |
865 | def cleanup(self, _): |
866 | """Disconnect all the DBus signals.""" |
867 | @@ -93,16 +104,23 @@ |
868 | |
869 | return _ |
870 | |
871 | - def get_creds_proxy(self): |
872 | - """Call the get_proxy_fn, and perhaps wrap the result in a defer.""" |
873 | + def get_platform_source(self): |
874 | + """Platform-specific source.""" |
875 | if sys.platform == 'win32': |
876 | from ubuntuone.platform.credentials import windows |
877 | source = windows |
878 | else: |
879 | from ubuntuone.platform.credentials import linux |
880 | source = linux |
881 | - result = defer.maybeDeferred(source.get_creds_proxy) |
882 | - return result |
883 | + return source |
884 | + |
885 | + @defer.inlineCallbacks |
886 | + def get_creds_proxy(self): |
887 | + """Call the platform-dependent get_creds_proxy caching the result.""" |
888 | + if self._proxy is None: |
889 | + source = self.get_platform_source() |
890 | + self._proxy = yield source.get_creds_proxy() |
891 | + defer.returnValue(self._proxy) |
892 | |
893 | @log_call(logger.debug) |
894 | @defer.inlineCallbacks |
895 | @@ -128,19 +146,21 @@ |
896 | |
897 | proxy = yield self.get_creds_proxy() |
898 | |
899 | - sig = proxy.register_to_credentials_found(d.callback) |
900 | - self._cleanup_signals.append(sig) |
901 | - |
902 | - sig = proxy.register_to_credentials_not_found(lambda: d.callback({})) |
903 | - self._cleanup_signals.append(sig) |
904 | - |
905 | - sig = proxy.register_to_credentials_error( |
906 | - lambda error_dict: d.errback(CredentialsError(error_dict))) |
907 | + sig = proxy.connect_to_signal('CredentialsFound', d.callback) |
908 | + self._cleanup_signals.append(sig) |
909 | + |
910 | + sig = proxy.connect_to_signal('CredentialsNotFound', |
911 | + partial(self.callback, result={}, deferred=d)) |
912 | + self._cleanup_signals.append(sig) |
913 | + |
914 | + sig = proxy.connect_to_signal('CredentialsError', |
915 | + partial(self.errback, deferred=d)) |
916 | self._cleanup_signals.append(sig) |
917 | |
918 | done = defer.Deferred() |
919 | - proxy.find_credentials(reply_handler=lambda: done.callback(None), |
920 | - error_handler=lambda *a: done.errback(a)) |
921 | + proxy.find_credentials( |
922 | + reply_handler=partial(self.callback, result=None, deferred=done), |
923 | + error_handler=partial(self.errback, deferred=done)) |
924 | |
925 | yield done |
926 | |
927 | @@ -161,16 +181,19 @@ |
928 | d.addBoth(self.cleanup) |
929 | |
930 | proxy = yield self.get_creds_proxy() |
931 | - sig = proxy.register_to_credentials_cleared(lambda: d.callback(None)) |
932 | + |
933 | + sig = proxy.connect_to_signal('CredentialsCleared', |
934 | + partial(self.callback, result=None, deferred=d)) |
935 | self._cleanup_signals.append(sig) |
936 | |
937 | - sig = proxy.register_to_credentials_error( |
938 | - lambda error_dict: d.errback(CredentialsError(error_dict))) |
939 | + sig = proxy.connect_to_signal('CredentialsError', |
940 | + partial(self.errback, deferred=d)) |
941 | self._cleanup_signals.append(sig) |
942 | |
943 | done = defer.Deferred() |
944 | - proxy.clear_credentials(reply_handler=lambda: done.callback(None), |
945 | - error_handler=lambda *a: done.errback(a)) |
946 | + proxy.clear_credentials( |
947 | + reply_handler=partial(self.callback, result=None, deferred=done), |
948 | + error_handler=partial(self.errback, deferred=done)) |
949 | |
950 | yield done |
951 | |
952 | @@ -193,17 +216,19 @@ |
953 | d.addBoth(self.cleanup) |
954 | |
955 | proxy = yield self.get_creds_proxy() |
956 | - sig = proxy.register_to_credentials_stored(lambda: d.callback(None)) |
957 | + |
958 | + sig = proxy.connect_to_signal('CredentialsStored', |
959 | + partial(self.callback, result=None, deferred=d)) |
960 | self._cleanup_signals.append(sig) |
961 | |
962 | - sig = proxy.register_to_credentials_error( |
963 | - lambda error_dict: d.errback(CredentialsError(error_dict))) |
964 | + sig = proxy.connect_to_signal('CredentialsError', |
965 | + partial(self.errback, deferred=d)) |
966 | self._cleanup_signals.append(sig) |
967 | |
968 | done = defer.Deferred() |
969 | proxy.store_credentials(token, |
970 | - reply_handler=lambda: done.callback(None), |
971 | - error_handler=lambda *a: done.errback(a)) |
972 | + reply_handler=partial(self.callback, result=None, deferred=done), |
973 | + error_handler=partial(self.errback, deferred=done)) |
974 | |
975 | yield done |
976 | |
977 | @@ -235,20 +260,21 @@ |
978 | |
979 | proxy = yield self.get_creds_proxy() |
980 | |
981 | - sig = proxy.register_to_credentials_found(d.callback) |
982 | - self._cleanup_signals.append(sig) |
983 | - |
984 | - sig = proxy.register_to_authorization_denied(lambda: d.callback(None)) |
985 | - self._cleanup_signals.append(sig) |
986 | - |
987 | - sig = proxy.register_to_credentials_error( |
988 | - lambda error_dict: d.errback(CredentialsError(error_dict))) |
989 | + sig = proxy.connect_to_signal('CredentialsFound', d.callback) |
990 | + self._cleanup_signals.append(sig) |
991 | + |
992 | + sig = proxy.connect_to_signal('AuthorizationDenied', |
993 | + partial(self.callback, result=None, deferred=d)) |
994 | + self._cleanup_signals.append(sig) |
995 | + |
996 | + sig = proxy.connect_to_signal('CredentialsError', |
997 | + partial(self.errback, deferred=d)) |
998 | self._cleanup_signals.append(sig) |
999 | |
1000 | done = defer.Deferred() |
1001 | proxy.register({'window_id': str(window_id)}, |
1002 | - reply_handler=lambda: done.callback(None), |
1003 | - error_handler=lambda *a: done.errback(a)) |
1004 | + reply_handler=partial(self.callback, result=None, deferred=done), |
1005 | + error_handler=partial(self.errback, deferred=done)) |
1006 | |
1007 | yield done |
1008 | |
1009 | @@ -282,20 +308,21 @@ |
1010 | |
1011 | proxy = yield self.get_creds_proxy() |
1012 | |
1013 | - sig = proxy.register_to_credentials_found(d.callback) |
1014 | - self._cleanup_signals.append(sig) |
1015 | - |
1016 | - sig = proxy.register_to_authorization_denied(lambda: d.callback(None)) |
1017 | - self._cleanup_signals.append(sig) |
1018 | - |
1019 | - sig = proxy.register_to_credentials_error( |
1020 | - lambda error_dict: d.errback(CredentialsError(error_dict))) |
1021 | + sig = proxy.connect_to_signal('CredentialsFound', d.callback) |
1022 | + self._cleanup_signals.append(sig) |
1023 | + |
1024 | + sig = proxy.connect_to_signal('AuthorizationDenied', |
1025 | + partial(self.callback, result=None, deferred=d)) |
1026 | + self._cleanup_signals.append(sig) |
1027 | + |
1028 | + sig = proxy.connect_to_signal('CredentialsError', |
1029 | + partial(self.errback, deferred=d)) |
1030 | self._cleanup_signals.append(sig) |
1031 | |
1032 | done = defer.Deferred() |
1033 | proxy.login({'window_id': str(window_id)}, |
1034 | - reply_handler=lambda: done.callback(None), |
1035 | - error_handler=lambda *a: done.errback(a)) |
1036 | + reply_handler=partial(self.callback, result=None, deferred=done), |
1037 | + error_handler=partial(self.errback, deferred=done)) |
1038 | |
1039 | yield done |
1040 | |
1041 | @@ -320,17 +347,17 @@ |
1042 | |
1043 | proxy = yield self.get_creds_proxy() |
1044 | |
1045 | - sig = proxy.register_to_credentials_found(d.callback) |
1046 | + sig = proxy.connect_to_signal('CredentialsFound', d.callback) |
1047 | self._cleanup_signals.append(sig) |
1048 | |
1049 | - sig = proxy.register_to_credentials_error( |
1050 | - lambda x, error_dict: d.errback(CredentialsError(error_dict))) |
1051 | + sig = proxy.connect_to_signal('CredentialsError', |
1052 | + partial(self.errback, deferred=d)) |
1053 | self._cleanup_signals.append(sig) |
1054 | |
1055 | done = defer.Deferred() |
1056 | proxy.login_email_password({'email': email, 'password': password}, |
1057 | - reply_handler=lambda: done.callback(None), |
1058 | - error_handler=lambda *a: done.errback(a)) |
1059 | + reply_handler=partial(self.callback, result=None, deferred=done), |
1060 | + error_handler=partial(self.errback, deferred=done)) |
1061 | |
1062 | yield done |
1063 | |
1064 | |
1065 | === modified file 'ubuntuone/platform/credentials/linux.py' |
1066 | --- ubuntuone/platform/credentials/linux.py 2011-08-16 13:44:20 +0000 |
1067 | +++ ubuntuone/platform/credentials/linux.py 2011-08-26 17:23:37 +0000 |
1068 | @@ -233,75 +233,16 @@ |
1069 | reply_handler=reply_handler, error_handler=error_handler) |
1070 | |
1071 | |
1072 | -class CredentialsManagementProxy(object): |
1073 | - """Proxy that allows to work with the dbus api. |
1074 | - |
1075 | - This proxy has been added to hide the exact details of |
1076 | - how the signals are connected. This allows the reuse of |
1077 | - the CredentialsManagementTool in diff platforms. |
1078 | - """ |
1079 | - |
1080 | - def __init__(self): |
1081 | - """Create a new instance.""" |
1082 | - bus = dbus.SessionBus() |
1083 | - try: |
1084 | - obj = bus.get_object(DBUS_BUS_NAME, |
1085 | - DBUS_CREDENTIALS_PATH, |
1086 | - follow_name_owner_changes=True) |
1087 | - self.proxy = dbus.Interface(obj, DBUS_CREDENTIALS_IFACE) |
1088 | - except: |
1089 | - logger.exception('get_creds_proxy:') |
1090 | - raise |
1091 | - |
1092 | - def find_credentials(self, *args, **kwargs): |
1093 | - """Relay the find_credentials method.""" |
1094 | - return self.proxy.find_credentials(*args, **kwargs) |
1095 | - |
1096 | - def clear_credentials(self, *args, **kwargs): |
1097 | - """Relay the clear_credentials method.""" |
1098 | - return self.proxy.clear_credentials(*args, **kwargs) |
1099 | - |
1100 | - def store_credentials(self, *args, **kwargs): |
1101 | - """Relay the store_credentials method.""" |
1102 | - return self.proxy.store_credentials(*args, **kwargs) |
1103 | - |
1104 | - def register(self, *args, **kwargs): |
1105 | - """Relay the register method.""" |
1106 | - return self.proxy.register(*args, **kwargs) |
1107 | - |
1108 | - def login(self, *args, **kwargs): |
1109 | - """Relay the login method.""" |
1110 | - return self.proxy.login(*args, **kwargs) |
1111 | - |
1112 | - def login_email_password(self, *args, **kwargs): |
1113 | - """Relay the login method.""" |
1114 | - return self.proxy.login_email_password(*args, **kwargs) |
1115 | - |
1116 | - def register_to_credentials_stored(self, callback): |
1117 | - """Register to the CredentialsStored dbus signal.""" |
1118 | - return self.proxy.connect_to_signal('CredentialsStored', callback) |
1119 | - |
1120 | - def register_to_credentials_cleared(self, callback): |
1121 | - """Register to the CredentialsCleared dbus signal.""" |
1122 | - return self.proxy.connect_to_signal('CredentialsCleared', callback) |
1123 | - |
1124 | - def register_to_credentials_found(self, callback): |
1125 | - """Register to the CredentialsFound dbus signal.""" |
1126 | - return self.proxy.connect_to_signal('CredentialsFound', callback) |
1127 | - |
1128 | - def register_to_credentials_not_found(self, callback): |
1129 | - """Register to the CredentialsFound dbus signal.""" |
1130 | - return self.proxy.connect_to_signal('CredentialsNotFound', callback) |
1131 | - |
1132 | - def register_to_authorization_denied(self, callback): |
1133 | - """Register to the AuthorizationDenied dbus signal.""" |
1134 | - return self.proxy.connect_to_signal('AuthorizationDenied', callback) |
1135 | - |
1136 | - def register_to_credentials_error(self, callback): |
1137 | - """Register to the CredentialsError dbus signal.""" |
1138 | - return self.proxy.connect_to_signal('CredentialsError', callback) |
1139 | - |
1140 | - |
1141 | def get_creds_proxy(): |
1142 | """Get the CredentialsManagement proxy.""" |
1143 | - return CredentialsManagementProxy() |
1144 | + bus = dbus.SessionBus() |
1145 | + try: |
1146 | + obj = bus.get_object(DBUS_BUS_NAME, |
1147 | + DBUS_CREDENTIALS_PATH, |
1148 | + follow_name_owner_changes=True) |
1149 | + proxy = dbus.Interface(obj, DBUS_CREDENTIALS_IFACE) |
1150 | + except: |
1151 | + logger.exception('get_creds_proxy:') |
1152 | + raise |
1153 | + |
1154 | + return proxy |
1155 | |
1156 | === modified file 'ubuntuone/platform/credentials/windows.py' |
1157 | --- ubuntuone/platform/credentials/windows.py 2011-08-16 13:44:20 +0000 |
1158 | +++ ubuntuone/platform/credentials/windows.py 2011-08-26 17:23:37 +0000 |
1159 | @@ -30,6 +30,7 @@ |
1160 | from ubuntuone.platform.credentials import ( |
1161 | APP_NAME, |
1162 | DESCRIPTION, |
1163 | + logger, |
1164 | NO_OP, |
1165 | PING_URL, |
1166 | TC_URL, |
1167 | @@ -44,13 +45,26 @@ |
1168 | self.proxy = proxy |
1169 | self.signal_name = signal_name |
1170 | self.callback = callback |
1171 | - setattr(self.proxy, signal_name, callback) |
1172 | + setattr(self.proxy, signal_name, self) |
1173 | |
1174 | def __call__(self, *args, **kwargs): |
1175 | """Call this instance.""" |
1176 | - func = getattr(self.proxy, self.signal_name, None) |
1177 | - if func is not None: |
1178 | - return func(*args, **kwargs) |
1179 | + app_name = args[0] if len(args) > 0 else None |
1180 | + logger.debug('Handling signal_name: %r, app_name: %r.', |
1181 | + self.signal_name, app_name) |
1182 | + |
1183 | + if app_name != APP_NAME: |
1184 | + # This fixed bug #818190: filter signals not related to APP_NAME |
1185 | + logger.info('Received %r but app_name %r does not match %r, ' \ |
1186 | + 'exiting.', self.signal_name, app_name, APP_NAME) |
1187 | + return |
1188 | + |
1189 | + if self.callback is not None: |
1190 | + # drop the app name, callers do not care about it |
1191 | + args = args[1:] |
1192 | + logger.debug('Calling %r with args %r and kwargs %r.', |
1193 | + self.callback, args, kwargs) |
1194 | + return self.callback(*args, **kwargs) |
1195 | |
1196 | def remove(self): |
1197 | """Remove this signal.""" |
1198 | @@ -61,10 +75,25 @@ |
1199 | class CredentialsManagement(object): |
1200 | """Object that manages Ubuntu One credentials.""" |
1201 | |
1202 | + _SIGNAL_TO_CALLBACK_MAPPING = { |
1203 | + 'AuthorizationDenied': 'on_authorization_denied_cb', |
1204 | + 'CredentialsCleared': 'on_credentials_cleared_cb', |
1205 | + 'CredentialsError': 'on_credentials_error_cb', |
1206 | + 'CredentialsFound': 'on_credentials_found_cb', |
1207 | + 'CredentialsNotFound': 'on_credentials_not_found_cb', |
1208 | + 'CredentialsStored': 'on_credentials_stored_cb', |
1209 | + } |
1210 | + |
1211 | def __init__(self, proxy, *args, **kwargs): |
1212 | super(CredentialsManagement, self).__init__(*args, **kwargs) |
1213 | self.sso_proxy = proxy |
1214 | |
1215 | + def connect_to_signal(self, signal_name, callback): |
1216 | + """Register 'callback' to be called when 'signal_name' is emitted.""" |
1217 | + cb_name = self._SIGNAL_TO_CALLBACK_MAPPING[signal_name] |
1218 | + match = RemovableSignal(self.sso_proxy, cb_name, callback) |
1219 | + return match |
1220 | + |
1221 | def find_credentials(self, reply_handler=NO_OP, error_handler=NO_OP): |
1222 | """Ask the Ubuntu One credentials.""" |
1223 | d = self.sso_proxy.find_credentials(APP_NAME, {}) |
1224 | @@ -97,7 +126,8 @@ |
1225 | d = self.sso_proxy.login(APP_NAME, params) |
1226 | d.addCallbacks(lambda _: reply_handler(), error_handler) |
1227 | |
1228 | - def login_email_password(self, args, reply_handler=NO_OP, error_handler=NO_OP): |
1229 | + def login_email_password(self, args, |
1230 | + reply_handler=NO_OP, error_handler=NO_OP): |
1231 | """Get credentials if found else login to Ubuntu One.""" |
1232 | params = {PING_URL_KEY: PING_URL} |
1233 | params.update(args) |
1234 | @@ -116,16 +146,13 @@ |
1235 | |
1236 | def register_to_credentials_found(self, callback): |
1237 | """Register to the CredentialsFound dbus signal.""" |
1238 | - # XXX: we are not filtering by app name (bug #818190) |
1239 | - pass_credentials = lambda app_name, creds: callback(creds) |
1240 | return RemovableSignal(self.sso_proxy, "on_credentials_found_cb", |
1241 | - pass_credentials) |
1242 | + callback) |
1243 | |
1244 | def register_to_credentials_not_found(self, callback): |
1245 | """Register to the CredentialsFound dbus signal.""" |
1246 | - pass_empty = lambda *args: callback() |
1247 | return RemovableSignal(self.sso_proxy, "on_credentials_not_found_cb", |
1248 | - pass_empty) |
1249 | + callback) |
1250 | |
1251 | def register_to_authorization_denied(self, callback): |
1252 | """Register to the AuthorizationDenied dbus signal.""" |
1253 | @@ -142,6 +169,7 @@ |
1254 | def get_creds_proxy(): |
1255 | """Get the CredentialsManagement proxy.""" |
1256 | client = UbuntuSSOClient() |
1257 | - client = yield client.connect() |
1258 | + yield client.connect() |
1259 | yield client.cred_management.register_to_signals() |
1260 | - defer.returnValue(CredentialsManagement(client.cred_management)) |
1261 | + result = CredentialsManagement(client.cred_management) |
1262 | + defer.returnValue(result) |
Very nice cleanup branch.
Some issues:
----
There's a latent issue in making the variable "done" an instance variable in CredentialsMana gementTool, and using it through all the inlineCallbacks generators in this class.
The "done" should be different for each of this generators, since more than one can be used at once.
I strongly believe instance variables *are not* clean to use here, and that they should be left as variables local to the generator. And perhaps we can have callback_done and errback_done get the "done" deferred from each generator via functools.partial.
----
This docstring is wrong (looks duplicated from the one above):
def CredentialsStor ed(self) :
"""Signal thrown when the credentials were cleared."""
----
The empty line should be restored before class CredentialsError.
----