Merge lp:~nataliabidart/ubuntu/maverick/ubuntu-sso-client/ubuntu-sso-client-0.99.3 into lp:ubuntu/maverick/ubuntu-sso-client

Proposed by Natalia Bidart
Status: Merged
Merged at revision: 9
Proposed branch: lp:~nataliabidart/ubuntu/maverick/ubuntu-sso-client/ubuntu-sso-client-0.99.3
Merge into: lp:ubuntu/maverick/ubuntu-sso-client
Diff against target: 1422 lines (+519/-241)
11 files modified
MANIFEST.in (+1/-0)
PKG-INFO (+1/-1)
data/ui.glade (+103/-106)
debian/changelog (+32/-0)
po/POTFILES.in (+1/-0)
run-tests (+1/-1)
setup.py (+2/-2)
ubuntu_sso/gui.py (+70/-46)
ubuntu_sso/main.py (+34/-11)
ubuntu_sso/tests/test_gui.py (+128/-45)
ubuntu_sso/tests/test_main.py (+146/-29)
To merge this branch: bzr merge lp:~nataliabidart/ubuntu/maverick/ubuntu-sso-client/ubuntu-sso-client-0.99.3
Reviewer Review Type Date Requested Status
Ubuntu Development Team Pending
Review via email: mp+33774@code.launchpad.net

Description of the change

