Merge lp:~nataliabidart/ubuntu/natty/ubuntu-sso-client/ubuntu-sso-client-1.1.8 into lp:ubuntu/natty/ubuntu-sso-client
- Natty (11.04)
- ubuntu-sso-client-1.1.8
- Merge into natty
Proposed by
Natalia Bidart
Status: | Merged |
---|---|
Merged at revision: | 23 |
Proposed branch: | lp:~nataliabidart/ubuntu/natty/ubuntu-sso-client/ubuntu-sso-client-1.1.8 |
Merge into: | lp:ubuntu/natty/ubuntu-sso-client |
Diff against target: |
2287 lines (+676/-719) 21 files modified
PKG-INFO (+1/-1) bin/ubuntu-sso-login (+8/-4) contrib/__init__.py (+0/-18) contrib/dbus_util.py (+0/-77) contrib/test (+0/-146) contrib/testing/__init__.py (+0/-1) contrib/testing/dbus-session.conf (+0/-63) contrib/testing/testcase.py (+0/-123) debian/changelog (+18/-0) run-tests (+13/-4) setup.py (+3/-4) ubuntu_sso/credentials.py (+24/-32) ubuntu_sso/gtk/gui.py (+27/-32) ubuntu_sso/gtk/tests/test_gui.py (+156/-87) ubuntu_sso/logger.py (+1/-0) ubuntu_sso/main.py (+53/-4) ubuntu_sso/tests/__init__.py (+14/-0) ubuntu_sso/tests/bin/show_gui (+7/-6) ubuntu_sso/tests/bin/show_nm_state (+3/-3) ubuntu_sso/tests/test_credentials.py (+56/-100) ubuntu_sso/tests/test_main.py (+292/-14) |
To merge this branch: | bzr merge lp:~nataliabidart/ubuntu/natty/ubuntu-sso-client/ubuntu-sso-client-1.1.8 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+46049@code.launchpad.net |
Commit message
Description of the change
* New upstream release:
[ Natalia B. Bidart <email address hidden>]
- The service should shutdown when unused
(LP: #701606),
- On error, {find,clear,
signal (LP: #696676).
- No more gobject dependency on non-GUI classes!
(LP: #695798).
- After login, if the storing of credentials fails, send LoginError
(LP: #693531).
- Use ubuntuone-dev-tools to run the tests and the lint checker
(LP: #686606).
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 2010-12-16 16:31:34 +0000 | |||
3 | +++ PKG-INFO 2011-01-13 00:33:10 +0000 | |||
4 | @@ -1,6 +1,6 @@ | |||
5 | 1 | Metadata-Version: 1.1 | 1 | Metadata-Version: 1.1 |
6 | 2 | Name: ubuntu-sso-client | 2 | Name: ubuntu-sso-client |
8 | 3 | Version: 1.1.7 | 3 | Version: 1.1.8 |
9 | 4 | Summary: Ubuntu Single Sign-On client | 4 | Summary: Ubuntu Single Sign-On client |
10 | 5 | Home-page: https://launchpad.net/ubuntu-sso-client | 5 | Home-page: https://launchpad.net/ubuntu-sso-client |
11 | 6 | Author: Natalia Bidart | 6 | Author: Natalia Bidart |
12 | 7 | 7 | ||
13 | === modified file 'bin/ubuntu-sso-login' | |||
14 | --- bin/ubuntu-sso-login 2010-10-11 13:22:16 +0000 | |||
15 | +++ bin/ubuntu-sso-login 2011-01-13 00:33:10 +0000 | |||
16 | @@ -21,7 +21,9 @@ | |||
17 | 21 | 21 | ||
18 | 22 | """Run the dbus service for UserManagement and ApplicationCredentials.""" | 22 | """Run the dbus service for UserManagement and ApplicationCredentials.""" |
19 | 23 | 23 | ||
21 | 24 | # import decimal even if we don't need it. | 24 | # Invalid name "ubuntu-sso-login", pylint: disable=C0103 |
22 | 25 | |||
23 | 26 | # import decimal even if we don't need it, pylint: disable=W0611 | ||
24 | 25 | import decimal | 27 | import decimal |
25 | 26 | # This is a workaround for LP: #467397. Some module in our depency chain sets | 28 | # This is a workaround for LP: #467397. Some module in our depency chain sets |
26 | 27 | # the locale and imports decimal, and that generates the following trace: | 29 | # the locale and imports decimal, and that generates the following trace: |
27 | @@ -70,8 +72,8 @@ | |||
28 | 70 | # See the link below for info: | 72 | # See the link below for info: |
29 | 71 | # www.listware.net/201004/gtk-devel-list/115067-unix-signals-in-glib.html | 73 | # www.listware.net/201004/gtk-devel-list/115067-unix-signals-in-glib.html |
30 | 72 | # | 74 | # |
33 | 73 | # gtk.main_quit and the logger methods are safe to be called from any thread. | 75 | # gtk.main_quit and the logger methods are safe to be called from any |
34 | 74 | # Just don't call other random stuff here. | 76 | # thread. Just don't call other random stuff here. |
35 | 75 | logger.info("Stoping Ubuntu SSO login manager since SIGHUP was received.") | 77 | logger.info("Stoping Ubuntu SSO login manager since SIGHUP was received.") |
36 | 76 | gtk.main_quit() | 78 | gtk.main_quit() |
37 | 77 | 79 | ||
38 | @@ -92,6 +94,8 @@ | |||
39 | 92 | bus_name = dbus.service.BusName(DBUS_BUS_NAME, bus=dbus.SessionBus()) | 94 | bus_name = dbus.service.BusName(DBUS_BUS_NAME, bus=dbus.SessionBus()) |
40 | 93 | SSOLogin(bus_name, object_path=DBUS_ACCOUNT_PATH) | 95 | SSOLogin(bus_name, object_path=DBUS_ACCOUNT_PATH) |
41 | 94 | SSOCredentials(bus_name, object_path=DBUS_CRED_PATH) | 96 | SSOCredentials(bus_name, object_path=DBUS_CRED_PATH) |
43 | 95 | CredentialsManagement(bus_name, object_path=DBUS_CREDENTIALS_PATH) | 97 | CredentialsManagement(timeout_func=gtk.timeout_add, |
44 | 98 | shutdown_func=gtk.main_quit, | ||
45 | 99 | bus_name=bus_name, object_path=DBUS_CREDENTIALS_PATH) | ||
46 | 96 | 100 | ||
47 | 97 | gtk.main() | 101 | gtk.main() |
48 | 98 | 102 | ||
49 | === removed directory 'contrib' | |||
50 | === removed file 'contrib/__init__.py' | |||
51 | --- contrib/__init__.py 2010-06-22 14:18:04 +0000 | |||
52 | +++ contrib/__init__.py 1970-01-01 00:00:00 +0000 | |||
53 | @@ -1,18 +0,0 @@ | |||
54 | 1 | # contrib - Extra required code to build/install the client | ||
55 | 2 | # | ||
56 | 3 | # Author: Rodney Dawes <rodney.dawes@canonical.com> | ||
57 | 4 | # | ||
58 | 5 | # Copyright 2009-2010 Canonical Ltd. | ||
59 | 6 | # | ||
60 | 7 | # This program is free software: you can redistribute it and/or modify it | ||
61 | 8 | # under the terms of the GNU General Public License version 3, as published | ||
62 | 9 | # by the Free Software Foundation. | ||
63 | 10 | # | ||
64 | 11 | # This program is distributed in the hope that it will be useful, but | ||
65 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranties of | ||
66 | 13 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
67 | 14 | # PURPOSE. See the GNU General Public License for more details. | ||
68 | 15 | # | ||
69 | 16 | # You should have received a copy of the GNU General Public License along | ||
70 | 17 | # with this program. If not, see <http://www.gnu.org/licenses/>. | ||
71 | 18 | """Extra things we need to build, test, or install the client.""" | ||
72 | 19 | 0 | ||
73 | === removed file 'contrib/dbus_util.py' | |||
74 | --- contrib/dbus_util.py 2010-09-08 19:25:02 +0000 | |||
75 | +++ contrib/dbus_util.py 1970-01-01 00:00:00 +0000 | |||
76 | @@ -1,77 +0,0 @@ | |||
77 | 1 | # | ||
78 | 2 | # Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> | ||
79 | 3 | # | ||
80 | 4 | # | ||
81 | 5 | # This program is free software: you can redistribute it and/or modify it | ||
82 | 6 | # under the terms of the GNU General Public License version 3, as published | ||
83 | 7 | # by the Free Software Foundation. | ||
84 | 8 | # | ||
85 | 9 | # This program is distributed in the hope that it will be useful, but | ||
86 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranties of | ||
87 | 11 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
88 | 12 | # PURPOSE. See the GNU General Public License for more details. | ||
89 | 13 | # | ||
90 | 14 | # You should have received a copy of the GNU General Public License along | ||
91 | 15 | # with this program. If not, see <http://www.gnu.org/licenses/>. | ||
92 | 16 | |||
93 | 17 | """Utilies to run a separated DBus session.""" | ||
94 | 18 | |||
95 | 19 | import os | ||
96 | 20 | import signal | ||
97 | 21 | import subprocess | ||
98 | 22 | |||
99 | 23 | from distutils.spawn import find_executable | ||
100 | 24 | |||
101 | 25 | SRCDIR = os.environ.get('SRCDIR', os.getcwd()) | ||
102 | 26 | |||
103 | 27 | |||
104 | 28 | class DBusLaunchError(Exception): | ||
105 | 29 | """Error while launching dbus-daemon.""" | ||
106 | 30 | |||
107 | 31 | |||
108 | 32 | class NotFoundError(Exception): | ||
109 | 33 | """Not found error.""" | ||
110 | 34 | |||
111 | 35 | |||
112 | 36 | class DBusRunner(object): | ||
113 | 37 | """A DBus runner.""" | ||
114 | 38 | |||
115 | 39 | # pylint: disable=C0103 | ||
116 | 40 | |||
117 | 41 | def __init__(self): | ||
118 | 42 | self.dbus_address = None | ||
119 | 43 | self.dbus_pid = None | ||
120 | 44 | self.running = False | ||
121 | 45 | |||
122 | 46 | def startDBus(self): | ||
123 | 47 | """Start our own session bus daemon for testing.""" | ||
124 | 48 | dbus = find_executable("dbus-daemon") | ||
125 | 49 | if not dbus: | ||
126 | 50 | raise NotFoundError("dbus-daemon was not found.") | ||
127 | 51 | |||
128 | 52 | config_file = os.path.join(os.path.abspath(SRCDIR), | ||
129 | 53 | "contrib", "testing", | ||
130 | 54 | "dbus-session.conf") | ||
131 | 55 | dbus_args = ["--fork", | ||
132 | 56 | "--config-file=" + config_file, | ||
133 | 57 | "--print-address=1", | ||
134 | 58 | "--print-pid=2"] | ||
135 | 59 | p = subprocess.Popen([dbus] + dbus_args, | ||
136 | 60 | bufsize=4096, stdout=subprocess.PIPE, | ||
137 | 61 | stderr=subprocess.PIPE) | ||
138 | 62 | |||
139 | 63 | self.dbus_address = "".join(p.stdout.readlines()).strip() | ||
140 | 64 | self.dbus_pid = int("".join(p.stderr.readlines()).strip()) | ||
141 | 65 | |||
142 | 66 | if self.dbus_address != "": | ||
143 | 67 | os.environ["DBUS_SESSION_BUS_ADDRESS"] = self.dbus_address | ||
144 | 68 | else: | ||
145 | 69 | os.kill(self.dbus_pid, signal.SIGKILL) | ||
146 | 70 | raise DBusLaunchError("There was a problem launching dbus-daemon.") | ||
147 | 71 | self.running = True | ||
148 | 72 | |||
149 | 73 | def stopDBus(self): | ||
150 | 74 | """Stop our DBus session bus daemon.""" | ||
151 | 75 | del os.environ["DBUS_SESSION_BUS_ADDRESS"] | ||
152 | 76 | os.kill(self.dbus_pid, signal.SIGKILL) | ||
153 | 77 | self.running = False | ||
154 | 78 | 0 | ||
155 | === removed file 'contrib/test' | |||
156 | --- contrib/test 2010-09-08 19:25:02 +0000 | |||
157 | +++ contrib/test 1970-01-01 00:00:00 +0000 | |||
158 | @@ -1,146 +0,0 @@ | |||
159 | 1 | #!/usr/bin/env python | ||
160 | 2 | # | ||
161 | 3 | # Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> | ||
162 | 4 | # | ||
163 | 5 | # Copyright 2009-2010 Canonical Ltd. | ||
164 | 6 | # | ||
165 | 7 | # This program is free software: you can redistribute it and/or modify it | ||
166 | 8 | # under the terms of the GNU General Public License version 3, as published | ||
167 | 9 | # by the Free Software Foundation. | ||
168 | 10 | # | ||
169 | 11 | # This program is distributed in the hope that it will be useful, but | ||
170 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranties of | ||
171 | 13 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
172 | 14 | # PURPOSE. See the GNU General Public License for more details. | ||
173 | 15 | # | ||
174 | 16 | # You should have received a copy of the GNU General Public License along | ||
175 | 17 | # with this program. If not, see <http://www.gnu.org/licenses/>. | ||
176 | 18 | |||
177 | 19 | import os | ||
178 | 20 | import re | ||
179 | 21 | import signal | ||
180 | 22 | import sys | ||
181 | 23 | import string | ||
182 | 24 | import subprocess | ||
183 | 25 | import unittest | ||
184 | 26 | |||
185 | 27 | sys.path.insert(0, os.path.abspath(".")) | ||
186 | 28 | |||
187 | 29 | from distutils.spawn import find_executable | ||
188 | 30 | |||
189 | 31 | |||
190 | 32 | class TestRunner(object): | ||
191 | 33 | |||
192 | 34 | def _load_unittest(self, relpath): | ||
193 | 35 | """Load unittests from a Python module with the given relative path.""" | ||
194 | 36 | assert relpath.endswith(".py"), ( | ||
195 | 37 | "%s does not appear to be a Python module" % relpath) | ||
196 | 38 | modpath = relpath.replace(os.path.sep, ".")[:-3] | ||
197 | 39 | module = __import__(modpath, None, None, [""]) | ||
198 | 40 | |||
199 | 41 | # If the module has a 'suite' or 'test_suite' function, use that | ||
200 | 42 | # to load the tests. | ||
201 | 43 | if hasattr(module, "suite"): | ||
202 | 44 | return module.suite() | ||
203 | 45 | elif hasattr(module, "test_suite"): | ||
204 | 46 | return module.test_suite() | ||
205 | 47 | else: | ||
206 | 48 | return unittest.defaultTestLoader.loadTestsFromModule(module) | ||
207 | 49 | |||
208 | 50 | def _collect_tests(self, testpath, test_pattern): | ||
209 | 51 | """Return the set of unittests.""" | ||
210 | 52 | suite = unittest.TestSuite() | ||
211 | 53 | if test_pattern: | ||
212 | 54 | pattern = re.compile('.*%s.*' % test_pattern) | ||
213 | 55 | else: | ||
214 | 56 | pattern = None | ||
215 | 57 | |||
216 | 58 | if testpath: | ||
217 | 59 | module_suite = self._load_unittest(testpath) | ||
218 | 60 | if pattern: | ||
219 | 61 | for inner_suite in module_suite._tests: | ||
220 | 62 | for test in inner_suite._tests: | ||
221 | 63 | if pattern.match(test.id()): | ||
222 | 64 | suite.addTest(test) | ||
223 | 65 | else: | ||
224 | 66 | suite.addTests(module_suite) | ||
225 | 67 | return suite | ||
226 | 68 | |||
227 | 69 | # We don't use the dirs variable, so ignore the warning | ||
228 | 70 | # pylint: disable=W0612 | ||
229 | 71 | for root, dirs, files in os.walk("ubuntu_sso"): | ||
230 | 72 | for file in files: | ||
231 | 73 | path = os.path.join(root, file) | ||
232 | 74 | if file.endswith(".py") and file.startswith("test_"): | ||
233 | 75 | module_suite = self._load_unittest(path) | ||
234 | 76 | if pattern: | ||
235 | 77 | for inner_suite in module_suite._tests: | ||
236 | 78 | for test in inner_suite._tests: | ||
237 | 79 | if pattern.match(test.id()): | ||
238 | 80 | suite.addTest(test) | ||
239 | 81 | else: | ||
240 | 82 | suite.addTests(module_suite) | ||
241 | 83 | return suite | ||
242 | 84 | |||
243 | 85 | def run(self, testpath, test_pattern=None, loops=None): | ||
244 | 86 | """run the tests. """ | ||
245 | 87 | # install the glib2reactor before any import of the reactor to avoid | ||
246 | 88 | # using the default SelectReactor and be able to run the dbus tests | ||
247 | 89 | from twisted.internet import glib2reactor | ||
248 | 90 | glib2reactor.install() | ||
249 | 91 | from twisted.internet import reactor | ||
250 | 92 | from twisted.trial.reporter import TreeReporter | ||
251 | 93 | from twisted.trial.runner import TrialRunner | ||
252 | 94 | |||
253 | 95 | from contrib.dbus_util import DBusRunner | ||
254 | 96 | dbus_runner = DBusRunner() | ||
255 | 97 | dbus_runner.startDBus() | ||
256 | 98 | |||
257 | 99 | workingDirectory = os.path.join(os.getcwd(), "_trial_temp", "tmp") | ||
258 | 100 | runner = TrialRunner(reporterFactory=TreeReporter, realTimeErrors=True, | ||
259 | 101 | workingDirectory=workingDirectory) | ||
260 | 102 | |||
261 | 103 | # setup a custom XDG_CACHE_HOME and create the logs directory | ||
262 | 104 | xdg_cache = os.path.join(os.getcwd(), "_trial_temp", "xdg_cache") | ||
263 | 105 | os.environ["XDG_CACHE_HOME"] = xdg_cache | ||
264 | 106 | # setup the ROOTDIR env var | ||
265 | 107 | os.environ['ROOTDIR'] = os.getcwd() | ||
266 | 108 | if not os.path.exists(xdg_cache): | ||
267 | 109 | os.makedirs(xdg_cache) | ||
268 | 110 | success = 0 | ||
269 | 111 | try: | ||
270 | 112 | suite = self._collect_tests(testpath, test_pattern) | ||
271 | 113 | if loops: | ||
272 | 114 | old_suite = suite | ||
273 | 115 | suite = unittest.TestSuite() | ||
274 | 116 | for x in xrange(loops): | ||
275 | 117 | suite.addTest(old_suite) | ||
276 | 118 | result = runner.run(suite) | ||
277 | 119 | success = result.wasSuccessful() | ||
278 | 120 | finally: | ||
279 | 121 | dbus_runner.stopDBus() | ||
280 | 122 | if not success: | ||
281 | 123 | sys.exit(1) | ||
282 | 124 | else: | ||
283 | 125 | sys.exit(0) | ||
284 | 126 | |||
285 | 127 | |||
286 | 128 | if __name__ == '__main__': | ||
287 | 129 | from optparse import OptionParser | ||
288 | 130 | usage = '%prog [options] path' | ||
289 | 131 | parser = OptionParser(usage=usage) | ||
290 | 132 | parser.add_option("-t", "--test", dest="test", | ||
291 | 133 | help="run specific tests, e.g: className.methodName") | ||
292 | 134 | parser.add_option("-l", "--loop", dest="loops", type="int", default=1, | ||
293 | 135 | help="loop selected tests LOOPS number of times", | ||
294 | 136 | metavar="LOOPS") | ||
295 | 137 | |||
296 | 138 | (options, args) = parser.parse_args() | ||
297 | 139 | if args: | ||
298 | 140 | testpath = args[0] | ||
299 | 141 | if not os.path.exists(testpath): | ||
300 | 142 | print "the path to test does not exists!" | ||
301 | 143 | sys.exit() | ||
302 | 144 | else: | ||
303 | 145 | testpath = None | ||
304 | 146 | TestRunner().run(testpath, options.test, options.loops) | ||
305 | 147 | 0 | ||
306 | === removed directory 'contrib/testing' | |||
307 | === removed file 'contrib/testing/__init__.py' | |||
308 | --- contrib/testing/__init__.py 2010-09-08 19:25:02 +0000 | |||
309 | +++ contrib/testing/__init__.py 1970-01-01 00:00:00 +0000 | |||
310 | @@ -1,1 +0,0 @@ | |||
311 | 1 | """Testing utilities for Ubuntu SSO code.""" | ||
312 | 2 | 0 | ||
313 | === removed file 'contrib/testing/dbus-session.conf' | |||
314 | --- contrib/testing/dbus-session.conf 2010-06-18 20:51:58 +0000 | |||
315 | +++ contrib/testing/dbus-session.conf 1970-01-01 00:00:00 +0000 | |||
316 | @@ -1,63 +0,0 @@ | |||
317 | 1 | <!-- This configuration file controls our test-only session bus --> | ||
318 | 2 | |||
319 | 3 | <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN" | ||
320 | 4 | "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> | ||
321 | 5 | <busconfig> | ||
322 | 6 | <!-- We only use a session bus --> | ||
323 | 7 | <type>session</type> | ||
324 | 8 | |||
325 | 9 | <listen>unix:tmpdir=/tmp</listen> | ||
326 | 10 | |||
327 | 11 | <!-- Load our own services. | ||
328 | 12 | To make other dbus service in this session bus, just add another servicedir entry. --> | ||
329 | 13 | <servicedir>dbus-session</servicedir> | ||
330 | 14 | <!-- Load the standard session services --> | ||
331 | 15 | <!--standard_session_servicedirs /--> | ||
332 | 16 | |||
333 | 17 | <policy context="default"> | ||
334 | 18 | <!-- Allow everything to be sent --> | ||
335 | 19 | <allow send_destination="*" eavesdrop="true"/> | ||
336 | 20 | <!-- Allow everything to be received --> | ||
337 | 21 | <allow eavesdrop="true"/> | ||
338 | 22 | <!-- Allow anyone to own anything --> | ||
339 | 23 | <allow own="*"/> | ||
340 | 24 | </policy> | ||
341 | 25 | |||
342 | 26 | <!-- Config files are placed here that among other things, | ||
343 | 27 | further restrict the above policy for specific services. --> | ||
344 | 28 | <includedir>/etc/dbus-1/session.d</includedir> | ||
345 | 29 | |||
346 | 30 | <!-- raise the service start timeout to 40 seconds as it can timeout | ||
347 | 31 | on the live cd on slow machines --> | ||
348 | 32 | <limit name="service_start_timeout">60000</limit> | ||
349 | 33 | |||
350 | 34 | <!-- This is included last so local configuration can override what's | ||
351 | 35 | in this standard file --> | ||
352 | 36 | <include ignore_missing="yes">session-local.conf</include> | ||
353 | 37 | |||
354 | 38 | <include ignore_missing="yes" if_selinux_enabled="yes" selinux_root_relative="yes">contexts/dbus_contexts</include> | ||
355 | 39 | |||
356 | 40 | <!-- For the session bus, override the default relatively-low limits | ||
357 | 41 | with essentially infinite limits, since the bus is just running | ||
358 | 42 | as the user anyway, using up bus resources is not something we need | ||
359 | 43 | to worry about. In some cases, we do set the limits lower than | ||
360 | 44 | "all available memory" if exceeding the limit is almost certainly a bug, | ||
361 | 45 | having the bus enforce a limit is nicer than a huge memory leak. But the | ||
362 | 46 | intent is that these limits should never be hit. --> | ||
363 | 47 | |||
364 | 48 | <!-- the memory limits are 1G instead of say 4G because they can't exceed 32-bit signed int max --> | ||
365 | 49 | <limit name="max_incoming_bytes">1000000000</limit> | ||
366 | 50 | <limit name="max_outgoing_bytes">1000000000</limit> | ||
367 | 51 | <limit name="max_message_size">1000000000</limit> | ||
368 | 52 | <limit name="service_start_timeout">120000</limit> | ||
369 | 53 | <limit name="auth_timeout">240000</limit> | ||
370 | 54 | <limit name="max_completed_connections">100000</limit> | ||
371 | 55 | <limit name="max_incomplete_connections">10000</limit> | ||
372 | 56 | <limit name="max_connections_per_user">100000</limit> | ||
373 | 57 | <limit name="max_pending_service_starts">10000</limit> | ||
374 | 58 | <limit name="max_names_per_connection">50000</limit> | ||
375 | 59 | <limit name="max_match_rules_per_connection">50000</limit> | ||
376 | 60 | <limit name="max_replies_per_connection">50000</limit> | ||
377 | 61 | <limit name="reply_timeout">300000</limit> | ||
378 | 62 | |||
379 | 63 | </busconfig> | ||
380 | 64 | 0 | ||
381 | === removed file 'contrib/testing/testcase.py' | |||
382 | --- contrib/testing/testcase.py 2010-10-11 13:22:16 +0000 | |||
383 | +++ contrib/testing/testcase.py 1970-01-01 00:00:00 +0000 | |||
384 | @@ -1,123 +0,0 @@ | |||
385 | 1 | # | ||
386 | 2 | # Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> | ||
387 | 3 | # Author: Natalia B. Bidart <natalia.bidart@canonical.com> | ||
388 | 4 | # | ||
389 | 5 | # Copyright 2009-2010 Canonical Ltd. | ||
390 | 6 | # | ||
391 | 7 | # This program is free software: you can redistribute it and/or modify it | ||
392 | 8 | # under the terms of the GNU General Public License version 3, as published | ||
393 | 9 | # by the Free Software Foundation. | ||
394 | 10 | # | ||
395 | 11 | # This program is distributed in the hope that it will be useful, but | ||
396 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranties of | ||
397 | 13 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
398 | 14 | # PURPOSE. See the GNU General Public License for more details. | ||
399 | 15 | # | ||
400 | 16 | # You should have received a copy of the GNU General Public License along | ||
401 | 17 | # with this program. If not, see <http://www.gnu.org/licenses/>. | ||
402 | 18 | """Base tests cases and test utilities.""" | ||
403 | 19 | |||
404 | 20 | import logging | ||
405 | 21 | |||
406 | 22 | import dbus | ||
407 | 23 | |||
408 | 24 | from dbus.mainloop.glib import DBusGMainLoop | ||
409 | 25 | from twisted.internet import defer | ||
410 | 26 | from twisted.python import failure | ||
411 | 27 | from twisted.trial.unittest import TestCase | ||
412 | 28 | |||
413 | 29 | |||
414 | 30 | class DBusTestCase(TestCase): | ||
415 | 31 | """Test the DBus event handling.""" | ||
416 | 32 | |||
417 | 33 | def setUp(self): | ||
418 | 34 | """Setup the infrastructure fo the test (dbus service).""" | ||
419 | 35 | self.loop = DBusGMainLoop(set_as_default=True) | ||
420 | 36 | self.bus = dbus.bus.BusConnection(mainloop=self.loop) | ||
421 | 37 | # monkeypatch busName.__del__ to avoid errors on gc | ||
422 | 38 | # we take care of releasing the name in shutdown | ||
423 | 39 | dbus.service.BusName.__del__ = lambda _: None | ||
424 | 40 | self.bus.set_exit_on_disconnect(False) | ||
425 | 41 | self.signal_receivers = set() | ||
426 | 42 | |||
427 | 43 | def tearDown(self): | ||
428 | 44 | """Cleanup the test.""" | ||
429 | 45 | d = self.cleanup_signal_receivers(self.signal_receivers) | ||
430 | 46 | d.addBoth(self._tear_down) | ||
431 | 47 | return d | ||
432 | 48 | |||
433 | 49 | def _tear_down(self, _): | ||
434 | 50 | """Shutdown.""" | ||
435 | 51 | self.bus.flush() | ||
436 | 52 | self.bus.close() | ||
437 | 53 | |||
438 | 54 | def error_handler(self, error): | ||
439 | 55 | """Default error handler for DBus calls.""" | ||
440 | 56 | if isinstance(error, failure.Failure): | ||
441 | 57 | self.fail(error.getErrorMessage()) | ||
442 | 58 | |||
443 | 59 | def cleanup_signal_receivers(self, signal_receivers): | ||
444 | 60 | """Cleanup self.signal_receivers and returns a deferred.""" | ||
445 | 61 | deferreds = [] | ||
446 | 62 | for match in signal_receivers: | ||
447 | 63 | d = defer.Deferred() | ||
448 | 64 | |||
449 | 65 | def callback(*args): | ||
450 | 66 | """Callback that accepts *args.""" | ||
451 | 67 | if not d.called: | ||
452 | 68 | d.callback(args) | ||
453 | 69 | |||
454 | 70 | self.bus.call_async(dbus.bus.BUS_DAEMON_NAME, | ||
455 | 71 | dbus.bus.BUS_DAEMON_PATH, | ||
456 | 72 | dbus.bus.BUS_DAEMON_IFACE, 'RemoveMatch', 's', | ||
457 | 73 | (str(match),), callback, self.error_handler) | ||
458 | 74 | deferreds.append(d) | ||
459 | 75 | if deferreds: | ||
460 | 76 | return defer.DeferredList(deferreds) | ||
461 | 77 | else: | ||
462 | 78 | return defer.succeed(True) | ||
463 | 79 | |||
464 | 80 | |||
465 | 81 | class MementoHandler(logging.Handler): | ||
466 | 82 | """A handler class which store logging records in a list.""" | ||
467 | 83 | |||
468 | 84 | def __init__(self, *args, **kwargs): | ||
469 | 85 | """Create the instance, and add a records attribute.""" | ||
470 | 86 | logging.Handler.__init__(self, *args, **kwargs) | ||
471 | 87 | self.records = [] | ||
472 | 88 | |||
473 | 89 | def emit(self, record): | ||
474 | 90 | """Just add the record to self.records.""" | ||
475 | 91 | self.records.append(record) | ||
476 | 92 | |||
477 | 93 | def check(self, level, *msgs): | ||
478 | 94 | """Verifies that the msgs are logged in the specified level.""" | ||
479 | 95 | for rec in self.records: | ||
480 | 96 | if rec.levelno == level and all(m in rec.message for m in msgs): | ||
481 | 97 | return True | ||
482 | 98 | return False | ||
483 | 99 | |||
484 | 100 | def check_debug(self, *msgs): | ||
485 | 101 | """Shortcut for checking in DEBUG.""" | ||
486 | 102 | return self.check(logging.DEBUG, *msgs) | ||
487 | 103 | |||
488 | 104 | def check_info(self, *msgs): | ||
489 | 105 | """Shortcut for checking in INFO.""" | ||
490 | 106 | return self.check(logging.INFO, *msgs) | ||
491 | 107 | |||
492 | 108 | def check_warning(self, *msgs): | ||
493 | 109 | """Shortcut for checking in WARNING.""" | ||
494 | 110 | return self.check(logging.WARNING, *msgs) | ||
495 | 111 | |||
496 | 112 | def check_error(self, *msgs): | ||
497 | 113 | """Shortcut for checking in ERROR.""" | ||
498 | 114 | return self.check(logging.ERROR, *msgs) | ||
499 | 115 | |||
500 | 116 | def check_exception(self, exception_class, *msgs): | ||
501 | 117 | """Shortcut for checking exceptions.""" | ||
502 | 118 | for rec in self.records: | ||
503 | 119 | if rec.levelno == logging.ERROR and \ | ||
504 | 120 | all(m in rec.exc_text for m in msgs) and \ | ||
505 | 121 | exception_class == rec.exc_info[0]: | ||
506 | 122 | return True | ||
507 | 123 | return False | ||
508 | 124 | 0 | ||
509 | === modified file 'debian/changelog' | |||
510 | --- debian/changelog 2010-12-17 20:25:51 +0000 | |||
511 | +++ debian/changelog 2011-01-13 00:33:10 +0000 | |||
512 | @@ -1,3 +1,21 @@ | |||
513 | 1 | ubuntu-sso-client (1.1.8-0ubuntu1) UNRELEASED; urgency=low | ||
514 | 2 | |||
515 | 3 | * New upstream release: | ||
516 | 4 | |||
517 | 5 | [ Natalia B. Bidart <natalia.bidart@canonical.com>] | ||
518 | 6 | - The service should shutdown when unused | ||
519 | 7 | (LP: #701606), | ||
520 | 8 | - On error, {find,clear,store}_credentials send proper CredentialsError | ||
521 | 9 | signal (LP: #696676). | ||
522 | 10 | - No more gobject dependency on non-GUI classes! | ||
523 | 11 | (LP: #695798). | ||
524 | 12 | - After login, if the storing of credentials fails, send LoginError | ||
525 | 13 | (LP: #693531). | ||
526 | 14 | - Use ubuntuone-dev-tools to run the tests and the lint checker | ||
527 | 15 | (LP: #686606). | ||
528 | 16 | |||
529 | 17 | -- Natalia Bidart (nessita) <nataliabidart@gmail.com> Wed, 12 Jan 2011 15:59:23 -0300 | ||
530 | 18 | |||
531 | 1 | ubuntu-sso-client (1.1.7-0ubuntu1) natty; urgency=low | 19 | ubuntu-sso-client (1.1.7-0ubuntu1) natty; urgency=low |
532 | 2 | 20 | ||
533 | 3 | * New upstream release. | 21 | * New upstream release. |
534 | 4 | 22 | ||
535 | === modified file 'run-tests' | |||
536 | --- run-tests 2010-10-11 13:22:16 +0000 | |||
537 | +++ run-tests 2011-01-13 00:33:10 +0000 | |||
538 | @@ -15,14 +15,23 @@ | |||
539 | 15 | # You should have received a copy of the GNU General Public License along | 15 | # You should have received a copy of the GNU General Public License along |
540 | 16 | # with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
541 | 17 | 17 | ||
542 | 18 | if [ $# -ne 0 ]; then | ||
543 | 19 | # an extra argument was given | ||
544 | 20 | MODULE="$@" | ||
545 | 21 | else | ||
546 | 22 | # run all tests, useful for tarmac and reviews | ||
547 | 23 | MODULE="ubuntu_sso" | ||
548 | 24 | fi | ||
549 | 25 | |||
550 | 18 | style_check() { | 26 | style_check() { |
552 | 19 | pylint contrib ubuntu_sso | 27 | u1lint |
553 | 20 | if [ -x `which pep8` ]; then | 28 | if [ -x `which pep8` ]; then |
555 | 21 | pep8 --repeat bin/ contrib/ ubuntu_sso/ | 29 | pep8 --repeat bin/ $MODULE |
556 | 22 | else | 30 | else |
557 | 23 | echo "Please install the 'pep8' package." | 31 | echo "Please install the 'pep8' package." |
558 | 24 | fi | 32 | fi |
559 | 25 | } | 33 | } |
560 | 26 | 34 | ||
563 | 27 | `which xvfb-run` ./contrib/test "$@" && style_check | 35 | echo "Running test suite for ""$MODULE" |
564 | 28 | rm -rf _trial_temp/ | 36 | `which xvfb-run` u1trial "$MODULE" && style_check |
565 | 37 | rm -rf _trial_temp | ||
566 | 29 | 38 | ||
567 | === modified file 'setup.py' | |||
568 | --- setup.py 2010-12-16 16:31:34 +0000 | |||
569 | +++ setup.py 2011-01-13 00:33:10 +0000 | |||
570 | @@ -31,16 +31,15 @@ | |||
571 | 31 | assert DistUtilsExtra.auto.__version__ >= '2.18', \ | 31 | assert DistUtilsExtra.auto.__version__ >= '2.18', \ |
572 | 32 | 'needs DistUtilsExtra.auto >= 2.18' | 32 | 'needs DistUtilsExtra.auto >= 2.18' |
573 | 33 | 33 | ||
574 | 34 | from distutils.core import setup | ||
575 | 35 | from distutils.spawn import find_executable | 34 | from distutils.spawn import find_executable |
577 | 36 | from distutils.command import clean, build | 35 | from distutils.command import clean |
578 | 37 | 36 | ||
579 | 38 | # Defining variables for various rules here, similar to a Makefile.am | 37 | # Defining variables for various rules here, similar to a Makefile.am |
580 | 39 | CLEANFILES = ['data/com.ubuntu.sso.service', 'po/ubuntu-sso-client.pot', | 38 | CLEANFILES = ['data/com.ubuntu.sso.service', 'po/ubuntu-sso-client.pot', |
581 | 40 | 'MANIFEST'] | 39 | 'MANIFEST'] |
582 | 41 | 40 | ||
583 | 42 | 41 | ||
585 | 43 | # XXX: This needs some serious cleanup | 42 | # This needs some serious cleanup |
586 | 44 | class SSOBuild(build_extra.build_extra): | 43 | class SSOBuild(build_extra.build_extra): |
587 | 45 | """Class to build the extra files.""" | 44 | """Class to build the extra files.""" |
588 | 46 | 45 | ||
589 | @@ -87,7 +86,7 @@ | |||
590 | 87 | 86 | ||
591 | 88 | DistUtilsExtra.auto.setup( | 87 | DistUtilsExtra.auto.setup( |
592 | 89 | name='ubuntu-sso-client', | 88 | name='ubuntu-sso-client', |
594 | 90 | version='1.1.7', | 89 | version='1.1.8', |
595 | 91 | license='GPL v3', | 90 | license='GPL v3', |
596 | 92 | author='Natalia Bidart', | 91 | author='Natalia Bidart', |
597 | 93 | author_email='natalia.bidart@canonical.com', | 92 | author_email='natalia.bidart@canonical.com', |
598 | 94 | 93 | ||
599 | === modified file 'ubuntu_sso/credentials.py' | |||
600 | --- ubuntu_sso/credentials.py 2010-11-30 13:21:17 +0000 | |||
601 | +++ ubuntu_sso/credentials.py 2011-01-13 00:33:10 +0000 | |||
602 | @@ -22,10 +22,12 @@ | |||
603 | 22 | 22 | ||
604 | 23 | * find_credentials | 23 | * find_credentials |
605 | 24 | * clear_credentials | 24 | * clear_credentials |
606 | 25 | * store_credentials | ||
607 | 25 | * register | 26 | * register |
608 | 26 | * login | 27 | * login |
609 | 27 | 28 | ||
611 | 28 | The first two returns immediately (for now). | 29 | The first three return a Deferred that will be fired when the operation was |
612 | 30 | completed. | ||
613 | 29 | 31 | ||
614 | 30 | The second two use the 'success_cb', 'error_cb' and 'denial_cb' to signal the | 32 | The second two use the 'success_cb', 'error_cb' and 'denial_cb' to signal the |
615 | 31 | caller when the credentials were retrieved successfully, when there was an | 33 | caller when the credentials were retrieved successfully, when there was an |
616 | @@ -41,8 +43,6 @@ | |||
617 | 41 | 43 | ||
618 | 42 | from functools import wraps | 44 | from functools import wraps |
619 | 43 | 45 | ||
620 | 44 | import gobject | ||
621 | 45 | |||
622 | 46 | from oauth import oauth | 46 | from oauth import oauth |
623 | 47 | from twisted.internet.defer import inlineCallbacks, returnValue | 47 | from twisted.internet.defer import inlineCallbacks, returnValue |
624 | 48 | 48 | ||
625 | @@ -187,13 +187,15 @@ | |||
626 | 187 | 187 | ||
627 | 188 | @handle_failures(msg='Problem while retrieving credentials') | 188 | @handle_failures(msg='Problem while retrieving credentials') |
628 | 189 | @inlineCallbacks | 189 | @inlineCallbacks |
630 | 190 | def _login_success_cb(self, dialog, app_name, email): | 190 | def _login_success_cb(self, app_name, email): |
631 | 191 | """Store credentials when the login/registration succeeded. | 191 | """Store credentials when the login/registration succeeded. |
632 | 192 | 192 | ||
633 | 193 | Also, open self.ping_url/email to notify about this new token. If any | 193 | Also, open self.ping_url/email to notify about this new token. If any |
634 | 194 | error occur, self.error_cb is called. Otherwise, self.success_cb is | 194 | error occur, self.error_cb is called. Otherwise, self.success_cb is |
635 | 195 | called. | 195 | called. |
636 | 196 | 196 | ||
637 | 197 | Return 0 on success, and a non-zero value (or None) on error. | ||
638 | 198 | |||
639 | 197 | """ | 199 | """ |
640 | 198 | logger.info('Login/registration was successful for app %r, email %r', | 200 | logger.info('Login/registration was successful for app %r, email %r', |
641 | 199 | app_name, email) | 201 | app_name, email) |
642 | @@ -202,19 +204,21 @@ | |||
643 | 202 | assert len(creds) > 0, 'Creds are empty! This should not happen' | 204 | assert len(creds) > 0, 'Creds are empty! This should not happen' |
644 | 203 | # ping a server with the credentials if we were requested to | 205 | # ping a server with the credentials if we were requested to |
645 | 204 | if self.ping_url is not None: | 206 | if self.ping_url is not None: |
647 | 205 | status = self._ping_url(app_name, email, creds) | 207 | status = yield self._ping_url(app_name, email, creds) |
648 | 206 | if status is None: | 208 | if status is None: |
649 | 207 | yield self.clear_credentials() | 209 | yield self.clear_credentials() |
650 | 208 | return | 210 | return |
651 | 209 | 211 | ||
652 | 210 | self.success_cb(creds) | 212 | self.success_cb(creds) |
653 | 213 | returnValue(0) | ||
654 | 211 | 214 | ||
656 | 212 | def _auth_denial_cb(self, dialog, app_name): | 215 | def _auth_denial_cb(self, app_name): |
657 | 213 | """The user decided not to allow the registration or login.""" | 216 | """The user decided not to allow the registration or login.""" |
658 | 214 | logger.warning('Login/registration was denied to app %r', app_name) | 217 | logger.warning('Login/registration was denied to app %r', app_name) |
659 | 215 | self.denial_cb(app_name) | 218 | self.denial_cb(app_name) |
660 | 216 | 219 | ||
662 | 217 | @handle_exceptions(msg='Problem opening the ping_url') | 220 | @handle_failures(msg='Problem opening the ping_url') |
663 | 221 | @inlineCallbacks | ||
664 | 218 | def _ping_url(self, app_name, email, credentials): | 222 | def _ping_url(self, app_name, email, credentials): |
665 | 219 | """Ping the self.ping_url with the email attached. | 223 | """Ping the self.ping_url with the email attached. |
666 | 220 | 224 | ||
667 | @@ -237,9 +241,12 @@ | |||
668 | 237 | request = urllib2.Request(url, headers=oauth_req.to_header()) | 241 | request = urllib2.Request(url, headers=oauth_req.to_header()) |
669 | 238 | logger.debug('Opening the url "%s" with urllib2.urlopen.', | 242 | logger.debug('Opening the url "%s" with urllib2.urlopen.', |
670 | 239 | request.get_full_url()) | 243 | request.get_full_url()) |
671 | 244 | # This code is blocking, we should change this. | ||
672 | 245 | # I've tried with deferToThread an twisted.web.client.getPage | ||
673 | 246 | # but the returned deferred will never be fired (nataliabidart). | ||
674 | 240 | response = urllib2.urlopen(request) | 247 | response = urllib2.urlopen(request) |
675 | 241 | logger.debug('Url opened. Response: %s.', response.code) | 248 | logger.debug('Url opened. Response: %s.', response.code) |
677 | 242 | return response.code | 249 | returnValue(response.code) |
678 | 243 | 250 | ||
679 | 244 | @handle_exceptions(msg='Problem opening the Ubuntu SSO user interface') | 251 | @handle_exceptions(msg='Problem opening the Ubuntu SSO user interface') |
680 | 245 | def _show_ui(self, login_only): | 252 | def _show_ui(self, login_only): |
681 | @@ -252,10 +259,9 @@ | |||
682 | 252 | tc_url=self.tc_url, help_text=self.help_text, | 259 | tc_url=self.tc_url, help_text=self.help_text, |
683 | 253 | window_id=self.window_id, login_only=login_only) | 260 | window_id=self.window_id, login_only=login_only) |
684 | 254 | 261 | ||
689 | 255 | self.gui.connect(gui.SIG_LOGIN_SUCCEEDED, self._login_success_cb) | 262 | self.gui.login_success_callback = self._login_success_cb |
690 | 256 | self.gui.connect(gui.SIG_REGISTRATION_SUCCEEDED, | 263 | self.gui.registration_success_callback = self._login_success_cb |
691 | 257 | self._login_success_cb) | 264 | self.gui.user_cancellation_callback = self._auth_denial_cb |
688 | 258 | self.gui.connect(gui.SIG_USER_CANCELATION, self._auth_denial_cb) | ||
692 | 259 | 265 | ||
693 | 260 | @handle_failures(msg='Problem while retrieving credentials') | 266 | @handle_failures(msg='Problem while retrieving credentials') |
694 | 261 | @inlineCallbacks | 267 | @inlineCallbacks |
695 | @@ -265,35 +271,23 @@ | |||
696 | 265 | if token is not None and len(token) > 0: | 271 | if token is not None and len(token) > 0: |
697 | 266 | self.success_cb(token) | 272 | self.success_cb(token) |
698 | 267 | elif token == {}: | 273 | elif token == {}: |
700 | 268 | gobject.idle_add(self._show_ui, login_only) | 274 | self._show_ui(login_only) |
701 | 269 | else: | 275 | else: |
702 | 270 | # something went wrong with find_credentials, already handled. | 276 | # something went wrong with find_credentials, already handled. |
703 | 271 | logger.info('_login_or_register: call to "find_credentials" went ' | 277 | logger.info('_login_or_register: call to "find_credentials" went ' |
704 | 272 | 'wrong, and was already handled.') | 278 | 'wrong, and was already handled.') |
705 | 273 | 279 | ||
706 | 274 | def error_cb(self, error_dict): | 280 | def error_cb(self, error_dict): |
712 | 275 | """Handle error. | 281 | """Handle error and notify the caller.""" |
713 | 276 | 282 | logger.error('Calling error callback at %r (error is %r).', | |
714 | 277 | Notify the caller and finish the GUI with error. | 283 | self._error_cb, error_dict) |
710 | 278 | |||
711 | 279 | """ | ||
715 | 280 | self._error_cb(self.app_name, error_dict) | 284 | self._error_cb(self.app_name, error_dict) |
716 | 281 | if self.gui is not None: | ||
717 | 282 | self.gui.finish_error(error=error_dict) | ||
718 | 283 | self.gui = None | ||
719 | 284 | 285 | ||
720 | 285 | def success_cb(self, creds): | 286 | def success_cb(self, creds): |
726 | 286 | """Handle success. | 287 | """Handle success and notify the caller.""" |
727 | 287 | 288 | logger.debug('Calling success callback at %r.', self._success_cb) | |
723 | 288 | Notify the caller and finish the GUI with success. | ||
724 | 289 | |||
725 | 290 | """ | ||
728 | 291 | self._success_cb(self.app_name, creds) | 289 | self._success_cb(self.app_name, creds) |
729 | 292 | if self.gui is not None: | ||
730 | 293 | self.gui.finish_success() | ||
731 | 294 | self.gui = None | ||
732 | 295 | 290 | ||
733 | 296 | @handle_failures(msg='Problem while retrieving credentials') | ||
734 | 297 | @inlineCallbacks | 291 | @inlineCallbacks |
735 | 298 | def find_credentials(self): | 292 | def find_credentials(self): |
736 | 299 | """Get the credentials for 'self.app_name'. Return {} if not there.""" | 293 | """Get the credentials for 'self.app_name'. Return {} if not there.""" |
737 | @@ -302,13 +296,11 @@ | |||
738 | 302 | 'result is {}? %s', self.app_name, creds is None) | 296 | 'result is {}? %s', self.app_name, creds is None) |
739 | 303 | returnValue(creds if creds is not None else {}) | 297 | returnValue(creds if creds is not None else {}) |
740 | 304 | 298 | ||
741 | 305 | @handle_failures(msg='Problem while deleting credentials') | ||
742 | 306 | @inlineCallbacks | 299 | @inlineCallbacks |
743 | 307 | def clear_credentials(self): | 300 | def clear_credentials(self): |
744 | 308 | """Clear the credentials for 'self.app_name'.""" | 301 | """Clear the credentials for 'self.app_name'.""" |
745 | 309 | yield Keyring().delete_credentials(self.app_name) | 302 | yield Keyring().delete_credentials(self.app_name) |
746 | 310 | 303 | ||
747 | 311 | @handle_failures(msg='Problem while storing credentials') | ||
748 | 312 | @inlineCallbacks | 304 | @inlineCallbacks |
749 | 313 | def store_credentials(self, token): | 305 | def store_credentials(self, token): |
750 | 314 | """Store the credentials for 'self.app_name'.""" | 306 | """Store the credentials for 'self.app_name'.""" |
751 | 315 | 307 | ||
752 | === modified file 'ubuntu_sso/gtk/gui.py' | |||
753 | --- ubuntu_sso/gtk/gui.py 2010-11-30 13:21:17 +0000 | |||
754 | +++ ubuntu_sso/gtk/gui.py 2011-01-13 00:33:10 +0000 | |||
755 | @@ -30,11 +30,11 @@ | |||
756 | 30 | 30 | ||
757 | 31 | import dbus | 31 | import dbus |
758 | 32 | import gettext | 32 | import gettext |
759 | 33 | import gobject | ||
760 | 34 | import gtk | 33 | import gtk |
761 | 35 | import xdg | 34 | import xdg |
762 | 36 | 35 | ||
763 | 37 | from dbus.mainloop.glib import DBusGMainLoop | 36 | from dbus.mainloop.glib import DBusGMainLoop |
764 | 37 | from twisted.internet.defer import inlineCallbacks | ||
765 | 38 | 38 | ||
766 | 39 | from ubuntu_sso import (DBUS_ACCOUNT_PATH, DBUS_BUS_NAME, DBUS_IFACE_USER_NAME, | 39 | from ubuntu_sso import (DBUS_ACCOUNT_PATH, DBUS_BUS_NAME, DBUS_IFACE_USER_NAME, |
767 | 40 | NO_OP) | 40 | NO_OP) |
768 | @@ -72,20 +72,6 @@ | |||
769 | 72 | HELP_TEXT_COLOR = gtk.gdk.Color("#bfbfbf") | 72 | HELP_TEXT_COLOR = gtk.gdk.Color("#bfbfbf") |
770 | 73 | WARNING_TEXT_COLOR = gtk.gdk.Color("red") | 73 | WARNING_TEXT_COLOR = gtk.gdk.Color("red") |
771 | 74 | 74 | ||
772 | 75 | SIG_LOGIN_SUCCEEDED = 'login-succeeded' | ||
773 | 76 | SIG_REGISTRATION_SUCCEEDED = 'registration-succeeded' | ||
774 | 77 | SIG_USER_CANCELATION = 'user-cancelation' | ||
775 | 78 | |||
776 | 79 | SIGNAL_ARGUMENTS = [ | ||
777 | 80 | (SIG_LOGIN_SUCCEEDED, (gobject.TYPE_STRING, gobject.TYPE_STRING,)), | ||
778 | 81 | (SIG_REGISTRATION_SUCCEEDED, (gobject.TYPE_STRING, gobject.TYPE_STRING,)), | ||
779 | 82 | (SIG_USER_CANCELATION, (gobject.TYPE_STRING,)), | ||
780 | 83 | ] | ||
781 | 84 | |||
782 | 85 | for sig, sig_args in SIGNAL_ARGUMENTS: | ||
783 | 86 | gobject.signal_new(sig, gtk.Window, gobject.SIGNAL_RUN_FIRST, | ||
784 | 87 | gobject.TYPE_NONE, sig_args) | ||
785 | 88 | |||
786 | 89 | 75 | ||
787 | 90 | def get_data_dir(): | 76 | def get_data_dir(): |
788 | 91 | """Build absolute path to the 'data' directory.""" | 77 | """Build absolute path to the 'data' directory.""" |
789 | @@ -198,7 +184,7 @@ | |||
790 | 198 | 184 | ||
791 | 199 | 185 | ||
792 | 200 | class UbuntuSSOClientGUI(object): | 186 | class UbuntuSSOClientGUI(object): |
794 | 201 | """Ubuntu single sign on GUI.""" | 187 | """Ubuntu single sign-on GUI.""" |
795 | 202 | 188 | ||
796 | 203 | CAPTCHA_SOLUTION_ENTRY = _('Type the characters above') | 189 | CAPTCHA_SOLUTION_ENTRY = _('Type the characters above') |
797 | 204 | CAPTCHA_LOAD_ERROR = _('There was a problem getting the captcha, ' | 190 | CAPTCHA_LOAD_ERROR = _('There was a problem getting the captcha, ' |
798 | @@ -256,7 +242,7 @@ | |||
799 | 256 | CAPTCHA_RELOAD_TOOLTIP = _('Reload') | 242 | CAPTCHA_RELOAD_TOOLTIP = _('Reload') |
800 | 257 | 243 | ||
801 | 258 | def __init__(self, app_name, tc_url='', help_text='', | 244 | def __init__(self, app_name, tc_url='', help_text='', |
803 | 259 | window_id=0, login_only=False, close_callback=None): | 245 | window_id=0, login_only=False): |
804 | 260 | """Create the GUI and initialize widgets.""" | 246 | """Create the GUI and initialize widgets.""" |
805 | 261 | gtk.link_button_set_uri_hook(NO_OP) | 247 | gtk.link_button_set_uri_hook(NO_OP) |
806 | 262 | 248 | ||
807 | @@ -270,7 +256,12 @@ | |||
808 | 270 | self.tc_url = tc_url | 256 | self.tc_url = tc_url |
809 | 271 | self.help_text = help_text | 257 | self.help_text = help_text |
810 | 272 | self.login_only = login_only | 258 | self.login_only = login_only |
812 | 273 | self.close_callback = close_callback | 259 | |
813 | 260 | self.close_callback = NO_OP | ||
814 | 261 | self.login_success_callback = NO_OP | ||
815 | 262 | self.registration_success_callback = NO_OP | ||
816 | 263 | self.user_cancellation_callback = NO_OP | ||
817 | 264 | |||
818 | 274 | self.user_email = None | 265 | self.user_email = None |
819 | 275 | self.user_password = None | 266 | self.user_password = None |
820 | 276 | 267 | ||
821 | @@ -730,17 +721,12 @@ | |||
822 | 730 | signal_name, handler, args, kwargs) | 721 | signal_name, handler, args, kwargs) |
823 | 731 | self.window.connect(signal_name, handler, *args, **kwargs) | 722 | self.window.connect(signal_name, handler, *args, **kwargs) |
824 | 732 | 723 | ||
825 | 733 | def emit(self, *args, **kwargs): | ||
826 | 734 | """Emit a signal proxing the main window.""" | ||
827 | 735 | logger.debug('emit: args %r, kwargs, %r', args, kwargs) | ||
828 | 736 | self.window.emit(*args, **kwargs) | ||
829 | 737 | |||
830 | 738 | def finish_success(self): | 724 | def finish_success(self): |
831 | 739 | """The whole process was completed succesfully. Show success page.""" | 725 | """The whole process was completed succesfully. Show success page.""" |
832 | 740 | self._done = True | 726 | self._done = True |
833 | 741 | self._set_current_page(self.success_vbox) | 727 | self._set_current_page(self.success_vbox) |
834 | 742 | 728 | ||
836 | 743 | def finish_error(self, error): | 729 | def finish_error(self): |
837 | 744 | """The whole process was not completed succesfully. Show error page.""" | 730 | """The whole process was not completed succesfully. Show error page.""" |
838 | 745 | self._done = True | 731 | self._done = True |
839 | 746 | self._set_current_page(self.error_vbox) | 732 | self._set_current_page(self.error_vbox) |
840 | @@ -766,18 +752,17 @@ | |||
841 | 766 | if self.window is not None: | 752 | if self.window is not None: |
842 | 767 | self.window.hide() | 753 | self.window.hide() |
843 | 768 | 754 | ||
845 | 769 | # process any pending events before emitting signals | 755 | # process any pending events before callbacking with result |
846 | 770 | while gtk.events_pending(): | 756 | while gtk.events_pending(): |
847 | 771 | gtk.main_iteration() | 757 | gtk.main_iteration() |
848 | 772 | 758 | ||
849 | 773 | if not self._done: | 759 | if not self._done: |
851 | 774 | self.emit(SIG_USER_CANCELATION, self.app_name) | 760 | self.user_cancellation_callback(self.app_name) |
852 | 775 | 761 | ||
853 | 776 | # call user defined callback | 762 | # call user defined callback |
858 | 777 | if self.close_callback is not None: | 763 | logger.info('Calling custom close_callback %r with params %r, %r', |
859 | 778 | logger.info('Calling custom close_callback %r with params %r, %r', | 764 | self.close_callback, args, kwargs) |
860 | 779 | self.close_callback, args, kwargs) | 765 | self.close_callback(*args, **kwargs) |
857 | 780 | self.close_callback(*args, **kwargs) | ||
861 | 781 | 766 | ||
862 | 782 | def on_sign_in_button_clicked(self, *args, **kwargs): | 767 | def on_sign_in_button_clicked(self, *args, **kwargs): |
863 | 783 | """User wants to sign in, present the Login page.""" | 768 | """User wants to sign in, present the Login page.""" |
864 | @@ -1096,10 +1081,15 @@ | |||
865 | 1096 | self._set_current_page(self.enter_details_vbox, warning_text=msg) | 1081 | self._set_current_page(self.enter_details_vbox, warning_text=msg) |
866 | 1097 | 1082 | ||
867 | 1098 | @log_call | 1083 | @log_call |
868 | 1084 | @inlineCallbacks | ||
869 | 1099 | def on_email_validated(self, app_name, email, *args, **kwargs): | 1085 | def on_email_validated(self, app_name, email, *args, **kwargs): |
870 | 1100 | """User email was successfully verified.""" | 1086 | """User email was successfully verified.""" |
871 | 1101 | self._done = True | 1087 | self._done = True |
873 | 1102 | self.emit(SIG_REGISTRATION_SUCCEEDED, self.app_name, email) | 1088 | result = yield self.registration_success_callback(self.app_name, email) |
874 | 1089 | if result == 0: | ||
875 | 1090 | self.finish_success() | ||
876 | 1091 | else: | ||
877 | 1092 | self.finish_error() | ||
878 | 1103 | 1093 | ||
879 | 1104 | @log_call | 1094 | @log_call |
880 | 1105 | def on_email_validation_error(self, app_name, error, *args, **kwargs): | 1095 | def on_email_validation_error(self, app_name, error, *args, **kwargs): |
881 | @@ -1112,10 +1102,15 @@ | |||
882 | 1112 | self._set_current_page(self.verify_email_vbox, warning_text=msg) | 1102 | self._set_current_page(self.verify_email_vbox, warning_text=msg) |
883 | 1113 | 1103 | ||
884 | 1114 | @log_call | 1104 | @log_call |
885 | 1105 | @inlineCallbacks | ||
886 | 1115 | def on_logged_in(self, app_name, email, *args, **kwargs): | 1106 | def on_logged_in(self, app_name, email, *args, **kwargs): |
887 | 1116 | """User was successfully logged in.""" | 1107 | """User was successfully logged in.""" |
888 | 1117 | self._done = True | 1108 | self._done = True |
890 | 1118 | self.emit(SIG_LOGIN_SUCCEEDED, self.app_name, email) | 1109 | result = yield self.login_success_callback(self.app_name, email) |
891 | 1110 | if result == 0: | ||
892 | 1111 | self.finish_success() | ||
893 | 1112 | else: | ||
894 | 1113 | self.finish_error() | ||
895 | 1119 | 1114 | ||
896 | 1120 | @log_call | 1115 | @log_call |
897 | 1121 | def on_login_error(self, app_name, error, *args, **kwargs): | 1116 | def on_login_error(self, app_name, error, *args, **kwargs): |
898 | 1122 | 1117 | ||
899 | === modified file 'ubuntu_sso/gtk/tests/test_gui.py' | |||
900 | --- ubuntu_sso/gtk/tests/test_gui.py 2010-11-30 13:21:17 +0000 | |||
901 | +++ ubuntu_sso/gtk/tests/test_gui.py 2011-01-13 00:33:10 +0000 | |||
902 | @@ -30,8 +30,8 @@ | |||
903 | 30 | import webkit | 30 | import webkit |
904 | 31 | 31 | ||
905 | 32 | from twisted.trial.unittest import TestCase | 32 | from twisted.trial.unittest import TestCase |
906 | 33 | from ubuntuone.devtools.handlers import MementoHandler | ||
907 | 33 | 34 | ||
908 | 34 | from contrib.testing.testcase import MementoHandler | ||
909 | 35 | from ubuntu_sso.gtk import gui | 35 | from ubuntu_sso.gtk import gui |
910 | 36 | from ubuntu_sso.tests import (APP_NAME, TC_URL, HELP_TEXT, CAPTCHA_ID, | 36 | from ubuntu_sso.tests import (APP_NAME, TC_URL, HELP_TEXT, CAPTCHA_ID, |
911 | 37 | CAPTCHA_SOLUTION, EMAIL, EMAIL_TOKEN, NAME, PASSWORD, RESET_PASSWORD_TOKEN) | 37 | CAPTCHA_SOLUTION, EMAIL, EMAIL_TOKEN, NAME, PASSWORD, RESET_PASSWORD_TOKEN) |
912 | @@ -517,6 +517,11 @@ | |||
913 | 517 | self.assertTrue(self._called, | 517 | self.assertTrue(self._called, |
914 | 518 | 'close_callback was called when window was closed.') | 518 | 'close_callback was called when window was closed.') |
915 | 519 | 519 | ||
916 | 520 | def test_close_callback_if_not_set(self): | ||
917 | 521 | """The close_callback is a no op if not set.""" | ||
918 | 522 | self.ui.on_close_clicked() | ||
919 | 523 | # no crash when close_callback is not set | ||
920 | 524 | |||
921 | 520 | def test_app_name_is_stored(self): | 525 | def test_app_name_is_stored(self): |
922 | 521 | """The app_name is stored for further use.""" | 526 | """The app_name is stored for further use.""" |
923 | 522 | self.assertIn(APP_NAME, self.ui.app_name) | 527 | self.assertIn(APP_NAME, self.ui.app_name) |
924 | @@ -555,18 +560,6 @@ | |||
925 | 555 | 560 | ||
926 | 556 | self.assertEqual(self.ui.bus.callbacks, {}) | 561 | self.assertEqual(self.ui.bus.callbacks, {}) |
927 | 557 | 562 | ||
928 | 558 | def test_close_callback(self): | ||
929 | 559 | """A close_callback parameter is called when closing the window.""" | ||
930 | 560 | ui = self.gui_class(close_callback=self._set_called, **self.kwargs) | ||
931 | 561 | ui.on_close_clicked() | ||
932 | 562 | self.assertTrue(self._called, 'close_callback was called on close.') | ||
933 | 563 | |||
934 | 564 | def test_close_callback_if_none(self): | ||
935 | 565 | """A close_callback parameter is not called if is None.""" | ||
936 | 566 | ui = self.gui_class(close_callback=None, **self.kwargs) | ||
937 | 567 | ui.on_close_clicked() | ||
938 | 568 | # no crash when close_callback is None | ||
939 | 569 | |||
940 | 570 | def test_pages_are_packed_into_container(self): | 563 | def test_pages_are_packed_into_container(self): |
941 | 571 | """All the pages are packed in the main container.""" | 564 | """All the pages are packed in the main container.""" |
942 | 572 | children = self.ui.content.get_children() | 565 | children = self.ui.content.get_children() |
943 | @@ -620,8 +613,7 @@ | |||
944 | 620 | buttons = filter(lambda name: 'cancel_button' in name or | 613 | buttons = filter(lambda name: 'cancel_button' in name or |
945 | 621 | 'close_button' in name, self.ui.widgets) | 614 | 'close_button' in name, self.ui.widgets) |
946 | 622 | for name in buttons: | 615 | for name in buttons: |
949 | 623 | self.ui = self.gui_class(close_callback=self._set_called, | 616 | self.ui.close_callback = self._set_called |
948 | 624 | **self.kwargs) | ||
950 | 625 | widget = getattr(self.ui, name) | 617 | widget = getattr(self.ui, name) |
951 | 626 | widget.clicked() | 618 | widget.clicked() |
952 | 627 | self.assertEqual(self._called, ((widget,), {}), msg % name) | 619 | self.assertEqual(self._called, ((widget,), {}), msg % name) |
953 | @@ -661,7 +653,7 @@ | |||
954 | 661 | 653 | ||
955 | 662 | def test_finish_error_shows_error_page(self): | 654 | def test_finish_error_shows_error_page(self): |
956 | 663 | """When calling 'finish_error' the error page is shown.""" | 655 | """When calling 'finish_error' the error page is shown.""" |
958 | 664 | self.ui.finish_error(error=self.error) | 656 | self.ui.finish_error() |
959 | 665 | self.assert_pages_visibility(finish=True) | 657 | self.assert_pages_visibility(finish=True) |
960 | 666 | self.assertEqual(self.ui.ERROR, self.ui.finish_vbox.label.get_text()) | 658 | self.assertEqual(self.ui.ERROR, self.ui.finish_vbox.label.get_text()) |
961 | 667 | 659 | ||
962 | @@ -1164,10 +1156,10 @@ | |||
963 | 1164 | self.click_verify_email_with_valid_data() | 1156 | self.click_verify_email_with_valid_data() |
964 | 1165 | self.assert_warnings_visibility() | 1157 | self.assert_warnings_visibility() |
965 | 1166 | 1158 | ||
968 | 1167 | def test_on_email_validated_shows_processing_page(self): | 1159 | def test_on_email_validated_shows_finish_page(self): |
969 | 1168 | """On email validated the procesing page is still shown.""" | 1160 | """On email validated the finish page is shown.""" |
970 | 1169 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) | 1161 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) |
972 | 1170 | self.assert_pages_visibility(processing=True) | 1162 | self.assert_pages_visibility(finish=True) |
973 | 1171 | 1163 | ||
974 | 1172 | def test_on_email_validated_does_not_clear_the_help_text(self): | 1164 | def test_on_email_validated_does_not_clear_the_help_text(self): |
975 | 1173 | """On email validated the help text is not removed.""" | 1165 | """On email validated the help text is not removed.""" |
976 | @@ -1227,6 +1219,32 @@ | |||
977 | 1227 | self.ui.verify_token_button.clicked() | 1219 | self.ui.verify_token_button.clicked() |
978 | 1228 | self.assertTrue(self._called) | 1220 | self.assertTrue(self._called) |
979 | 1229 | 1221 | ||
980 | 1222 | def test_after_registration_success_finish_success(self): | ||
981 | 1223 | """After REGISTRATION_SUCCESS is called, finish_success is called. | ||
982 | 1224 | |||
983 | 1225 | Only when REGISTRATION_SUCCESS returns 0. | ||
984 | 1226 | |||
985 | 1227 | """ | ||
986 | 1228 | self.patch(self.ui, 'finish_success', self._set_called) | ||
987 | 1229 | self.ui.registration_success_callback = lambda app, email: 0 | ||
988 | 1230 | |||
989 | 1231 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) | ||
990 | 1232 | |||
991 | 1233 | self.assertEqual(self._called, ((), {})) | ||
992 | 1234 | |||
993 | 1235 | def test_after_registration_error_finish_error(self): | ||
994 | 1236 | """After REGISTRATION_SUCCESS is called, finish_error is called. | ||
995 | 1237 | |||
996 | 1238 | Only when REGISTRATION_SUCCESS returns a non-zero value. | ||
997 | 1239 | |||
998 | 1240 | """ | ||
999 | 1241 | self.patch(self.ui, 'finish_error', self._set_called) | ||
1000 | 1242 | self.ui.registration_success_callback = lambda app, email: -1 | ||
1001 | 1243 | |||
1002 | 1244 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) | ||
1003 | 1245 | |||
1004 | 1246 | self.assertEqual(self._called, ((), {})) | ||
1005 | 1247 | |||
1006 | 1230 | 1248 | ||
1007 | 1231 | class VerifyEmailValidationTestCase(UbuntuSSOClientTestCase): | 1249 | class VerifyEmailValidationTestCase(UbuntuSSOClientTestCase): |
1008 | 1232 | """Test suite for the user registration validation (verify email page).""" | 1250 | """Test suite for the user registration validation (verify email page).""" |
1009 | @@ -1480,11 +1498,11 @@ | |||
1010 | 1480 | self.click_connect_with_valid_data() | 1498 | self.click_connect_with_valid_data() |
1011 | 1481 | self.assert_pages_visibility(processing=True) | 1499 | self.assert_pages_visibility(processing=True) |
1012 | 1482 | 1500 | ||
1015 | 1483 | def test_on_logged_in_morphs_to_processing_page(self): | 1501 | def test_on_logged_in_morphs_to_finish_page(self): |
1016 | 1484 | """When user logged in the processing page is still shown.""" | 1502 | """When user logged in the finish page is shown.""" |
1017 | 1485 | self.click_connect_with_valid_data() | 1503 | self.click_connect_with_valid_data() |
1018 | 1486 | self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL) | 1504 | self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL) |
1020 | 1487 | self.assert_pages_visibility(processing=True) | 1505 | self.assert_pages_visibility(finish=True) |
1021 | 1488 | 1506 | ||
1022 | 1489 | def test_on_login_error_morphs_to_login_page(self): | 1507 | def test_on_login_error_morphs_to_login_page(self): |
1023 | 1490 | """On user login error, the previous page is shown.""" | 1508 | """On user login error, the previous page is shown.""" |
1024 | @@ -1541,6 +1559,32 @@ | |||
1025 | 1541 | self.assertEqual(self.ui.user_email, EMAIL) | 1559 | self.assertEqual(self.ui.user_email, EMAIL) |
1026 | 1542 | self.assertEqual(self.ui.user_password, PASSWORD) | 1560 | self.assertEqual(self.ui.user_password, PASSWORD) |
1027 | 1543 | 1561 | ||
1028 | 1562 | def test_after_login_success_finish_success(self): | ||
1029 | 1563 | """After LOGIN_SUCCESSFULL is called, finish_success is called. | ||
1030 | 1564 | |||
1031 | 1565 | Only when LOGIN_SUCCESSFULL returns 0. | ||
1032 | 1566 | |||
1033 | 1567 | """ | ||
1034 | 1568 | self.patch(self.ui, 'finish_success', self._set_called) | ||
1035 | 1569 | self.ui.login_success_callback = lambda app, email: 0 | ||
1036 | 1570 | |||
1037 | 1571 | self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL) | ||
1038 | 1572 | |||
1039 | 1573 | self.assertEqual(self._called, ((), {})) | ||
1040 | 1574 | |||
1041 | 1575 | def test_after_login_error_finish_error(self): | ||
1042 | 1576 | """After LOGIN_SUCCESSFULL is called, finish_error is called. | ||
1043 | 1577 | |||
1044 | 1578 | Only when LOGIN_SUCCESSFULL returns a non-zero value. | ||
1045 | 1579 | |||
1046 | 1580 | """ | ||
1047 | 1581 | self.patch(self.ui, 'finish_error', self._set_called) | ||
1048 | 1582 | self.ui.login_success_callback = lambda app, email: -1 | ||
1049 | 1583 | |||
1050 | 1584 | self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL) | ||
1051 | 1585 | |||
1052 | 1586 | self.assertEqual(self._called, ((), {})) | ||
1053 | 1587 | |||
1054 | 1544 | 1588 | ||
1055 | 1545 | class LoginValidationTestCase(UbuntuSSOClientTestCase): | 1589 | class LoginValidationTestCase(UbuntuSSOClientTestCase): |
1056 | 1546 | """Test suite for the user login validation.""" | 1590 | """Test suite for the user login validation.""" |
1057 | @@ -2060,119 +2104,144 @@ | |||
1058 | 2060 | self.assertEqual(self.ui.help_label.get_text(), HELP_TEXT) | 2104 | self.assertEqual(self.ui.help_label.get_text(), HELP_TEXT) |
1059 | 2061 | 2105 | ||
1060 | 2062 | 2106 | ||
1063 | 2063 | class SignalsTestCase(UbuntuSSOClientTestCase): | 2107 | class CallbacksTestCase(UbuntuSSOClientTestCase): |
1064 | 2064 | """Test the GTK signal emission.""" | 2108 | """Test the GTK callback calls.""" |
1065 | 2109 | |||
1066 | 2110 | LOGIN_SUCCESSFULL = 'login_success_callback' | ||
1067 | 2111 | REGISTRATION_SUCCESS = 'registration_success_callback' | ||
1068 | 2112 | USER_CANCELLATION = 'user_cancellation_callback' | ||
1069 | 2065 | 2113 | ||
1070 | 2066 | def setUp(self): | 2114 | def setUp(self): |
1071 | 2067 | """Init.""" | 2115 | """Init.""" |
1073 | 2068 | super(SignalsTestCase, self).setUp() | 2116 | super(CallbacksTestCase, self).setUp() |
1074 | 2069 | self._called = {} | 2117 | self._called = {} |
1080 | 2070 | for sig_name, _ in gui.SIGNAL_ARGUMENTS: | 2118 | for name in (self.LOGIN_SUCCESSFULL, |
1081 | 2071 | self.ui.connect(sig_name, self._set_called, sig_name) | 2119 | self.REGISTRATION_SUCCESS, |
1082 | 2072 | 2120 | self.USER_CANCELLATION): | |
1083 | 2073 | def _set_called(self, widget, *args, **kwargs): | 2121 | setattr(self.ui, name, self._set_called(name)) |
1084 | 2074 | """Keep trace of signals emition.""" | 2122 | |
1085 | 2123 | def _set_called(self, callback_name): | ||
1086 | 2124 | """Keep trace of callbacks calls.""" | ||
1087 | 2125 | |||
1088 | 2075 | # pylint: disable=W0221 | 2126 | # pylint: disable=W0221 |
1093 | 2076 | self._called[args[-1]] = (widget, args[:-1], kwargs) | 2127 | |
1094 | 2077 | 2128 | def inner(*args, **kwargs): | |
1095 | 2078 | def test_closing_main_window_sends_outcome_as_signal(self): | 2129 | """Store arguments used in this call.""" |
1096 | 2079 | """A signal is sent when closing the main window.""" | 2130 | self._called[callback_name] = args |
1097 | 2131 | |||
1098 | 2132 | return inner | ||
1099 | 2133 | |||
1100 | 2134 | def test_closing_main_window(self): | ||
1101 | 2135 | """When closing the main window, USER_CANCELLATION is called.""" | ||
1102 | 2080 | self.ui.window.emit('delete-event', gtk.gdk.Event(gtk.gdk.DELETE)) | 2136 | self.ui.window.emit('delete-event', gtk.gdk.Event(gtk.gdk.DELETE)) |
1105 | 2081 | expected = (self.ui.window, (APP_NAME,), {}) | 2137 | self.assertEqual(self._called[self.USER_CANCELLATION], (APP_NAME,)) |
1104 | 2082 | self.assertEqual(self._called[gui.SIG_USER_CANCELATION], expected) | ||
1106 | 2083 | 2138 | ||
1111 | 2084 | def test_every_cancel_emits_proper_signal(self): | 2139 | def test_every_cancel_calls_proper_callback(self): |
1112 | 2085 | """Clicking on any cancel button, 'user-cancelation' signal is sent.""" | 2140 | """When any cancel button is clicked, USER_CANCELLATION is called.""" |
1113 | 2086 | sig = gui.SIG_USER_CANCELATION | 2141 | msg = 'user_cancellation_callback is called when "%s" is clicked.' |
1110 | 2087 | msg = 'user-cancelation is emitted when "%s" is clicked.' | ||
1114 | 2088 | buttons = filter(lambda name: 'cancel_button' in name, self.ui.widgets) | 2142 | buttons = filter(lambda name: 'cancel_button' in name, self.ui.widgets) |
1115 | 2089 | for name in buttons: | 2143 | for name in buttons: |
1116 | 2090 | self.ui = self.gui_class(**self.kwargs) | ||
1117 | 2091 | self.ui.connect(sig, self._set_called, sig) | ||
1118 | 2092 | widget = getattr(self.ui, name) | 2144 | widget = getattr(self.ui, name) |
1119 | 2093 | widget.clicked() | 2145 | widget.clicked() |
1122 | 2094 | expected_args = (self.ui.window, (APP_NAME,), {}) | 2146 | self.assertEqual(self._called[self.USER_CANCELLATION], (APP_NAME,), |
1123 | 2095 | self.assertEqual(self._called[sig], expected_args, msg % name) | 2147 | msg % name) |
1124 | 2096 | self._called = {} | 2148 | self._called = {} |
1125 | 2097 | 2149 | ||
1128 | 2098 | def test_on_user_registration_error_proper_signal_is_emitted(self): | 2150 | def test_on_user_registration_error_proper_callback_is_called(self): |
1129 | 2099 | """On UserRegistrationError, SIG_USER_CANCELATION signal is sent.""" | 2151 | """On UserRegistrationError, USER_CANCELLATION is called.""" |
1130 | 2100 | self.ui.on_user_registration_error(app_name=APP_NAME, error=self.error) | 2152 | self.ui.on_user_registration_error(app_name=APP_NAME, error=self.error) |
1131 | 2101 | self.ui.on_close_clicked() | 2153 | self.ui.on_close_clicked() |
1138 | 2102 | expected = (self.ui.window, (APP_NAME,), {}) | 2154 | |
1139 | 2103 | self.assertEqual(expected, | 2155 | self.assertEqual(self._called[self.USER_CANCELLATION], (APP_NAME,)) |
1140 | 2104 | self._called[gui.SIG_USER_CANCELATION]) | 2156 | |
1141 | 2105 | 2157 | def test_on_email_validated_proper_callback_is_called(self): | |
1142 | 2106 | def test_on_email_validated_proper_signals_is_emitted(self): | 2158 | """On EmailValidated, REGISTRATION_SUCCESS is called.""" |
1137 | 2107 | """On EmailValidated, 'registration-succeeded' signal is sent.""" | ||
1143 | 2108 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) | 2159 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) |
1144 | 2109 | self.ui.on_close_clicked() | 2160 | self.ui.on_close_clicked() |
1150 | 2110 | self.assertEqual((self.ui.window, (APP_NAME, EMAIL), {}), | 2161 | |
1151 | 2111 | self._called[gui.SIG_REGISTRATION_SUCCEEDED]) | 2162 | self.assertEqual(self._called[self.REGISTRATION_SUCCESS], |
1152 | 2112 | 2163 | (APP_NAME, EMAIL)) | |
1153 | 2113 | def test_on_email_validation_error_proper_signals_is_emitted(self): | 2164 | |
1154 | 2114 | """On EmailValidationError, SIG_USER_CANCELATION signal is sent.""" | 2165 | def test_on_email_validation_error_proper_callback_is_called(self): |
1155 | 2166 | """On EmailValidationError, USER_CANCELLATION is called.""" | ||
1156 | 2115 | self.ui.on_email_validation_error(app_name=APP_NAME, error=self.error) | 2167 | self.ui.on_email_validation_error(app_name=APP_NAME, error=self.error) |
1157 | 2116 | self.ui.on_close_clicked() | 2168 | self.ui.on_close_clicked() |
1164 | 2117 | expected = (self.ui.window, (APP_NAME,), {}) | 2169 | |
1165 | 2118 | self.assertEqual(expected, | 2170 | self.assertEqual(self._called[self.USER_CANCELLATION], (APP_NAME,)) |
1166 | 2119 | self._called[gui.SIG_USER_CANCELATION]) | 2171 | |
1167 | 2120 | 2172 | def test_on_logged_in_proper_callback_is_called(self): | |
1168 | 2121 | def test_on_logged_in_proper_signals_is_emitted(self): | 2173 | """On LoggedIn, LOGIN_SUCCESSFULL is called.""" |
1163 | 2122 | """On LoggedIn, 'login-succeeded' signal is sent.""" | ||
1169 | 2123 | self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL) | 2174 | self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL) |
1170 | 2124 | self.ui.on_close_clicked() | 2175 | self.ui.on_close_clicked() |
1176 | 2125 | self.assertEqual((self.ui.window, (APP_NAME, EMAIL), {}), | 2176 | |
1177 | 2126 | self._called[gui.SIG_LOGIN_SUCCEEDED]) | 2177 | self.assertEqual(self._called[self.LOGIN_SUCCESSFULL], |
1178 | 2127 | 2178 | (APP_NAME, EMAIL)) | |
1179 | 2128 | def test_on_login_error_proper_signals_is_emitted(self): | 2179 | |
1180 | 2129 | """On LoginError, SIG_USER_CANCELATION signal is sent.""" | 2180 | def test_on_login_error_proper_callback_is_called(self): |
1181 | 2181 | """On LoginError, USER_CANCELLATION is called.""" | ||
1182 | 2130 | self.click_connect_with_valid_data() | 2182 | self.click_connect_with_valid_data() |
1183 | 2131 | self.ui.on_login_error(app_name=APP_NAME, error=self.error) | 2183 | self.ui.on_login_error(app_name=APP_NAME, error=self.error) |
1184 | 2132 | self.ui.on_close_clicked() | 2184 | self.ui.on_close_clicked() |
1191 | 2133 | expected = (self.ui.window, (APP_NAME,), {}) | 2185 | |
1192 | 2134 | self.assertEqual(expected, | 2186 | self.assertEqual(self._called[self.USER_CANCELLATION], (APP_NAME,)) |
1193 | 2135 | self._called[gui.SIG_USER_CANCELATION]) | 2187 | |
1194 | 2136 | 2188 | def test_registration_success_even_if_prior_registration_error(self): | |
1195 | 2137 | def test_registration_successfull_even_if_prior_registration_error(self): | 2189 | """Only one callback is called with the final outcome. |
1196 | 2138 | """Only one signal is sent with the final outcome.""" | 2190 | |
1197 | 2191 | When the user successfully registers, REGISTRATION_SUCCESS is | ||
1198 | 2192 | called even if there were errors before. | ||
1199 | 2193 | |||
1200 | 2194 | """ | ||
1201 | 2139 | self.click_join_with_valid_data() | 2195 | self.click_join_with_valid_data() |
1202 | 2140 | self.ui.on_user_registration_error(app_name=APP_NAME, error=self.error) | 2196 | self.ui.on_user_registration_error(app_name=APP_NAME, error=self.error) |
1203 | 2141 | self.click_join_with_valid_data() | 2197 | self.click_join_with_valid_data() |
1204 | 2142 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) | 2198 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) |
1205 | 2143 | self.ui.on_close_clicked() | 2199 | self.ui.on_close_clicked() |
1206 | 2144 | 2200 | ||
1212 | 2145 | self.assertEqual(len(self._called), 1) | 2201 | self.assertEqual(self._called[self.REGISTRATION_SUCCESS], |
1213 | 2146 | self.assertTrue(gui.SIG_REGISTRATION_SUCCEEDED in self._called) | 2202 | (APP_NAME, EMAIL)) |
1214 | 2147 | 2203 | ||
1215 | 2148 | def test_login_successfull_even_if_prior_login_error(self): | 2204 | def test_login_success_even_if_prior_login_error(self): |
1216 | 2149 | """Only one signal is sent with the final outcome.""" | 2205 | """Only one callback is called with the final outcome. |
1217 | 2206 | |||
1218 | 2207 | When the user successfully logins, LOGIN_SUCCESSFULL is called even if | ||
1219 | 2208 | there were errors before. | ||
1220 | 2209 | |||
1221 | 2210 | """ | ||
1222 | 2150 | self.click_connect_with_valid_data() | 2211 | self.click_connect_with_valid_data() |
1223 | 2151 | self.ui.on_login_error(app_name=APP_NAME, error=self.error) | 2212 | self.ui.on_login_error(app_name=APP_NAME, error=self.error) |
1224 | 2152 | self.click_connect_with_valid_data() | 2213 | self.click_connect_with_valid_data() |
1225 | 2153 | self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL) | 2214 | self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL) |
1226 | 2154 | self.ui.on_close_clicked() | 2215 | self.ui.on_close_clicked() |
1227 | 2155 | 2216 | ||
1230 | 2156 | self.assertEqual(len(self._called), 1) | 2217 | self.assertEqual(self._called[self.LOGIN_SUCCESSFULL], |
1231 | 2157 | self.assertTrue(gui.SIG_LOGIN_SUCCEEDED in self._called) | 2218 | (APP_NAME, EMAIL)) |
1232 | 2158 | 2219 | ||
1233 | 2159 | def test_user_cancelation_even_if_prior_registration_error(self): | 2220 | def test_user_cancelation_even_if_prior_registration_error(self): |
1235 | 2160 | """Only one signal is sent with the final outcome.""" | 2221 | """Only one callback is called with the final outcome. |
1236 | 2222 | |||
1237 | 2223 | When the user closes the window, USER_CANCELLATION is called even if | ||
1238 | 2224 | there were registration errors before. | ||
1239 | 2225 | |||
1240 | 2226 | """ | ||
1241 | 2161 | self.click_join_with_valid_data() | 2227 | self.click_join_with_valid_data() |
1242 | 2162 | self.ui.on_user_registration_error(app_name=APP_NAME, error=self.error) | 2228 | self.ui.on_user_registration_error(app_name=APP_NAME, error=self.error) |
1243 | 2163 | self.ui.join_cancel_button.clicked() | 2229 | self.ui.join_cancel_button.clicked() |
1244 | 2164 | 2230 | ||
1247 | 2165 | self.assertEqual(len(self._called), 1) | 2231 | self.assertEqual(self._called[self.USER_CANCELLATION], (APP_NAME,)) |
1246 | 2166 | self.assertTrue(gui.SIG_USER_CANCELATION in self._called) | ||
1248 | 2167 | 2232 | ||
1249 | 2168 | def test_user_cancelation_even_if_prior_login_error(self): | 2233 | def test_user_cancelation_even_if_prior_login_error(self): |
1251 | 2169 | """Only one signal is sent with the final outcome.""" | 2234 | """Only one callback is called with the final outcome. |
1252 | 2235 | |||
1253 | 2236 | When the user closes the window, USER_CANCELLATION is called even if | ||
1254 | 2237 | there were login errors before. | ||
1255 | 2238 | |||
1256 | 2239 | """ | ||
1257 | 2170 | self.click_connect_with_valid_data() | 2240 | self.click_connect_with_valid_data() |
1258 | 2171 | self.ui.on_login_error(app_name=APP_NAME, error=self.error) | 2241 | self.ui.on_login_error(app_name=APP_NAME, error=self.error) |
1259 | 2172 | self.ui.login_cancel_button.clicked() | 2242 | self.ui.login_cancel_button.clicked() |
1260 | 2173 | 2243 | ||
1263 | 2174 | self.assertEqual(len(self._called), 1) | 2244 | self.assertEqual(self._called[self.USER_CANCELLATION], (APP_NAME,)) |
1262 | 2175 | self.assertTrue(gui.SIG_USER_CANCELATION in self._called) | ||
1264 | 2176 | 2245 | ||
1265 | 2177 | 2246 | ||
1266 | 2178 | class DefaultButtonsTestCase(UbuntuSSOClientTestCase): | 2247 | class DefaultButtonsTestCase(UbuntuSSOClientTestCase): |
1267 | 2179 | 2248 | ||
1268 | === modified file 'ubuntu_sso/logger.py' | |||
1269 | --- ubuntu_sso/logger.py 2010-10-11 13:22:16 +0000 | |||
1270 | +++ ubuntu_sso/logger.py 2011-01-13 00:33:10 +0000 | |||
1271 | @@ -57,6 +57,7 @@ | |||
1272 | 57 | logger.addHandler(MAIN_HANDLER) | 57 | logger.addHandler(MAIN_HANDLER) |
1273 | 58 | if os.environ.get('DEBUG'): | 58 | if os.environ.get('DEBUG'): |
1274 | 59 | debug_handler = logging.StreamHandler(sys.stderr) | 59 | debug_handler = logging.StreamHandler(sys.stderr) |
1275 | 60 | debug_handler.setFormatter(logging.Formatter(fmt=FMT)) | ||
1276 | 60 | logger.addHandler(debug_handler) | 61 | logger.addHandler(debug_handler) |
1277 | 61 | 62 | ||
1278 | 62 | return logger | 63 | return logger |
1279 | 63 | 64 | ||
1280 | === modified file 'ubuntu_sso/main.py' | |||
1281 | --- ubuntu_sso/main.py 2010-12-16 16:31:34 +0000 | |||
1282 | +++ ubuntu_sso/main.py 2011-01-13 00:33:10 +0000 | |||
1283 | @@ -50,6 +50,7 @@ | |||
1284 | 50 | 50 | ||
1285 | 51 | logger = setup_logging("ubuntu_sso.main") | 51 | logger = setup_logging("ubuntu_sso.main") |
1286 | 52 | U1_PING_URL = "https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/" | 52 | U1_PING_URL = "https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/" |
1287 | 53 | TIMEOUT_INTERVAL = 500 | ||
1288 | 53 | 54 | ||
1289 | 54 | 55 | ||
1290 | 55 | class SSOLoginProcessor(Account): | 56 | class SSOLoginProcessor(Account): |
1291 | @@ -198,7 +199,9 @@ | |||
1292 | 198 | # pylint: disable=E1101 | 199 | # pylint: disable=E1101 |
1293 | 199 | d = Keyring().set_credentials(app_name, credentials) | 200 | d = Keyring().set_credentials(app_name, credentials) |
1294 | 200 | d.addCallback(lambda _: self.LoggedIn(app_name, email)) | 201 | d.addCallback(lambda _: self.LoggedIn(app_name, email)) |
1296 | 201 | d.addErrback(lambda _: self.UserNotValidated(app_name, email)) | 202 | d.addErrback(lambda failure: \ |
1297 | 203 | self.LoginError(app_name, | ||
1298 | 204 | except_to_errdict(failure.value))) | ||
1299 | 202 | else: | 205 | else: |
1300 | 203 | self.UserNotValidated(app_name, email) | 206 | self.UserNotValidated(app_name, email) |
1301 | 204 | blocking(f, app_name, success_cb, self.LoginError) | 207 | blocking(f, app_name, success_cb, self.LoginError) |
1302 | @@ -419,6 +422,12 @@ | |||
1303 | 419 | 422 | ||
1304 | 420 | """ | 423 | """ |
1305 | 421 | 424 | ||
1306 | 425 | def __init__(self, timeout_func, shutdown_func, *args, **kwargs): | ||
1307 | 426 | super(CredentialsManagement, self).__init__(*args, **kwargs) | ||
1308 | 427 | self._ref_count = 0 | ||
1309 | 428 | self.timeout_func = timeout_func | ||
1310 | 429 | self.shutdown_func = shutdown_func | ||
1311 | 430 | |||
1312 | 422 | # Operator not preceded by a space (fails with dbus decorators) | 431 | # Operator not preceded by a space (fails with dbus decorators) |
1313 | 423 | # pylint: disable=C0322 | 432 | # pylint: disable=C0322 |
1314 | 424 | 433 | ||
1315 | @@ -434,39 +443,70 @@ | |||
1316 | 434 | result[DENIAL_CB_KEY] = self.AuthorizationDenied | 443 | result[DENIAL_CB_KEY] = self.AuthorizationDenied |
1317 | 435 | return result | 444 | return result |
1318 | 436 | 445 | ||
1319 | 446 | def _process_failure(self, failure, app_name): | ||
1320 | 447 | """Process the 'failure' and emit CredentialsError.""" | ||
1321 | 448 | self.CredentialsError(app_name, except_to_errdict(failure.value)) | ||
1322 | 449 | |||
1323 | 450 | def _get_ref_count(self): | ||
1324 | 451 | """Get value of ref_count.""" | ||
1325 | 452 | logger.debug('ref_count is %r.', self._ref_count) | ||
1326 | 453 | return self._ref_count | ||
1327 | 454 | |||
1328 | 455 | def _set_ref_count(self, new_value): | ||
1329 | 456 | """Set a new value to ref_count.""" | ||
1330 | 457 | logger.debug('ref_count is %r, changing value to %r.', | ||
1331 | 458 | self._ref_count, new_value) | ||
1332 | 459 | if new_value < 0: | ||
1333 | 460 | self._ref_count = 0 | ||
1334 | 461 | msg = 'Attempting to decrease ref_count to a negative value (%r).' | ||
1335 | 462 | logger.warning(msg, new_value) | ||
1336 | 463 | else: | ||
1337 | 464 | self._ref_count = new_value | ||
1338 | 465 | |||
1339 | 466 | if self._ref_count == 0: | ||
1340 | 467 | self.timeout_func(TIMEOUT_INTERVAL, self.shutdown_func) | ||
1341 | 468 | |||
1342 | 469 | ref_count = property(fget=_get_ref_count, fset=_set_ref_count) | ||
1343 | 470 | |||
1344 | 437 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') | 471 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') |
1345 | 438 | def AuthorizationDenied(self, app_name): | 472 | def AuthorizationDenied(self, app_name): |
1346 | 439 | """Signal thrown when the user denies the authorization.""" | 473 | """Signal thrown when the user denies the authorization.""" |
1347 | 474 | self.ref_count -= 1 | ||
1348 | 440 | logger.info('%s: emitting AuthorizationDenied with app_name "%s".', | 475 | logger.info('%s: emitting AuthorizationDenied with app_name "%s".', |
1349 | 441 | self.__class__.__name__, app_name) | 476 | self.__class__.__name__, app_name) |
1350 | 442 | 477 | ||
1351 | 443 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='sa{ss}') | 478 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='sa{ss}') |
1352 | 444 | def CredentialsFound(self, app_name, credentials): | 479 | def CredentialsFound(self, app_name, credentials): |
1353 | 445 | """Signal thrown when the credentials are found.""" | 480 | """Signal thrown when the credentials are found.""" |
1354 | 481 | self.ref_count -= 1 | ||
1355 | 446 | logger.info('%s: emitting CredentialsFound with app_name "%s".', | 482 | logger.info('%s: emitting CredentialsFound with app_name "%s".', |
1356 | 447 | self.__class__.__name__, app_name) | 483 | self.__class__.__name__, app_name) |
1357 | 448 | 484 | ||
1358 | 449 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') | 485 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') |
1359 | 450 | def CredentialsNotFound(self, app_name): | 486 | def CredentialsNotFound(self, app_name): |
1360 | 451 | """Signal thrown when the credentials are not found.""" | 487 | """Signal thrown when the credentials are not found.""" |
1361 | 488 | self.ref_count -= 1 | ||
1362 | 452 | logger.info('%s: emitting CredentialsNotFound with app_name "%s".', | 489 | logger.info('%s: emitting CredentialsNotFound with app_name "%s".', |
1363 | 453 | self.__class__.__name__, app_name) | 490 | self.__class__.__name__, app_name) |
1364 | 454 | 491 | ||
1365 | 455 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') | 492 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') |
1366 | 456 | def CredentialsCleared(self, app_name): | 493 | def CredentialsCleared(self, app_name): |
1367 | 457 | """Signal thrown when the credentials were cleared.""" | 494 | """Signal thrown when the credentials were cleared.""" |
1368 | 495 | self.ref_count -= 1 | ||
1369 | 458 | logger.info('%s: emitting CredentialsCleared with app_name "%s".', | 496 | logger.info('%s: emitting CredentialsCleared with app_name "%s".', |
1370 | 459 | self.__class__.__name__, app_name) | 497 | self.__class__.__name__, app_name) |
1371 | 460 | 498 | ||
1372 | 461 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') | 499 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='s') |
1373 | 462 | def CredentialsStored(self, app_name): | 500 | def CredentialsStored(self, app_name): |
1374 | 463 | """Signal thrown when the credentials were cleared.""" | 501 | """Signal thrown when the credentials were cleared.""" |
1375 | 502 | self.ref_count -= 1 | ||
1376 | 464 | logger.info('%s: emitting CredentialsStored with app_name "%s".', | 503 | logger.info('%s: emitting CredentialsStored with app_name "%s".', |
1377 | 465 | self.__class__.__name__, app_name) | 504 | self.__class__.__name__, app_name) |
1378 | 466 | 505 | ||
1379 | 467 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='sa{ss}') | 506 | @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='sa{ss}') |
1380 | 468 | def CredentialsError(self, app_name, error_dict): | 507 | def CredentialsError(self, app_name, error_dict): |
1381 | 469 | """Signal thrown when there is a problem getting the credentials.""" | 508 | """Signal thrown when there is a problem getting the credentials.""" |
1382 | 509 | self.ref_count -= 1 | ||
1383 | 470 | logger.error('%s: emitting CredentialsError with app_name "%s" and ' | 510 | logger.error('%s: emitting CredentialsError with app_name "%s" and ' |
1384 | 471 | 'error_dict %r.', self.__class__.__name__, app_name, | 511 | 'error_dict %r.', self.__class__.__name__, app_name, |
1385 | 472 | error_dict) | 512 | error_dict) |
1386 | @@ -482,6 +522,7 @@ | |||
1387 | 482 | - 'args' is a dictionary, currently not used. | 522 | - 'args' is a dictionary, currently not used. |
1388 | 483 | 523 | ||
1389 | 484 | """ | 524 | """ |
1390 | 525 | self.ref_count += 1 | ||
1391 | 485 | 526 | ||
1392 | 486 | def success_cb(credentials): | 527 | def success_cb(credentials): |
1393 | 487 | """Find credentials and notify using signals.""" | 528 | """Find credentials and notify using signals.""" |
1394 | @@ -494,7 +535,7 @@ | |||
1395 | 494 | d = obj.find_credentials() | 535 | d = obj.find_credentials() |
1396 | 495 | # pylint: disable=E1101 | 536 | # pylint: disable=E1101 |
1397 | 496 | d.addCallback(success_cb) | 537 | d.addCallback(success_cb) |
1399 | 497 | d.addErrback(self.CredentialsError) | 538 | d.addErrback(self._process_failure, app_name) |
1400 | 498 | 539 | ||
1401 | 499 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, | 540 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, |
1402 | 500 | in_signature='sa{ss}', out_signature='') | 541 | in_signature='sa{ss}', out_signature='') |
1403 | @@ -507,11 +548,13 @@ | |||
1404 | 507 | - 'args' is a dictionary, currently not used. | 548 | - 'args' is a dictionary, currently not used. |
1405 | 508 | 549 | ||
1406 | 509 | """ | 550 | """ |
1407 | 551 | self.ref_count += 1 | ||
1408 | 552 | |||
1409 | 510 | obj = Credentials(app_name) | 553 | obj = Credentials(app_name) |
1410 | 511 | d = obj.clear_credentials() | 554 | d = obj.clear_credentials() |
1411 | 512 | # pylint: disable=E1101 | 555 | # pylint: disable=E1101 |
1412 | 513 | d.addCallback(lambda _: self.CredentialsCleared(app_name)) | 556 | d.addCallback(lambda _: self.CredentialsCleared(app_name)) |
1414 | 514 | d.addErrback(self.CredentialsError) | 557 | d.addErrback(self._process_failure, app_name) |
1415 | 515 | 558 | ||
1416 | 516 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, | 559 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, |
1417 | 517 | in_signature='sa{ss}', out_signature='') | 560 | in_signature='sa{ss}', out_signature='') |
1418 | @@ -526,16 +569,20 @@ | |||
1419 | 526 | 'consumer_secret'. | 569 | 'consumer_secret'. |
1420 | 527 | 570 | ||
1421 | 528 | """ | 571 | """ |
1422 | 572 | self.ref_count += 1 | ||
1423 | 573 | |||
1424 | 529 | obj = Credentials(app_name) | 574 | obj = Credentials(app_name) |
1425 | 530 | d = obj.store_credentials(args) | 575 | d = obj.store_credentials(args) |
1426 | 531 | # pylint: disable=E1101 | 576 | # pylint: disable=E1101 |
1427 | 532 | d.addCallback(lambda _: self.CredentialsStored(app_name)) | 577 | d.addCallback(lambda _: self.CredentialsStored(app_name)) |
1429 | 533 | d.addErrback(self.CredentialsError) | 578 | d.addErrback(self._process_failure, app_name) |
1430 | 534 | 579 | ||
1431 | 535 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, | 580 | @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE, |
1432 | 536 | in_signature='sa{ss}', out_signature='') | 581 | in_signature='sa{ss}', out_signature='') |
1433 | 537 | def register(self, app_name, args): | 582 | def register(self, app_name, args): |
1434 | 538 | """Get credentials if found else prompt GUI to register.""" | 583 | """Get credentials if found else prompt GUI to register.""" |
1435 | 584 | self.ref_count += 1 | ||
1436 | 585 | |||
1437 | 539 | obj = Credentials(app_name, **self._parse_args(args)) | 586 | obj = Credentials(app_name, **self._parse_args(args)) |
1438 | 540 | obj.register() | 587 | obj.register() |
1439 | 541 | 588 | ||
1440 | @@ -543,5 +590,7 @@ | |||
1441 | 543 | in_signature='sa{ss}', out_signature='') | 590 | in_signature='sa{ss}', out_signature='') |
1442 | 544 | def login(self, app_name, args): | 591 | def login(self, app_name, args): |
1443 | 545 | """Get credentials if found else prompt GUI to login.""" | 592 | """Get credentials if found else prompt GUI to login.""" |
1444 | 593 | self.ref_count += 1 | ||
1445 | 594 | |||
1446 | 546 | obj = Credentials(app_name, **self._parse_args(args)) | 595 | obj = Credentials(app_name, **self._parse_args(args)) |
1447 | 547 | obj.login() | 596 | obj.login() |
1448 | 548 | 597 | ||
1449 | === modified file 'ubuntu_sso/tests/__init__.py' | |||
1450 | --- ubuntu_sso/tests/__init__.py 2010-11-30 13:21:17 +0000 | |||
1451 | +++ ubuntu_sso/tests/__init__.py 2011-01-13 00:33:10 +0000 | |||
1452 | @@ -18,6 +18,8 @@ | |||
1453 | 18 | 18 | ||
1454 | 19 | import os | 19 | import os |
1455 | 20 | 20 | ||
1456 | 21 | from twisted.trial import unittest | ||
1457 | 22 | |||
1458 | 21 | from ubuntu_sso.keyring import get_token_name | 23 | from ubuntu_sso.keyring import get_token_name |
1459 | 22 | 24 | ||
1460 | 23 | APP_NAME = 'The Super App!' | 25 | APP_NAME = 'The Super App!' |
1461 | @@ -45,3 +47,15 @@ | |||
1462 | 45 | TOKEN_NAME = get_token_name(APP_NAME) | 47 | TOKEN_NAME = get_token_name(APP_NAME) |
1463 | 46 | TC_URL = 'http://localhost/' | 48 | TC_URL = 'http://localhost/' |
1464 | 47 | WINDOW_ID = 5 | 49 | WINDOW_ID = 5 |
1465 | 50 | |||
1466 | 51 | |||
1467 | 52 | class TestCase(unittest.TestCase): | ||
1468 | 53 | """Customized test case that keeps tracks of method calls.""" | ||
1469 | 54 | |||
1470 | 55 | def setUp(self): | ||
1471 | 56 | super(TestCase, self).setUp() | ||
1472 | 57 | self._called = False | ||
1473 | 58 | |||
1474 | 59 | def _set_called(self, *args, **kwargs): | ||
1475 | 60 | """Keep track of a method call.""" | ||
1476 | 61 | self._called = (args, kwargs) | ||
1477 | 48 | 62 | ||
1478 | === modified file 'ubuntu_sso/tests/bin/show_gui' | |||
1479 | --- ubuntu_sso/tests/bin/show_gui 2010-11-30 13:21:17 +0000 | |||
1480 | +++ ubuntu_sso/tests/bin/show_gui 2011-01-13 00:33:10 +0000 | |||
1481 | @@ -31,11 +31,12 @@ | |||
1482 | 31 | 'Nam sed lorem nibh. Suspendisse gravida nulla non nunc suscipit' \ | 31 | 'Nam sed lorem nibh. Suspendisse gravida nulla non nunc suscipit' \ |
1483 | 32 | ' pulvinar tempus ut augue.' | 32 | ' pulvinar tempus ut augue.' |
1484 | 33 | 33 | ||
1485 | 34 | main_quit = lambda *args, **kwargs: gtk.main_quit() | ||
1486 | 35 | |||
1487 | 36 | 34 | ||
1488 | 37 | if __name__ == '__main__': | 35 | if __name__ == '__main__': |
1490 | 38 | tc_url=TC_URL | 36 | |
1491 | 37 | # pylint: disable=C0103, E1101 | ||
1492 | 38 | |||
1493 | 39 | tc_url = TC_URL | ||
1494 | 39 | login_only = False | 40 | login_only = False |
1495 | 40 | xid = 0 | 41 | xid = 0 |
1496 | 41 | 42 | ||
1497 | @@ -51,7 +52,7 @@ | |||
1498 | 51 | win.show() | 52 | win.show() |
1499 | 52 | xid = win.window.xid | 53 | xid = win.window.xid |
1500 | 53 | 54 | ||
1504 | 54 | UbuntuSSOClientGUI(close_callback=main_quit, app_name=APP_NAME, | 55 | UbuntuSSOClientGUI(close_callback=lambda *args, **kwargs: gtk.main_quit(), |
1505 | 55 | tc_url=tc_url, help_text=HELP_TEXT, window_id=xid, | 56 | app_name=APP_NAME, tc_url=tc_url, help_text=HELP_TEXT, |
1506 | 56 | login_only=login_only) | 57 | window_id=xid, login_only=login_only) |
1507 | 57 | gtk.main() | 58 | gtk.main() |
1508 | 58 | 59 | ||
1509 | === modified file 'ubuntu_sso/tests/bin/show_nm_state' | |||
1510 | --- ubuntu_sso/tests/bin/show_nm_state 2010-09-08 19:25:02 +0000 | |||
1511 | +++ ubuntu_sso/tests/bin/show_nm_state 2011-01-13 00:33:10 +0000 | |||
1512 | @@ -26,7 +26,6 @@ | |||
1513 | 26 | from ubuntu_sso.networkstate import NetworkManagerState, NM_STATE_NAMES | 26 | from ubuntu_sso.networkstate import NetworkManagerState, NM_STATE_NAMES |
1514 | 27 | 27 | ||
1515 | 28 | DBusGMainLoop(set_as_default=True) | 28 | DBusGMainLoop(set_as_default=True) |
1516 | 29 | loop = gobject.MainLoop() | ||
1517 | 30 | 29 | ||
1518 | 31 | 30 | ||
1519 | 32 | def got_state(state): | 31 | def got_state(state): |
1520 | @@ -34,8 +33,9 @@ | |||
1521 | 34 | try: | 33 | try: |
1522 | 35 | print NM_STATE_NAMES[state] | 34 | print NM_STATE_NAMES[state] |
1523 | 36 | finally: | 35 | finally: |
1525 | 37 | loop.quit() | 36 | gobject.MainLoop().quit() |
1526 | 38 | 37 | ||
1527 | 38 | # pylint: disable=C0103 | ||
1528 | 39 | nms = NetworkManagerState(got_state) | 39 | nms = NetworkManagerState(got_state) |
1529 | 40 | nms.find_online_state() | 40 | nms.find_online_state() |
1531 | 41 | loop.run() | 41 | gobject.MainLoop().run() |
1532 | 42 | 42 | ||
1533 | === modified file 'ubuntu_sso/tests/test_credentials.py' | |||
1534 | --- ubuntu_sso/tests/test_credentials.py 2010-11-30 13:21:17 +0000 | |||
1535 | +++ ubuntu_sso/tests/test_credentials.py 2011-01-13 00:33:10 +0000 | |||
1536 | @@ -21,13 +21,11 @@ | |||
1537 | 21 | import logging | 21 | import logging |
1538 | 22 | import urllib | 22 | import urllib |
1539 | 23 | 23 | ||
1540 | 24 | import gobject | ||
1541 | 25 | |||
1542 | 26 | from twisted.internet import defer | 24 | from twisted.internet import defer |
1543 | 27 | from twisted.internet.defer import inlineCallbacks | 25 | from twisted.internet.defer import inlineCallbacks |
1544 | 28 | from twisted.trial.unittest import TestCase, FailTest | 26 | from twisted.trial.unittest import TestCase, FailTest |
1545 | 27 | from ubuntuone.devtools.handlers import MementoHandler | ||
1546 | 29 | 28 | ||
1547 | 30 | from contrib.testing.testcase import MementoHandler | ||
1548 | 31 | from ubuntu_sso import credentials | 29 | from ubuntu_sso import credentials |
1549 | 32 | from ubuntu_sso.credentials import (APP_NAME_KEY, HELP_TEXT_KEY, NO_OP, | 30 | from ubuntu_sso.credentials import (APP_NAME_KEY, HELP_TEXT_KEY, NO_OP, |
1550 | 33 | PING_URL_KEY, TC_URL_KEY, UI_CLASS_KEY, UI_MODULE_KEY, WINDOW_ID_KEY, | 31 | PING_URL_KEY, TC_URL_KEY, UI_CLASS_KEY, UI_MODULE_KEY, WINDOW_ID_KEY, |
1551 | @@ -60,10 +58,6 @@ | |||
1552 | 60 | WINDOW_ID_KEY: WINDOW_ID, | 58 | WINDOW_ID_KEY: WINDOW_ID, |
1553 | 61 | } | 59 | } |
1554 | 62 | 60 | ||
1555 | 63 | SIG_LOGIN_SUCCEEDED = '1' | ||
1556 | 64 | SIG_REGISTRATION_SUCCEEDED = '2' | ||
1557 | 65 | SIG_USER_CANCELATION = '3' | ||
1558 | 66 | |||
1559 | 67 | 61 | ||
1560 | 68 | class SampleMiscException(Exception): | 62 | class SampleMiscException(Exception): |
1561 | 69 | """An error to be used while testing.""" | 63 | """An error to be used while testing.""" |
1562 | @@ -82,17 +76,9 @@ | |||
1563 | 82 | def __init__(self, *args, **kwargs): | 76 | def __init__(self, *args, **kwargs): |
1564 | 83 | self.args = args | 77 | self.args = args |
1565 | 84 | self.kwargs = kwargs | 78 | self.kwargs = kwargs |
1577 | 85 | self.signals = [] | 79 | self.login_success_callback = None |
1578 | 86 | self.methods = [] | 80 | self.registration_success_callback = None |
1579 | 87 | self.connect = lambda *a: self.signals.append(a) | 81 | self.user_cancellation_callback = None |
1569 | 88 | |||
1570 | 89 | def finish_success(self): | ||
1571 | 90 | """Fake the success finish.""" | ||
1572 | 91 | self.methods.append('finish_success') | ||
1573 | 92 | |||
1574 | 93 | def finish_error(self, error): | ||
1575 | 94 | """Fake the error finish.""" | ||
1576 | 95 | self.methods.append(('finish_error', error)) | ||
1580 | 96 | 82 | ||
1581 | 97 | 83 | ||
1582 | 98 | class BasicTestCase(TestCase): | 84 | class BasicTestCase(TestCase): |
1583 | @@ -100,7 +86,6 @@ | |||
1584 | 100 | 86 | ||
1585 | 101 | def setUp(self): | 87 | def setUp(self): |
1586 | 102 | """Init.""" | 88 | """Init.""" |
1587 | 103 | self.patch(gobject, 'idle_add', lambda f, *a, **kw: f(*a, **kw)) | ||
1588 | 104 | self._called = False # helper | 89 | self._called = False # helper |
1589 | 105 | 90 | ||
1590 | 106 | self.memento = MementoHandler() | 91 | self.memento = MementoHandler() |
1591 | @@ -226,45 +211,21 @@ | |||
1592 | 226 | 211 | ||
1593 | 227 | self.assertEqual(getattr(self.obj, UI_MODULE_KEY), GTK_GUI_MODULE) | 212 | self.assertEqual(getattr(self.obj, UI_MODULE_KEY), GTK_GUI_MODULE) |
1594 | 228 | 213 | ||
1634 | 229 | def test_success_cb_gui_none(self): | 214 | def test_success_cb(self): |
1635 | 230 | """Success callback calls the caller but not the GUI.""" | 215 | """Success callback calls the caller.""" |
1636 | 231 | self.obj.gui = None | 216 | self.obj.gui = None |
1637 | 232 | self.obj.success_cb(creds=TOKEN) | 217 | self.obj.success_cb(creds=TOKEN) |
1638 | 233 | 218 | ||
1639 | 234 | self.assertEqual(self._called, (('success', APP_NAME, TOKEN), {}), | 219 | self.assertEqual(self._called, (('success', APP_NAME, TOKEN), {}), |
1640 | 235 | 'caller _success_cb was called.') | 220 | 'caller _success_cb was called.') |
1641 | 236 | 221 | ||
1642 | 237 | def test_success_cb_gui_not_none(self): | 222 | def test_error_cb(self): |
1643 | 238 | """Success callback calls the caller and finish the GUI.""" | 223 | """Error callback calls the caller.""" |
1644 | 239 | self.obj.gui = ui = FakedClientGUI(APP_NAME) | 224 | error_dict = {'foo': 'bar'} |
1645 | 240 | self.obj.success_cb(creds=TOKEN) | 225 | self.obj.error_cb(error_dict=error_dict) |
1646 | 241 | 226 | ||
1647 | 242 | self.assertEqual(self._called, (('success', APP_NAME, TOKEN), {}), | 227 | self.assertEqual(self._called, (('error', APP_NAME, error_dict), {}), |
1648 | 243 | 'caller _success_cb was called.') | 228 | 'caller _error_cb was called.') |
1610 | 244 | self.assertEqual(ui.methods, ['finish_success'], | ||
1611 | 245 | 'GUI finish_success was called.') | ||
1612 | 246 | self.assertTrue(self.obj.gui is None, 'gui is reset to None.') | ||
1613 | 247 | |||
1614 | 248 | def test_error_cb_gui_none(self): | ||
1615 | 249 | """Error callback calls the caller but not the GUI.""" | ||
1616 | 250 | self.obj.gui = None | ||
1617 | 251 | error_dict = {'foo': 'bar'} | ||
1618 | 252 | self.obj.error_cb(error_dict=error_dict) | ||
1619 | 253 | |||
1620 | 254 | self.assertEqual(self._called, (('error', APP_NAME, error_dict), {}), | ||
1621 | 255 | 'caller _error_cb was called.') | ||
1622 | 256 | |||
1623 | 257 | def test_error_cb_gui_not_none(self): | ||
1624 | 258 | """Error callback calls the caller and finish the GUI.""" | ||
1625 | 259 | self.obj.gui = ui = FakedClientGUI(APP_NAME) | ||
1626 | 260 | error_dict = {'foo': 'bar'} | ||
1627 | 261 | self.obj.error_cb(error_dict=error_dict) | ||
1628 | 262 | |||
1629 | 263 | self.assertEqual(self._called, (('error', APP_NAME, error_dict), {}), | ||
1630 | 264 | 'caller _error_cb was called.') | ||
1631 | 265 | self.assertEqual(ui.methods, [('finish_error', error_dict)], | ||
1632 | 266 | 'GUI finish_error was called.') | ||
1633 | 267 | self.assertTrue(self.obj.gui is None, 'gui is reset to None.') | ||
1649 | 268 | 229 | ||
1650 | 269 | 230 | ||
1651 | 270 | class CredentialsLoginSuccessTestCase(CredentialsTestCase): | 231 | class CredentialsLoginSuccessTestCase(CredentialsTestCase): |
1652 | @@ -276,12 +237,12 @@ | |||
1653 | 276 | self.patch(credentials.Keyring, 'get_credentials', | 237 | self.patch(credentials.Keyring, 'get_credentials', |
1654 | 277 | lambda kr, app: defer.succeed(None)) | 238 | lambda kr, app: defer.succeed(None)) |
1655 | 278 | 239 | ||
1658 | 279 | yield self.obj._login_success_cb(dialog=None, app_name=APP_NAME, | 240 | result = yield self.obj._login_success_cb(APP_NAME, EMAIL) |
1657 | 280 | email=EMAIL) | ||
1659 | 281 | 241 | ||
1660 | 282 | msg = 'Creds are empty! This should not happen' | 242 | msg = 'Creds are empty! This should not happen' |
1661 | 283 | self.assert_error_cb_called(msg='Problem while retrieving credentials', | 243 | self.assert_error_cb_called(msg='Problem while retrieving credentials', |
1662 | 284 | detailed_error=AssertionError(msg)) | 244 | detailed_error=AssertionError(msg)) |
1663 | 245 | self.assertEqual(result, None) | ||
1664 | 285 | 246 | ||
1665 | 286 | @inlineCallbacks | 247 | @inlineCallbacks |
1666 | 287 | def test_cred_error(self): | 248 | def test_cred_error(self): |
1667 | @@ -290,11 +251,11 @@ | |||
1668 | 290 | self.patch(credentials.Keyring, 'get_credentials', | 251 | self.patch(credentials.Keyring, 'get_credentials', |
1669 | 291 | lambda kr, app: defer.fail(expected_error)) | 252 | lambda kr, app: defer.fail(expected_error)) |
1670 | 292 | 253 | ||
1673 | 293 | yield self.obj._login_success_cb(dialog=None, app_name=APP_NAME, | 254 | result = yield self.obj._login_success_cb(APP_NAME, EMAIL) |
1672 | 294 | email=EMAIL) | ||
1674 | 295 | 255 | ||
1675 | 296 | msg = 'Problem while retrieving credentials' | 256 | msg = 'Problem while retrieving credentials' |
1676 | 297 | self.assert_error_cb_called(msg=msg, detailed_error=expected_error) | 257 | self.assert_error_cb_called(msg=msg, detailed_error=expected_error) |
1677 | 258 | self.assertEqual(result, None) | ||
1678 | 298 | self.assertTrue(self.memento.check_exception(SampleMiscException)) | 259 | self.assertTrue(self.memento.check_exception(SampleMiscException)) |
1679 | 299 | 260 | ||
1680 | 300 | @inlineCallbacks | 261 | @inlineCallbacks |
1681 | @@ -304,10 +265,10 @@ | |||
1682 | 304 | lambda kr, app: defer.succeed(TOKEN)) | 265 | lambda kr, app: defer.succeed(TOKEN)) |
1683 | 305 | self.patch(self.obj, '_ping_url', lambda *a, **kw: 200) | 266 | self.patch(self.obj, '_ping_url', lambda *a, **kw: 200) |
1684 | 306 | 267 | ||
1687 | 307 | yield self.obj._login_success_cb(dialog=None, app_name=APP_NAME, | 268 | result = yield self.obj._login_success_cb(APP_NAME, EMAIL) |
1686 | 308 | email=EMAIL) | ||
1688 | 309 | 269 | ||
1689 | 310 | self.assertEqual(self._called, (('success', APP_NAME, TOKEN), {})) | 270 | self.assertEqual(self._called, (('success', APP_NAME, TOKEN), {})) |
1690 | 271 | self.assertEqual(result, 0) | ||
1691 | 311 | 272 | ||
1692 | 312 | @inlineCallbacks | 273 | @inlineCallbacks |
1693 | 313 | def test_ping_error(self): | 274 | def test_ping_error(self): |
1694 | @@ -324,12 +285,12 @@ | |||
1695 | 324 | self.patch(self.obj, 'clear_credentials', | 285 | self.patch(self.obj, 'clear_credentials', |
1696 | 325 | lambda: setattr(self, '_cred_cleared', True)) | 286 | lambda: setattr(self, '_cred_cleared', True)) |
1697 | 326 | 287 | ||
1700 | 327 | yield self.obj._login_success_cb(dialog=None, app_name=APP_NAME, | 288 | result = yield self.obj._login_success_cb(APP_NAME, EMAIL) |
1699 | 328 | email=EMAIL) | ||
1701 | 329 | 289 | ||
1702 | 330 | # error cb called correctly | 290 | # error cb called correctly |
1703 | 331 | msg = 'Problem opening the ping_url' | 291 | msg = 'Problem opening the ping_url' |
1704 | 332 | self.assert_error_cb_called(msg=msg, detailed_error=FailTest(error)) | 292 | self.assert_error_cb_called(msg=msg, detailed_error=FailTest(error)) |
1705 | 293 | self.assertEqual(result, None) | ||
1706 | 333 | 294 | ||
1707 | 334 | # credentials cleared | 295 | # credentials cleared |
1708 | 335 | self.assertTrue(self._cred_cleared) | 296 | self.assertTrue(self._cred_cleared) |
1709 | @@ -349,8 +310,7 @@ | |||
1710 | 349 | self.patch(self.obj, '_ping_url', | 310 | self.patch(self.obj, '_ping_url', |
1711 | 350 | lambda *a, **kw: setattr(self, '_url_pinged', (a, kw))) | 311 | lambda *a, **kw: setattr(self, '_url_pinged', (a, kw))) |
1712 | 351 | 312 | ||
1715 | 352 | yield self.obj._login_success_cb(dialog=None, app_name=APP_NAME, | 313 | yield self.obj._login_success_cb(APP_NAME, EMAIL) |
1714 | 353 | email=EMAIL) | ||
1716 | 354 | 314 | ||
1717 | 355 | self.assertEqual(self._url_pinged, ((APP_NAME, EMAIL, TOKEN), {})) | 315 | self.assertEqual(self._url_pinged, ((APP_NAME, EMAIL, TOKEN), {})) |
1718 | 356 | 316 | ||
1719 | @@ -366,10 +326,10 @@ | |||
1720 | 366 | self.patch(self.obj, 'clear_credentials', self._set_called) | 326 | self.patch(self.obj, 'clear_credentials', self._set_called) |
1721 | 367 | self.obj.ping_url = None | 327 | self.obj.ping_url = None |
1722 | 368 | 328 | ||
1725 | 369 | yield self.obj._login_success_cb(dialog=None, app_name=APP_NAME, | 329 | result = yield self.obj._login_success_cb(APP_NAME, EMAIL) |
1724 | 370 | email=EMAIL) | ||
1726 | 371 | 330 | ||
1727 | 372 | self.assertEqual(self._called, (('success', APP_NAME, TOKEN), {})) | 331 | self.assertEqual(self._called, (('success', APP_NAME, TOKEN), {})) |
1728 | 332 | self.assertEqual(result, 0) | ||
1729 | 373 | 333 | ||
1730 | 374 | 334 | ||
1731 | 375 | class CredentialsAuthDeniedTestCase(CredentialsTestCase): | 335 | class CredentialsAuthDeniedTestCase(CredentialsTestCase): |
1732 | @@ -377,10 +337,9 @@ | |||
1733 | 377 | 337 | ||
1734 | 378 | def test_auth_denial_cb(self): | 338 | def test_auth_denial_cb(self): |
1735 | 379 | """On auth denied, self.denial_cb is called.""" | 339 | """On auth denied, self.denial_cb is called.""" |
1738 | 380 | self.obj.gui = ui = FakedClientGUI(APP_NAME) | 340 | self.obj._auth_denial_cb(app_name=APP_NAME) |
1739 | 381 | self.obj._auth_denial_cb(dialog=None, app_name=APP_NAME) | 341 | |
1740 | 382 | self.assertEqual(self._called, (('denial', APP_NAME), {})) | 342 | self.assertEqual(self._called, (('denial', APP_NAME), {})) |
1741 | 383 | self.assertEqual(ui.methods, [], 'no GUI method was called.') | ||
1742 | 384 | 343 | ||
1743 | 385 | 344 | ||
1744 | 386 | class PingUrlTestCase(CredentialsTestCase): | 345 | class PingUrlTestCase(CredentialsTestCase): |
1745 | @@ -401,24 +360,29 @@ | |||
1746 | 401 | 360 | ||
1747 | 402 | self.patch(credentials.urllib2, 'urlopen', faked_urlopen) | 361 | self.patch(credentials.urllib2, 'urlopen', faked_urlopen) |
1748 | 403 | 362 | ||
1749 | 363 | @inlineCallbacks | ||
1750 | 404 | def test_ping_url_if_url_is_none(self): | 364 | def test_ping_url_if_url_is_none(self): |
1751 | 405 | """self.ping_url is opened.""" | 365 | """self.ping_url is opened.""" |
1752 | 406 | self.patch(credentials.urllib2, 'urlopen', self.fail) | 366 | self.patch(credentials.urllib2, 'urlopen', self.fail) |
1753 | 407 | self.obj.ping_url = None | 367 | self.obj.ping_url = None |
1755 | 408 | self.obj._ping_url(app_name=APP_NAME, email=EMAIL, credentials=TOKEN) | 368 | yield self.obj._ping_url(app_name=APP_NAME, email=EMAIL, |
1756 | 369 | credentials=TOKEN) | ||
1757 | 409 | # no failure | 370 | # no failure |
1758 | 410 | 371 | ||
1759 | 372 | @inlineCallbacks | ||
1760 | 411 | def test_ping_url(self): | 373 | def test_ping_url(self): |
1761 | 412 | """On auth success, self.ping_url is opened.""" | 374 | """On auth success, self.ping_url is opened.""" |
1763 | 413 | self.obj._ping_url(app_name=APP_NAME, email=EMAIL, credentials=TOKEN) | 375 | yield self.obj._ping_url(app_name=APP_NAME, email=EMAIL, |
1764 | 376 | credentials=TOKEN) | ||
1765 | 414 | 377 | ||
1766 | 415 | self.assertIsInstance(self._request, credentials.urllib2.Request) | 378 | self.assertIsInstance(self._request, credentials.urllib2.Request) |
1767 | 416 | self.assertEqual(self._request.get_full_url(), | 379 | self.assertEqual(self._request.get_full_url(), |
1768 | 417 | self.obj.ping_url + EMAIL) | 380 | self.obj.ping_url + EMAIL) |
1769 | 418 | 381 | ||
1770 | 382 | @inlineCallbacks | ||
1771 | 419 | def test_request_is_signed_with_credentials(self): | 383 | def test_request_is_signed_with_credentials(self): |
1772 | 420 | """The http request to self.ping_url is signed with the credentials.""" | 384 | """The http request to self.ping_url is signed with the credentials.""" |
1774 | 421 | result = self.obj._ping_url(APP_NAME, EMAIL, TOKEN) | 385 | result = yield self.obj._ping_url(APP_NAME, EMAIL, TOKEN) |
1775 | 422 | headers = self._request.headers | 386 | headers = self._request.headers |
1776 | 423 | 387 | ||
1777 | 424 | self.assertIn('Authorization', headers) | 388 | self.assertIn('Authorization', headers) |
1778 | @@ -431,12 +395,13 @@ | |||
1779 | 431 | self.assertIn(expected, oauth_stuff) | 395 | self.assertIn(expected, oauth_stuff) |
1780 | 432 | self.assertEqual(result, 200) | 396 | self.assertEqual(result, 200) |
1781 | 433 | 397 | ||
1782 | 398 | @inlineCallbacks | ||
1783 | 434 | def test_ping_url_error(self): | 399 | def test_ping_url_error(self): |
1784 | 435 | """Exception is handled if ping fails.""" | 400 | """Exception is handled if ping fails.""" |
1785 | 436 | error = 'Blu' | 401 | error = 'Blu' |
1786 | 437 | self.patch(credentials.urllib2, 'urlopen', lambda r: self.fail(error)) | 402 | self.patch(credentials.urllib2, 'urlopen', lambda r: self.fail(error)) |
1787 | 438 | 403 | ||
1789 | 439 | self.obj._ping_url(APP_NAME, EMAIL, TOKEN) | 404 | yield self.obj._ping_url(APP_NAME, EMAIL, TOKEN) |
1790 | 440 | 405 | ||
1791 | 441 | msg = 'Problem opening the ping_url' | 406 | msg = 'Problem opening the ping_url' |
1792 | 442 | self.assert_error_cb_called(msg=msg, detailed_error=FailTest(error)) | 407 | self.assert_error_cb_called(msg=msg, detailed_error=FailTest(error)) |
1793 | @@ -472,11 +437,8 @@ | |||
1794 | 472 | self.patch(credentials.Keyring, 'get_credentials', | 437 | self.patch(credentials.Keyring, 'get_credentials', |
1795 | 473 | lambda kr, app: defer.fail(expected_error)) | 438 | lambda kr, app: defer.fail(expected_error)) |
1796 | 474 | 439 | ||
1802 | 475 | yield self.obj.find_credentials() | 440 | yield self.assertFailure(self.obj.find_credentials(), |
1803 | 476 | 441 | SampleMiscException) | |
1799 | 477 | msg = 'Problem while retrieving credentials' | ||
1800 | 478 | self.assert_error_cb_called(msg=msg, detailed_error=expected_error) | ||
1801 | 479 | self.assertTrue(self.memento.check_exception(SampleMiscException)) | ||
1804 | 480 | 442 | ||
1805 | 481 | 443 | ||
1806 | 482 | class ClearCredentialsTestCase(CredentialsTestCase): | 444 | class ClearCredentialsTestCase(CredentialsTestCase): |
1807 | @@ -498,11 +460,8 @@ | |||
1808 | 498 | self.patch(credentials.Keyring, 'delete_credentials', | 460 | self.patch(credentials.Keyring, 'delete_credentials', |
1809 | 499 | lambda kr, app: defer.fail(expected_error)) | 461 | lambda kr, app: defer.fail(expected_error)) |
1810 | 500 | 462 | ||
1816 | 501 | yield self.obj.clear_credentials() | 463 | yield self.assertFailure(self.obj.clear_credentials(), |
1817 | 502 | 464 | SampleMiscException) | |
1813 | 503 | msg = 'Problem while deleting credentials' | ||
1814 | 504 | self.assert_error_cb_called(msg=msg, detailed_error=expected_error) | ||
1815 | 505 | self.assertTrue(self.memento.check_exception(SampleMiscException)) | ||
1818 | 506 | 465 | ||
1819 | 507 | 466 | ||
1820 | 508 | class StoreCredentialsTestCase(CredentialsTestCase): | 467 | class StoreCredentialsTestCase(CredentialsTestCase): |
1821 | @@ -524,11 +483,8 @@ | |||
1822 | 524 | self.patch(credentials.Keyring, 'set_credentials', | 483 | self.patch(credentials.Keyring, 'set_credentials', |
1823 | 525 | lambda kr, app, token: defer.fail(expected_error)) | 484 | lambda kr, app, token: defer.fail(expected_error)) |
1824 | 526 | 485 | ||
1830 | 527 | yield self.obj.store_credentials(TOKEN) | 486 | yield self.assertFailure(self.obj.store_credentials(TOKEN), |
1831 | 528 | 487 | SampleMiscException) | |
1827 | 529 | msg = 'Problem while storing credentials' | ||
1828 | 530 | self.assert_error_cb_called(msg=msg, detailed_error=expected_error) | ||
1829 | 531 | self.assertTrue(self.memento.check_exception(SampleMiscException)) | ||
1832 | 532 | 488 | ||
1833 | 533 | 489 | ||
1834 | 534 | class RegisterTestCase(CredentialsTestCase): | 490 | class RegisterTestCase(CredentialsTestCase): |
1835 | @@ -592,17 +548,17 @@ | |||
1836 | 592 | 548 | ||
1837 | 593 | @inlineCallbacks | 549 | @inlineCallbacks |
1838 | 594 | def test_connects_gui_signals(self): | 550 | def test_connects_gui_signals(self): |
1840 | 595 | """Outcome signals from GUI are connected to callbacks.""" | 551 | """GUI callbacks are properly connected.""" |
1841 | 596 | self.patch(credentials.Keyring, 'get_credentials', | 552 | self.patch(credentials.Keyring, 'get_credentials', |
1842 | 597 | lambda kr, app: defer.succeed(None)) | 553 | lambda kr, app: defer.succeed(None)) |
1843 | 598 | |||
1844 | 599 | expected = [ | ||
1845 | 600 | (SIG_LOGIN_SUCCEEDED, self.obj._login_success_cb), | ||
1846 | 601 | (SIG_REGISTRATION_SUCCEEDED, self.obj._login_success_cb), | ||
1847 | 602 | (SIG_USER_CANCELATION, self.obj._auth_denial_cb), | ||
1848 | 603 | ] | ||
1849 | 604 | yield getattr(self.obj, self.operation)() | 554 | yield getattr(self.obj, self.operation)() |
1851 | 605 | self.assertEqual(self.obj.gui.signals, expected) | 555 | |
1852 | 556 | self.assertEqual(self.obj.gui.login_success_callback, | ||
1853 | 557 | self.obj._login_success_cb) | ||
1854 | 558 | self.assertEqual(self.obj.gui.registration_success_callback, | ||
1855 | 559 | self.obj._login_success_cb) | ||
1856 | 560 | self.assertEqual(self.obj.gui.user_cancellation_callback, | ||
1857 | 561 | self.obj._auth_denial_cb) | ||
1858 | 606 | 562 | ||
1859 | 607 | @inlineCallbacks | 563 | @inlineCallbacks |
1860 | 608 | def test_gui_is_created(self): | 564 | def test_gui_is_created(self): |
1861 | 609 | 565 | ||
1862 | === modified file 'ubuntu_sso/tests/test_main.py' | |||
1863 | --- ubuntu_sso/tests/test_main.py 2010-12-16 16:31:34 +0000 | |||
1864 | +++ ubuntu_sso/tests/test_main.py 2011-01-13 00:33:10 +0000 | |||
1865 | @@ -27,21 +27,22 @@ | |||
1866 | 27 | from twisted.internet import defer | 27 | from twisted.internet import defer |
1867 | 28 | from twisted.internet.defer import Deferred, inlineCallbacks | 28 | from twisted.internet.defer import Deferred, inlineCallbacks |
1868 | 29 | from twisted.trial.unittest import TestCase | 29 | from twisted.trial.unittest import TestCase |
1869 | 30 | from ubuntuone.devtools.handlers import MementoHandler | ||
1870 | 30 | 31 | ||
1871 | 31 | import ubuntu_sso.keyring | 32 | import ubuntu_sso.keyring |
1872 | 32 | import ubuntu_sso.main | 33 | import ubuntu_sso.main |
1873 | 33 | 34 | ||
1874 | 34 | from contrib.testing.testcase import MementoHandler | ||
1875 | 35 | from ubuntu_sso import DBUS_CREDENTIALS_IFACE | 35 | from ubuntu_sso import DBUS_CREDENTIALS_IFACE |
1876 | 36 | from ubuntu_sso.keyring import U1_APP_NAME | 36 | from ubuntu_sso.keyring import U1_APP_NAME |
1878 | 37 | from ubuntu_sso.main import (U1_PING_URL, blocking, except_to_errdict, | 37 | from ubuntu_sso.main import (U1_PING_URL, TIMEOUT_INTERVAL, |
1879 | 38 | blocking, except_to_errdict, | ||
1880 | 38 | CredentialsManagement, SSOCredentials, SSOLogin) | 39 | CredentialsManagement, SSOCredentials, SSOLogin) |
1881 | 39 | from ubuntu_sso.main import (HELP_TEXT_KEY, PING_URL_KEY, | 40 | from ubuntu_sso.main import (HELP_TEXT_KEY, PING_URL_KEY, |
1882 | 40 | TC_URL_KEY, UI_CLASS_KEY, UI_MODULE_KEY, WINDOW_ID_KEY, | 41 | TC_URL_KEY, UI_CLASS_KEY, UI_MODULE_KEY, WINDOW_ID_KEY, |
1883 | 41 | SUCCESS_CB_KEY, ERROR_CB_KEY, DENIAL_CB_KEY) | 42 | SUCCESS_CB_KEY, ERROR_CB_KEY, DENIAL_CB_KEY) |
1884 | 42 | from ubuntu_sso.tests import (APP_NAME, TC_URL, HELP_TEXT, CAPTCHA_ID, | 43 | from ubuntu_sso.tests import (APP_NAME, TC_URL, HELP_TEXT, CAPTCHA_ID, |
1885 | 43 | CAPTCHA_SOLUTION, EMAIL, EMAIL_TOKEN, PASSWORD, PING_URL, TOKEN, | 44 | CAPTCHA_SOLUTION, EMAIL, EMAIL_TOKEN, PASSWORD, PING_URL, TOKEN, |
1887 | 44 | TOKEN_NAME, WINDOW_ID) | 45 | TOKEN_NAME, WINDOW_ID, TestCase) |
1888 | 45 | 46 | ||
1889 | 46 | 47 | ||
1890 | 47 | # Access to a protected member 'yyy' of a client class | 48 | # Access to a protected member 'yyy' of a client class |
1891 | @@ -70,6 +71,8 @@ | |||
1892 | 70 | class SsoDbusTestCase(TestCase): | 71 | class SsoDbusTestCase(TestCase): |
1893 | 71 | """Test the SSOLogin DBus interface.""" | 72 | """Test the SSOLogin DBus interface.""" |
1894 | 72 | 73 | ||
1895 | 74 | timeout = 2 | ||
1896 | 75 | |||
1897 | 73 | def setUp(self): | 76 | def setUp(self): |
1898 | 74 | """Create the mocking bus.""" | 77 | """Create the mocking bus.""" |
1899 | 75 | self.mocker = Mocker() | 78 | self.mocker = Mocker() |
1900 | @@ -256,8 +259,8 @@ | |||
1901 | 256 | client.login(APP_NAME, EMAIL, PASSWORD) | 259 | client.login(APP_NAME, EMAIL, PASSWORD) |
1902 | 257 | return d | 260 | return d |
1903 | 258 | 261 | ||
1906 | 259 | def test_login_error(self): | 262 | def test_login_error_get_token_name(self): |
1907 | 260 | """Test that the login method fails as expected.""" | 263 | """The login method fails as expected when get_token_name fails.""" |
1908 | 261 | d = Deferred() | 264 | d = Deferred() |
1909 | 262 | self.create_mock_processor() | 265 | self.create_mock_processor() |
1910 | 263 | self.patch(ubuntu_sso.main, "blocking", fake_err_blocking) | 266 | self.patch(ubuntu_sso.main, "blocking", fake_err_blocking) |
1911 | @@ -284,6 +287,40 @@ | |||
1912 | 284 | client.login(APP_NAME, EMAIL, PASSWORD) | 287 | client.login(APP_NAME, EMAIL, PASSWORD) |
1913 | 285 | return d | 288 | return d |
1914 | 286 | 289 | ||
1915 | 290 | def test_login_error_set_credentials(self): | ||
1916 | 291 | """The login method fails as expected when set_credentials fails.""" | ||
1917 | 292 | d = Deferred() | ||
1918 | 293 | processor = self.create_mock_processor() | ||
1919 | 294 | processor.login(EMAIL, PASSWORD, TOKEN_NAME) | ||
1920 | 295 | self.mocker.result(TOKEN) | ||
1921 | 296 | processor.is_validated(TOKEN) | ||
1922 | 297 | self.mocker.result(True) | ||
1923 | 298 | |||
1924 | 299 | self.patch(ubuntu_sso.main, "blocking", fake_ok_blocking) | ||
1925 | 300 | |||
1926 | 301 | def fake_set_creds(*args): | ||
1927 | 302 | """A fake Keyring.set_credentials that fails.""" | ||
1928 | 303 | return defer.fail(BlockingSampleException()) | ||
1929 | 304 | |||
1930 | 305 | self.patch(ubuntu_sso.main.Keyring, "set_credentials", fake_set_creds) | ||
1931 | 306 | self.mocker.replay() | ||
1932 | 307 | |||
1933 | 308 | def verify(app_name, errdict): | ||
1934 | 309 | """The actual test.""" | ||
1935 | 310 | self.assertEqual(app_name, APP_NAME) | ||
1936 | 311 | self.assertEqual(errdict["errtype"], "BlockingSampleException") | ||
1937 | 312 | self.assertFalse(self.keyring_was_set, "Keyring should not be set") | ||
1938 | 313 | d.callback("Ok") | ||
1939 | 314 | |||
1940 | 315 | client = SSOLogin(self.mockbusname, | ||
1941 | 316 | sso_login_processor_class=self.mockprocessorclass) | ||
1942 | 317 | fail = lambda app, res: d.errback((app, res)) | ||
1943 | 318 | self.patch(client, "LoggedIn", fail) | ||
1944 | 319 | self.patch(client, "LoginError", verify) | ||
1945 | 320 | self.patch(client, "UserNotValidated", fail) | ||
1946 | 321 | client.login(APP_NAME, EMAIL, PASSWORD) | ||
1947 | 322 | return d | ||
1948 | 323 | |||
1949 | 287 | def test_validate_email(self): | 324 | def test_validate_email(self): |
1950 | 288 | """Test that the validate_email method works ok.""" | 325 | """Test that the validate_email method works ok.""" |
1951 | 289 | d = Deferred() | 326 | d = Deferred() |
1952 | @@ -666,21 +703,30 @@ | |||
1953 | 666 | class CredentialsManagementTestCase(TestCase): | 703 | class CredentialsManagementTestCase(TestCase): |
1954 | 667 | """Tests for the CredentialsManagement DBus interface.""" | 704 | """Tests for the CredentialsManagement DBus interface.""" |
1955 | 668 | 705 | ||
1956 | 706 | timeout = 2 | ||
1957 | 669 | base_args = {HELP_TEXT_KEY: HELP_TEXT, PING_URL_KEY: PING_URL, | 707 | base_args = {HELP_TEXT_KEY: HELP_TEXT, PING_URL_KEY: PING_URL, |
1958 | 670 | TC_URL_KEY: TC_URL, WINDOW_ID_KEY: WINDOW_ID, | 708 | TC_URL_KEY: TC_URL, WINDOW_ID_KEY: WINDOW_ID, |
1959 | 671 | UI_CLASS_KEY: 'SuperUI', UI_MODULE_KEY: 'foo.bar.baz', | 709 | UI_CLASS_KEY: 'SuperUI', UI_MODULE_KEY: 'foo.bar.baz', |
1960 | 672 | } | 710 | } |
1961 | 673 | 711 | ||
1962 | 674 | def setUp(self): | 712 | def setUp(self): |
1963 | 713 | super(CredentialsManagementTestCase, self).setUp() | ||
1964 | 714 | |||
1965 | 675 | self.mocker = Mocker() | 715 | self.mocker = Mocker() |
1967 | 676 | self.client = CredentialsManagement() | 716 | self.client = CredentialsManagement(timeout_func=lambda *a: None, |
1968 | 717 | shutdown_func=lambda *a: None) | ||
1969 | 677 | self.args = {} | 718 | self.args = {} |
1970 | 678 | self.cred_args = {} | 719 | self.cred_args = {} |
1971 | 679 | 720 | ||
1972 | 721 | self.memento = MementoHandler() | ||
1973 | 722 | self.memento.setLevel(logging.DEBUG) | ||
1974 | 723 | ubuntu_sso.main.logger.addHandler(self.memento) | ||
1975 | 724 | |||
1976 | 680 | def tearDown(self): | 725 | def tearDown(self): |
1977 | 681 | """Verify the mocking stuff and shut it down.""" | 726 | """Verify the mocking stuff and shut it down.""" |
1978 | 682 | self.mocker.verify() | 727 | self.mocker.verify() |
1979 | 683 | self.mocker.restore() | 728 | self.mocker.restore() |
1980 | 729 | super(CredentialsManagementTestCase, self).tearDown() | ||
1981 | 684 | 730 | ||
1982 | 685 | def assert_dbus_method_correct(self, method): | 731 | def assert_dbus_method_correct(self, method): |
1983 | 686 | """Check that 'method' is a dbus method with proper signatures.""" | 732 | """Check that 'method' is a dbus method with proper signatures.""" |
1984 | @@ -703,10 +749,168 @@ | |||
1985 | 703 | self.assertIsInstance(self.client, ubuntu_sso.main.dbus.service.Object) | 749 | self.assertIsInstance(self.client, ubuntu_sso.main.dbus.service.Object) |
1986 | 704 | 750 | ||
1987 | 705 | 751 | ||
1992 | 706 | class CredentialsManagementFindClearTestCase(CredentialsManagementTestCase): | 752 | class CredentialsManagementRefCountingTestCase(CredentialsManagementTestCase): |
1993 | 707 | """Tests for the CredentialsManagement find/clear/store methods.""" | 753 | """Tests for the CredentialsManagement ref counting.""" |
1994 | 708 | 754 | ||
1995 | 709 | timeout = 5 | 755 | def test_ref_counting(self): |
1996 | 756 | """Ref counting is in place.""" | ||
1997 | 757 | self.assertEqual(self.client.ref_count, 0) | ||
1998 | 758 | |||
1999 | 759 | def test_find_credentials(self): | ||
2000 | 760 | """Keep proper track of on going requests.""" | ||
2001 | 761 | self.client.find_credentials(APP_NAME, self.args) | ||
2002 | 762 | |||
2003 | 763 | self.assertEqual(self.client.ref_count, 1) | ||
2004 | 764 | |||
2005 | 765 | def test_clear_credentials(self): | ||
2006 | 766 | """Keep proper track of on going requests.""" | ||
2007 | 767 | self.client.clear_credentials(APP_NAME, self.args) | ||
2008 | 768 | |||
2009 | 769 | self.assertEqual(self.client.ref_count, 1) | ||
2010 | 770 | |||
2011 | 771 | def test_store_credentials(self): | ||
2012 | 772 | """Keep proper track of on going requests.""" | ||
2013 | 773 | self.client.store_credentials(APP_NAME, self.args) | ||
2014 | 774 | |||
2015 | 775 | self.assertEqual(self.client.ref_count, 1) | ||
2016 | 776 | |||
2017 | 777 | def test_register(self): | ||
2018 | 778 | """Keep proper track of on going requests.""" | ||
2019 | 779 | self.client.register(APP_NAME, self.args) | ||
2020 | 780 | |||
2021 | 781 | self.assertEqual(self.client.ref_count, 1) | ||
2022 | 782 | |||
2023 | 783 | def test_login(self): | ||
2024 | 784 | """Keep proper track of on going requests.""" | ||
2025 | 785 | self.client.login(APP_NAME, self.args) | ||
2026 | 786 | |||
2027 | 787 | self.assertEqual(self.client.ref_count, 1) | ||
2028 | 788 | |||
2029 | 789 | def test_several_requests(self): | ||
2030 | 790 | """Requests can be nested.""" | ||
2031 | 791 | self.client.login(APP_NAME, self.args) | ||
2032 | 792 | self.client.clear_credentials(APP_NAME, self.args) | ||
2033 | 793 | self.client.find_credentials(APP_NAME, self.args) | ||
2034 | 794 | self.client.register(APP_NAME, self.args) | ||
2035 | 795 | self.client.store_credentials(APP_NAME, self.args) | ||
2036 | 796 | |||
2037 | 797 | self.assertEqual(self.client.ref_count, 5) | ||
2038 | 798 | |||
2039 | 799 | def test_credentials_found(self): | ||
2040 | 800 | """Ref counter is decreased when a signal is sent.""" | ||
2041 | 801 | self.client.ref_count = 3 | ||
2042 | 802 | self.client.CredentialsFound(APP_NAME, TOKEN) | ||
2043 | 803 | |||
2044 | 804 | self.assertEqual(self.client.ref_count, 2) | ||
2045 | 805 | |||
2046 | 806 | def test_credentials_not_found(self): | ||
2047 | 807 | """Ref counter is decreased when a signal is sent.""" | ||
2048 | 808 | self.client.ref_count = 3 | ||
2049 | 809 | self.client.CredentialsNotFound(APP_NAME) | ||
2050 | 810 | |||
2051 | 811 | self.assertEqual(self.client.ref_count, 2) | ||
2052 | 812 | |||
2053 | 813 | def test_credentials_cleared(self): | ||
2054 | 814 | """Ref counter is decreased when a signal is sent.""" | ||
2055 | 815 | self.client.ref_count = 3 | ||
2056 | 816 | self.client.CredentialsCleared(APP_NAME) | ||
2057 | 817 | |||
2058 | 818 | self.assertEqual(self.client.ref_count, 2) | ||
2059 | 819 | |||
2060 | 820 | def test_credentials_stored(self): | ||
2061 | 821 | """Ref counter is decreased when a signal is sent.""" | ||
2062 | 822 | self.client.ref_count = 3 | ||
2063 | 823 | self.client.CredentialsStored(APP_NAME) | ||
2064 | 824 | |||
2065 | 825 | self.assertEqual(self.client.ref_count, 2) | ||
2066 | 826 | |||
2067 | 827 | def test_credentials_error(self): | ||
2068 | 828 | """Ref counter is decreased when a signal is sent.""" | ||
2069 | 829 | self.client.ref_count = 3 | ||
2070 | 830 | self.client.CredentialsError(APP_NAME, {'error_type': 'test'}) | ||
2071 | 831 | |||
2072 | 832 | self.assertEqual(self.client.ref_count, 2) | ||
2073 | 833 | |||
2074 | 834 | def test_authorization_denied(self): | ||
2075 | 835 | """Ref counter is decreased when a signal is sent.""" | ||
2076 | 836 | self.client.ref_count = 3 | ||
2077 | 837 | self.client.AuthorizationDenied(APP_NAME) | ||
2078 | 838 | |||
2079 | 839 | self.assertEqual(self.client.ref_count, 2) | ||
2080 | 840 | |||
2081 | 841 | def test_credentials_found_when_ref_count_is_not_positive(self): | ||
2082 | 842 | """Ref counter is decreased when a signal is sent.""" | ||
2083 | 843 | self.client._ref_count = -3 | ||
2084 | 844 | self.client.CredentialsFound(APP_NAME, TOKEN) | ||
2085 | 845 | |||
2086 | 846 | self.assertEqual(self.client.ref_count, 0) | ||
2087 | 847 | msg = 'Attempting to decrease ref_count to a negative value (-4).' | ||
2088 | 848 | self.assertTrue(self.memento.check_warning(msg)) | ||
2089 | 849 | |||
2090 | 850 | def test_credentials_not_found_when_ref_count_is_not_positive(self): | ||
2091 | 851 | """Ref counter is decreased when a signal is sent.""" | ||
2092 | 852 | self.client._ref_count = -3 | ||
2093 | 853 | self.client.CredentialsNotFound(APP_NAME) | ||
2094 | 854 | |||
2095 | 855 | self.assertEqual(self.client.ref_count, 0) | ||
2096 | 856 | msg = 'Attempting to decrease ref_count to a negative value (-4).' | ||
2097 | 857 | self.assertTrue(self.memento.check_warning(msg)) | ||
2098 | 858 | |||
2099 | 859 | def test_credentials_cleared_when_ref_count_is_not_positive(self): | ||
2100 | 860 | """Ref counter is decreased when a signal is sent.""" | ||
2101 | 861 | self.client._ref_count = -3 | ||
2102 | 862 | self.client.CredentialsCleared(APP_NAME) | ||
2103 | 863 | |||
2104 | 864 | self.assertEqual(self.client.ref_count, 0) | ||
2105 | 865 | msg = 'Attempting to decrease ref_count to a negative value (-4).' | ||
2106 | 866 | self.assertTrue(self.memento.check_warning(msg)) | ||
2107 | 867 | |||
2108 | 868 | def test_credentials_stored_when_ref_count_is_not_positive(self): | ||
2109 | 869 | """Ref counter is decreased when a signal is sent.""" | ||
2110 | 870 | self.client._ref_count = -3 | ||
2111 | 871 | self.client.CredentialsStored(APP_NAME) | ||
2112 | 872 | |||
2113 | 873 | self.assertEqual(self.client.ref_count, 0) | ||
2114 | 874 | msg = 'Attempting to decrease ref_count to a negative value (-4).' | ||
2115 | 875 | self.assertTrue(self.memento.check_warning(msg)) | ||
2116 | 876 | |||
2117 | 877 | def test_credentials_error_when_ref_count_is_not_positive(self): | ||
2118 | 878 | """Ref counter is decreased when a signal is sent.""" | ||
2119 | 879 | self.client._ref_count = -3 | ||
2120 | 880 | self.client.CredentialsError(APP_NAME, {'error_type': 'test'}) | ||
2121 | 881 | |||
2122 | 882 | self.assertEqual(self.client.ref_count, 0) | ||
2123 | 883 | msg = 'Attempting to decrease ref_count to a negative value (-4).' | ||
2124 | 884 | self.assertTrue(self.memento.check_warning(msg)) | ||
2125 | 885 | |||
2126 | 886 | def test_autorization_denied_when_ref_count_is_not_positive(self): | ||
2127 | 887 | """Ref counter is decreased when a signal is sent.""" | ||
2128 | 888 | self.client._ref_count = -3 | ||
2129 | 889 | self.client.AuthorizationDenied(APP_NAME) | ||
2130 | 890 | |||
2131 | 891 | self.assertEqual(self.client.ref_count, 0) | ||
2132 | 892 | msg = 'Attempting to decrease ref_count to a negative value (-4).' | ||
2133 | 893 | self.assertTrue(self.memento.check_warning(msg)) | ||
2134 | 894 | |||
2135 | 895 | def test_on_zero_ref_count_shutdown(self): | ||
2136 | 896 | """When ref count reaches 0, queue shutdown op.""" | ||
2137 | 897 | self.client.timeout_func = self._set_called | ||
2138 | 898 | self.client.find_credentials(APP_NAME, self.args) | ||
2139 | 899 | self.client.CredentialsFound(APP_NAME, TOKEN) | ||
2140 | 900 | |||
2141 | 901 | self.assertEqual(self._called, | ||
2142 | 902 | ((TIMEOUT_INTERVAL, self.client.shutdown_func), {})) | ||
2143 | 903 | |||
2144 | 904 | def test_on_non_zero_ref_count_do_not_shutdown(self): | ||
2145 | 905 | """If ref count is not 0, do not queue shutdown op.""" | ||
2146 | 906 | self.client.timeout_func = self._set_called | ||
2147 | 907 | self.client.find_credentials(APP_NAME, self.args) | ||
2148 | 908 | |||
2149 | 909 | self.assertEqual(self._called, False) | ||
2150 | 910 | |||
2151 | 911 | |||
2152 | 912 | class CredentialsManagementFindTestCase(CredentialsManagementTestCase): | ||
2153 | 913 | """Tests for the CredentialsManagement find method.""" | ||
2154 | 710 | 914 | ||
2155 | 711 | def test_find_credentials(self): | 915 | def test_find_credentials(self): |
2156 | 712 | """The credentials are asked and returned in signals.""" | 916 | """The credentials are asked and returned in signals.""" |
2157 | @@ -762,7 +966,8 @@ | |||
2158 | 762 | else: | 966 | else: |
2159 | 763 | d.callback(app_name) | 967 | d.callback(app_name) |
2160 | 764 | 968 | ||
2162 | 765 | self.patch(self.client, 'CredentialsFound', d.errback) | 969 | self.patch(self.client, 'CredentialsFound', |
2163 | 970 | lambda app, creds: d.errback(app)) | ||
2164 | 766 | self.patch(self.client, 'CredentialsNotFound', verify) | 971 | self.patch(self.client, 'CredentialsNotFound', verify) |
2165 | 767 | 972 | ||
2166 | 768 | self.create_mock_backend().find_credentials() | 973 | self.create_mock_backend().find_credentials() |
2167 | @@ -772,6 +977,32 @@ | |||
2168 | 772 | self.client.find_credentials(APP_NAME, self.args) | 977 | self.client.find_credentials(APP_NAME, self.args) |
2169 | 773 | return d | 978 | return d |
2170 | 774 | 979 | ||
2171 | 980 | def test_find_credentials_error(self): | ||
2172 | 981 | """If find_credentials fails, CredentialsError is sent.""" | ||
2173 | 982 | d = Deferred() | ||
2174 | 983 | |||
2175 | 984 | def verify(app_name, errdict): | ||
2176 | 985 | """The actual test.""" | ||
2177 | 986 | self.assertEqual(errdict["errtype"], "BlockingSampleException") | ||
2178 | 987 | self.assertEqual(app_name, APP_NAME) | ||
2179 | 988 | d.callback("Ok") | ||
2180 | 989 | |||
2181 | 990 | self.patch(self.client, 'CredentialsFound', | ||
2182 | 991 | lambda app, creds: d.errback(app)) | ||
2183 | 992 | self.patch(self.client, 'CredentialsNotFound', d.errback) | ||
2184 | 993 | self.patch(self.client, 'CredentialsError', verify) | ||
2185 | 994 | |||
2186 | 995 | self.create_mock_backend().find_credentials() | ||
2187 | 996 | self.mocker.result(defer.fail(BlockingSampleException())) | ||
2188 | 997 | self.mocker.replay() | ||
2189 | 998 | |||
2190 | 999 | self.client.find_credentials(APP_NAME, self.args) | ||
2191 | 1000 | return d | ||
2192 | 1001 | |||
2193 | 1002 | |||
2194 | 1003 | class CredentialsManagementClearTestCase(CredentialsManagementTestCase): | ||
2195 | 1004 | """Tests for the CredentialsManagement clear method.""" | ||
2196 | 1005 | |||
2197 | 775 | def test_clear_credentials(self): | 1006 | def test_clear_credentials(self): |
2198 | 776 | """The credentials are removed.""" | 1007 | """The credentials are removed.""" |
2199 | 777 | self.create_mock_backend().clear_credentials() | 1008 | self.create_mock_backend().clear_credentials() |
2200 | @@ -795,7 +1026,8 @@ | |||
2201 | 795 | d.callback(app_name) | 1026 | d.callback(app_name) |
2202 | 796 | 1027 | ||
2203 | 797 | self.patch(self.client, 'CredentialsCleared', verify) | 1028 | self.patch(self.client, 'CredentialsCleared', verify) |
2205 | 798 | self.patch(self.client, 'CredentialsError', d.errback) | 1029 | self.patch(self.client, 'CredentialsError', |
2206 | 1030 | lambda app, err: d.errback(app)) | ||
2207 | 799 | 1031 | ||
2208 | 800 | self.create_mock_backend().clear_credentials() | 1032 | self.create_mock_backend().clear_credentials() |
2209 | 801 | self.mocker.result(defer.succeed(APP_NAME)) | 1033 | self.mocker.result(defer.succeed(APP_NAME)) |
2210 | @@ -804,6 +1036,30 @@ | |||
2211 | 804 | self.client.clear_credentials(APP_NAME, self.args) | 1036 | self.client.clear_credentials(APP_NAME, self.args) |
2212 | 805 | return d | 1037 | return d |
2213 | 806 | 1038 | ||
2214 | 1039 | def test_clear_credentials_error(self): | ||
2215 | 1040 | """If clear_credentials fails, CredentialsError is sent.""" | ||
2216 | 1041 | d = Deferred() | ||
2217 | 1042 | |||
2218 | 1043 | def verify(app_name, errdict): | ||
2219 | 1044 | """The actual test.""" | ||
2220 | 1045 | self.assertEqual(errdict["errtype"], "BlockingSampleException") | ||
2221 | 1046 | self.assertEqual(app_name, APP_NAME) | ||
2222 | 1047 | d.callback("Ok") | ||
2223 | 1048 | |||
2224 | 1049 | self.patch(self.client, 'CredentialsCleared', d.errback) | ||
2225 | 1050 | self.patch(self.client, 'CredentialsError', verify) | ||
2226 | 1051 | |||
2227 | 1052 | self.create_mock_backend().clear_credentials() | ||
2228 | 1053 | self.mocker.result(defer.fail(BlockingSampleException())) | ||
2229 | 1054 | self.mocker.replay() | ||
2230 | 1055 | |||
2231 | 1056 | self.client.clear_credentials(APP_NAME, self.args) | ||
2232 | 1057 | return d | ||
2233 | 1058 | |||
2234 | 1059 | |||
2235 | 1060 | class CredentialsManagementStoreTestCase(CredentialsManagementTestCase): | ||
2236 | 1061 | """Tests for the CredentialsManagement store method.""" | ||
2237 | 1062 | |||
2238 | 807 | def test_store_credentials(self): | 1063 | def test_store_credentials(self): |
2239 | 808 | """The credentials are stored and the outcome is a signal.""" | 1064 | """The credentials are stored and the outcome is a signal.""" |
2240 | 809 | self.create_mock_backend().store_credentials(TOKEN) | 1065 | self.create_mock_backend().store_credentials(TOKEN) |
2241 | @@ -831,7 +1087,8 @@ | |||
2242 | 831 | d.callback(app_name) | 1087 | d.callback(app_name) |
2243 | 832 | 1088 | ||
2244 | 833 | self.patch(self.client, 'CredentialsStored', verify) | 1089 | self.patch(self.client, 'CredentialsStored', verify) |
2246 | 834 | self.patch(self.client, 'CredentialsError', d.errback) | 1090 | self.patch(self.client, 'CredentialsError', |
2247 | 1091 | lambda app, err: d.errback(app)) | ||
2248 | 835 | 1092 | ||
2249 | 836 | self.create_mock_backend().store_credentials(TOKEN) | 1093 | self.create_mock_backend().store_credentials(TOKEN) |
2250 | 837 | self.mocker.result(defer.succeed(APP_NAME)) | 1094 | self.mocker.result(defer.succeed(APP_NAME)) |
2251 | @@ -840,6 +1097,26 @@ | |||
2252 | 840 | self.client.store_credentials(APP_NAME, TOKEN) | 1097 | self.client.store_credentials(APP_NAME, TOKEN) |
2253 | 841 | return d | 1098 | return d |
2254 | 842 | 1099 | ||
2255 | 1100 | def test_store_credentials_error(self): | ||
2256 | 1101 | """If store_credentials fails, CredentialsError is sent.""" | ||
2257 | 1102 | d = Deferred() | ||
2258 | 1103 | |||
2259 | 1104 | def verify(app_name, errdict): | ||
2260 | 1105 | """The actual test.""" | ||
2261 | 1106 | self.assertEqual(errdict["errtype"], "BlockingSampleException") | ||
2262 | 1107 | self.assertEqual(app_name, APP_NAME) | ||
2263 | 1108 | d.callback("Ok") | ||
2264 | 1109 | |||
2265 | 1110 | self.patch(self.client, 'CredentialsStored', d.errback) | ||
2266 | 1111 | self.patch(self.client, 'CredentialsError', verify) | ||
2267 | 1112 | |||
2268 | 1113 | self.create_mock_backend().store_credentials(TOKEN) | ||
2269 | 1114 | self.mocker.result(defer.fail(BlockingSampleException())) | ||
2270 | 1115 | self.mocker.replay() | ||
2271 | 1116 | |||
2272 | 1117 | self.client.store_credentials(APP_NAME, TOKEN) | ||
2273 | 1118 | return d | ||
2274 | 1119 | |||
2275 | 843 | 1120 | ||
2276 | 844 | class CredentialsManagementOpsTestCase(CredentialsManagementTestCase): | 1121 | class CredentialsManagementOpsTestCase(CredentialsManagementTestCase): |
2277 | 845 | """Tests for the CredentialsManagement login/register methods.""" | 1122 | """Tests for the CredentialsManagement login/register methods.""" |
2278 | @@ -881,7 +1158,8 @@ | |||
2279 | 881 | """Tests for the CredentialsManagement DBus signals.""" | 1158 | """Tests for the CredentialsManagement DBus signals.""" |
2280 | 882 | 1159 | ||
2281 | 883 | def setUp(self): | 1160 | def setUp(self): |
2283 | 884 | self.client = CredentialsManagement() | 1161 | self.client = CredentialsManagement(timeout_func=lambda *a: None, |
2284 | 1162 | shutdown_func=lambda *a: None) | ||
2285 | 885 | 1163 | ||
2286 | 886 | self.memento = MementoHandler() | 1164 | self.memento = MementoHandler() |
2287 | 887 | self.memento.setLevel(logging.DEBUG) | 1165 | self.memento.setLevel(logging.DEBUG) |