Release 0.99.3 (Bug fixes for UI freeze).

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 'MANIFEST.in'
2--- MANIFEST.in 2010-08-24 15:47:58 +0000
3+++ MANIFEST.in 2010-08-26 12:56:23 +0000
4@@ -1,6 +1,7 @@
5 include MANIFEST.in
6 include COPYING README
7 include run-tests
8+recursive-include po *
9 recursive-include bin *
10 recursive-include data *
11 recursive-include ubuntu_sso *.py
12
13=== modified file 'PKG-INFO'
14--- PKG-INFO 2010-08-24 15:47:58 +0000
15+++ PKG-INFO 2010-08-26 12:56:23 +0000
16@@ -1,6 +1,6 @@
17 Metadata-Version: 1.1
18 Name: ubuntu-sso-client
19-Version: 0.99.2
20+Version: 0.99.3
21 Summary: Ubuntu Single Sign-On client
22 Home-page: https://launchpad.net/ubuntu-sso-client
23 Author: Natalia Bidart
24
25=== removed file 'data/email.png'
26Binary files data/email.png 2010-08-12 00:00:08 +0000 and data/email.png 1970-01-01 00:00:00 +0000 differ
27=== modified file 'data/ui.glade'
28--- data/ui.glade 2010-08-24 15:47:58 +0000
29+++ data/ui.glade 2010-08-26 12:56:23 +0000
30@@ -4,6 +4,7 @@
31 <!-- interface-naming-policy project-wide -->
32 <object class="GtkWindow" id="window">
33 <property name="border_width">20</property>
34+ <property name="resizable">False</property>
35 <property name="window_position">center</property>
36 <signal name="delete_event" handler="on_close_clicked"/>
37 <child>
38@@ -59,19 +60,6 @@
39 <property name="visible">True</property>
40 <property name="spacing">10</property>
41 <child>
42- <placeholder/>
43- </child>
44- <child>
45- <object class="GtkLabel" id="name_warning_label">
46- <property name="visible">True</property>
47- <property name="wrap">True</property>
48- </object>
49- <packing>
50- <property name="expand">False</property>
51- <property name="position">1</property>
52- </packing>
53- </child>
54- <child>
55 <object class="GtkHBox" id="emails_hbox">
56 <property name="visible">True</property>
57 <property name="spacing">5</property>
58@@ -89,14 +77,7 @@
59 </packing>
60 </child>
61 <child>
62- <object class="GtkLabel" id="email_warning_label">
63- <property name="visible">True</property>
64- <property name="wrap">True</property>
65- </object>
66- <packing>
67- <property name="expand">False</property>
68- <property name="position">3</property>
69- </packing>
70+ <placeholder/>
71 </child>
72 <child>
73 <object class="GtkHBox" id="passwords_hbox">
74@@ -126,63 +107,102 @@
75 </packing>
76 </child>
77 <child>
78- <object class="GtkLabel" id="password_warning_label">
79- <property name="visible">True</property>
80- <property name="wrap">True</property>
81- </object>
82- <packing>
83- <property name="position">6</property>
84- </packing>
85- </child>
86- <child>
87 <placeholder/>
88 </child>
89 <child>
90- <object class="GtkEventBox" id="captcha_loading">
91- <property name="width_request">300</property>
92- <property name="height_request">60</property>
93- <property name="visible">True</property>
94- <child>
95- <placeholder/>
96- </child>
97- </object>
98- <packing>
99- <property name="expand">False</property>
100- <property name="fill">False</property>
101+ <object class="GtkHBox" id="hbox1">
102+ <property name="visible">True</property>
103+ <child>
104+ <object class="GtkVBox" id="captcha_vbox">
105+ <property name="visible">True</property>
106+ <property name="homogeneous">True</property>
107+ <child>
108+ <object class="GtkEventBox" id="captcha_loading">
109+ <property name="width_request">300</property>
110+ <property name="height_request">60</property>
111+ <property name="visible">True</property>
112+ <child>
113+ <placeholder/>
114+ </child>
115+ </object>
116+ <packing>
117+ <property name="expand">False</property>
118+ <property name="fill">False</property>
119+ <property name="position">0</property>
120+ </packing>
121+ </child>
122+ <child>
123+ <object class="GtkImage" id="captcha_image">
124+ <property name="width_request">300</property>
125+ <property name="height_request">60</property>
126+ <property name="visible">True</property>
127+ <property name="stock">gtk-missing-image</property>
128+ </object>
129+ <packing>
130+ <property name="position">1</property>
131+ </packing>
132+ </child>
133+ </object>
134+ <packing>
135+ <property name="position">0</property>
136+ </packing>
137+ </child>
138+ <child>
139+ <object class="GtkVBox" id="vbox1">
140+ <property name="visible">True</property>
141+ <child>
142+ <object class="GtkButton" id="captcha_reload_button">
143+ <property name="visible">True</property>
144+ <property name="can_focus">True</property>
145+ <property name="receives_default">True</property>
146+ <property name="relief">none</property>
147+ <property name="focus_on_click">False</property>
148+ <signal name="clicked" handler="on_captcha_reload_button_clicked"/>
149+ <child>
150+ <object class="GtkImage" id="image1">
151+ <property name="visible">True</property>
152+ <property name="icon_name">reload</property>
153+ </object>
154+ </child>
155+ </object>
156+ <packing>
157+ <property name="expand">False</property>
158+ <property name="position">0</property>
159+ </packing>
160+ </child>
161+ <child>
162+ <placeholder/>
163+ </child>
164+ <child>
165+ <placeholder/>
166+ </child>
167+ </object>
168+ <packing>
169+ <property name="expand">False</property>
170+ <property name="position">1</property>
171+ </packing>
172+ </child>
173+ </object>
174+ <packing>
175+ <property name="position">7</property>
176+ </packing>
177+ </child>
178+ <child>
179+ <object class="GtkVBox" id="captcha_solution_vbox">
180+ <property name="visible">True</property>
181+ <property name="spacing">10</property>
182+ <child>
183+ <placeholder/>
184+ </child>
185+ <child>
186+ <placeholder/>
187+ </child>
188+ </object>
189+ <packing>
190 <property name="position">8</property>
191 </packing>
192 </child>
193 <child>
194- <object class="GtkImage" id="captcha_image">
195- <property name="visible">True</property>
196- <property name="stock">gtk-missing-image</property>
197- </object>
198- <packing>
199- <property name="position">9</property>
200- </packing>
201- </child>
202- <child>
203- <object class="GtkVBox" id="captcha_solution_vbox">
204- <property name="visible">True</property>
205- <property name="spacing">10</property>
206- <child>
207- <placeholder/>
208- </child>
209- <child>
210- <object class="GtkLabel" id="captcha_solution_warning_label">
211- <property name="visible">True</property>
212- <property name="wrap">True</property>
213- </object>
214- <packing>
215- <property name="position">1</property>
216- </packing>
217- </child>
218- </object>
219- <packing>
220- <property name="position">10</property>
221- </packing>
222- </child>
223- <child>
224 <object class="GtkCheckButton" id="yes_to_updates_checkbutton">
225 <property name="label" translatable="yes">yes to updates</property>
226 <property name="visible">True</property>
227@@ -193,11 +213,11 @@
228 </object>
229 <packing>
230 <property name="expand">False</property>
231- <property name="position">11</property>
232+ <property name="position">9</property>
233 </packing>
234 </child>
235 <child>
236- <object class="GtkHBox" id="hbox1">
237+ <object class="GtkHBox" id="tc_hbox">
238 <property name="visible">True</property>
239 <child>
240 <object class="GtkCheckButton" id="yes_to_tc_checkbutton">
241@@ -231,7 +251,7 @@
242 </object>
243 <packing>
244 <property name="expand">False</property>
245- <property name="position">12</property>
246+ <property name="position">10</property>
247 </packing>
248 </child>
249 <child>
250@@ -240,7 +260,7 @@
251 <property name="wrap">True</property>
252 </object>
253 <packing>
254- <property name="position">13</property>
255+ <property name="position">11</property>
256 </packing>
257 </child>
258 <child>
259@@ -280,7 +300,7 @@
260 </object>
261 <packing>
262 <property name="expand">False</property>
263- <property name="position">14</property>
264+ <property name="position">12</property>
265 </packing>
266 </child>
267 <child>
268@@ -295,9 +315,12 @@
269 </object>
270 <packing>
271 <property name="expand">False</property>
272- <property name="position">15</property>
273+ <property name="position">13</property>
274 </packing>
275 </child>
276+ <child>
277+ <placeholder/>
278+ </child>
279 </object>
280 <object class="GtkVBox" id="processing_vbox">
281 <property name="visible">True</property>
282@@ -310,15 +333,6 @@
283 <property name="visible">True</property>
284 <property name="spacing">10</property>
285 <child>
286- <object class="GtkImage" id="verify_email_image">
287- <property name="visible">True</property>
288- <property name="stock">gtk-missing-image</property>
289- </object>
290- <packing>
291- <property name="position">0</property>
292- </packing>
293- </child>
294- <child>
295 <placeholder/>
296 </child>
297 <child>
298@@ -344,7 +358,7 @@
299 </object>
300 <packing>
301 <property name="expand">False</property>
302- <property name="position">2</property>
303+ <property name="position">1</property>
304 </packing>
305 </child>
306 </object>
307@@ -359,6 +373,7 @@
308 <property name="border_width">10</property>
309 <property name="hscrollbar_policy">never</property>
310 <property name="vscrollbar_policy">automatic</property>
311+ <property name="shadow_type">in</property>
312 <child>
313 <placeholder/>
314 </child>
315@@ -412,24 +427,6 @@
316 <placeholder/>
317 </child>
318 <child>
319- <object class="GtkLabel" id="login_email_warning_label">
320- <property name="visible">True</property>
321- <property name="label" translatable="yes">label</property>
322- </object>
323- <packing>
324- <property name="position">2</property>
325- </packing>
326- </child>
327- <child>
328- <object class="GtkLabel" id="login_password_warning_label">
329- <property name="visible">True</property>
330- <property name="label" translatable="yes">label</property>
331- </object>
332- <packing>
333- <property name="position">4</property>
334- </packing>
335- </child>
336- <child>
337 <object class="GtkLinkButton" id="forgotten_password_button">
338 <property name="label" translatable="yes">button</property>
339 <property name="visible">True</property>
340@@ -440,7 +437,7 @@
341 <signal name="clicked" handler="on_forgotten_password_button_clicked"/>
342 </object>
343 <packing>
344- <property name="position">5</property>
345+ <property name="position">2</property>
346 </packing>
347 </child>
348 </object>
349
350=== modified file 'debian/changelog'
351--- debian/changelog 2010-08-24 20:30:45 +0000
352+++ debian/changelog 2010-08-26 12:56:23 +0000
353@@ -1,3 +1,35 @@
354+ubuntu-sso-client (0.99.3-0ubuntu1) UNRELEASED; urgency=low
355+
356+ * New upstream release:
357+
358+ [ john.lenton@canonical.com ]
359+ * changed the "reset password" header and help text (LP: #622991).
360+ * changed the "verify" header and help text, and removed the email image
361+ (LP: #622988, LP: #622830).
362+
363+ [ john.lenton@canonical.com ]
364+ * added a reload button for the captcha (LP: #616459).
365+
366+ [ natalia.bidart@canonical.com ]
367+ * Warnings for entries are shown as secondary icons (LP: #624336).
368+
369+ [ natalia.bidart@canonical.com ]
370+ * Main window can not be maximized (LP: #624101).
371+
372+ [ natalia.bidart@canonical.com ]
373+ * Pinging the U1 url is done before sending any credential signal. Also,
374+ ping is signed with user credentials (LP: #624034).
375+
376+ [ john.lenton@canonical.com ]
377+ * Put a border around the webkit box (LP: #624240).
378+ * Hide the T&C link of no T&C url is provided (LP: #624241).
379+ * Hide the help text on the T&C page (LP: #624242).
380+
381+ [ Alejandro J. Cura <alecu@canonical.com> ]
382+ * Turn exceptions into a dictionary able to go thru DBus (LP: #624018)
383+
384+ -- Natalia Bidart (nessita) <nataliabidart@gmail.com> Wed, 25 Aug 2010 22:07:42 -0300
385+
386 ubuntu-sso-client (0.99.2-0ubuntu1) maverick; urgency=low
387
388 * New upstream release:
389
390=== added directory 'po'
391=== added file 'po/POTFILES.in'
392--- po/POTFILES.in 1970-01-01 00:00:00 +0000
393+++ po/POTFILES.in 2010-08-26 12:56:23 +0000
394@@ -0,0 +1,1 @@
395+ubuntu_sso/gui.py
396
397=== modified file 'run-tests'
398--- run-tests 2010-08-19 16:02:09 +0000
399+++ run-tests 2010-08-26 12:56:23 +0000
400@@ -15,7 +15,7 @@
401 # You should have received a copy of the GNU General Public License along
402 # with this program. If not, see <http://www.gnu.org/licenses/>.
403
404-`which xvfb-run` ./contrib/test $@
405+`which xvfb-run` ./contrib/test "$@"
406 pyflakes bin ubuntu_sso
407 if [ -x `which pep8` ]; then
408 pep8 --repeat bin/ contrib/ \
409
410=== modified file 'setup.py'
411--- setup.py 2010-08-24 15:47:58 +0000
412+++ setup.py 2010-08-26 12:56:23 +0000
413@@ -81,7 +81,7 @@
414
415 DistUtilsExtra.auto.setup(
416 name='ubuntu-sso-client',
417- version='0.99.2',
418+ version='0.99.3',
419 license='GPL v3',
420 author='Natalia Bidart',
421 author_email='natalia.bidart@canonical.com',
422@@ -93,7 +93,7 @@
423 data_files=[
424 ('share/dbus-1/services', ['data/com.ubuntu.sso.service',]),
425 ('lib/ubuntu-sso-client', ['bin/ubuntu-sso-login',]),
426- ('share/ubuntu-sso-client/data', ['data/ui.glade', 'data/email.png',]),
427+ ('share/ubuntu-sso-client/data', ['data/ui.glade',]),
428 ('/etc/xdg/ubuntu-sso/', ['data/oauth_urls',]),
429 ('/etc/xdg/ubuntu-sso/oauth_registration.d',
430 ['data/oauth_registration.d/ubuntuone',]),
431
432=== modified file 'ubuntu_sso/gui.py'
433--- ubuntu_sso/gui.py 2010-08-24 15:47:58 +0000
434+++ ubuntu_sso/gui.py 2010-08-26 12:56:23 +0000
435@@ -120,7 +120,7 @@
436 def __init__(self, label, is_password=False, *args, **kwargs):
437 self.label = label
438 self.is_password = is_password
439- self._user_input = None
440+ self.warning = None
441
442 super(LabeledEntry, self).__init__(*args, **kwargs)
443
444@@ -129,6 +129,7 @@
445 self.set_tooltip_text(self.label)
446 self.connect('focus-in-event', self._clear_text)
447 self.connect('focus-out-event', self._set_label)
448+ self.clear_warning()
449 self.show()
450
451 def _clear_text(self, *args, **kwargs):
452@@ -162,6 +163,20 @@
453 result = ''
454 return result
455
456+ def set_warning(self, warning_msg):
457+ """Display warning as secondary icon, set 'warning_msg' as tooltip."""
458+ self.warning = warning_msg
459+ self.set_property('secondary-icon-stock', gtk.STOCK_DIALOG_WARNING)
460+ self.set_property('secondary-icon-sensitive', True)
461+ self.set_property('secondary-icon-tooltip-text', warning_msg)
462+
463+ def clear_warning(self):
464+ """Remove any warning."""
465+ self.warning = None
466+ self.set_property('secondary-icon-stock', None)
467+ self.set_property('secondary-icon-sensitive', False)
468+ self.set_property('secondary-icon-tooltip-text', None)
469+
470
471 class UbuntuSSOClientGUI(object):
472 """Ubuntu single sign on GUI."""
473@@ -194,9 +209,9 @@
474 PASSWORD_MISMATCH = _('The passwords don\'t match, please double check ' \
475 'and try entering them again.')
476 PASSWORD_TOO_WEAK = _('The password is too weak.')
477- REQUEST_PASSWORD_TOKEN_LABEL = _('To reset your password enter your ' \
478- 'email address below:')
479- RESET_PASSWORD = _('Reset Password')
480+ REQUEST_PASSWORD_TOKEN_LABEL = _('To reset your %(app_name)s password,'
481+ ' enter your email address below:')
482+ RESET_PASSWORD = _('Reset password')
483 RESET_CODE_ENTRY = _('Reset code')
484 RESET_EMAIL_ENTRY = _('Email address')
485 SET_NEW_PASSWORD_LABEL = _('A password reset code has been sent to ' \
486@@ -208,12 +223,15 @@
487 'required to subscribe.')
488 UNKNOWN_ERROR = _('There was an error when trying to complete the ' \
489 'process. Please check the information and try again.')
490- VERIFY_EMAIL_LABEL = _('Enter verification code.\n\nA verification code ' \
491- 'has just been sent to your email address.\n' \
492- 'Please enter your code from the email. ' \
493- 'An example is shown below.')
494+ VERIFY_EMAIL_LABEL = ('<b>%s</b>\n\n' % _('Enter verification code') +
495+ _('Check %(email)s for an email from'
496+ ' Ubuntu Single Sign On.'
497+ ' This message contains a verification code.'
498+ ' Enter the code in the field below and click OK'
499+ ' to complete creating your %(app_name)s account'))
500 YES_TO_TC = _('I agree with the %(app_name)s ') # Terms&Conditions button
501 YES_TO_UPDATES = _('Yes! Email me %(app_name)s tips and updates.')
502+ CAPTCHA_RELOAD_TOOLTIP = _('Reload')
503
504 def __init__(self, app_name, tc_uri, help_text,
505 window_id=0, login_only=False, close_callback=None):
506@@ -274,6 +292,7 @@
507 assert getattr(self, name) is not None
508
509 self.window.set_icon_name('ubuntu-logo')
510+ self.captcha_reload_button.set_tooltip_text(self.CAPTCHA_RELOAD_TOOLTIP)
511
512 self.bus = dbus.SessionBus()
513 self.bus.add_signal_receiver = self._log(self.bus.add_signal_receiver)
514@@ -397,6 +416,8 @@
515 for widget in self.warnings:
516 widget.set_text('')
517 widget.hide()
518+ for widget in self.entries:
519+ getattr(self, widget).clear_warning()
520
521 def _non_empty_input(self, widget):
522 """Return weather widget has non empty content."""
523@@ -434,6 +455,14 @@
524 else:
525 page.hide()
526
527+ def _generate_captcha(self):
528+ """Ask for a new captcha; update the ui to reflect the fact."""
529+ logger.info('Calling generate_captcha with filename path at %r',
530+ self._captcha_filename)
531+ self.backend.generate_captcha(self.app_name, self._captcha_filename,
532+ reply_handler=NO_OP, error_handler=NO_OP)
533+ self._set_captcha_loading()
534+
535 def _set_captcha_loading(self):
536 """Present a spinner to the user while the captcha is downloaded."""
537 self.captcha_image.hide()
538@@ -472,27 +501,25 @@
539 self.password_help_label.set_markup(help_msg)
540
541 if not os.path.exists(self._captcha_filename):
542- self._set_captcha_loading()
543+ self._generate_captcha()
544 else:
545 self._set_captcha_image()
546
547 msg = self.YES_TO_UPDATES % {'app_name': self.app_name}
548 self.yes_to_updates_checkbutton.set_label(msg)
549- msg = self.YES_TO_TC % {'app_name': self.app_name}
550- self.yes_to_tc_checkbutton.set_label(msg)
551- self.tc_button.set_label(self.TC)
552+ if self.tc_uri:
553+ msg = self.YES_TO_TC % {'app_name': self.app_name}
554+ self.yes_to_tc_checkbutton.set_label(msg)
555+ self.tc_button.set_label(self.TC)
556+ else:
557+ self.tc_hbox.hide_all()
558 self.login_button.set_label(self.LOGIN_BUTTON_LABEL)
559
560- logger.info('Calling generate_captcha with filename path at %r',
561- self._captcha_filename)
562- f = self.backend.generate_captcha
563- f(self.app_name, self._captcha_filename,
564- reply_handler=NO_OP, error_handler=NO_OP)
565-
566 return self.enter_details_vbox
567
568 def _build_tc_page(self):
569 """Build the Terms & Conditions page."""
570+ self.tc_browser_vbox.help_text = ''
571 return self.tc_browser_vbox
572
573 def _build_processing_page(self):
574@@ -503,13 +530,8 @@
575
576 def _build_verify_email_page(self):
577 """Build the verify email page."""
578- self.verify_email_vbox.help_text = self.VERIFY_EMAIL_LABEL
579 self.verify_email_vbox.pack_start(self.email_token_entry, expand=False)
580- self.verify_email_vbox.reorder_child(self.email_token_entry, 1)
581-
582- fname = get_data_file('email.png')
583- self._email_example_pixbuf = gtk.gdk.pixbuf_new_from_file(fname)
584- self.verify_email_image.set_from_pixbuf(self._email_example_pixbuf)
585+ self.verify_email_vbox.reorder_child(self.email_token_entry, 0)
586
587 return self.verify_email_vbox
588
589@@ -529,7 +551,7 @@
590 self.login_details_vbox.pack_start(self.login_email_entry)
591 self.login_details_vbox.reorder_child(self.login_email_entry, 0)
592 self.login_details_vbox.pack_start(self.login_password_entry)
593- self.login_details_vbox.reorder_child(self.login_password_entry, 2)
594+ self.login_details_vbox.reorder_child(self.login_password_entry, 1)
595
596 msg = self.FORGOTTEN_PASSWORD_BUTTON
597 self.forgotten_password_button.set_label(msg)
598@@ -540,7 +562,7 @@
599 def _build_request_password_token_page(self):
600 """Build the login page."""
601 self.request_password_token_vbox.header = self.RESET_PASSWORD
602- text = self.REQUEST_PASSWORD_TOKEN_LABEL
603+ text = self.REQUEST_PASSWORD_TOKEN_LABEL % {'app_name': self.app_label}
604 self.request_password_token_vbox.help_text = text
605
606 entry = self.reset_email_entry
607@@ -624,41 +646,40 @@
608
609 name = self.name_entry.get_text()
610 if not name:
611- self._set_warning_message(self.name_warning_label,
612- self.FIELD_REQUIRED)
613+ self.name_entry.set_warning(self.FIELD_REQUIRED)
614 error |= True
615
616 # check email
617 email1 = self.email1_entry.get_text()
618 email2 = self.email2_entry.get_text()
619 if email1 != email2:
620- self._set_warning_message(self.email_warning_label,
621- self.EMAIL_MISMATCH)
622+ self.email1_entry.set_warning(self.EMAIL_MISMATCH)
623+ self.email2_entry.set_warning(self.EMAIL_MISMATCH)
624 error |= True
625
626 if '@' not in email1:
627- self._set_warning_message(self.email_warning_label,
628- self.EMAIL_INVALID)
629+ self.email1_entry.set_warning(self.EMAIL_INVALID)
630+ self.email2_entry.set_warning(self.EMAIL_INVALID)
631 error |= True
632
633 if not email1:
634- self._set_warning_message(self.email_warning_label,
635- self.FIELD_REQUIRED)
636+ self.email1_entry.set_warning(self.FIELD_REQUIRED)
637+ self.email2_entry.set_warning(self.FIELD_REQUIRED)
638 error |= True
639
640 # check password
641 password1 = self.password1_entry.get_text()
642 password2 = self.password2_entry.get_text()
643 if password1 != password2:
644- self._set_warning_message(self.password_warning_label,
645- self.PASSWORD_MISMATCH)
646+ self.password1_entry.set_warning(self.PASSWORD_MISMATCH)
647+ self.password2_entry.set_warning(self.PASSWORD_MISMATCH)
648 error |= True
649
650 if (len(password1) < 8 or
651 re.search('[A-Z]', password1) is None or
652 re.search('\d+', password1) is None):
653- self._set_warning_message(self.password_warning_label,
654- self.PASSWORD_TOO_WEAK)
655+ self.password1_entry.set_warning(self.PASSWORD_TOO_WEAK)
656+ self.password2_entry.set_warning(self.PASSWORD_TOO_WEAK)
657 error |= True
658
659 # check T&C
660@@ -669,8 +690,7 @@
661
662 captcha_solution = self.captcha_solution_entry.get_text()
663 if not captcha_solution:
664- self._set_warning_message(self.captcha_solution_warning_label,
665- self.FIELD_REQUIRED)
666+ self.captcha_solution_entry.set_warning(self.FIELD_REQUIRED)
667 error |= True
668
669 if error:
670@@ -717,20 +737,17 @@
671 email = self.login_email_entry.get_text()
672
673 if '@' not in email:
674- self._set_warning_message(self.login_email_warning_label,
675- self.EMAIL_INVALID)
676+ self.login_email_entry.set_warning(self.EMAIL_INVALID)
677 error |= True
678
679 if not email:
680- self._set_warning_message(self.login_email_warning_label,
681- self.FIELD_REQUIRED)
682+ self.login_email_entry.set_warning(self.FIELD_REQUIRED)
683 error |= True
684
685 password = self.login_password_entry.get_text()
686
687 if not password:
688- self._set_warning_message(self.login_password_warning_label,
689- self.FIELD_REQUIRED)
690+ self.login_password_entry.set_warning(self.FIELD_REQUIRED)
691 error |= True
692
693 if error:
694@@ -813,6 +830,10 @@
695 browser.destroy()
696 del browser
697
698+ def on_captcha_reload_button_clicked(self, *args, **kwargs):
699+ """User clicked the reload captcha button."""
700+ self._generate_captcha()
701+
702 # backend callbacks
703
704 @log_call
705@@ -829,6 +850,9 @@
706 @log_call
707 def on_user_registered(self, app_name, email, *args, **kwargs):
708 """Registration can go on, user needs to verify email."""
709+ help_text = self.VERIFY_EMAIL_LABEL % {'app_name': self.app_name,
710+ 'email': email}
711+ self.verify_email_vbox.help_text = help_text
712 self._set_current_page(self.verify_email_vbox)
713
714 @log_call
715
716=== modified file 'ubuntu_sso/main.py'
717--- ubuntu_sso/main.py 2010-08-24 15:47:58 +0000
718+++ ubuntu_sso/main.py 2010-08-26 12:56:23 +0000
719@@ -44,7 +44,7 @@
720 from lazr.restfulclient.authorize.oauth import OAuthAuthorizer
721 from lazr.restfulclient.errors import HTTPError
722 from lazr.restfulclient.resource import ServiceRoot
723-from oauth.oauth import OAuthToken
724+from oauth import oauth
725
726 from ubuntu_sso import (DBUS_IFACE_AUTH_NAME, DBUS_IFACE_USER_NAME,
727 DBUS_IFACE_CRED_NAME, DBUS_CRED_PATH, DBUS_BUS_NAME, gui)
728@@ -59,7 +59,7 @@
729
730 OLD_KEY_NAME = "UbuntuOne token for https://ubuntuone.com"
731 U1_APP_NAME = "Ubuntu One"
732-PING_URL = "http://one.ubuntu.com/oauth/sso-finished-so-get-tokens/"
733+PING_URL = "http://edge.one.ubuntu.com/oauth/sso-finished-so-get-tokens/"
734
735
736 class NoDefaultConfigError(Exception):
737@@ -235,7 +235,7 @@
738 token = self.login(email=email, password=password,
739 token_name=token_name)
740
741- oauth_token = OAuthToken(token['token'], token['token_secret'])
742+ oauth_token = oauth.OAuthToken(token['token'], token['token_secret'])
743 authorizer = OAuthAuthorizer(token['consumer_key'],
744 token['consumer_secret'],
745 oauth_token)
746@@ -289,10 +289,18 @@
747
748 def except_to_errdict(e):
749 """Turn an exception into a dictionary to return thru DBus."""
750- return {
751- "errtype": type(e).__name__,
752- "message": "\n".join(str(arg) for arg in e.args),
753+ result = {
754+ "errtype": e.__class__.__name__,
755+ "errargs": repr(e.args),
756 }
757+ if len(e.args) == 0:
758+ result["message"] = e.__class__.__doc__
759+ elif isinstance(e.args[0], dict):
760+ result.update(e.args[0])
761+ elif isinstance(e.args[0], basestring):
762+ result["message"] = e.args[0]
763+
764+ return result
765
766
767 def blocking(f, app_name, result_cb, error_cb):
768@@ -302,7 +310,7 @@
769 try:
770 result_cb(app_name, f())
771 except Exception, e:
772- msg = "Exception while running DBus blocking code in a thread."""
773+ msg = "Exception while running DBus blocking code in a thread:"
774 logger.exception(msg)
775 error_cb(app_name, except_to_errdict(e))
776 threading.Thread(target=_in_thread).start()
777@@ -479,6 +487,7 @@
778 logger.info('Login successful for app %r, email %r', app_name, email)
779 try:
780 creds = keyring_get_credentials(app_name)
781+ self._ping_url(app_name, email, creds)
782 self.CredentialsFound(app_name, creds)
783 except Exception:
784 msg = "Problem getting the credentials from the keyring."
785@@ -495,10 +504,26 @@
786 """The user decides not to allow the registration or login."""
787 self.AuthorizationDenied(app_name)
788
789- def _ping_url(self, dialog, app_name, email):
790+ def _ping_url(self, app_name, email, credentials):
791 """Ping the given url."""
792+ logger.info('Maybe pinging url %s for app_name %r', PING_URL, app_name)
793 if app_name == U1_APP_NAME:
794- urllib2.urlopen(PING_URL + email)
795+ url = PING_URL + email
796+ consumer = oauth.OAuthConsumer(credentials['consumer_key'],
797+ credentials['consumer_secret'])
798+ token = oauth.OAuthToken(credentials['token'],
799+ credentials['token_secret'])
800+ get_request = oauth.OAuthRequest.from_consumer_and_token
801+ oauth_req = get_request(oauth_consumer=consumer, token=token,
802+ http_method="GET", http_url=url)
803+ oauth_req.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(),
804+ consumer, token)
805+ request = urllib2.Request(url, headers=oauth_req.to_header())
806+ logger.debug('Opening the ping url with urllib2.urlopen. ' \
807+ 'Request to: %s', request.get_full_url())
808+ response = urllib2.urlopen(request)
809+ logger.debug('Url opened. Response: %s.', response.code)
810+ return response.code
811
812 def _show_login_or_register_ui(self, app_name, tc_url, help_text,
813 win_id, login_only=False):
814@@ -507,11 +532,9 @@
815 gui_app = gui.UbuntuSSOClientGUI(app_name, tc_url,
816 help_text, win_id, login_only)
817 gui_app.connect(gui.SIG_LOGIN_SUCCEEDED, self._login_success_cb)
818- gui_app.connect(gui.SIG_LOGIN_SUCCEEDED, self._ping_url)
819 gui_app.connect(gui.SIG_LOGIN_FAILED, self._login_error_cb)
820 gui_app.connect(gui.SIG_REGISTRATION_SUCCEEDED,
821 self._login_success_cb)
822- gui_app.connect(gui.SIG_REGISTRATION_SUCCEEDED, self._ping_url)
823 gui_app.connect(gui.SIG_REGISTRATION_FAILED, self._login_error_cb)
824 gui_app.connect(gui.SIG_USER_CANCELATION,
825 self._login_auth_denied_cb)
826
827=== modified file 'ubuntu_sso/tests/test_gui.py'
828--- ubuntu_sso/tests/test_gui.py 2010-08-24 15:47:58 +0000
829+++ ubuntu_sso/tests/test_gui.py 2010-08-26 12:56:23 +0000
830@@ -262,6 +262,39 @@
831 self.entry.set_text('a')
832 self.assertEqual(self.entry.get_text(), 'a')
833
834+ def test_no_warning_by_default(self):
835+ """No secondary icon by default."""
836+ self.assertEqual(self.entry.warning, None)
837+ self.assertEqual(self.entry.get_property('secondary-icon-stock'),
838+ None)
839+ self.assertEqual(self.entry.get_property('secondary-icon-sensitive'),
840+ False)
841+ prop = self.entry.get_property('secondary-icon-tooltip-text')
842+ self.assertEqual(prop, None)
843+
844+ def test_set_warning(self):
845+ """Setting a warning show the proper secondary icon."""
846+ msg = 'You failed!'
847+ self.entry.set_warning(msg)
848+ self.assertEqual(self.entry.warning, msg)
849+ self.assertEqual(self.entry.get_property('secondary-icon-stock'),
850+ gtk.STOCK_DIALOG_WARNING)
851+ self.assertEqual(self.entry.get_property('secondary-icon-sensitive'),
852+ True)
853+ prop = self.entry.get_property('secondary-icon-tooltip-text')
854+ self.assertEqual(prop, msg)
855+
856+ def test_clear_warning(self):
857+ """Clearing a warning no longer show the secondary icon."""
858+ self.entry.clear_warning()
859+ self.assertEqual(self.entry.warning, None)
860+ self.assertEqual(self.entry.get_property('secondary-icon-stock'),
861+ None)
862+ self.assertEqual(self.entry.get_property('secondary-icon-sensitive'),
863+ False)
864+ prop = self.entry.get_property('secondary-icon-tooltip-text')
865+ self.assertEqual(prop, None)
866+
867
868 class PasswordLabeledEntryTestCase(LabeledEntryTestCase):
869 """Test suite for the labeled entry when is_password is True."""
870@@ -331,7 +364,7 @@
871 self.assertEqual(visible, widget.get_property('visible'),
872 msg % (name, '' if visible else 'not '))
873
874- def assert_correct_warning(self, label, message):
875+ def assert_correct_label_warning(self, label, message):
876 """Check that a warning is shown displaying 'message'."""
877 # warning label is visible
878 self.assertTrue(label.get_property('visible'))
879@@ -345,6 +378,10 @@
880 actual = label.style.fg[gtk.STATE_NORMAL]
881 self.assertEqual(expected, actual) # until realized this will fail
882
883+ def assert_correct_entry_warning(self, entry, message):
884+ """Check that a warning is shown displaying 'message'."""
885+ self.assertEqual(entry.warning, message)
886+
887 def assert_pages_visibility(self, **kwargs):
888 """The pages has the correct visibility."""
889 for i in self.pages:
890@@ -418,6 +455,10 @@
891 """The main window is shown at startup."""
892 self.assertTrue(self.ui.window.get_property('visible'))
893
894+ def test_main_window_is_not_resizable(self):
895+ """The main window can not be resized."""
896+ self.assertFalse(self.ui.window.get_property('resizable'))
897+
898 def test_closing_main_window_calls_close_callback(self):
899 """The close_callback is called when closing the main window."""
900 self.ui.close_callback = self._set_called
901@@ -711,15 +752,47 @@
902 self.assertTrue(self.ui.captcha_image.get_property('visible'))
903 self.assertEqual(self._called, ((self.ui._captcha_filename,), {}))
904
905+ def test_captcha_reload_button_visible(self):
906+ """The captcha reload button is initially visible."""
907+ self.assertTrue(self.ui.captcha_reload_button.get_visible(),
908+ "The captcha button is not visible")
909+
910+ def test_captcha_reload_button_reloads_captcha(self):
911+ """The captcha reload button loads a new captcha."""
912+ self.ui.on_captcha_generated(app_name=APP_NAME, captcha_id=CAPTCHA_ID)
913+ self.patch(self.ui, '_generate_captcha', self._set_called)
914+ self.ui.captcha_reload_button.clicked()
915+ self.assertEqual(self._called, ((), {}))
916+
917+ def test_captcha_reload_button_has_tooltip(self):
918+ """The captcha reload button has a tooltip."""
919+ self.assertEqual(self.ui.captcha_reload_button.get_tooltip_text(),
920+ self.ui.CAPTCHA_RELOAD_TOOLTIP)
921+
922 def test_login_button_has_correct_wording(self):
923 """The sign in button has the proper wording."""
924 actual = self.ui.login_button.get_label()
925 self.assertEqual(self.ui.LOGIN_BUTTON_LABEL, actual)
926
927
928+class NoTermsAndConditionsTestCase(UbuntuSSOClientTestCase):
929+ """Test suite for the user registration (with no t&c link)."""
930+
931+ kwargs = dict(app_name=APP_NAME, tc_uri='', help_text=HELP_TEXT)
932+
933+ def test_no_tc_link(self):
934+ """The T&C button and checkbox are not shown if no link is provided"""
935+ self.assertEqual(self.ui.tc_hbox.get_visible(), False)
936+
937+
938 class TermsAndConditionsTestCase(UbuntuSSOClientTestCase):
939 """Test suite for the user registration (terms & conditions page)."""
940
941+ def test_has_tc_link(self):
942+ """The T&C button and checkbox are shown if the link is provided"""
943+ self.assertEqual(self.ui.tc_button.get_visible(), True)
944+ self.assertEqual(self.ui.yes_to_tc_checkbutton.get_visible(), True)
945+
946 def test_tc_browser_is_created_when_tc_page_is_shown(self):
947 """The webkit browser is created when the TC page is shown."""
948 self.ui.tc_browser_vbox.show()
949@@ -758,6 +831,11 @@
950 """Terms & Conditions has the proper wording."""
951 self.assertEqual(self.ui.tc_button.get_label(), self.ui.TC)
952
953+ def test_tc_has_no_help_text(self):
954+ """The help text is removed."""
955+ self.ui.tc_button.clicked()
956+ self.assertEqual('', self.ui.help_label.get_text())
957+
958 def test_tc_browser_opens_the_proper_uri(self):
959 """Terms & Conditions browser shows the proper uri."""
960 self.ui.tc_button.clicked()
961@@ -780,8 +858,8 @@
962
963 def test_warning_label_is_shown(self):
964 """On UserRegistrationError the warning label is shown."""
965- self.assert_correct_warning(self.ui.warning_label,
966- self.ui.UNKNOWN_ERROR)
967+ self.assert_correct_label_warning(self.ui.warning_label,
968+ self.ui.UNKNOWN_ERROR)
969
970
971 class VerifyEmailTestCase(UbuntuSSOClientTestCase):
972@@ -793,12 +871,6 @@
973 self.ui.on_user_registered(app_name=APP_NAME, email=EMAIL)
974 self.click_verify_email_with_valid_data()
975
976- def test_verify_email_image_is_correct(self):
977- """The email-example image is shown."""
978- pixbuf = self.ui.verify_email_image.get_pixbuf()
979- self.assertTrue(pixbuf is not None)
980- self.assertEqual(self.ui._email_example_pixbuf, pixbuf)
981-
982 def test_registration_successful_shows_verify_email_vbox(self):
983 """Receiving 'registration_successful' shows the verify email vbox."""
984 self.ui.on_user_registered(app_name=APP_NAME, email=EMAIL)
985@@ -807,8 +879,9 @@
986 def test_help_label_display_correct_wording(self):
987 """The help_label display VERIFY_EMAIL_LABEL."""
988 msg = 'help_label must read "%s" (got "%s" instead).'
989- actual = self.ui.help_label.get_text()
990- expected = self.ui.VERIFY_EMAIL_LABEL
991+ actual = self.ui.help_label.get_label()
992+ expected = self.ui.VERIFY_EMAIL_LABEL % {'app_name': APP_NAME,
993+ 'email': EMAIL}
994 self.assertEqual(expected, actual, msg % (expected, actual))
995
996 def test_on_verify_token_button_clicked_calls_validate_email(self):
997@@ -847,8 +920,8 @@
998 """On email validation error, the verify_email page is shown."""
999 self.ui.on_email_validation_error(app_name=APP_NAME, error=ERROR)
1000 self.assert_pages_visibility(verify_email=True)
1001- self.assert_correct_warning(self.ui.warning_label,
1002- self.ui.UNKNOWN_ERROR)
1003+ self.assert_correct_label_warning(self.ui.warning_label,
1004+ self.ui.UNKNOWN_ERROR)
1005
1006 def test_success_label_is_correct(self):
1007 """The success message is correct."""
1008@@ -871,8 +944,8 @@
1009
1010 self.ui.join_ok_button.clicked() # submit form
1011
1012- self.assert_correct_warning(self.ui.name_warning_label,
1013- self.ui.FIELD_REQUIRED)
1014+ self.assert_correct_entry_warning(self.ui.name_entry,
1015+ self.ui.FIELD_REQUIRED)
1016 self.assertNotIn('register_user', self.ui.backend._called)
1017
1018 def test_warning_is_shown_if_empty_email(self):
1019@@ -882,8 +955,10 @@
1020
1021 self.ui.join_ok_button.clicked() # submit form
1022
1023- self.assert_correct_warning(self.ui.email_warning_label,
1024- self.ui.FIELD_REQUIRED)
1025+ self.assert_correct_entry_warning(self.ui.email1_entry,
1026+ self.ui.FIELD_REQUIRED)
1027+ self.assert_correct_entry_warning(self.ui.email2_entry,
1028+ self.ui.FIELD_REQUIRED)
1029 self.assertNotIn('register_user', self.ui.backend._called)
1030
1031 def test_warning_is_shown_if_email_mismatch(self):
1032@@ -893,8 +968,10 @@
1033
1034 self.ui.join_ok_button.clicked() # submit form
1035
1036- self.assert_correct_warning(self.ui.email_warning_label,
1037- self.ui.EMAIL_MISMATCH)
1038+ self.assert_correct_entry_warning(self.ui.email1_entry,
1039+ self.ui.EMAIL_MISMATCH)
1040+ self.assert_correct_entry_warning(self.ui.email2_entry,
1041+ self.ui.EMAIL_MISMATCH)
1042 self.assertNotIn('register_user', self.ui.backend._called)
1043
1044 def test_warning_is_shown_if_invalid_email(self):
1045@@ -904,8 +981,10 @@
1046
1047 self.ui.join_ok_button.clicked() # submit form
1048
1049- self.assert_correct_warning(self.ui.email_warning_label,
1050- self.ui.EMAIL_INVALID)
1051+ self.assert_correct_entry_warning(self.ui.email1_entry,
1052+ self.ui.EMAIL_INVALID)
1053+ self.assert_correct_entry_warning(self.ui.email2_entry,
1054+ self.ui.EMAIL_INVALID)
1055 self.assertNotIn('register_user', self.ui.backend._called)
1056
1057 def test_password_help_is_always_shown(self):
1058@@ -923,8 +1002,10 @@
1059
1060 self.ui.join_ok_button.clicked() # submit form
1061
1062- self.assert_correct_warning(self.ui.password_warning_label,
1063- self.ui.PASSWORD_MISMATCH)
1064+ self.assert_correct_entry_warning(self.ui.password1_entry,
1065+ self.ui.PASSWORD_MISMATCH)
1066+ self.assert_correct_entry_warning(self.ui.password2_entry,
1067+ self.ui.PASSWORD_MISMATCH)
1068 self.assertNotIn('register_user', self.ui.backend._called)
1069
1070 def test_warning_is_shown_if_password_too_weak(self):
1071@@ -936,8 +1017,10 @@
1072
1073 self.ui.join_ok_button.clicked() # submit form
1074
1075- self.assert_correct_warning(self.ui.password_warning_label,
1076- self.ui.PASSWORD_TOO_WEAK)
1077+ self.assert_correct_entry_warning(self.ui.password1_entry,
1078+ self.ui.PASSWORD_TOO_WEAK)
1079+ self.assert_correct_entry_warning(self.ui.password2_entry,
1080+ self.ui.PASSWORD_TOO_WEAK)
1081 self.assertNotIn('register_user', self.ui.backend._called)
1082
1083 def test_warning_is_shown_if_tc_not_accepted(self):
1084@@ -947,8 +1030,8 @@
1085
1086 self.ui.join_ok_button.clicked() # submit form
1087
1088- self.assert_correct_warning(self.ui.tc_warning_label,
1089- self.ui.TC_NOT_ACCEPTED)
1090+ self.assert_correct_label_warning(self.ui.tc_warning_label,
1091+ self.ui.TC_NOT_ACCEPTED)
1092 self.assertNotIn('register_user', self.ui.backend._called)
1093
1094 def test_warning_is_shown_if_not_captcha_solution(self):
1095@@ -958,8 +1041,8 @@
1096
1097 self.ui.join_ok_button.clicked() # submit form
1098
1099- self.assert_correct_warning(self.ui.captcha_solution_warning_label,
1100- self.ui.FIELD_REQUIRED)
1101+ self.assert_correct_entry_warning(self.ui.captcha_solution_entry,
1102+ self.ui.FIELD_REQUIRED)
1103 self.assertNotIn('register_user', self.ui.backend._called)
1104
1105 def test_no_warning_messages_if_valid_data_on_enter_details(self):
1106@@ -1060,8 +1143,8 @@
1107 """On user login error, a warning is shown with proper wording."""
1108 self.click_connect_with_valid_data()
1109 self.ui.on_login_error(app_name=APP_NAME, error=ERROR)
1110- self.assert_correct_warning(self.ui.warning_label,
1111- self.ui.UNKNOWN_ERROR)
1112+ self.assert_correct_label_warning(self.ui.warning_label,
1113+ self.ui.UNKNOWN_ERROR)
1114
1115 def test_back_to_registration_hides_warning(self):
1116 """After user login error, warning is hidden when clicking 'Back'."""
1117@@ -1085,8 +1168,8 @@
1118
1119 self.ui.login_ok_button.clicked() # submit form
1120
1121- self.assert_correct_warning(self.ui.login_email_warning_label,
1122- self.ui.FIELD_REQUIRED)
1123+ self.assert_correct_entry_warning(self.ui.login_email_entry,
1124+ self.ui.FIELD_REQUIRED)
1125 self.assertNotIn('login', self.ui.backend._called)
1126
1127 def test_warning_is_shown_if_invalid_email(self):
1128@@ -1095,8 +1178,8 @@
1129
1130 self.ui.login_ok_button.clicked() # submit form
1131
1132- self.assert_correct_warning(self.ui.login_email_warning_label,
1133- self.ui.EMAIL_INVALID)
1134+ self.assert_correct_entry_warning(self.ui.login_email_entry,
1135+ self.ui.EMAIL_INVALID)
1136 self.assertNotIn('login', self.ui.backend._called)
1137
1138 def test_warning_is_shown_if_empty_password(self):
1139@@ -1105,8 +1188,8 @@
1140
1141 self.ui.login_ok_button.clicked() # submit form
1142
1143- self.assert_correct_warning(self.ui.login_password_warning_label,
1144- self.ui.FIELD_REQUIRED)
1145+ self.assert_correct_entry_warning(self.ui.login_password_entry,
1146+ self.ui.FIELD_REQUIRED)
1147 self.assertNotIn('login', self.ui.backend._called)
1148
1149 def test_no_warning_messages_if_valid_data(self):
1150@@ -1143,8 +1226,8 @@
1151
1152 def test_on_forgotten_password_button_clicked_help_text(self):
1153 """Clicking forgotten_password_button the help is properly changed."""
1154- self.assertEqual(self.ui.help_label.get_text(),
1155- self.ui.REQUEST_PASSWORD_TOKEN_LABEL)
1156+ wanted = self.ui.REQUEST_PASSWORD_TOKEN_LABEL % {'app_name': APP_NAME}
1157+ self.assertEqual(self.ui.help_label.get_text(), wanted)
1158
1159 def test_on_forgotten_password_button_clicked_header_label(self):
1160 """Clicking forgotten_password_button the title is properly changed."""
1161@@ -1219,8 +1302,8 @@
1162 def test_on_password_reset_error_shows_login_page(self):
1163 """When reset token wasn't successfuly sent the login page is shown."""
1164 self.ui.on_password_reset_error(app_name=APP_NAME, error=ERROR)
1165- self.assert_correct_warning(self.ui.warning_label,
1166- self.ui.UNKNOWN_ERROR)
1167+ self.assert_correct_label_warning(self.ui.warning_label,
1168+ self.ui.UNKNOWN_ERROR)
1169 self.assert_pages_visibility(login=True)
1170
1171
1172@@ -1269,15 +1352,15 @@
1173 def test_on_password_changed_shows_success_page(self):
1174 """When password was successfuly changed the success page is shown."""
1175 self.ui.on_password_changed(app_name=APP_NAME, email=EMAIL)
1176- self.assert_correct_warning(self.ui.warning_label,
1177- self.ui.PASSWORD_CHANGED)
1178+ self.assert_correct_label_warning(self.ui.warning_label,
1179+ self.ui.PASSWORD_CHANGED)
1180 self.assert_pages_visibility(login=True)
1181
1182 def test_on_password_change_error_shows_login_page(self):
1183 """When password wasn't changed the reset password page is shown."""
1184 self.ui.on_password_change_error(app_name=APP_NAME, error=ERROR)
1185- self.assert_correct_warning(self.ui.warning_label,
1186- self.ui.UNKNOWN_ERROR)
1187+ self.assert_correct_label_warning(self.ui.warning_label,
1188+ self.ui.UNKNOWN_ERROR)
1189 self.assert_pages_visibility(request_password_token=True)
1190
1191
1192
1193=== modified file 'ubuntu_sso/tests/test_main.py'
1194--- ubuntu_sso/tests/test_main.py 2010-08-24 15:47:58 +0000
1195+++ ubuntu_sso/tests/test_main.py 2010-08-26 12:56:23 +0000
1196@@ -61,7 +61,7 @@
1197 RESET_PASSWORD_TOKEN = '8G5Wtq'
1198 TOKEN = {u'consumer_key': u'xQ7xDAz',
1199 u'consumer_secret': u'KzCJWCTNbbntwfyCKKjomJDzlgqxLy',
1200- u'name': u'test',
1201+ u'token_name': u'test',
1202 u'token': u'GkInOfSMGwTXAUoVQwLUoPxElEEUdhsLVNTPhxHJDUIeHCPNEo',
1203 u'token_secret': u'qFYImEtlczPbsCnYyuwLoPDlPEnvNcIktZphPQklAWrvyfFMV'}
1204 TOKEN_NAME = get_token_name(APP_NAME)
1205@@ -81,6 +81,14 @@
1206 LOGIN_ONLY_GUI_ARGS = (APP_NAME, None, HELP, WINDOW_ID, True)
1207
1208
1209+class FakedResponse(object):
1210+ """Fake a urlopen response."""
1211+
1212+ def __init__(self, *args, **kwargs):
1213+ for k, v in kwargs.iteritems():
1214+ setattr(self, k, v)
1215+
1216+
1217 class FakedCaptchas(object):
1218 """Fake the captcha generator."""
1219
1220@@ -735,6 +743,60 @@
1221 return d
1222
1223
1224+class TestExceptToErrdictException(Exception):
1225+ """A dummy exception for the following testcase."""
1226+
1227+
1228+class ExceptToErrdictTestCase(TestCase):
1229+ """Tests for the except_to_errdict function."""
1230+
1231+ def test_first_arg_is_dict(self):
1232+ """If the first arg is a dict, use it as the base dict."""
1233+ sample_dict = {
1234+ "errorcode1": "error message 1",
1235+ "errorcode2": "error message 2",
1236+ "errorcode3": "error message 3",
1237+ }
1238+ e = TestExceptToErrdictException(sample_dict)
1239+ result = except_to_errdict(e)
1240+
1241+ self.assertEqual(result["errtype"], e.__class__.__name__)
1242+ for k in sample_dict.keys():
1243+ self.assertIn(k, result)
1244+ self.assertEqual(result[k], sample_dict[k])
1245+
1246+ def test_first_arg_is_str(self):
1247+ """If the first arg is a str, use it as the message."""
1248+ sample_string = "a sample string"
1249+ e = TestExceptToErrdictException(sample_string)
1250+ result = except_to_errdict(e)
1251+ self.assertEqual(result["errtype"], e.__class__.__name__)
1252+ self.assertEqual(result["message"], sample_string)
1253+
1254+ def test_first_arg_is_unicode(self):
1255+ """If the first arg is a unicode, use it as the message."""
1256+ sample_string = u"a sample string"
1257+ e = TestExceptToErrdictException(sample_string)
1258+ result = except_to_errdict(e)
1259+ self.assertEqual(result["errtype"], e.__class__.__name__)
1260+ self.assertEqual(result["message"], sample_string)
1261+
1262+ def test_no_args_at_all(self):
1263+ """If there are no args, use the class docstring."""
1264+ e = TestExceptToErrdictException()
1265+ result = except_to_errdict(e)
1266+ self.assertEqual(result["errtype"], e.__class__.__name__)
1267+ self.assertEqual(result["message"], e.__class__.__doc__)
1268+
1269+ def test_some_other_thing_as_first_arg(self):
1270+ """If first arg is not basestring nor dict, then repr all args."""
1271+ sample_args = (None, u"unicode2\ufffd", "errorcode3")
1272+ e = TestExceptToErrdictException(*sample_args)
1273+ result = except_to_errdict(e)
1274+ self.assertEqual(result["errtype"], e.__class__.__name__)
1275+ self.assertEqual(result["errargs"], repr(sample_args))
1276+
1277+
1278 class KeyringCredentialsTestCase(MockerTestCase):
1279 """Checks the functions that access the keyring."""
1280
1281@@ -1163,10 +1225,8 @@
1282
1283 expected = [
1284 (gui.SIG_LOGIN_SUCCEEDED, self.client._login_success_cb),
1285- (gui.SIG_LOGIN_SUCCEEDED, self.client._ping_url),
1286 (gui.SIG_LOGIN_FAILED, self.client._login_error_cb),
1287 (gui.SIG_REGISTRATION_SUCCEEDED, self.client._login_success_cb),
1288- (gui.SIG_REGISTRATION_SUCCEEDED, self.client._ping_url),
1289 (gui.SIG_REGISTRATION_FAILED, self.client._login_error_cb),
1290 (gui.SIG_USER_CANCELATION, self.client._login_auth_denied_cb),
1291 ]
1292@@ -1225,10 +1285,8 @@
1293
1294 expected = [
1295 (gui.SIG_LOGIN_SUCCEEDED, self.client._login_success_cb),
1296- (gui.SIG_LOGIN_SUCCEEDED, self.client._ping_url),
1297 (gui.SIG_LOGIN_FAILED, self.client._login_error_cb),
1298 (gui.SIG_REGISTRATION_SUCCEEDED, self.client._login_success_cb),
1299- (gui.SIG_REGISTRATION_SUCCEEDED, self.client._ping_url),
1300 (gui.SIG_REGISTRATION_FAILED, self.client._login_error_cb),
1301 (gui.SIG_USER_CANCELATION, self.client._login_auth_denied_cb),
1302 ]
1303@@ -1236,36 +1294,95 @@
1304 self.login_only(*LOGIN_ONLY_ARGS)
1305 self.assertEqual(self.signals, expected)
1306
1307+
1308+class PingServerTestCase(TestCase):
1309+ """On successful login/registration, the U1 server is pinged."""
1310+
1311+ def setUp(self):
1312+ """Init."""
1313+ self.patch(ubuntu_sso.main, 'keyring_get_credentials', lambda a: TOKEN)
1314+ self.calls = []
1315+ self.args = None
1316+ self.kwargs = None
1317+
1318+ def fake_it(*args, **kwargs):
1319+ """Fake a call."""
1320+ self.args = args
1321+ self.kwargs = kwargs
1322+ return FakedResponse(code=200)
1323+
1324+ self.patch(urllib2, 'urlopen', fake_it)
1325+
1326+ self.client = SSOCredentials(None)
1327+
1328+ self.memento = MementoHandler()
1329+ self.memento.setLevel(logging.DEBUG)
1330+ logger.addHandler(self.memento)
1331+
1332+ def _patch(self, name):
1333+ """Patch a method so when it's called its name is stored."""
1334+ self.patch(self.client, name,
1335+ lambda *a, **kw: self.calls.append((name, a, kw)))
1336+
1337 def test_on_registration_successful_u1_server_is_pinged(self):
1338 """When a registration is successful, the PING_URL is pinged."""
1339- self.args = None
1340- self.kwargs = None
1341-
1342- def fake_it(*args, **kwargs):
1343- """Fake a call."""
1344- self.args = args
1345- self.kwargs = kwargs
1346-
1347- self.patch(urllib2, 'urlopen', fake_it)
1348-
1349- self.client._ping_url(None, U1_APP_NAME, EMAIL)
1350-
1351- self.assertEqual(self.args, (PING_URL + EMAIL,))
1352+ self.client._login_success_cb(None, U1_APP_NAME, EMAIL)
1353+
1354+ self.assertEqual(len(self.args), 1)
1355+ self.assertEqual(self.args[0].get_full_url(), PING_URL + EMAIL)
1356 self.assertEqual(self.kwargs, {})
1357
1358 def test_on_registration_successful_no_server_is_pinged(self):
1359 """When a registration is successful, the PING_URL is not pinged."""
1360- self.args = None
1361- self.kwargs = None
1362-
1363- def fake_it(*args, **kwargs):
1364- """Fake a call."""
1365- self.args = args
1366- self.kwargs = kwargs
1367-
1368- self.patch(urllib2, 'urlopen', fake_it)
1369-
1370- self.client._ping_url(None, APP_NAME, EMAIL)
1371+ self.client._login_success_cb(None, APP_NAME, EMAIL)
1372
1373 self.assertEqual(self.args, None)
1374 self.assertEqual(self.kwargs, None)
1375+
1376+ def test_ping_is_signed_with_credentials(self):
1377+ """Ping to PING_URL is signed with user credentials."""
1378+ result = self.client._ping_url(U1_APP_NAME, EMAIL, TOKEN)
1379+ headers = self.args[0].headers
1380+ self.assertIn('Authorization', headers)
1381+ oauth_stuff = headers['Authorization']
1382+
1383+ expected = 'oauth_consumer_key="xQ7xDAz", ' \
1384+ 'oauth_signature_method="HMAC-SHA1", oauth_version="1.0", ' \
1385+ 'oauth_token="GkInOfSMGwTXAUoVQwLUoPxElEEUdhsLVNTPhxHJDUIeHCPNEo' \
1386+ '", oauth_signature="'
1387+ self.assertIn(expected, oauth_stuff)
1388+ self.assertEqual(result, 200)
1389+
1390+ def test_ping_is_done_before_sending_signal(self):
1391+ """Ping the server before sending any credential signal."""
1392+ self._patch('_ping_url')
1393+ self._patch('CredentialsFound')
1394+ self._patch('CredentialsError')
1395+ self._patch('AuthorizationDenied')
1396+
1397+ self.client._login_success_cb(None, APP_NAME, EMAIL)
1398+
1399+ self.assertEqual(len(self.calls), 2)
1400+ self.assertEqual(self.calls[0], ('_ping_url',
1401+ (APP_NAME, EMAIL, TOKEN), {}))
1402+ self.assertEqual(self.calls[1], ('CredentialsFound',
1403+ (APP_NAME, TOKEN), {}))
1404+
1405+ def test_send_error_if_ping_failed(self):
1406+ """Ping the server before sending any credential signal."""
1407+ self.expected = None
1408+
1409+ def fail(*args, **kwargs):
1410+ self.expected = AssertionError((args, kwargs))
1411+ raise self.expected
1412+
1413+ self.patch(self.client, '_ping_url', fail)
1414+ self._patch('CredentialsFound')
1415+ self._patch('CredentialsError')
1416+ self._patch('AuthorizationDenied')
1417+
1418+ self.client._login_success_cb(None, APP_NAME, EMAIL)
1419+
1420+ self.assertEqual(len(self.calls), 1)
1421+ self.assertEqual(self.calls[0][0], 'CredentialsError')
1422+ self.assertEqual(self.calls[0][1][0], APP_NAME)

Subscribers

People subscribed via source and target branches

to all changes: