Merge lp:~nataliabidart/ubuntu/maverick/ubuntu-sso-client/ubuntu-sso-client-0.99.4 into lp:ubuntu/maverick/ubuntu-sso-client
- Maverick (10.10)
- ubuntu-sso-client-0.99.4
- Merge into maverick
Proposed by
Natalia Bidart
on 2010-08-27
| Status: | Merged |
|---|---|
| Merged at revision: | 11 |
| Proposed branch: | lp:~nataliabidart/ubuntu/maverick/ubuntu-sso-client/ubuntu-sso-client-0.99.4 |
| Merge into: | lp:ubuntu/maverick/ubuntu-sso-client |
| Diff against target: |
2354 lines (+1021/-331) 10 files modified
PKG-INFO (+1/-1) data/ui.glade (+38/-22) debian/changelog (+43/-0) setup.py (+4/-3) ubuntu_sso/gui.py (+183/-80) ubuntu_sso/keyring.py (+89/-38) ubuntu_sso/main.py (+22/-35) ubuntu_sso/tests/test_gui.py (+447/-50) ubuntu_sso/tests/test_keyring.py (+125/-29) ubuntu_sso/tests/test_main.py (+69/-73) |
| To merge this branch: | bzr merge lp:~nataliabidart/ubuntu/maverick/ubuntu-sso-client/ubuntu-sso-client-0.99.4 |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Ubuntu Development Team | 2010-08-27 | Pending | |
|
Review via email:
|
|||
Commit Message
Description of the Change
High priority bug fixes after UI freeze (v0.99.4).
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-08-26 01:07:41 +0000 |
| 3 | +++ PKG-INFO 2010-08-27 22:32:43 +0000 |
| 4 | @@ -1,6 +1,6 @@ |
| 5 | Metadata-Version: 1.1 |
| 6 | Name: ubuntu-sso-client |
| 7 | -Version: 0.99.3 |
| 8 | +Version: 0.99.4 |
| 9 | Summary: Ubuntu Single Sign-On client |
| 10 | Home-page: https://launchpad.net/ubuntu-sso-client |
| 11 | Author: Natalia Bidart |
| 12 | |
| 13 | === modified file 'data/ui.glade' |
| 14 | --- data/ui.glade 2010-08-26 01:07:41 +0000 |
| 15 | +++ data/ui.glade 2010-08-27 22:32:43 +0000 |
| 16 | @@ -60,6 +60,12 @@ |
| 17 | <property name="visible">True</property> |
| 18 | <property name="spacing">10</property> |
| 19 | <child> |
| 20 | + <placeholder/> |
| 21 | + </child> |
| 22 | + <child> |
| 23 | + <placeholder/> |
| 24 | + </child> |
| 25 | + <child> |
| 26 | <object class="GtkHBox" id="emails_hbox"> |
| 27 | <property name="visible">True</property> |
| 28 | <property name="spacing">5</property> |
| 29 | @@ -77,9 +83,6 @@ |
| 30 | </packing> |
| 31 | </child> |
| 32 | <child> |
| 33 | - <placeholder/> |
| 34 | - </child> |
| 35 | - <child> |
| 36 | <object class="GtkHBox" id="passwords_hbox"> |
| 37 | <property name="visible">True</property> |
| 38 | <property name="spacing">5</property> |
| 39 | @@ -107,9 +110,6 @@ |
| 40 | </packing> |
| 41 | </child> |
| 42 | <child> |
| 43 | - <placeholder/> |
| 44 | - </child> |
| 45 | - <child> |
| 46 | <object class="GtkHBox" id="hbox1"> |
| 47 | <property name="visible">True</property> |
| 48 | <child> |
| 49 | @@ -585,27 +585,43 @@ |
| 50 | <property name="visible">True</property> |
| 51 | <property name="spacing">10</property> |
| 52 | <child> |
| 53 | - <object class="GtkAlignment" id="alignment1"> |
| 54 | + <object class="GtkVBox" id="vbox2"> |
| 55 | <property name="visible">True</property> |
| 56 | - <property name="xscale">0</property> |
| 57 | - <property name="yscale">0</property> |
| 58 | - <child> |
| 59 | - <object class="GtkVBox" id="set_new_password_details_vbox"> |
| 60 | - <property name="visible">True</property> |
| 61 | - <property name="spacing">5</property> |
| 62 | - <child> |
| 63 | - <placeholder/> |
| 64 | - </child> |
| 65 | - <child> |
| 66 | - <placeholder/> |
| 67 | - </child> |
| 68 | - <child> |
| 69 | - <placeholder/> |
| 70 | - </child> |
| 71 | + <child> |
| 72 | + <object class="GtkAlignment" id="alignment1"> |
| 73 | + <property name="visible">True</property> |
| 74 | + <property name="xscale">0</property> |
| 75 | + <property name="yscale">0</property> |
| 76 | + <child> |
| 77 | + <object class="GtkVBox" id="set_new_password_details_vbox"> |
| 78 | + <property name="visible">True</property> |
| 79 | + <property name="spacing">5</property> |
| 80 | + <child> |
| 81 | + <placeholder/> |
| 82 | + </child> |
| 83 | + <child> |
| 84 | + <placeholder/> |
| 85 | + </child> |
| 86 | + <child> |
| 87 | + <placeholder/> |
| 88 | + </child> |
| 89 | + </object> |
| 90 | + </child> |
| 91 | + </object> |
| 92 | + <packing> |
| 93 | + <property name="position">0</property> |
| 94 | + </packing> |
| 95 | + </child> |
| 96 | + <child> |
| 97 | + <object class="GtkLabel" id="reset_password_help_label"> |
| 98 | + <property name="visible">True</property> |
| 99 | + <property name="label" translatable="yes">label</property> |
| 100 | + <property name="wrap">True</property> |
| 101 | </object> |
| 102 | </child> |
| 103 | </object> |
| 104 | <packing> |
| 105 | + <property name="padding">5</property> |
| 106 | <property name="position">0</property> |
| 107 | </packing> |
| 108 | </child> |
| 109 | |
| 110 | === modified file 'debian/changelog' |
| 111 | --- debian/changelog 2010-08-26 13:05:03 +0000 |
| 112 | +++ debian/changelog 2010-08-27 22:32:43 +0000 |
| 113 | @@ -1,3 +1,46 @@ |
| 114 | +ubuntu-sso-client (0.99.4-0ubuntu1) UNRELEASED; urgency=low |
| 115 | + |
| 116 | + * New upstream release: |
| 117 | + |
| 118 | + [ natalia.bidart@canonical.com ] |
| 119 | + * Validate form data for verify token page, request password token and set |
| 120 | + new password (LP: #625361). |
| 121 | + * Validate password strength on reset password page (LP: #616528). |
| 122 | + * Labels are not as wide as the parent windowm but a little bit less wide |
| 123 | + (LP: #625009). |
| 124 | + |
| 125 | + [ Alejandro J. Cura <alecu@canonical.com> ] |
| 126 | + * Store the credentials after the email validation step (LP: #625003) |
| 127 | + |
| 128 | + [ natalia.bidart@canonical.com |
| 129 | + * Every form can be submitted by activating the buttons and/or the entries |
| 130 | + (LP: #616421). |
| 131 | + |
| 132 | + [ David Planella <david.planella@ubuntu.com> ] |
| 133 | + * Make setup.py actually use python-distutils-extra, which will allow the |
| 134 | + .deb package to build the POT file required to import translations into |
| 135 | + Launchpad (LP: #624891). |
| 136 | + |
| 137 | + [ natalia.bidart@canonical.com ] |
| 138 | + * Errors from SSO servers are being shown now to users, matching |
| 139 | + error-specific to fields (LP: #616101). |
| 140 | + * Also, be robust when SSO server answer with a string where it's supposed |
| 141 | + to be a list (LP: #623447). |
| 142 | + |
| 143 | + [ Alejandro J. Cura <alecu@canonical.com> ] |
| 144 | + * Use the keyring unlocking gnomekeyring APIs (LP: #623622) |
| 145 | + * Search all keyrings for the credentials (LP: #624033) |
| 146 | + |
| 147 | + [ natalia.bidart@canonical.com ] |
| 148 | + * Customize "help_text" for the login only dialog (LP: #624097). |
| 149 | + * Label areas are as wide as the parent window (LP: #616551). |
| 150 | + |
| 151 | + [ Alejandro J. Cura <alecu@canonical.com> ] |
| 152 | + * The list of error strings as returned by the SSO webservice can't go thru |
| 153 | + DBus (LP: #624358). |
| 154 | + |
| 155 | + -- Natalia Bidart (nessita) <nataliabidart@gmail.com> Fri, 27 Aug 2010 19:16:55 -0300 |
| 156 | + |
| 157 | ubuntu-sso-client (0.99.3-0ubuntu1) maverick; urgency=low |
| 158 | |
| 159 | * New upstream release: |
| 160 | |
| 161 | === modified file 'setup.py' |
| 162 | --- setup.py 2010-08-26 01:07:41 +0000 |
| 163 | +++ setup.py 2010-08-27 22:32:43 +0000 |
| 164 | @@ -21,6 +21,7 @@ |
| 165 | |
| 166 | try: |
| 167 | import DistUtilsExtra.auto |
| 168 | + from DistUtilsExtra.command import build_extra |
| 169 | except ImportError: |
| 170 | print >> sys.stderr, 'To build this program you need '\ |
| 171 | 'https://launchpad.net/python-distutils-extra' |
| 172 | @@ -36,7 +37,7 @@ |
| 173 | CLEANFILES = ['data/com.ubuntu.sso.service'] |
| 174 | |
| 175 | # XXX: This needs some serious cleanup |
| 176 | -class SSOBuild(build.build): |
| 177 | +class SSOBuild(build_extra.build_extra): |
| 178 | """Class to build the extra files.""" |
| 179 | |
| 180 | description = 'build extra files needed by ubuntu-sso-client' |
| 181 | @@ -61,7 +62,7 @@ |
| 182 | ) |
| 183 | |
| 184 | # Run the parent build command |
| 185 | - build.build.run(self) |
| 186 | + build_extra.build_extra.run(self) |
| 187 | |
| 188 | |
| 189 | class SSOClean(clean.clean): |
| 190 | @@ -81,7 +82,7 @@ |
| 191 | |
| 192 | DistUtilsExtra.auto.setup( |
| 193 | name='ubuntu-sso-client', |
| 194 | - version='0.99.3', |
| 195 | + version='0.99.4', |
| 196 | license='GPL v3', |
| 197 | author='Natalia Bidart', |
| 198 | author_email='natalia.bidart@canonical.com', |
| 199 | |
| 200 | === modified file 'ubuntu_sso/gui.py' |
| 201 | --- ubuntu_sso/gui.py 2010-08-26 01:07:41 +0000 |
| 202 | +++ ubuntu_sso/gui.py 2010-08-27 22:32:43 +0000 |
| 203 | @@ -168,6 +168,7 @@ |
| 204 | self.warning = warning_msg |
| 205 | self.set_property('secondary-icon-stock', gtk.STOCK_DIALOG_WARNING) |
| 206 | self.set_property('secondary-icon-sensitive', True) |
| 207 | + self.set_property('secondary-icon-activatable', False) |
| 208 | self.set_property('secondary-icon-tooltip-text', warning_msg) |
| 209 | |
| 210 | def clear_warning(self): |
| 211 | @@ -175,6 +176,7 @@ |
| 212 | self.warning = None |
| 213 | self.set_property('secondary-icon-stock', None) |
| 214 | self.set_property('secondary-icon-sensitive', False) |
| 215 | + self.set_property('secondary-icon-activatable', False) |
| 216 | self.set_property('secondary-icon-tooltip-text', None) |
| 217 | |
| 218 | |
| 219 | @@ -253,12 +255,10 @@ |
| 220 | builder.add_from_file(ui_filename) |
| 221 | builder.connect_signals(self) |
| 222 | |
| 223 | - # XXX: every button should have tests for 'activate' signal |
| 224 | - # see LP: #616421 |
| 225 | - |
| 226 | self.widgets = [] |
| 227 | self.warnings = [] |
| 228 | self.cancels = [] |
| 229 | + self.labels = [] |
| 230 | for obj in builder.get_objects(): |
| 231 | name = getattr(obj, 'name', None) |
| 232 | if name is None and isinstance(obj, gtk.Buildable): |
| 233 | @@ -275,6 +275,10 @@ |
| 234 | if 'cancel_button' in name: |
| 235 | obj.connect('clicked', self.on_close_clicked) |
| 236 | self.cancels.append(obj) |
| 237 | + if '_button' in name: |
| 238 | + obj.connect('activate', lambda w: w.clicked()) |
| 239 | + if 'label' in name: |
| 240 | + self.labels.append(obj) |
| 241 | |
| 242 | self.entries = ('name_entry', 'email1_entry', 'email2_entry', |
| 243 | 'password1_entry', 'password2_entry', |
| 244 | @@ -292,7 +296,6 @@ |
| 245 | assert getattr(self, name) is not None |
| 246 | |
| 247 | self.window.set_icon_name('ubuntu-logo') |
| 248 | - self.captcha_reload_button.set_tooltip_text(self.CAPTCHA_RELOAD_TOOLTIP) |
| 249 | |
| 250 | self.bus = dbus.SessionBus() |
| 251 | self.bus.add_signal_receiver = self._log(self.bus.add_signal_receiver) |
| 252 | @@ -316,17 +319,26 @@ |
| 253 | self._append_page(self._build_request_password_token_page()) |
| 254 | self._append_page(self._build_set_new_password_page()) |
| 255 | |
| 256 | + window_size = None |
| 257 | if not login_only: |
| 258 | + window_size = (550, 600) |
| 259 | self._append_page(self._build_enter_details_page()) |
| 260 | self._append_page(self._build_tc_page()) |
| 261 | self._append_page(self._build_verify_email_page()) |
| 262 | self.login_button.grab_focus() |
| 263 | self._set_current_page(self.enter_details_vbox) |
| 264 | else: |
| 265 | + window_size = (400, 350) |
| 266 | self.login_back_button.hide() |
| 267 | self.login_ok_button.grab_focus() |
| 268 | + self.login_vbox.help_text = help_text |
| 269 | self._set_current_page(self.login_vbox) |
| 270 | |
| 271 | + self.window.set_size_request(*window_size) |
| 272 | + size_req = (int(window_size[0] * 0.9), -1) |
| 273 | + for label in self.labels: |
| 274 | + label.set_size_request(*size_req) |
| 275 | + |
| 276 | self._setup_signals() |
| 277 | self._gtk_signal_log = [] |
| 278 | |
| 279 | @@ -487,16 +499,17 @@ |
| 280 | |
| 281 | self.enter_details_vbox.pack_start(self.name_entry, expand=False) |
| 282 | self.enter_details_vbox.reorder_child(self.name_entry, 0) |
| 283 | - self.captcha_solution_vbox.pack_start(self.captcha_solution_entry, |
| 284 | - expand=False) |
| 285 | - self.captcha_solution_vbox.reorder_child(self.captcha_solution_entry, |
| 286 | - 0) |
| 287 | - |
| 288 | - self.emails_hbox.pack_start(self.email1_entry) |
| 289 | - self.emails_hbox.pack_start(self.email2_entry) |
| 290 | - |
| 291 | - self.passwords_hbox.pack_start(self.password1_entry) |
| 292 | - self.passwords_hbox.pack_start(self.password2_entry) |
| 293 | + entry = self.captcha_solution_entry |
| 294 | + self.captcha_solution_vbox.pack_start(entry, expand=False) |
| 295 | + self.captcha_solution_vbox.reorder_child(entry, 0) |
| 296 | + msg = self.CAPTCHA_RELOAD_TOOLTIP |
| 297 | + self.captcha_reload_button.set_tooltip_text(msg) |
| 298 | + |
| 299 | + self.emails_hbox.pack_start(self.email1_entry, expand=False) |
| 300 | + self.emails_hbox.pack_start(self.email2_entry, expand=False) |
| 301 | + |
| 302 | + self.passwords_hbox.pack_start(self.password1_entry, expand=False) |
| 303 | + self.passwords_hbox.pack_start(self.password2_entry, expand=False) |
| 304 | help_msg = '<small>%s</small>' % self.PASSWORD_HELP |
| 305 | self.password_help_label.set_markup(help_msg) |
| 306 | |
| 307 | @@ -515,6 +528,11 @@ |
| 308 | self.tc_hbox.hide_all() |
| 309 | self.login_button.set_label(self.LOGIN_BUTTON_LABEL) |
| 310 | |
| 311 | + for entry in (self.name_entry, self.email1_entry, self.email2_entry, |
| 312 | + self.password1_entry, self.password2_entry, |
| 313 | + self.captcha_solution_entry): |
| 314 | + entry.connect('activate', lambda w: self.join_ok_button.clicked()) |
| 315 | + |
| 316 | return self.enter_details_vbox |
| 317 | |
| 318 | def _build_tc_page(self): |
| 319 | @@ -530,6 +548,8 @@ |
| 320 | |
| 321 | def _build_verify_email_page(self): |
| 322 | """Build the verify email page.""" |
| 323 | + cb = lambda w: self.verify_token_button.clicked() |
| 324 | + self.email_token_entry.connect('activate', cb) |
| 325 | self.verify_email_vbox.pack_start(self.email_token_entry, expand=False) |
| 326 | self.verify_email_vbox.reorder_child(self.email_token_entry, 0) |
| 327 | |
| 328 | @@ -537,7 +557,6 @@ |
| 329 | |
| 330 | def _build_success_page(self): |
| 331 | """Build the success page.""" |
| 332 | - #self.success_vbox.help_text = '' |
| 333 | self.success_label.set_markup('<span size="x-large">%s</span>' % |
| 334 | self.SUCCESS) |
| 335 | return self.success_vbox |
| 336 | @@ -557,6 +576,9 @@ |
| 337 | self.forgotten_password_button.set_label(msg) |
| 338 | self.login_ok_button.grab_focus() |
| 339 | |
| 340 | + for entry in (self.login_email_entry, self.login_password_entry): |
| 341 | + entry.connect('activate', lambda w: self.login_ok_button.clicked()) |
| 342 | + |
| 343 | return self.login_vbox |
| 344 | |
| 345 | def _build_request_password_token_page(self): |
| 346 | @@ -566,12 +588,16 @@ |
| 347 | self.request_password_token_vbox.help_text = text |
| 348 | |
| 349 | entry = self.reset_email_entry |
| 350 | - self.request_password_token_details_vbox.pack_start(entry) |
| 351 | + self.request_password_token_details_vbox.pack_start(entry, |
| 352 | + expand=False) |
| 353 | cb = self.on_reset_email_entry_changed |
| 354 | self.reset_email_entry.connect('changed', cb) |
| 355 | self.request_password_token_ok_button.set_label(self.NEXT) |
| 356 | self.request_password_token_ok_button.set_sensitive(False) |
| 357 | |
| 358 | + cb = lambda w: self.request_password_token_ok_button.clicked() |
| 359 | + self.reset_email_entry.connect('activate', cb) |
| 360 | + |
| 361 | return self.request_password_token_vbox |
| 362 | |
| 363 | def _build_set_new_password_page(self): |
| 364 | @@ -579,21 +605,52 @@ |
| 365 | self.set_new_password_vbox.header = self.RESET_PASSWORD |
| 366 | self.set_new_password_vbox.help_text = self.SET_NEW_PASSWORD_LABEL |
| 367 | |
| 368 | + cb = lambda w: self.set_new_password_ok_button.clicked() |
| 369 | for entry in (self.reset_code_entry, |
| 370 | self.reset_password1_entry, |
| 371 | self.reset_password2_entry): |
| 372 | - self.set_new_password_details_vbox.pack_start(entry) |
| 373 | + self.set_new_password_details_vbox.pack_start(entry, expand=False) |
| 374 | + entry.connect('activate', cb) |
| 375 | |
| 376 | cb = self.on_set_new_password_entries_changed |
| 377 | self.reset_code_entry.connect('changed', cb) |
| 378 | self.reset_password1_entry.connect('changed', cb) |
| 379 | self.reset_password2_entry.connect('changed', cb) |
| 380 | + help_msg = '<small>%s</small>' % self.PASSWORD_HELP |
| 381 | + self.reset_password_help_label.set_markup(help_msg) |
| 382 | |
| 383 | self.set_new_password_ok_button.set_label(self.RESET_PASSWORD) |
| 384 | self.set_new_password_ok_button.set_sensitive(False) |
| 385 | |
| 386 | return self.set_new_password_vbox |
| 387 | |
| 388 | + def _validate_email(self, email1, email2=None): |
| 389 | + """Validate 'email1', return error message if not valid. |
| 390 | + |
| 391 | + If 'email2' is given, must match 'email1'. |
| 392 | + """ |
| 393 | + if email2 is not None and email1 != email2: |
| 394 | + return self.EMAIL_MISMATCH |
| 395 | + |
| 396 | + if not email1: |
| 397 | + return self.FIELD_REQUIRED |
| 398 | + |
| 399 | + if '@' not in email1: |
| 400 | + return self.EMAIL_INVALID |
| 401 | + |
| 402 | + def _validate_password(self, password1, password2=None): |
| 403 | + """Validate 'password1', return error message if not valid. |
| 404 | + |
| 405 | + If 'password2' is given, must match 'email1'. |
| 406 | + """ |
| 407 | + if password2 is not None and password1 != password2: |
| 408 | + return self.PASSWORD_MISMATCH |
| 409 | + |
| 410 | + if (len(password1) < 8 or |
| 411 | + re.search('[A-Z]', password1) is None or |
| 412 | + re.search('\d+', password1) is None): |
| 413 | + return self.PASSWORD_TOO_WEAK |
| 414 | + |
| 415 | # GTK callbacks |
| 416 | |
| 417 | def run(self): |
| 418 | @@ -640,6 +697,9 @@ |
| 419 | |
| 420 | def on_join_ok_button_clicked(self, *args, **kwargs): |
| 421 | """Submit info for processing, present the processing vbox.""" |
| 422 | + if not self.join_ok_button.is_sensitive(): |
| 423 | + return |
| 424 | + |
| 425 | self._clear_warnings() |
| 426 | |
| 427 | error = False |
| 428 | @@ -647,56 +707,40 @@ |
| 429 | name = self.name_entry.get_text() |
| 430 | if not name: |
| 431 | self.name_entry.set_warning(self.FIELD_REQUIRED) |
| 432 | - error |= True |
| 433 | + error = True |
| 434 | |
| 435 | # check email |
| 436 | email1 = self.email1_entry.get_text() |
| 437 | email2 = self.email2_entry.get_text() |
| 438 | - if email1 != email2: |
| 439 | - self.email1_entry.set_warning(self.EMAIL_MISMATCH) |
| 440 | - self.email2_entry.set_warning(self.EMAIL_MISMATCH) |
| 441 | - error |= True |
| 442 | - |
| 443 | - if '@' not in email1: |
| 444 | - self.email1_entry.set_warning(self.EMAIL_INVALID) |
| 445 | - self.email2_entry.set_warning(self.EMAIL_INVALID) |
| 446 | - error |= True |
| 447 | - |
| 448 | - if not email1: |
| 449 | - self.email1_entry.set_warning(self.FIELD_REQUIRED) |
| 450 | - self.email2_entry.set_warning(self.FIELD_REQUIRED) |
| 451 | - error |= True |
| 452 | + msg = self._validate_email(email1, email2) |
| 453 | + if msg is not None: |
| 454 | + self.email1_entry.set_warning(msg) |
| 455 | + self.email2_entry.set_warning(msg) |
| 456 | + error = True |
| 457 | |
| 458 | # check password |
| 459 | password1 = self.password1_entry.get_text() |
| 460 | password2 = self.password2_entry.get_text() |
| 461 | - if password1 != password2: |
| 462 | - self.password1_entry.set_warning(self.PASSWORD_MISMATCH) |
| 463 | - self.password2_entry.set_warning(self.PASSWORD_MISMATCH) |
| 464 | - error |= True |
| 465 | - |
| 466 | - if (len(password1) < 8 or |
| 467 | - re.search('[A-Z]', password1) is None or |
| 468 | - re.search('\d+', password1) is None): |
| 469 | - self.password1_entry.set_warning(self.PASSWORD_TOO_WEAK) |
| 470 | - self.password2_entry.set_warning(self.PASSWORD_TOO_WEAK) |
| 471 | - error |= True |
| 472 | + msg = self._validate_password(password1, password2) |
| 473 | + if msg is not None: |
| 474 | + self.password1_entry.set_warning(msg) |
| 475 | + self.password2_entry.set_warning(msg) |
| 476 | + error = True |
| 477 | |
| 478 | # check T&C |
| 479 | if not self.yes_to_tc_checkbutton.get_active(): |
| 480 | self._set_warning_message(self.tc_warning_label, |
| 481 | self.TC_NOT_ACCEPTED) |
| 482 | - error |= True |
| 483 | + error = True |
| 484 | |
| 485 | captcha_solution = self.captcha_solution_entry.get_text() |
| 486 | if not captcha_solution: |
| 487 | self.captcha_solution_entry.set_warning(self.FIELD_REQUIRED) |
| 488 | - error |= True |
| 489 | + error = True |
| 490 | |
| 491 | if error: |
| 492 | return |
| 493 | |
| 494 | - self._clear_warnings() |
| 495 | self._set_current_page(self.processing_vbox) |
| 496 | |
| 497 | logger.info('Calling register_user with email %r, password <hidden>,' \ |
| 498 | @@ -716,14 +760,22 @@ |
| 499 | |
| 500 | def on_verify_token_button_clicked(self, *args, **kwargs): |
| 501 | """The user entered the email token, let's verify!""" |
| 502 | + if not self.verify_token_button.is_sensitive(): |
| 503 | + return |
| 504 | + |
| 505 | + self._clear_warnings() |
| 506 | + |
| 507 | + email_token = self.email_token_entry.get_text() |
| 508 | + if not email_token: |
| 509 | + self.email_token_entry.set_warning(self.FIELD_REQUIRED) |
| 510 | + return |
| 511 | + |
| 512 | email = self.email1_entry.get_text() |
| 513 | password = self.password1_entry.get_text() |
| 514 | - email_token = self.email_token_entry.get_text() |
| 515 | - |
| 516 | + f = self.backend.validate_email |
| 517 | logger.info('Calling validate_email with email %r, password <hidden>' \ |
| 518 | - ', app_name %r and email_token %r.', email, |
| 519 | - self.app_name, email_token) |
| 520 | - f = self.backend.validate_email |
| 521 | + ', app_name %r and email_token %r.', email, self.app_name, |
| 522 | + email_token) |
| 523 | f(self.app_name, email, password, email_token, |
| 524 | reply_handler=NO_OP, error_handler=NO_OP) |
| 525 | |
| 526 | @@ -731,30 +783,27 @@ |
| 527 | |
| 528 | def on_login_connect_button_clicked(self, *args, **kwargs): |
| 529 | """User wants to connect!""" |
| 530 | + if not self.login_ok_button.is_sensitive(): |
| 531 | + return |
| 532 | + |
| 533 | self._clear_warnings() |
| 534 | |
| 535 | error = False |
| 536 | + |
| 537 | email = self.login_email_entry.get_text() |
| 538 | - |
| 539 | - if '@' not in email: |
| 540 | - self.login_email_entry.set_warning(self.EMAIL_INVALID) |
| 541 | - error |= True |
| 542 | - |
| 543 | - if not email: |
| 544 | - self.login_email_entry.set_warning(self.FIELD_REQUIRED) |
| 545 | - error |= True |
| 546 | + msg = self._validate_email(email) |
| 547 | + if msg is not None: |
| 548 | + self.login_email_entry.set_warning(msg) |
| 549 | + error = True |
| 550 | |
| 551 | password = self.login_password_entry.get_text() |
| 552 | - |
| 553 | if not password: |
| 554 | self.login_password_entry.set_warning(self.FIELD_REQUIRED) |
| 555 | - error |= True |
| 556 | + error = True |
| 557 | |
| 558 | if error: |
| 559 | return |
| 560 | |
| 561 | - self._clear_warnings() |
| 562 | - |
| 563 | f = self.backend.login |
| 564 | f(self.app_name, email, password, |
| 565 | reply_handler=NO_OP, error_handler=NO_OP) |
| 566 | @@ -771,7 +820,16 @@ |
| 567 | |
| 568 | def on_request_password_token_ok_button_clicked(self, *args, **kwargs): |
| 569 | """User entered the email address to reset the password.""" |
| 570 | + if not self.request_password_token_ok_button.is_sensitive(): |
| 571 | + return |
| 572 | + |
| 573 | + self._clear_warnings() |
| 574 | + |
| 575 | email = self.reset_email_entry.get_text() |
| 576 | + msg = self._validate_email(email) |
| 577 | + if msg is not None: |
| 578 | + self.reset_email_entry.set_warning(msg) |
| 579 | + return |
| 580 | |
| 581 | logger.info('Calling request_password_reset_token with %r.', email) |
| 582 | f = self.backend.request_password_reset_token |
| 583 | @@ -799,13 +857,30 @@ |
| 584 | |
| 585 | def on_set_new_password_ok_button_clicked(self, *args, **kwargs): |
| 586 | """User entered reset code and new passwords.""" |
| 587 | - email = self.reset_email_entry.get_text() |
| 588 | + if not self.set_new_password_ok_button.is_sensitive(): |
| 589 | + return |
| 590 | + |
| 591 | + self._clear_warnings() |
| 592 | + |
| 593 | + error = False |
| 594 | + |
| 595 | token = self.reset_code_entry.get_text() |
| 596 | - # XXX: validate passwords! |
| 597 | - # see LP: #616528 |
| 598 | + if not token: |
| 599 | + self.reset_code_entry.set_warning(self.FIELD_REQUIRED) |
| 600 | + error = True |
| 601 | + |
| 602 | password1 = self.reset_password1_entry.get_text() |
| 603 | - #password2 = self.reset_password2_entry.get_text() |
| 604 | - |
| 605 | + password2 = self.reset_password2_entry.get_text() |
| 606 | + msg = self._validate_password(password1, password2) |
| 607 | + if msg is not None: |
| 608 | + self.reset_password1_entry.set_warning(msg) |
| 609 | + self.reset_password2_entry.set_warning(msg) |
| 610 | + error = True |
| 611 | + |
| 612 | + if error: |
| 613 | + return |
| 614 | + |
| 615 | + email = self.reset_email_entry.get_text() |
| 616 | logger.info('Calling set_new_password with email %r, token %r and ' \ |
| 617 | 'new password: <hidden>.', email, token) |
| 618 | f = self.backend.set_new_password |
| 619 | @@ -836,6 +911,17 @@ |
| 620 | |
| 621 | # backend callbacks |
| 622 | |
| 623 | + def _build_general_error_message(self, errordict): |
| 624 | + """Concatenate __all__ and message from the errordict.""" |
| 625 | + result = None |
| 626 | + msg1 = errordict.get('__all__') |
| 627 | + msg2 = errordict.get('message') |
| 628 | + if msg1 is not None and msg2 is not None: |
| 629 | + result = '\n'.join((msg1, msg2)) |
| 630 | + else: |
| 631 | + result = msg1 if msg1 is not None else msg2 |
| 632 | + return result |
| 633 | + |
| 634 | @log_call |
| 635 | def on_captcha_generated(self, app_name, captcha_id, *args, **kwargs): |
| 636 | """Captcha image has been generated and is available to be shown.""" |
| 637 | @@ -858,10 +944,21 @@ |
| 638 | @log_call |
| 639 | def on_user_registration_error(self, app_name, error, *args, **kwargs): |
| 640 | """Captcha image generation failed.""" |
| 641 | - self._set_current_page(self.enter_details_vbox, |
| 642 | - warning_text=self.UNKNOWN_ERROR) |
| 643 | + msg = error.get('email') |
| 644 | + if msg is not None: |
| 645 | + self.email1_entry.set_warning(msg) |
| 646 | + self.email2_entry.set_warning(msg) |
| 647 | + |
| 648 | + msg = error.get('password') |
| 649 | + if msg is not None: |
| 650 | + self.password1_entry.set_warning(msg) |
| 651 | + self.password2_entry.set_warning(msg) |
| 652 | + |
| 653 | + msg = self._build_general_error_message(error) |
| 654 | + self._set_current_page(self.enter_details_vbox, warning_text=msg) |
| 655 | + |
| 656 | self._gtk_signal_log.append((SIG_REGISTRATION_FAILED, self.app_name, |
| 657 | - error)) |
| 658 | + msg)) |
| 659 | |
| 660 | @log_call |
| 661 | def on_email_validated(self, app_name, email, *args, **kwargs): |
| 662 | @@ -873,10 +970,15 @@ |
| 663 | @log_call |
| 664 | def on_email_validation_error(self, app_name, error, *args, **kwargs): |
| 665 | """User email validation failed.""" |
| 666 | - self._set_current_page(self.verify_email_vbox, |
| 667 | - warning_text=self.UNKNOWN_ERROR) |
| 668 | + msg = error.get('email_token') |
| 669 | + if msg is not None: |
| 670 | + self.email_token_entry.set_warning(msg) |
| 671 | + |
| 672 | + msg = self._build_general_error_message(error) |
| 673 | + self._set_current_page(self.verify_email_vbox, warning_text=msg) |
| 674 | + |
| 675 | self._gtk_signal_log.append((SIG_REGISTRATION_FAILED, self.app_name, |
| 676 | - error)) |
| 677 | + msg)) |
| 678 | |
| 679 | @log_call |
| 680 | def on_logged_in(self, app_name, email, *args, **kwargs): |
| 681 | @@ -888,10 +990,10 @@ |
| 682 | @log_call |
| 683 | def on_login_error(self, app_name, error, *args, **kwargs): |
| 684 | """User was not successfully logged in.""" |
| 685 | - self._set_current_page(self.login_vbox, |
| 686 | - warning_text=self.UNKNOWN_ERROR) |
| 687 | + msg = self._build_general_error_message(error) |
| 688 | + self._set_current_page(self.login_vbox, warning_text=msg) |
| 689 | self._gtk_signal_log.append((SIG_LOGIN_FAILED, self.app_name, |
| 690 | - error)) |
| 691 | + msg)) |
| 692 | |
| 693 | @log_call |
| 694 | def on_password_reset_token_sent(self, app_name, email, *args, **kwargs): |
| 695 | @@ -903,8 +1005,8 @@ |
| 696 | @log_call |
| 697 | def on_password_reset_error(self, app_name, error, *args, **kwargs): |
| 698 | """Password reset failed.""" |
| 699 | - self._set_current_page(self.login_vbox, |
| 700 | - warning_text=self.UNKNOWN_ERROR) |
| 701 | + msg = self._build_general_error_message(error) |
| 702 | + self._set_current_page(self.login_vbox, warning_text=msg) |
| 703 | |
| 704 | @log_call |
| 705 | def on_password_changed(self, app_name, email, *args, **kwargs): |
| 706 | @@ -915,5 +1017,6 @@ |
| 707 | @log_call |
| 708 | def on_password_change_error(self, app_name, error, *args, **kwargs): |
| 709 | """Password reset failed.""" |
| 710 | + msg = self._build_general_error_message(error) |
| 711 | self._set_current_page(self.request_password_token_vbox, |
| 712 | - warning_text=self.UNKNOWN_ERROR) |
| 713 | + warning_text=msg) |
| 714 | |
| 715 | === modified file 'ubuntu_sso/keyring.py' |
| 716 | --- ubuntu_sso/keyring.py 2010-08-19 16:02:09 +0000 |
| 717 | +++ ubuntu_sso/keyring.py 2010-08-27 22:32:43 +0000 |
| 718 | @@ -19,77 +19,128 @@ |
| 719 | |
| 720 | """Handle keys in the gnome kerying.""" |
| 721 | |
| 722 | +import socket |
| 723 | +import urllib |
| 724 | +import urlparse |
| 725 | + |
| 726 | import gnomekeyring |
| 727 | |
| 728 | -from urllib import urlencode |
| 729 | -from urlparse import parse_qsl |
| 730 | +from ubuntu_sso.logger import setupLogging |
| 731 | +logger = setupLogging("ubuntu_sso.main") |
| 732 | + |
| 733 | +U1_APP_NAME = "Ubuntu One" |
| 734 | +U1_KEY_NAME = "UbuntuOne token for https://ubuntuone.com" |
| 735 | +U1_KEY_ATTR = { |
| 736 | + "oauth-consumer-key": "ubuntuone", |
| 737 | + "ubuntuone-realm": "https://ubuntuone.com", |
| 738 | +} |
| 739 | + |
| 740 | + |
| 741 | +def get_token_name(app_name): |
| 742 | + """Build the token name.""" |
| 743 | + quoted_app_name = urllib.quote(app_name) |
| 744 | + computer_name = socket.gethostname() |
| 745 | + quoted_computer_name = urllib.quote(computer_name) |
| 746 | + return "%s - %s" % (quoted_app_name, quoted_computer_name) |
| 747 | |
| 748 | |
| 749 | class Keyring(object): |
| 750 | - |
| 751 | + """A Keyring for a given application name.""" |
| 752 | KEYRING_NAME = "login" |
| 753 | |
| 754 | def __init__(self, app_name): |
| 755 | + """Initialize this instance given the app_name.""" |
| 756 | if not gnomekeyring.is_available(): |
| 757 | raise gnomekeyring.NoKeyringDaemonError |
| 758 | self.app_name = app_name |
| 759 | + self.token_name = get_token_name(self.app_name) |
| 760 | |
| 761 | def _create_keyring(self, name): |
| 762 | - """Creates a keyring, if it already exists, do nothing.""" |
| 763 | + """Creates a keyring, or if it already exists, it does nothing.""" |
| 764 | keyring_names = gnomekeyring.list_keyring_names_sync() |
| 765 | if not name in keyring_names: |
| 766 | gnomekeyring.create_sync(name) |
| 767 | |
| 768 | - def _get_item_id_from_name(self, sync, name): |
| 769 | - """Return the ID for a named item.""" |
| 770 | - for item_id in gnomekeyring.list_item_ids_sync(sync): |
| 771 | - item_info = gnomekeyring.item_get_info_sync(sync, item_id) |
| 772 | - display_name = item_info.get_display_name() |
| 773 | - if display_name == name: |
| 774 | - return item_id |
| 775 | - |
| 776 | - def _get_item_info_from_name(self, sync, name): |
| 777 | - """Return the ID for a named item.""" |
| 778 | - for item_id in gnomekeyring.list_item_ids_sync(sync): |
| 779 | - item_info = gnomekeyring.item_get_info_sync(sync, item_id) |
| 780 | - display_name = item_info.get_display_name() |
| 781 | - if display_name == name: |
| 782 | - return item_info |
| 783 | + def _find_keyring_item(self): |
| 784 | + """Return the keyring item or None if not found.""" |
| 785 | + try: |
| 786 | + items = gnomekeyring.find_items_sync( |
| 787 | + gnomekeyring.ITEM_GENERIC_SECRET, |
| 788 | + self._get_keyring_attr()) |
| 789 | + except gnomekeyring.NoMatchError: |
| 790 | + # if no items found, return None |
| 791 | + return None |
| 792 | + |
| 793 | + # we priorize the item in the "login" keyring |
| 794 | + for item in items: |
| 795 | + if item.keyring == "login": |
| 796 | + return item |
| 797 | + |
| 798 | + # if not on the "login" keyring, we return the first item |
| 799 | + return items[0] |
| 800 | + |
| 801 | + def _get_keyring_attr(self): |
| 802 | + """Build the keyring attributes for this credentials.""" |
| 803 | + attr = {"key-type": "Ubuntu SSO credentials", |
| 804 | + "token-name": self.token_name} |
| 805 | + return attr |
| 806 | |
| 807 | def set_ubuntusso_attr(self, cred): |
| 808 | """Set the credentials of the Ubuntu SSO item.""" |
| 809 | # Creates the secret from the credentials |
| 810 | - secret = urlencode(cred) |
| 811 | + secret = urllib.urlencode(cred) |
| 812 | |
| 813 | - # Create the keyring |
| 814 | + # Create the keyring if it does not exists |
| 815 | self._create_keyring(self.KEYRING_NAME) |
| 816 | |
| 817 | - # No need to delete the item if it already exists |
| 818 | - |
| 819 | - # A set of attributes for this credentials |
| 820 | - attr = {"key-type": "Ubuntu SSO credentials", |
| 821 | - "token-name": cred["name"].encode("utf8")} |
| 822 | - |
| 823 | # Add our SSO credentials to the keyring |
| 824 | gnomekeyring.item_create_sync(self.KEYRING_NAME, |
| 825 | - gnomekeyring.ITEM_GENERIC_SECRET, self.app_name, attr, |
| 826 | - secret, True) |
| 827 | + gnomekeyring.ITEM_GENERIC_SECRET, self.app_name, |
| 828 | + self._get_keyring_attr(), secret, True) |
| 829 | |
| 830 | def get_ubuntusso_attr(self): |
| 831 | """Return the secret of the SSO item in a dictionary.""" |
| 832 | # If we have no attributes, return None |
| 833 | - exist = self._get_item_info_from_name(self.KEYRING_NAME, self.app_name) |
| 834 | - if exist is not None: |
| 835 | - secret = self._get_item_info_from_name(self.KEYRING_NAME, |
| 836 | - self.app_name).get_secret() |
| 837 | - return dict(parse_qsl(secret)) |
| 838 | + item = self._find_keyring_item() |
| 839 | + if item is not None: |
| 840 | + return dict(urlparse.parse_qsl(item.secret)) |
| 841 | + else: |
| 842 | + # if no item found, try getting the old credentials |
| 843 | + if self.app_name == U1_APP_NAME: |
| 844 | + return try_old_credentials(self.app_name) |
| 845 | + # nothing was found |
| 846 | + return None |
| 847 | |
| 848 | def delete_ubuntusso_attr(self): |
| 849 | """Delete a set of credentials from the keyring.""" |
| 850 | - item_id = self._get_item_id_from_name(self.KEYRING_NAME, |
| 851 | - self.app_name) |
| 852 | - if item_id is not None: |
| 853 | - gnomekeyring.item_delete_sync(self.KEYRING_NAME, item_id) |
| 854 | + item = self._find_keyring_item() |
| 855 | + if item is not None: |
| 856 | + gnomekeyring.item_delete_sync(item.keyring, item.item_id) |
| 857 | + |
| 858 | + |
| 859 | +class UbuntuOneOAuthKeyring(Keyring): |
| 860 | + |
| 861 | + def _get_keyring_attr(self): |
| 862 | + """Build the keyring attributes for this credentials.""" |
| 863 | + return U1_KEY_ATTR |
| 864 | + |
| 865 | + |
| 866 | +def try_old_credentials(app_name): |
| 867 | + """Try to get old U1 credentials and format them as new.""" |
| 868 | + logger.debug('trying to get old credentials.') |
| 869 | + old_creds = UbuntuOneOAuthKeyring(U1_KEY_NAME).get_ubuntusso_attr() |
| 870 | + if old_creds is not None: |
| 871 | + # Old creds found, build a new credentials dict with them |
| 872 | + creds = { |
| 873 | + 'consumer_key': "ubuntuone", |
| 874 | + 'consumer_secret': "hammertime", |
| 875 | + 'name': U1_KEY_NAME, |
| 876 | + 'token': old_creds["oauth_token"], |
| 877 | + 'token_secret': old_creds["oauth_token_secret"], |
| 878 | + } |
| 879 | + logger.debug('found old credentials') |
| 880 | + return creds |
| 881 | + logger.debug('try_old_credentials: No old credentials for this app.') |
| 882 | |
| 883 | |
| 884 | if __name__ == "__main__": |
| 885 | |
| 886 | === modified file 'ubuntu_sso/main.py' |
| 887 | --- ubuntu_sso/main.py 2010-08-26 01:07:41 +0000 |
| 888 | +++ ubuntu_sso/main.py 2010-08-27 22:32:43 +0000 |
| 889 | @@ -28,11 +28,9 @@ |
| 890 | """ |
| 891 | |
| 892 | import re |
| 893 | -import socket |
| 894 | import time |
| 895 | import threading |
| 896 | import traceback |
| 897 | -import urllib |
| 898 | import urllib2 |
| 899 | import urlparse |
| 900 | |
| 901 | @@ -49,7 +47,7 @@ |
| 902 | from ubuntu_sso import (DBUS_IFACE_AUTH_NAME, DBUS_IFACE_USER_NAME, |
| 903 | DBUS_IFACE_CRED_NAME, DBUS_CRED_PATH, DBUS_BUS_NAME, gui) |
| 904 | from ubuntu_sso.config import get_config |
| 905 | -from ubuntu_sso.keyring import Keyring |
| 906 | +from ubuntu_sso.keyring import Keyring, get_token_name, U1_APP_NAME |
| 907 | from ubuntu_sso.logger import setupLogging |
| 908 | logger = setupLogging("ubuntu_sso.main") |
| 909 | |
| 910 | @@ -57,8 +55,6 @@ |
| 911 | # Disable the invalid name warning, as we have a lot of DBus style names |
| 912 | # pylint: disable-msg=C0103 |
| 913 | |
| 914 | -OLD_KEY_NAME = "UbuntuOne token for https://ubuntuone.com" |
| 915 | -U1_APP_NAME = "Ubuntu One" |
| 916 | PING_URL = "http://edge.one.ubuntu.com/oauth/sso-finished-so-get-tokens/" |
| 917 | |
| 918 | |
| 919 | @@ -113,32 +109,9 @@ |
| 920 | creds = Keyring(app_name).get_ubuntusso_attr() |
| 921 | logger.debug('keyring_get_credentials: Keyring returned credentials? %r', |
| 922 | creds is not None) |
| 923 | - if creds is None and app_name == U1_APP_NAME: |
| 924 | - logger.debug('keyring_get_credentials: trying for old service.') |
| 925 | - # No new creds, try to get old credentials |
| 926 | - old_creds = Keyring(OLD_KEY_NAME).get_ubuntusso_attr() |
| 927 | - if old_creds is not None: |
| 928 | - # Old creds found, build a new credentials dict with them |
| 929 | - creds = { |
| 930 | - 'consumer_key': "ubuntuone", |
| 931 | - 'consumer_secret': "hammertime", |
| 932 | - 'token_name': OLD_KEY_NAME, |
| 933 | - 'token': old_creds["oauth_token"], |
| 934 | - 'token_secret': old_creds["oauth_token_secret"], |
| 935 | - } |
| 936 | - else: |
| 937 | - logger.debug('keyring_get_credentials: Keyring returned credentials.') |
| 938 | return creds |
| 939 | |
| 940 | |
| 941 | -def get_token_name(app_name): |
| 942 | - """Build the token name.""" |
| 943 | - quoted_app_name = urllib.quote(app_name) |
| 944 | - computer_name = socket.gethostname() |
| 945 | - quoted_computer_name = urllib.quote(computer_name) |
| 946 | - return "%s - %s" % (quoted_app_name, quoted_computer_name) |
| 947 | - |
| 948 | - |
| 949 | class SSOLoginProcessor(object): |
| 950 | """Login and register users using the Ubuntu Single Sign On service.""" |
| 951 | |
| 952 | @@ -163,6 +136,17 @@ |
| 953 | re.search('\d+', password)) # one number |
| 954 | return res |
| 955 | |
| 956 | + def _format_webservice_errors(self, errdict): |
| 957 | + """Turn each list of strings in the errdict into a LF separated str.""" |
| 958 | + result = {} |
| 959 | + for k, v in errdict.iteritems(): |
| 960 | + # workaround until bug #624955 is solved |
| 961 | + if isinstance(v, basestring): |
| 962 | + result[k] = v |
| 963 | + else: |
| 964 | + result[k] = "\n".join(v) |
| 965 | + return result |
| 966 | + |
| 967 | def generate_captcha(self, filename): |
| 968 | """Generate a captcha using the SSO service.""" |
| 969 | logger.debug('generate_captcha: requesting captcha, filename: %r', |
| 970 | @@ -203,7 +187,8 @@ |
| 971 | logger.info('register_user: email: %r result: %r', email, result) |
| 972 | |
| 973 | if result['status'] == 'error': |
| 974 | - raise RegistrationError(result['errors']) |
| 975 | + errorsdict = self._format_webservice_errors(result['errors']) |
| 976 | + raise RegistrationError(errorsdict) |
| 977 | elif result['status'] != 'ok': |
| 978 | raise RegistrationError('Received unknown status: %s' % result) |
| 979 | else: |
| 980 | @@ -243,9 +228,10 @@ |
| 981 | result = sso_service.accounts.validate_email(email_token=email_token) |
| 982 | logger.info('validate_email: email: %r result: %r', email, result) |
| 983 | if 'errors' in result: |
| 984 | - raise EmailTokenError(result['errors']) |
| 985 | + errorsdict = self._format_webservice_errors(result['errors']) |
| 986 | + raise EmailTokenError(errorsdict) |
| 987 | elif 'email' in result: |
| 988 | - return result['email'] |
| 989 | + return token |
| 990 | else: |
| 991 | raise EmailTokenError('Received invalid reply: %s' % result) |
| 992 | |
| 993 | @@ -257,7 +243,7 @@ |
| 994 | result = service(email=email) |
| 995 | except HTTPError, e: |
| 996 | logger.exception('request_password_reset_token failed with:') |
| 997 | - raise ResetPasswordTokenError(e.content) |
| 998 | + raise ResetPasswordTokenError(e.content.split('\n')[0]) |
| 999 | |
| 1000 | if result['status'] == 'ok': |
| 1001 | return email |
| 1002 | @@ -279,7 +265,7 @@ |
| 1003 | new_password=new_password) |
| 1004 | except HTTPError, e: |
| 1005 | logger.exception('set_new_password failed with:') |
| 1006 | - raise NewPasswordError(e.content) |
| 1007 | + raise NewPasswordError(e.content.split('\n')[0]) |
| 1008 | |
| 1009 | if result['status'] == 'ok': |
| 1010 | return email |
| 1011 | @@ -291,7 +277,6 @@ |
| 1012 | """Turn an exception into a dictionary to return thru DBus.""" |
| 1013 | result = { |
| 1014 | "errtype": e.__class__.__name__, |
| 1015 | - "errargs": repr(e.args), |
| 1016 | } |
| 1017 | if len(e.args) == 0: |
| 1018 | result["message"] = e.__class__.__doc__ |
| 1019 | @@ -414,8 +399,10 @@ |
| 1020 | def f(): |
| 1021 | """Inner function that will be run in a thread.""" |
| 1022 | token_name = get_token_name(app_name) |
| 1023 | - return self.processor().validate_email(email, password, |
| 1024 | + credentials = self.processor().validate_email(email, password, |
| 1025 | email_token, token_name) |
| 1026 | + keyring_store_credentials(app_name, credentials) |
| 1027 | + return email |
| 1028 | blocking(f, app_name, self.EmailValidated, self.EmailValidationError) |
| 1029 | |
| 1030 | # request_password_reset_token signals |
| 1031 | |
| 1032 | === modified file 'ubuntu_sso/tests/test_gui.py' |
| 1033 | --- ubuntu_sso/tests/test_gui.py 2010-08-26 01:07:41 +0000 |
| 1034 | +++ ubuntu_sso/tests/test_gui.py 2010-08-27 22:32:43 +0000 |
| 1035 | @@ -44,7 +44,6 @@ |
| 1036 | CAPTCHA_SOLUTION = 'william Byrd' |
| 1037 | EMAIL = 'test@example.com' |
| 1038 | EMAIL_TOKEN = 'B2Pgtf' |
| 1039 | -ERROR = 'Something bad happened!' |
| 1040 | NAME = 'Juanito Pérez' |
| 1041 | PASSWORD = 'h3lloWorld' |
| 1042 | RESET_PASSWORD_TOKEN = '8G5Wtq' |
| 1043 | @@ -269,6 +268,8 @@ |
| 1044 | None) |
| 1045 | self.assertEqual(self.entry.get_property('secondary-icon-sensitive'), |
| 1046 | False) |
| 1047 | + self.assertEqual(self.entry.get_property('secondary-icon-activatable'), |
| 1048 | + False) |
| 1049 | prop = self.entry.get_property('secondary-icon-tooltip-text') |
| 1050 | self.assertEqual(prop, None) |
| 1051 | |
| 1052 | @@ -281,6 +282,8 @@ |
| 1053 | gtk.STOCK_DIALOG_WARNING) |
| 1054 | self.assertEqual(self.entry.get_property('secondary-icon-sensitive'), |
| 1055 | True) |
| 1056 | + self.assertEqual(self.entry.get_property('secondary-icon-activatable'), |
| 1057 | + False) |
| 1058 | prop = self.entry.get_property('secondary-icon-tooltip-text') |
| 1059 | self.assertEqual(prop, msg) |
| 1060 | |
| 1061 | @@ -292,6 +295,8 @@ |
| 1062 | None) |
| 1063 | self.assertEqual(self.entry.get_property('secondary-icon-sensitive'), |
| 1064 | False) |
| 1065 | + self.assertEqual(self.entry.get_property('secondary-icon-activatable'), |
| 1066 | + False) |
| 1067 | prop = self.entry.get_property('secondary-icon-tooltip-text') |
| 1068 | self.assertEqual(prop, None) |
| 1069 | |
| 1070 | @@ -338,6 +343,7 @@ |
| 1071 | 'tc_browser', 'login', 'request_password_token', |
| 1072 | 'set_new_password') |
| 1073 | self.ui = self.gui_class(**self.kwargs) |
| 1074 | + self.ERROR = {'message': self.ui.UNKNOWN_ERROR} |
| 1075 | |
| 1076 | def tearDown(self): |
| 1077 | """Clean up.""" |
| 1078 | @@ -358,11 +364,13 @@ |
| 1079 | def assert_warnings_visibility(self, visible=False): |
| 1080 | """Every warning label should be 'visible'.""" |
| 1081 | msg = '"%s" should be %svisible.' |
| 1082 | - warnings = filter(lambda name: 'warning' in name, self.ui.widgets) |
| 1083 | - for name in warnings: |
| 1084 | + for name in self.ui.widgets: |
| 1085 | widget = getattr(self.ui, name) |
| 1086 | - self.assertEqual(visible, widget.get_property('visible'), |
| 1087 | - msg % (name, '' if visible else 'not ')) |
| 1088 | + if 'warning' in name: |
| 1089 | + self.assertEqual(visible, widget.get_property('visible'), |
| 1090 | + msg % (name, '' if visible else 'not ')) |
| 1091 | + elif 'entry' in name: |
| 1092 | + self.assertEqual(widget.warning, '') |
| 1093 | |
| 1094 | def assert_correct_label_warning(self, label, message): |
| 1095 | """Check that a warning is shown displaying 'message'.""" |
| 1096 | @@ -533,6 +541,16 @@ |
| 1097 | # text content is correct |
| 1098 | self.assertEqual(expected, actual, msg % (name, expected, actual)) |
| 1099 | |
| 1100 | + def test_initial_size_for_labels(self): |
| 1101 | + """Labels have the correct width.""" |
| 1102 | + expected = (int(self.ui.window.get_size_request()[0] * 0.9), -1) |
| 1103 | + msg = 'Label %r must have size request %s (got %s instead).' |
| 1104 | + labels = [i for i in self.ui.widgets if 'label' in i] |
| 1105 | + for label in labels: |
| 1106 | + widget = getattr(self.ui, label) |
| 1107 | + actual = widget.get_size_request() |
| 1108 | + self.assertEqual(expected, actual, msg % (label, expected, actual)) |
| 1109 | + |
| 1110 | def test_password_fields_are_password(self): |
| 1111 | msg = '"%s" should be a password LabeledEntry instance.' |
| 1112 | passwords = filter(lambda name: 'password' in name, |
| 1113 | @@ -543,7 +561,7 @@ |
| 1114 | |
| 1115 | def test_warning_fields_are_hidden(self): |
| 1116 | """Every warning label should be not visible.""" |
| 1117 | - self.assert_warnings_visibility(visible=False) |
| 1118 | + self.assert_warnings_visibility() |
| 1119 | |
| 1120 | def test_cancel_buttons_close_window(self): |
| 1121 | """Every cancel button should close the window when clicked.""" |
| 1122 | @@ -558,6 +576,17 @@ |
| 1123 | self.assertEqual(self._called, ((widget,), {}), msg % name) |
| 1124 | self._called = False |
| 1125 | |
| 1126 | + def test_all_buttons_are_activatable(self): |
| 1127 | + """Every button should be activatable.""" |
| 1128 | + msg = '"%s" should be activatable.' |
| 1129 | + buttons = filter(lambda name: '_button' in name, self.ui.widgets) |
| 1130 | + for name in buttons: |
| 1131 | + widget = getattr(self.ui, name) |
| 1132 | + widget.connect('clicked', self._set_called) |
| 1133 | + widget.activate() |
| 1134 | + self.assertEqual(self._called, ((widget,), {}), msg % name) |
| 1135 | + self._called = False |
| 1136 | + |
| 1137 | def test_window_icon(self): |
| 1138 | """Main window has the proper icon.""" |
| 1139 | self.assertEqual('ubuntu-logo', self.ui.window.get_icon_name()) |
| 1140 | @@ -585,7 +614,7 @@ |
| 1141 | self.assertEqual(self._called, ((xid,), {})) |
| 1142 | |
| 1143 | |
| 1144 | -class RegistrationEnterDetailsTestCase(UbuntuSSOClientTestCase): |
| 1145 | +class EnterDetailsTestCase(UbuntuSSOClientTestCase): |
| 1146 | """Test suite for the user registration (enter details page).""" |
| 1147 | |
| 1148 | def test_initial_text_for_header_label(self): |
| 1149 | @@ -774,6 +803,50 @@ |
| 1150 | actual = self.ui.login_button.get_label() |
| 1151 | self.assertEqual(self.ui.LOGIN_BUTTON_LABEL, actual) |
| 1152 | |
| 1153 | + def test_activate_name_entry_clicks_connect(self): |
| 1154 | + """Activating any entry generates a connect attempt.""" |
| 1155 | + self.ui.join_ok_button.connect('clicked', self._set_called) |
| 1156 | + self.ui.name_entry.activate() |
| 1157 | + self.assertEqual(self._called, ((self.ui.join_ok_button,), {})) |
| 1158 | + |
| 1159 | + def test_activate_email_entry_clicks_connect(self): |
| 1160 | + """Activating any entry generates a connect attempt.""" |
| 1161 | + self.ui.join_ok_button.connect('clicked', self._set_called) |
| 1162 | + self.ui.email1_entry.activate() |
| 1163 | + self.assertEqual(self._called, ((self.ui.join_ok_button,), {})) |
| 1164 | + |
| 1165 | + self._called = False |
| 1166 | + self.ui.email2_entry.activate() |
| 1167 | + self.assertEqual(self._called, ((self.ui.join_ok_button,), {})) |
| 1168 | + |
| 1169 | + def test_activate_password_entry_clicks_connect(self): |
| 1170 | + """Activating any entry generates a connect attempt.""" |
| 1171 | + self.ui.join_ok_button.connect('clicked', self._set_called) |
| 1172 | + self.ui.password1_entry.activate() |
| 1173 | + self.assertEqual(self._called, ((self.ui.join_ok_button,), {})) |
| 1174 | + |
| 1175 | + self._called = False |
| 1176 | + self.ui.password2_entry.activate() |
| 1177 | + self.assertEqual(self._called, ((self.ui.join_ok_button,), {})) |
| 1178 | + |
| 1179 | + def test_activate_captcha_solution_entry_clicks_connect(self): |
| 1180 | + """Activating any entry generates a connect attempt.""" |
| 1181 | + self.ui.join_ok_button.connect('clicked', self._set_called) |
| 1182 | + self.ui.captcha_solution_entry.activate() |
| 1183 | + self.assertEqual(self._called, ((self.ui.join_ok_button,), {})) |
| 1184 | + |
| 1185 | + def test_join_ok_button_does_nothing_if_clicked_but_disabled(self): |
| 1186 | + """The join form can only be submitted if the button is sensitive.""" |
| 1187 | + self.patch(self.ui.name_entry, 'get_text', self._set_called) |
| 1188 | + |
| 1189 | + self.ui.join_ok_button.set_sensitive(False) |
| 1190 | + self.ui.join_ok_button.clicked() |
| 1191 | + self.assertFalse(self._called) |
| 1192 | + |
| 1193 | + self.ui.join_ok_button.set_sensitive(True) |
| 1194 | + self.ui.join_ok_button.clicked() |
| 1195 | + self.assertTrue(self._called) |
| 1196 | + |
| 1197 | |
| 1198 | class NoTermsAndConditionsTestCase(UbuntuSSOClientTestCase): |
| 1199 | """Test suite for the user registration (with no t&c link).""" |
| 1200 | @@ -843,24 +916,46 @@ |
| 1201 | test_tc_browser_opens_the_proper_uri.skip = 'The freaking test wont work.' |
| 1202 | |
| 1203 | |
| 1204 | -class UserRegistrationErrorTestCase(UbuntuSSOClientTestCase): |
| 1205 | +class RegistrationErrorTestCase(UbuntuSSOClientTestCase): |
| 1206 | """Test suite for the user registration error handling.""" |
| 1207 | |
| 1208 | def setUp(self): |
| 1209 | """Init.""" |
| 1210 | - super(UserRegistrationErrorTestCase, self).setUp() |
| 1211 | + super(RegistrationErrorTestCase, self).setUp() |
| 1212 | self.click_join_with_valid_data() |
| 1213 | - self.ui.on_user_registration_error(app_name=APP_NAME, error=ERROR) |
| 1214 | |
| 1215 | def test_previous_page_is_shown(self): |
| 1216 | """On UserRegistrationError the previous page is shown.""" |
| 1217 | + self.ui.on_user_registration_error(app_name=APP_NAME, error=self.ERROR) |
| 1218 | self.assert_pages_visibility(enter_details=True) |
| 1219 | |
| 1220 | def test_warning_label_is_shown(self): |
| 1221 | """On UserRegistrationError the warning label is shown.""" |
| 1222 | + self.ui.on_user_registration_error(app_name=APP_NAME, error=self.ERROR) |
| 1223 | self.assert_correct_label_warning(self.ui.warning_label, |
| 1224 | self.ui.UNKNOWN_ERROR) |
| 1225 | |
| 1226 | + def test_specific_errors_from_backend_are_shown(self): |
| 1227 | + """Specific errors from backend are used.""" |
| 1228 | + error = {'errtype': 'RegistrationError', |
| 1229 | + 'message': 'We\'re so doomed.', |
| 1230 | + 'email': 'Enter a valid e-mail address.', |
| 1231 | + 'password': 'I don\'t like your password.', |
| 1232 | + '__all__': 'Wrong captcha solution.'} |
| 1233 | + |
| 1234 | + self.ui.on_user_registration_error(app_name=APP_NAME, error=error) |
| 1235 | + |
| 1236 | + expected = '\n'.join((error['__all__'], error['message'])) |
| 1237 | + self.assert_correct_label_warning(self.ui.warning_label, expected) |
| 1238 | + self.assert_correct_entry_warning(self.ui.email1_entry, |
| 1239 | + error['email']) |
| 1240 | + self.assert_correct_entry_warning(self.ui.email2_entry, |
| 1241 | + error['email']) |
| 1242 | + self.assert_correct_entry_warning(self.ui.password1_entry, |
| 1243 | + error['password']) |
| 1244 | + self.assert_correct_entry_warning(self.ui.password2_entry, |
| 1245 | + error['password']) |
| 1246 | + |
| 1247 | |
| 1248 | class VerifyEmailTestCase(UbuntuSSOClientTestCase): |
| 1249 | """Test suite for the user registration (verify email page).""" |
| 1250 | @@ -899,30 +994,44 @@ |
| 1251 | self.click_verify_email_with_valid_data() |
| 1252 | self.assert_pages_visibility(processing=True) |
| 1253 | |
| 1254 | - def test_no_warning_messages_if_valid_data_on_verify_token(self): |
| 1255 | + def test_no_warning_messages_if_valid_data(self): |
| 1256 | """No warning messages are shown if the data is valid.""" |
| 1257 | # this will certainly NOT generate warnings |
| 1258 | self.click_verify_email_with_valid_data() |
| 1259 | - self.assert_warnings_visibility(visible=False) |
| 1260 | + self.assert_warnings_visibility() |
| 1261 | |
| 1262 | def test_on_email_validated_shows_success_page(self): |
| 1263 | """On email validated the success page is shown.""" |
| 1264 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) |
| 1265 | self.assert_pages_visibility(success=True) |
| 1266 | |
| 1267 | - def test_on_email_validated_clears_the_help_text(self): |
| 1268 | - """On email validated the help text is removed.""" |
| 1269 | + def test_on_email_validated_does_not_clear_the_help_text(self): |
| 1270 | + """On email validated the help text is not removed.""" |
| 1271 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) |
| 1272 | - self.assertEqual('', self.ui.help_label.get_text()) |
| 1273 | - test_on_email_validated_clears_the_help_text.skip = 'Maybe this is wrong.' |
| 1274 | + self.assertEqual(self.ui.verify_email_vbox.help_text, |
| 1275 | + self.ui.help_label.get_label()) |
| 1276 | |
| 1277 | def test_on_email_validation_error_verify_email_is_shown(self): |
| 1278 | """On email validation error, the verify_email page is shown.""" |
| 1279 | - self.ui.on_email_validation_error(app_name=APP_NAME, error=ERROR) |
| 1280 | + self.ui.on_email_validation_error(app_name=APP_NAME, error=self.ERROR) |
| 1281 | self.assert_pages_visibility(verify_email=True) |
| 1282 | self.assert_correct_label_warning(self.ui.warning_label, |
| 1283 | self.ui.UNKNOWN_ERROR) |
| 1284 | |
| 1285 | + def test_specific_errors_from_backend_are_shown(self): |
| 1286 | + """Specific errors from backend are used.""" |
| 1287 | + error = {'errtype': 'EmailValidationError', |
| 1288 | + 'message': 'We\'re so doomed.', |
| 1289 | + 'email_token': 'Enter a valid e-mail address.', |
| 1290 | + '__all__': 'We all are gonna die.'} |
| 1291 | + |
| 1292 | + self.ui.on_email_validation_error(app_name=APP_NAME, error=error) |
| 1293 | + |
| 1294 | + expected = '\n'.join((error['__all__'], error['message'])) |
| 1295 | + self.assert_correct_label_warning(self.ui.warning_label, expected) |
| 1296 | + self.assert_correct_entry_warning(self.ui.email_token_entry, |
| 1297 | + error['email_token']) |
| 1298 | + |
| 1299 | def test_success_label_is_correct(self): |
| 1300 | """The success message is correct.""" |
| 1301 | self.assertEqual(self.ui.SUCCESS, self.ui.success_label.get_text()) |
| 1302 | @@ -934,15 +1043,74 @@ |
| 1303 | self.ui.success_close_button.clicked() |
| 1304 | self.assertFalse(self.ui.window.get_property('visible')) |
| 1305 | |
| 1306 | + def test_activate_email_token_entry_clicks_verify_token(self): |
| 1307 | + """Activating any entry generates a connect attempt.""" |
| 1308 | + self.ui.verify_token_button.connect('clicked', self._set_called) |
| 1309 | + self.ui.email_token_entry.activate() |
| 1310 | + self.assertEqual(self._called, ((self.ui.verify_token_button,), {})) |
| 1311 | + |
| 1312 | + def test_verify_token_button_does_nothing_if_clicked_but_disabled(self): |
| 1313 | + """The email token can only be submitted if the button is sensitive.""" |
| 1314 | + self.patch(self.ui.email_token_entry, 'get_text', self._set_called) |
| 1315 | + |
| 1316 | + self.ui.verify_token_button.set_sensitive(False) |
| 1317 | + self.ui.verify_token_button.clicked() |
| 1318 | + self.assertFalse(self._called) |
| 1319 | + |
| 1320 | + self.ui.verify_token_button.set_sensitive(True) |
| 1321 | + self.ui.verify_token_button.clicked() |
| 1322 | + self.assertTrue(self._called) |
| 1323 | + |
| 1324 | + |
| 1325 | +class VerifyEmailValidationTestCase(UbuntuSSOClientTestCase): |
| 1326 | + """Test suite for the user registration (verify email page).""" |
| 1327 | + |
| 1328 | + def setUp(self): |
| 1329 | + """Init.""" |
| 1330 | + super(VerifyEmailValidationTestCase, self).setUp() |
| 1331 | + self.ui.on_user_registered(app_name=APP_NAME, email=EMAIL) |
| 1332 | + |
| 1333 | + def test_warning_is_shown_if_empty_email_token(self): |
| 1334 | + """A warning message is shown if email token is empty.""" |
| 1335 | + self.ui.email_token_entry.set_text('') |
| 1336 | + |
| 1337 | + self.ui.verify_token_button.clicked() |
| 1338 | + |
| 1339 | + self.assert_correct_entry_warning(self.ui.email_token_entry, |
| 1340 | + self.ui.FIELD_REQUIRED) |
| 1341 | + self.assertNotIn('validate_email', self.ui.backend._called) |
| 1342 | + |
| 1343 | + def test_no_warning_messages_if_valid_data(self): |
| 1344 | + """No warning messages are shown if the data is valid.""" |
| 1345 | + # this will certainly NOT generate warnings |
| 1346 | + self.click_verify_email_with_valid_data() |
| 1347 | + |
| 1348 | + self.assert_warnings_visibility() |
| 1349 | + |
| 1350 | + def test_no_warning_messages_if_valid_data_after_invalid_data(self): |
| 1351 | + """No warnings if the data is valid (with prior invalid data).""" |
| 1352 | + # this will certainly generate warnings |
| 1353 | + self.ui.verify_token_button.clicked() |
| 1354 | + |
| 1355 | + # this will certainly NOT generate warnings |
| 1356 | + self.click_verify_email_with_valid_data() |
| 1357 | + |
| 1358 | + self.assert_warnings_visibility() |
| 1359 | + |
| 1360 | |
| 1361 | class RegistrationValidationTestCase(UbuntuSSOClientTestCase): |
| 1362 | """Test suite for the user registration validations.""" |
| 1363 | |
| 1364 | + def setUp(self): |
| 1365 | + """Init.""" |
| 1366 | + super(RegistrationValidationTestCase, self).setUp() |
| 1367 | + self.ui.join_ok_button.set_sensitive(True) |
| 1368 | + |
| 1369 | def test_warning_is_shown_if_name_empty(self): |
| 1370 | """A warning message is shown if name is empty.""" |
| 1371 | self.ui.name_entry.set_text('') |
| 1372 | |
| 1373 | - self.ui.join_ok_button.clicked() # submit form |
| 1374 | + self.ui.join_ok_button.clicked() |
| 1375 | |
| 1376 | self.assert_correct_entry_warning(self.ui.name_entry, |
| 1377 | self.ui.FIELD_REQUIRED) |
| 1378 | @@ -953,7 +1121,7 @@ |
| 1379 | self.ui.email1_entry.set_text('') |
| 1380 | self.ui.email2_entry.set_text('') |
| 1381 | |
| 1382 | - self.ui.join_ok_button.clicked() # submit form |
| 1383 | + self.ui.join_ok_button.clicked() |
| 1384 | |
| 1385 | self.assert_correct_entry_warning(self.ui.email1_entry, |
| 1386 | self.ui.FIELD_REQUIRED) |
| 1387 | @@ -966,7 +1134,7 @@ |
| 1388 | self.ui.email1_entry.set_text(EMAIL) |
| 1389 | self.ui.email2_entry.set_text(EMAIL * 2) |
| 1390 | |
| 1391 | - self.ui.join_ok_button.clicked() # submit form |
| 1392 | + self.ui.join_ok_button.clicked() |
| 1393 | |
| 1394 | self.assert_correct_entry_warning(self.ui.email1_entry, |
| 1395 | self.ui.EMAIL_MISMATCH) |
| 1396 | @@ -979,7 +1147,7 @@ |
| 1397 | self.ui.email1_entry.set_text('q') |
| 1398 | self.ui.email2_entry.set_text('q') |
| 1399 | |
| 1400 | - self.ui.join_ok_button.clicked() # submit form |
| 1401 | + self.ui.join_ok_button.clicked() |
| 1402 | |
| 1403 | self.assert_correct_entry_warning(self.ui.email1_entry, |
| 1404 | self.ui.EMAIL_INVALID) |
| 1405 | @@ -1000,7 +1168,7 @@ |
| 1406 | self.ui.password1_entry.set_text(PASSWORD) |
| 1407 | self.ui.password2_entry.set_text(PASSWORD * 2) |
| 1408 | |
| 1409 | - self.ui.join_ok_button.clicked() # submit form |
| 1410 | + self.ui.join_ok_button.clicked() |
| 1411 | |
| 1412 | self.assert_correct_entry_warning(self.ui.password1_entry, |
| 1413 | self.ui.PASSWORD_MISMATCH) |
| 1414 | @@ -1015,7 +1183,7 @@ |
| 1415 | self.ui.password1_entry.set_text(w) |
| 1416 | self.ui.password2_entry.set_text(w) |
| 1417 | |
| 1418 | - self.ui.join_ok_button.clicked() # submit form |
| 1419 | + self.ui.join_ok_button.clicked() |
| 1420 | |
| 1421 | self.assert_correct_entry_warning(self.ui.password1_entry, |
| 1422 | self.ui.PASSWORD_TOO_WEAK) |
| 1423 | @@ -1028,7 +1196,7 @@ |
| 1424 | # don't agree to TC |
| 1425 | self.ui.yes_to_tc_checkbutton.set_active(False) |
| 1426 | |
| 1427 | - self.ui.join_ok_button.clicked() # submit form |
| 1428 | + self.ui.join_ok_button.clicked() |
| 1429 | |
| 1430 | self.assert_correct_label_warning(self.ui.tc_warning_label, |
| 1431 | self.ui.TC_NOT_ACCEPTED) |
| 1432 | @@ -1039,18 +1207,18 @@ |
| 1433 | # captcha solution will be empty |
| 1434 | self.ui.captcha_solution_entry.set_text('') |
| 1435 | |
| 1436 | - self.ui.join_ok_button.clicked() # submit form |
| 1437 | + self.ui.join_ok_button.clicked() |
| 1438 | |
| 1439 | self.assert_correct_entry_warning(self.ui.captcha_solution_entry, |
| 1440 | self.ui.FIELD_REQUIRED) |
| 1441 | self.assertNotIn('register_user', self.ui.backend._called) |
| 1442 | |
| 1443 | - def test_no_warning_messages_if_valid_data_on_enter_details(self): |
| 1444 | + def test_no_warning_messages_if_valid_data(self): |
| 1445 | """No warning messages are shown if the data is valid.""" |
| 1446 | # this will certainly NOT generate warnings |
| 1447 | self.click_join_with_valid_data() |
| 1448 | |
| 1449 | - self.assert_warnings_visibility(visible=False) |
| 1450 | + self.assert_warnings_visibility() |
| 1451 | |
| 1452 | def test_no_warning_messages_if_valid_data_after_invalid_data(self): |
| 1453 | """No warnings if the data is valid (with prior invalid data).""" |
| 1454 | @@ -1060,7 +1228,7 @@ |
| 1455 | # this will certainly NOT generate warnings |
| 1456 | self.click_join_with_valid_data() |
| 1457 | |
| 1458 | - self.assert_warnings_visibility(visible=False) |
| 1459 | + self.assert_warnings_visibility() |
| 1460 | |
| 1461 | |
| 1462 | class LoginTestCase(UbuntuSSOClientTestCase): |
| 1463 | @@ -1136,23 +1304,58 @@ |
| 1464 | def test_on_login_error_morphs_to_login_page(self): |
| 1465 | """On user login error, the previous page is shown.""" |
| 1466 | self.click_connect_with_valid_data() |
| 1467 | - self.ui.on_login_error(app_name=APP_NAME, error=ERROR) |
| 1468 | + self.ui.on_login_error(app_name=APP_NAME, error=self.ERROR) |
| 1469 | self.assert_pages_visibility(login=True) |
| 1470 | |
| 1471 | def test_on_login_error_a_warning_is_shown(self): |
| 1472 | """On user login error, a warning is shown with proper wording.""" |
| 1473 | self.click_connect_with_valid_data() |
| 1474 | - self.ui.on_login_error(app_name=APP_NAME, error=ERROR) |
| 1475 | + self.ui.on_login_error(app_name=APP_NAME, error=self.ERROR) |
| 1476 | self.assert_correct_label_warning(self.ui.warning_label, |
| 1477 | self.ui.UNKNOWN_ERROR) |
| 1478 | |
| 1479 | + def test_specific_errors_from_backend_are_shown(self): |
| 1480 | + """Specific errors from backend are used.""" |
| 1481 | + error = {'errtype': 'AuthenticationError', |
| 1482 | + 'message': 'We\'re so doomed.', |
| 1483 | + '__all__': 'We all are gonna die.'} |
| 1484 | + |
| 1485 | + self.ui.on_login_error(app_name=APP_NAME, error=error) |
| 1486 | + |
| 1487 | + expected = '\n'.join((error['__all__'], error['message'])) |
| 1488 | + self.assert_correct_label_warning(self.ui.warning_label, expected) |
| 1489 | + |
| 1490 | def test_back_to_registration_hides_warning(self): |
| 1491 | """After user login error, warning is hidden when clicking 'Back'.""" |
| 1492 | self.click_connect_with_valid_data() |
| 1493 | - self.ui.on_login_error(app_name=APP_NAME, error=ERROR) |
| 1494 | + self.ui.on_login_error(app_name=APP_NAME, error=self.ERROR) |
| 1495 | self.ui.login_back_button.clicked() |
| 1496 | self.assertFalse(self.ui.warning_label.get_property('visible')) |
| 1497 | |
| 1498 | + def test_activate_email_entry_clicks_login(self): |
| 1499 | + """Activating any entry generates a connect attempt.""" |
| 1500 | + self.ui.login_ok_button.connect('clicked', self._set_called) |
| 1501 | + self.ui.login_email_entry.activate() |
| 1502 | + self.assertEqual(self._called, ((self.ui.login_ok_button,), {})) |
| 1503 | + |
| 1504 | + def test_activate_password_entry_clicks_login(self): |
| 1505 | + """Activating any entry generates a connect attempt.""" |
| 1506 | + self.ui.login_ok_button.connect('clicked', self._set_called) |
| 1507 | + self.ui.login_password_entry.activate() |
| 1508 | + self.assertEqual(self._called, ((self.ui.login_ok_button,), {})) |
| 1509 | + |
| 1510 | + def test_login_ok_button_does_nothing_if_clicked_but_disabled(self): |
| 1511 | + """The join form can only be submitted if the button is sensitive.""" |
| 1512 | + self.patch(self.ui.login_email_entry, 'get_text', self._set_called) |
| 1513 | + |
| 1514 | + self.ui.login_ok_button.set_sensitive(False) |
| 1515 | + self.ui.login_ok_button.clicked() |
| 1516 | + self.assertFalse(self._called) |
| 1517 | + |
| 1518 | + self.ui.login_ok_button.set_sensitive(True) |
| 1519 | + self.ui.login_ok_button.clicked() |
| 1520 | + self.assertTrue(self._called) |
| 1521 | + |
| 1522 | |
| 1523 | class LoginValidationTestCase(UbuntuSSOClientTestCase): |
| 1524 | """Test suite for the user login validation.""" |
| 1525 | @@ -1166,7 +1369,7 @@ |
| 1526 | """A warning message is shown if email is empty.""" |
| 1527 | self.ui.login_email_entry.set_text('') |
| 1528 | |
| 1529 | - self.ui.login_ok_button.clicked() # submit form |
| 1530 | + self.ui.login_ok_button.clicked() |
| 1531 | |
| 1532 | self.assert_correct_entry_warning(self.ui.login_email_entry, |
| 1533 | self.ui.FIELD_REQUIRED) |
| 1534 | @@ -1176,7 +1379,7 @@ |
| 1535 | """A warning message is shown if email is invalid.""" |
| 1536 | self.ui.login_email_entry.set_text('q') |
| 1537 | |
| 1538 | - self.ui.login_ok_button.clicked() # submit form |
| 1539 | + self.ui.login_ok_button.clicked() |
| 1540 | |
| 1541 | self.assert_correct_entry_warning(self.ui.login_email_entry, |
| 1542 | self.ui.EMAIL_INVALID) |
| 1543 | @@ -1186,7 +1389,7 @@ |
| 1544 | """A warning message is shown if password is empty.""" |
| 1545 | self.ui.login_password_entry.set_text('') |
| 1546 | |
| 1547 | - self.ui.login_ok_button.clicked() # submit form |
| 1548 | + self.ui.login_ok_button.clicked() |
| 1549 | |
| 1550 | self.assert_correct_entry_warning(self.ui.login_password_entry, |
| 1551 | self.ui.FIELD_REQUIRED) |
| 1552 | @@ -1197,7 +1400,7 @@ |
| 1553 | # this will certainly NOT generate warnings |
| 1554 | self.click_connect_with_valid_data() |
| 1555 | |
| 1556 | - self.assert_warnings_visibility(visible=False) |
| 1557 | + self.assert_warnings_visibility() |
| 1558 | |
| 1559 | def test_no_warning_messages_if_valid_data_after_invalid_data(self): |
| 1560 | """No warnings if the data is valid (with prior invalid data).""" |
| 1561 | @@ -1207,7 +1410,7 @@ |
| 1562 | # this will certainly NOT generate warnings |
| 1563 | self.click_connect_with_valid_data() |
| 1564 | |
| 1565 | - self.assert_warnings_visibility(visible=False) |
| 1566 | + self.assert_warnings_visibility() |
| 1567 | |
| 1568 | |
| 1569 | class ResetPasswordTestCase(UbuntuSSOClientTestCase): |
| 1570 | @@ -1301,11 +1504,86 @@ |
| 1571 | |
| 1572 | def test_on_password_reset_error_shows_login_page(self): |
| 1573 | """When reset token wasn't successfuly sent the login page is shown.""" |
| 1574 | - self.ui.on_password_reset_error(app_name=APP_NAME, error=ERROR) |
| 1575 | + self.ui.on_password_reset_error(app_name=APP_NAME, error=self.ERROR) |
| 1576 | self.assert_correct_label_warning(self.ui.warning_label, |
| 1577 | self.ui.UNKNOWN_ERROR) |
| 1578 | self.assert_pages_visibility(login=True) |
| 1579 | |
| 1580 | + def test_specific_errors_from_backend_are_shown(self): |
| 1581 | + """Specific errors from backend are used.""" |
| 1582 | + error = {'errtype': 'ResetPasswordTokenError', |
| 1583 | + 'message': 'We\'re so doomed.', |
| 1584 | + '__all__': 'We all are gonna die.'} |
| 1585 | + |
| 1586 | + self.ui.on_password_reset_error(app_name=APP_NAME, error=error) |
| 1587 | + |
| 1588 | + expected = '\n'.join((error['__all__'], error['message'])) |
| 1589 | + self.assert_correct_label_warning(self.ui.warning_label, expected) |
| 1590 | + |
| 1591 | + def test_activate_reset_email_entry_clicks_login(self): |
| 1592 | + """Activating any entry generates a connect attempt.""" |
| 1593 | + self.ui.request_password_token_ok_button.connect('clicked', |
| 1594 | + self._set_called) |
| 1595 | + self.ui.reset_email_entry.activate() |
| 1596 | + self.assertEqual(self._called, |
| 1597 | + ((self.ui.request_password_token_ok_button,), {})) |
| 1598 | + |
| 1599 | + def test_ok_button_does_nothing_if_clicked_but_disabled(self): |
| 1600 | + """The password token can be requested if the button is sensitive.""" |
| 1601 | + self.patch(self.ui.reset_email_entry, 'get_text', self._set_called) |
| 1602 | + |
| 1603 | + self.ui.request_password_token_ok_button.set_sensitive(False) |
| 1604 | + self.ui.request_password_token_ok_button.clicked() |
| 1605 | + self.assertFalse(self._called) |
| 1606 | + |
| 1607 | + self.ui.request_password_token_ok_button.set_sensitive(True) |
| 1608 | + self.ui.request_password_token_ok_button.clicked() |
| 1609 | + self.assertTrue(self._called) |
| 1610 | + |
| 1611 | + |
| 1612 | +class ResetPasswordValidationTestCase(UbuntuSSOClientTestCase): |
| 1613 | + """Test suite for the password reset validations.""" |
| 1614 | + |
| 1615 | + def test_warning_is_shown_if_empty_email(self): |
| 1616 | + """A warning message is shown if emails are empty.""" |
| 1617 | + self.ui.reset_email_entry.set_text(' ') |
| 1618 | + |
| 1619 | + self.ui.request_password_token_ok_button.set_sensitive(True) |
| 1620 | + self.ui.request_password_token_ok_button.clicked() |
| 1621 | + |
| 1622 | + self.assert_correct_entry_warning(self.ui.reset_email_entry, |
| 1623 | + self.ui.FIELD_REQUIRED) |
| 1624 | + self.assertNotIn('request_password_reset_token', |
| 1625 | + self.ui.backend._called) |
| 1626 | + |
| 1627 | + def test_warning_is_shown_if_invalid_email(self): |
| 1628 | + """A warning message is shown if email is invalid.""" |
| 1629 | + self.ui.reset_email_entry.set_text('q') |
| 1630 | + |
| 1631 | + self.ui.request_password_token_ok_button.clicked() |
| 1632 | + |
| 1633 | + self.assert_correct_entry_warning(self.ui.reset_email_entry, |
| 1634 | + self.ui.EMAIL_INVALID) |
| 1635 | + self.assertNotIn('request_password_reset_token', |
| 1636 | + self.ui.backend._called) |
| 1637 | + |
| 1638 | + def test_no_warning_messages_if_valid_data(self): |
| 1639 | + """No warning messages are shown if the data is valid.""" |
| 1640 | + # this will certainly NOT generate warnings |
| 1641 | + self.click_request_password_token_with_valid_data() |
| 1642 | + |
| 1643 | + self.assert_warnings_visibility() |
| 1644 | + |
| 1645 | + def test_no_warning_messages_if_valid_data_after_invalid_data(self): |
| 1646 | + """No warnings if the data is valid (with prior invalid data).""" |
| 1647 | + # this will certainly generate warnings |
| 1648 | + self.ui.request_password_token_ok_button.clicked() |
| 1649 | + |
| 1650 | + # this will certainly NOT generate warnings |
| 1651 | + self.click_request_password_token_with_valid_data() |
| 1652 | + |
| 1653 | + self.assert_warnings_visibility() |
| 1654 | + |
| 1655 | |
| 1656 | class SetNewPasswordTestCase(UbuntuSSOClientTestCase): |
| 1657 | """Test suite for setting a new password functionality.""" |
| 1658 | @@ -1358,11 +1636,123 @@ |
| 1659 | |
| 1660 | def test_on_password_change_error_shows_login_page(self): |
| 1661 | """When password wasn't changed the reset password page is shown.""" |
| 1662 | - self.ui.on_password_change_error(app_name=APP_NAME, error=ERROR) |
| 1663 | + self.ui.on_password_change_error(app_name=APP_NAME, error=self.ERROR) |
| 1664 | self.assert_correct_label_warning(self.ui.warning_label, |
| 1665 | self.ui.UNKNOWN_ERROR) |
| 1666 | self.assert_pages_visibility(request_password_token=True) |
| 1667 | |
| 1668 | + def test_specific_errors_from_backend_are_shown(self): |
| 1669 | + """Specific errors from backend are used.""" |
| 1670 | + error = {'errtype': 'NewPasswordError', |
| 1671 | + 'message': 'We\'re so doomed.', |
| 1672 | + '__all__': 'We all are gonna die.'} |
| 1673 | + |
| 1674 | + self.ui.on_password_change_error(app_name=APP_NAME, error=error) |
| 1675 | + |
| 1676 | + expected = '\n'.join((error['__all__'], error['message'])) |
| 1677 | + self.assert_correct_label_warning(self.ui.warning_label, expected) |
| 1678 | + |
| 1679 | + def test_activate_reset_code_entry_clicks_set_new_password(self): |
| 1680 | + """Activating any entry generates a connect attempt.""" |
| 1681 | + self.ui.set_new_password_ok_button.connect('clicked', self._set_called) |
| 1682 | + self.ui.reset_code_entry.activate() |
| 1683 | + self.assertEqual(self._called, |
| 1684 | + ((self.ui.set_new_password_ok_button,), {})) |
| 1685 | + |
| 1686 | + def test_activate_password_entry_clicks_set_new_password(self): |
| 1687 | + """Activating any entry generates a connect attempt.""" |
| 1688 | + self.ui.set_new_password_ok_button.connect('clicked', self._set_called) |
| 1689 | + self.ui.reset_password1_entry.activate() |
| 1690 | + self.assertEqual(self._called, |
| 1691 | + ((self.ui.set_new_password_ok_button,), {})) |
| 1692 | + |
| 1693 | + self._called = False |
| 1694 | + self.ui.reset_password2_entry.activate() |
| 1695 | + self.assertEqual(self._called, |
| 1696 | + ((self.ui.set_new_password_ok_button,), {})) |
| 1697 | + |
| 1698 | + def test_ok_button_does_nothing_if_clicked_but_disabled(self): |
| 1699 | + """The new passwrd can only be set if the button is sensitive.""" |
| 1700 | + self.patch(self.ui.reset_code_entry, 'get_text', self._set_called) |
| 1701 | + |
| 1702 | + self.ui.set_new_password_ok_button.set_sensitive(False) |
| 1703 | + self.ui.set_new_password_ok_button.clicked() |
| 1704 | + self.assertFalse(self._called) |
| 1705 | + |
| 1706 | + self.ui.set_new_password_ok_button.set_sensitive(True) |
| 1707 | + self.ui.set_new_password_ok_button.clicked() |
| 1708 | + self.assertTrue(self._called) |
| 1709 | + |
| 1710 | + |
| 1711 | +class SetNewPasswordValidationTestCase(UbuntuSSOClientTestCase): |
| 1712 | + """Test suite for validations for setting a new password.""" |
| 1713 | + |
| 1714 | + def test_warning_is_shown_if_reset_code_empty(self): |
| 1715 | + """A warning message is shown if reset_code is empty.""" |
| 1716 | + self.ui.reset_code_entry.set_text('') |
| 1717 | + |
| 1718 | + self.ui.set_new_password_ok_button.set_sensitive(True) |
| 1719 | + self.ui.set_new_password_ok_button.clicked() |
| 1720 | + |
| 1721 | + self.assert_correct_entry_warning(self.ui.reset_code_entry, |
| 1722 | + self.ui.FIELD_REQUIRED) |
| 1723 | + self.assertNotIn('set_new_password', self.ui.backend._called) |
| 1724 | + |
| 1725 | + def test_password_help_is_always_shown(self): |
| 1726 | + """Password help text is correctly displayed.""" |
| 1727 | + visible = self.ui.reset_password_help_label.get_property('visible') |
| 1728 | + self.assertTrue(visible, 'password help text is visible.') |
| 1729 | + self.assertEqual(self.ui.reset_password_help_label.get_text(), |
| 1730 | + self.ui.PASSWORD_HELP) |
| 1731 | + self.assertNotIn('set_new_password', self.ui.backend._called) |
| 1732 | + |
| 1733 | + def test_warning_is_shown_if_password_mismatch(self): |
| 1734 | + """A warning message is shown if password doesn't match.""" |
| 1735 | + self.ui.reset_password1_entry.set_text(PASSWORD) |
| 1736 | + self.ui.reset_password2_entry.set_text(PASSWORD * 2) |
| 1737 | + |
| 1738 | + self.ui.set_new_password_ok_button.set_sensitive(True) |
| 1739 | + self.ui.set_new_password_ok_button.clicked() |
| 1740 | + |
| 1741 | + self.assert_correct_entry_warning(self.ui.reset_password1_entry, |
| 1742 | + self.ui.PASSWORD_MISMATCH) |
| 1743 | + self.assert_correct_entry_warning(self.ui.reset_password2_entry, |
| 1744 | + self.ui.PASSWORD_MISMATCH) |
| 1745 | + self.assertNotIn('set_new_password', self.ui.backend._called) |
| 1746 | + |
| 1747 | + def test_warning_is_shown_if_password_too_weak(self): |
| 1748 | + """A warning message is shown if password is too weak.""" |
| 1749 | + # password will match but will be too weak |
| 1750 | + for w in ('', 'h3lloWo', PASSWORD.lower(), 'helloWorld'): |
| 1751 | + self.ui.reset_password1_entry.set_text(w) |
| 1752 | + self.ui.reset_password2_entry.set_text(w) |
| 1753 | + |
| 1754 | + self.ui.set_new_password_ok_button.set_sensitive(True) |
| 1755 | + self.ui.set_new_password_ok_button.clicked() |
| 1756 | + |
| 1757 | + self.assert_correct_entry_warning(self.ui.reset_password1_entry, |
| 1758 | + self.ui.PASSWORD_TOO_WEAK) |
| 1759 | + self.assert_correct_entry_warning(self.ui.reset_password2_entry, |
| 1760 | + self.ui.PASSWORD_TOO_WEAK) |
| 1761 | + self.assertNotIn('set_new_password', self.ui.backend._called) |
| 1762 | + |
| 1763 | + def test_no_warning_messages_if_valid_data(self): |
| 1764 | + """No warning messages are shown if the data is valid.""" |
| 1765 | + # this will certainly NOT generate warnings |
| 1766 | + self.click_set_new_password_with_valid_data() |
| 1767 | + |
| 1768 | + self.assert_warnings_visibility() |
| 1769 | + |
| 1770 | + def test_no_warning_messages_if_valid_data_after_invalid_data(self): |
| 1771 | + """No warnings if the data is valid (with prior invalid data).""" |
| 1772 | + # this will certainly generate warnings |
| 1773 | + self.ui.set_new_password_ok_button.clicked() |
| 1774 | + |
| 1775 | + # this will certainly NOT generate warnings |
| 1776 | + self.click_set_new_password_with_valid_data() |
| 1777 | + |
| 1778 | + self.assert_warnings_visibility() |
| 1779 | + |
| 1780 | |
| 1781 | class DbusTestCase(UbuntuSSOClientTestCase): |
| 1782 | """Test suite for the dbus calls.""" |
| 1783 | @@ -1408,6 +1798,10 @@ |
| 1784 | """The login_ok_button has the focus.""" |
| 1785 | self.assertTrue(self.ui.login_ok_button.is_focus()) |
| 1786 | |
| 1787 | + def test_help_text_is_used(self): |
| 1788 | + """The passed help_text is used.""" |
| 1789 | + self.assertEqual(self.ui.help_label.get_text(), HELP_TEXT) |
| 1790 | + |
| 1791 | |
| 1792 | class SignalsTestCase(UbuntuSSOClientTestCase): |
| 1793 | |
| 1794 | @@ -1438,9 +1832,10 @@ |
| 1795 | |
| 1796 | def test_on_user_registration_error_proper_signal_is_emitted(self): |
| 1797 | """On UserRegistrationError, 'registration-failed' signal is sent.""" |
| 1798 | - self.ui.on_user_registration_error(app_name=APP_NAME, error=ERROR) |
| 1799 | + self.ui.on_user_registration_error(app_name=APP_NAME, error=self.ERROR) |
| 1800 | self.ui.on_close_clicked() |
| 1801 | - self.assertEqual((self.ui.window, (APP_NAME, ERROR), {}), |
| 1802 | + expected = (self.ui.window, (APP_NAME, self.ui.UNKNOWN_ERROR), {}) |
| 1803 | + self.assertEqual(expected, |
| 1804 | self._called[gui.SIG_REGISTRATION_FAILED]) |
| 1805 | |
| 1806 | def test_on_email_validated_proper_signals_is_emitted(self): |
| 1807 | @@ -1452,10 +1847,11 @@ |
| 1808 | |
| 1809 | def test_on_email_validation_error_proper_signals_is_emitted(self): |
| 1810 | """On EmailValidationError, 'registration-failed' signal is sent.""" |
| 1811 | - self.ui.on_email_validation_error(app_name=APP_NAME, error=ERROR) |
| 1812 | + self.ui.on_email_validation_error(app_name=APP_NAME, error=self.ERROR) |
| 1813 | self.ui.on_close_clicked() |
| 1814 | - self.assertEqual((self.ui.window, (APP_NAME, ERROR), {}), |
| 1815 | - self._called[gui.SIG_REGISTRATION_FAILED]) |
| 1816 | + expected = (self.ui.window, (APP_NAME, self.ui.UNKNOWN_ERROR), {}) |
| 1817 | + self.assertEqual(expected, |
| 1818 | + self._called[gui.SIG_REGISTRATION_FAILED]) |
| 1819 | |
| 1820 | def test_on_logged_in_proper_signals_is_emitted(self): |
| 1821 | """On LoggedIn, 'login-succeeded' signal is sent.""" |
| 1822 | @@ -1467,15 +1863,16 @@ |
| 1823 | def test_on_login_error_proper_signals_is_emitted(self): |
| 1824 | """On LoginError, 'login-failed' signal is sent.""" |
| 1825 | self.click_connect_with_valid_data() |
| 1826 | - self.ui.on_login_error(app_name=APP_NAME, error=ERROR) |
| 1827 | + self.ui.on_login_error(app_name=APP_NAME, error=self.ERROR) |
| 1828 | self.ui.on_close_clicked() |
| 1829 | - self.assertEqual((self.ui.window, (APP_NAME, ERROR), {}), |
| 1830 | - self._called[gui.SIG_LOGIN_FAILED]) |
| 1831 | + expected = (self.ui.window, (APP_NAME, self.ui.UNKNOWN_ERROR), {}) |
| 1832 | + self.assertEqual(expected, |
| 1833 | + self._called[gui.SIG_LOGIN_FAILED]) |
| 1834 | |
| 1835 | def test_registration_successfull_even_if_prior_registration_error(self): |
| 1836 | """Only one signal is sent with the final outcome.""" |
| 1837 | self.click_join_with_valid_data() |
| 1838 | - self.ui.on_user_registration_error(app_name=APP_NAME, error=ERROR) |
| 1839 | + self.ui.on_user_registration_error(app_name=APP_NAME, error=self.ERROR) |
| 1840 | self.click_join_with_valid_data() |
| 1841 | self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL) |
| 1842 | self.ui.on_close_clicked() |
| 1843 | @@ -1486,7 +1883,7 @@ |
| 1844 | def test_login_successfull_even_if_prior_login_error(self): |
| 1845 | """Only one signal is sent with the final outcome.""" |
| 1846 | self.click_connect_with_valid_data() |
| 1847 | - self.ui.on_login_error(app_name=APP_NAME, error=ERROR) |
| 1848 | + self.ui.on_login_error(app_name=APP_NAME, error=self.ERROR) |
| 1849 | self.click_connect_with_valid_data() |
| 1850 | self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL) |
| 1851 | self.ui.on_close_clicked() |
| 1852 | @@ -1497,7 +1894,7 @@ |
| 1853 | def test_user_cancelation_even_if_prior_registration_error(self): |
| 1854 | """Only one signal is sent with the final outcome.""" |
| 1855 | self.click_join_with_valid_data() |
| 1856 | - self.ui.on_user_registration_error(app_name=APP_NAME, error=ERROR) |
| 1857 | + self.ui.on_user_registration_error(app_name=APP_NAME, error=self.ERROR) |
| 1858 | self.ui.join_cancel_button.clicked() |
| 1859 | |
| 1860 | self.assertEqual(len(self._called), 1) |
| 1861 | @@ -1506,7 +1903,7 @@ |
| 1862 | def test_user_cancelation_even_if_prior_login_error(self): |
| 1863 | """Only one signal is sent with the final outcome.""" |
| 1864 | self.click_connect_with_valid_data() |
| 1865 | - self.ui.on_login_error(app_name=APP_NAME, error=ERROR) |
| 1866 | + self.ui.on_login_error(app_name=APP_NAME, error=self.ERROR) |
| 1867 | self.ui.login_cancel_button.clicked() |
| 1868 | |
| 1869 | self.assertEqual(len(self._called), 1) |
| 1870 | |
| 1871 | === modified file 'ubuntu_sso/tests/test_keyring.py' |
| 1872 | --- ubuntu_sso/tests/test_keyring.py 2010-08-19 16:02:09 +0000 |
| 1873 | +++ ubuntu_sso/tests/test_keyring.py 2010-08-27 22:32:43 +0000 |
| 1874 | @@ -17,24 +17,39 @@ |
| 1875 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1876 | """Tests for the keyring.py module.""" |
| 1877 | |
| 1878 | +import itertools |
| 1879 | +import socket |
| 1880 | +import urllib |
| 1881 | + |
| 1882 | import gnomekeyring |
| 1883 | from twisted.trial.unittest import TestCase |
| 1884 | |
| 1885 | from ubuntu_sso import keyring |
| 1886 | |
| 1887 | |
| 1888 | -class MockInfoSync(object): |
| 1889 | - """A mock object that represents a fake key.""" |
| 1890 | - |
| 1891 | - def __init__(self, (key, key_name, secret)): |
| 1892 | +def build_fake_gethostname(fake_hostname): |
| 1893 | + """Return a fake hostname getter.""" |
| 1894 | + return lambda *a: fake_hostname |
| 1895 | + |
| 1896 | + |
| 1897 | +class MockKeyringItem(object): |
| 1898 | + """A mock object that fakes an item found in a keyring search.""" |
| 1899 | + |
| 1900 | + def __init__(self, item_id, keyring, attributes, secret): |
| 1901 | """Initialize this instance.""" |
| 1902 | - self.key = key |
| 1903 | - self.key_name = key_name |
| 1904 | + self.item_id = item_id |
| 1905 | + self.keyring = keyring |
| 1906 | + self.attributes = attributes |
| 1907 | self.secret = secret |
| 1908 | |
| 1909 | - def get_display_name(self): |
| 1910 | - """Return info on the mocked object.""" |
| 1911 | - return self.key_name |
| 1912 | + def matches(self, search_attr): |
| 1913 | + """See if this item matches a given search.""" |
| 1914 | + for k, v in search_attr.items(): |
| 1915 | + if k not in self.attributes: |
| 1916 | + return False |
| 1917 | + if self.attributes[k] != v: |
| 1918 | + return False |
| 1919 | + return True |
| 1920 | |
| 1921 | |
| 1922 | class MockGnomeKeyring(object): |
| 1923 | @@ -43,28 +58,33 @@ |
| 1924 | def __init__(self): |
| 1925 | """Initialize this instance.""" |
| 1926 | self.keyrings = set() |
| 1927 | - self.store = [] |
| 1928 | + self.id_counter = itertools.count() |
| 1929 | + self.store = {} |
| 1930 | self.deleted = [] |
| 1931 | |
| 1932 | + def _get_next_id(self): |
| 1933 | + """Return the next keyring id.""" |
| 1934 | + return self.id_counter.next() |
| 1935 | + |
| 1936 | def item_create_sync(self, keyring_name, item_type, key_name, attr, |
| 1937 | secret, update_if_exists): |
| 1938 | - """Sets a value in the keyring.""" |
| 1939 | - # we'll use the attr as the dict key, so make it a tuple |
| 1940 | - key = tuple(attr.items()) |
| 1941 | - self.store.append((key, key_name, secret)) |
| 1942 | + """Add a key to a keyring.""" |
| 1943 | + new_id = self._get_next_id() |
| 1944 | + i = MockKeyringItem(new_id, keyring_name, attr, secret) |
| 1945 | + self.store[new_id] = i |
| 1946 | |
| 1947 | def item_delete_sync(self, keyring_name, item_id): |
| 1948 | - """Makes a list of deleted items.""" |
| 1949 | - key, key_name, secret = self.store.pop(item_id) |
| 1950 | - self.deleted.append(key_name) |
| 1951 | - |
| 1952 | - def list_item_ids_sync(self, keyring_name): |
| 1953 | - """Return a list of ids for all the items.""" |
| 1954 | - return [n for n, v in enumerate(self.store)] |
| 1955 | - |
| 1956 | - def item_get_info_sync(self, keyring_name, item_id): |
| 1957 | - """Return an info sync object for the item.""" |
| 1958 | - return MockInfoSync(self.store[item_id]) |
| 1959 | + """Delete a key from a keyring, and keep a list of deleted keys.""" |
| 1960 | + item = self.store.pop(item_id) |
| 1961 | + assert keyring_name == item.keyring |
| 1962 | + self.deleted.append(item) |
| 1963 | + |
| 1964 | + def find_items_sync(self, item_type, attr): |
| 1965 | + """Find all keys that match the given attributes.""" |
| 1966 | + items = [i for i in self.store.values() if i.matches(attr)] |
| 1967 | + if len(items) == 0: |
| 1968 | + raise gnomekeyring.NoMatchError() |
| 1969 | + return items |
| 1970 | |
| 1971 | def list_keyring_names_sync(self): |
| 1972 | """The keyring you are looking for may be here.""" |
| 1973 | @@ -79,6 +99,32 @@ |
| 1974 | return True |
| 1975 | |
| 1976 | |
| 1977 | +class TestTokenNameBuilder(TestCase): |
| 1978 | + """Test the method that builds the token name.""" |
| 1979 | + |
| 1980 | + def test_get_simple_token_name(self): |
| 1981 | + """A simple token name is built right.""" |
| 1982 | + sample_app_name = "UbuntuTwo" |
| 1983 | + sample_hostname = "Darkstar" |
| 1984 | + expected_result = "UbuntuTwo - Darkstar" |
| 1985 | + |
| 1986 | + fake_gethostname = build_fake_gethostname(sample_hostname) |
| 1987 | + self.patch(socket, "gethostname", fake_gethostname) |
| 1988 | + result = keyring.get_token_name(sample_app_name) |
| 1989 | + self.assertEqual(result, expected_result) |
| 1990 | + |
| 1991 | + def test_get_complex_token_name(self): |
| 1992 | + """A complex token name is built right too.""" |
| 1993 | + sample_app_name = "Ubuntu Eleven" |
| 1994 | + sample_hostname = "Mate+Cocido" |
| 1995 | + expected_result = "Ubuntu%20Eleven - Mate%2BCocido" |
| 1996 | + |
| 1997 | + fake_gethostname = build_fake_gethostname(sample_hostname) |
| 1998 | + self.patch(socket, "gethostname", fake_gethostname) |
| 1999 | + result = keyring.get_token_name(sample_app_name) |
| 2000 | + self.assertEqual(result, expected_result) |
| 2001 | + |
| 2002 | + |
| 2003 | class TestKeyring(TestCase): |
| 2004 | """Test the gnome keyring related functions.""" |
| 2005 | def setUp(self): |
| 2006 | @@ -89,11 +135,10 @@ |
| 2007 | self.patch(gnomekeyring, "create_sync", self.mgk.create_sync) |
| 2008 | self.patch(gnomekeyring, "list_keyring_names_sync", |
| 2009 | self.mgk.list_keyring_names_sync) |
| 2010 | - self.patch(gnomekeyring, "list_item_ids_sync", |
| 2011 | - self.mgk.list_item_ids_sync) |
| 2012 | - self.patch(gnomekeyring, "item_get_info_sync", |
| 2013 | - self.mgk.item_get_info_sync) |
| 2014 | + self.patch(gnomekeyring, "find_items_sync", self.mgk.find_items_sync) |
| 2015 | self.patch(gnomekeyring, "item_delete_sync", self.mgk.item_delete_sync) |
| 2016 | + fake_gethostname = build_fake_gethostname("darkstar") |
| 2017 | + self.patch(socket, "gethostname", fake_gethostname) |
| 2018 | |
| 2019 | def test_set_ubuntusso(self): |
| 2020 | """Test that the set method does not erase previous keys.""" |
| 2021 | @@ -113,3 +158,54 @@ |
| 2022 | |
| 2023 | self.assertEqual(len(self.mgk.store), 0) |
| 2024 | self.assertEqual(len(self.mgk.deleted), 1) |
| 2025 | + |
| 2026 | + def test_get_credentials(self): |
| 2027 | + """Test that credentials are properly retrieved.""" |
| 2028 | + sample_creds = {"name": "sample creds name"} |
| 2029 | + keyring.Keyring("appname").set_ubuntusso_attr(sample_creds) |
| 2030 | + |
| 2031 | + result = keyring.Keyring("appname").get_ubuntusso_attr() |
| 2032 | + self.assertEqual(result, sample_creds) |
| 2033 | + |
| 2034 | + def test_get_old_cred_found(self): |
| 2035 | + """The method returns a new set of creds if old creds are found.""" |
| 2036 | + sample_oauth_token = "sample oauth token" |
| 2037 | + sample_oauth_secret = "sample oauth secret" |
| 2038 | + old_creds = { |
| 2039 | + "oauth_token": sample_oauth_token, |
| 2040 | + "oauth_token_secret": sample_oauth_secret, |
| 2041 | + } |
| 2042 | + secret = urllib.urlencode(old_creds) |
| 2043 | + self.mgk.item_create_sync(keyring.U1_APP_NAME, None, |
| 2044 | + keyring.Keyring.KEYRING_NAME, |
| 2045 | + keyring.U1_KEY_ATTR, |
| 2046 | + secret, True) |
| 2047 | + |
| 2048 | + result = keyring.Keyring(keyring.U1_APP_NAME).get_ubuntusso_attr() |
| 2049 | + |
| 2050 | + self.assertIn("token", result) |
| 2051 | + self.assertEqual(result["token"], sample_oauth_token) |
| 2052 | + self.assertIn("token_secret", result) |
| 2053 | + self.assertEqual(result["token_secret"], sample_oauth_secret) |
| 2054 | + |
| 2055 | + def test_get_old_cred_found_but_not_asked_for(self): |
| 2056 | + """Returns None if old creds are present but the appname is not U1""" |
| 2057 | + sample_oauth_token = "sample oauth token" |
| 2058 | + sample_oauth_secret = "sample oauth secret" |
| 2059 | + old_creds = { |
| 2060 | + "oauth_token": sample_oauth_token, |
| 2061 | + "oauth_token_secret": sample_oauth_secret, |
| 2062 | + } |
| 2063 | + secret = urllib.urlencode(old_creds) |
| 2064 | + self.mgk.item_create_sync(keyring.U1_APP_NAME, None, |
| 2065 | + keyring.Keyring.KEYRING_NAME, |
| 2066 | + keyring.U1_KEY_ATTR, |
| 2067 | + secret, True) |
| 2068 | + |
| 2069 | + result = keyring.Keyring("Software Center").get_ubuntusso_attr() |
| 2070 | + self.assertEqual(result, None) |
| 2071 | + |
| 2072 | + def test_get_old_cred_not_found(self): |
| 2073 | + """The method returns None if no old nor new credentials found.""" |
| 2074 | + result = keyring.Keyring(keyring.U1_APP_NAME).get_ubuntusso_attr() |
| 2075 | + self.assertEqual(result, None) |
| 2076 | |
| 2077 | === modified file 'ubuntu_sso/tests/test_main.py' |
| 2078 | --- ubuntu_sso/tests/test_main.py 2010-08-26 01:07:41 +0000 |
| 2079 | +++ ubuntu_sso/tests/test_main.py 2010-08-27 22:32:43 +0000 |
| 2080 | @@ -31,19 +31,19 @@ |
| 2081 | from twisted.internet.defer import Deferred |
| 2082 | from twisted.trial.unittest import TestCase |
| 2083 | |
| 2084 | +import ubuntu_sso.keyring |
| 2085 | import ubuntu_sso.main |
| 2086 | |
| 2087 | from contrib.testing.testcase import MementoHandler |
| 2088 | from ubuntu_sso import config, gui |
| 2089 | +from ubuntu_sso.keyring import get_token_name, U1_APP_NAME |
| 2090 | from ubuntu_sso.main import ( |
| 2091 | AuthenticationError, BadRealmError, blocking, EmailTokenError, |
| 2092 | - except_to_errdict, get_token_name, |
| 2093 | - InvalidEmailError, InvalidPasswordError, |
| 2094 | + except_to_errdict, InvalidEmailError, InvalidPasswordError, |
| 2095 | keyring_get_credentials, keyring_store_credentials, logger, |
| 2096 | - LoginProcessor, NewPasswordError, OLD_KEY_NAME, PING_URL, |
| 2097 | + LoginProcessor, NewPasswordError, PING_URL, |
| 2098 | RegistrationError, ResetPasswordTokenError, |
| 2099 | - SSOCredentials, SSOLogin, SSOLoginProcessor, |
| 2100 | - U1_APP_NAME) |
| 2101 | + SSOCredentials, SSOLogin, SSOLoginProcessor) |
| 2102 | |
| 2103 | |
| 2104 | APP_NAME = 'The Coolest App Ever' |
| 2105 | @@ -55,6 +55,7 @@ |
| 2106 | "Can't reset password for this account" |
| 2107 | RESET_TOKEN_INVALID_CONTENT = "AuthToken matching query does not exist." |
| 2108 | EMAIL = 'test@example.com' |
| 2109 | +EMAIL_ALREADY_REGISTERED = 'a@example.com' |
| 2110 | EMAIL_TOKEN = 'B2Pgtf' |
| 2111 | HELP = 'help text' |
| 2112 | PASSWORD = 'be4tiFul' |
| 2113 | @@ -103,7 +104,10 @@ |
| 2114 | |
| 2115 | def register(self, email, password, captcha_id, captcha_solution): |
| 2116 | """Fake registration. Return a fix result.""" |
| 2117 | - if captcha_id is None and captcha_solution is None: |
| 2118 | + if email == EMAIL_ALREADY_REGISTERED: |
| 2119 | + return {'status': 'error', |
| 2120 | + 'errors': {'email': 'Email already registered'}} |
| 2121 | + elif captcha_id is None and captcha_solution is None: |
| 2122 | return STATUS_UNKNOWN |
| 2123 | elif captcha_id != CAPTCHA_ID or captcha_solution != CAPTCHA_SOLUTION: |
| 2124 | return STATUS_ERROR |
| 2125 | @@ -147,7 +151,10 @@ |
| 2126 | """Fake the email validation. Return a fix result.""" |
| 2127 | if email_token is None: |
| 2128 | return STATUS_EMAIL_UNKNOWN |
| 2129 | - if email_token != EMAIL_TOKEN: |
| 2130 | + elif email_token == EMAIL_ALREADY_REGISTERED: |
| 2131 | + return {'status': 'error', |
| 2132 | + 'errors': {'email': 'Email already registered'}} |
| 2133 | + elif email_token != EMAIL_TOKEN: |
| 2134 | return STATUS_EMAIL_ERROR |
| 2135 | else: |
| 2136 | return STATUS_EMAIL_OK |
| 2137 | @@ -231,7 +238,19 @@ |
| 2138 | failure = self.assertRaises(RegistrationError, |
| 2139 | self.processor.register_user, |
| 2140 | **self.register_kwargs) |
| 2141 | - self.assertIn(STATUS_ERROR['errors'], failure) |
| 2142 | + for k, v in failure.args[0].items(): |
| 2143 | + self.assertIn(k, STATUS_ERROR['errors']) |
| 2144 | + self.assertEqual(v, "\n".join(STATUS_ERROR['errors'][k])) |
| 2145 | + |
| 2146 | + def test_register_user_if_status_error_with_string_message(self): |
| 2147 | + """Proper error is raised if register fails.""" |
| 2148 | + self.register_kwargs['email'] = EMAIL_ALREADY_REGISTERED |
| 2149 | + failure = self.assertRaises(RegistrationError, |
| 2150 | + self.processor.register_user, |
| 2151 | + **self.register_kwargs) |
| 2152 | + for k, v in failure.args[0].items(): |
| 2153 | + self.assertIn(k, {'email': 'Email already registered'}) |
| 2154 | + self.assertEqual(v, 'Email already registered') |
| 2155 | |
| 2156 | def test_register_user_if_status_unknown(self): |
| 2157 | """Proper error is raised if register returns an unknown status.""" |
| 2158 | @@ -261,7 +280,7 @@ |
| 2159 | """A email is succesfuy validated in the SSO server.""" |
| 2160 | self.login_kwargs['email_token'] = EMAIL_TOKEN # valid email token |
| 2161 | result = self.processor.validate_email(**self.login_kwargs) |
| 2162 | - self.assertEqual(EMAIL, result, 'email validation was successful.') |
| 2163 | + self.assertEqual(TOKEN, result, 'email validation was successful.') |
| 2164 | |
| 2165 | def test_validate_email_if_status_error(self): |
| 2166 | """Proper error is raised if email validation fails.""" |
| 2167 | @@ -269,7 +288,19 @@ |
| 2168 | failure = self.assertRaises(EmailTokenError, |
| 2169 | self.processor.validate_email, |
| 2170 | **self.login_kwargs) |
| 2171 | - self.assertIn(STATUS_EMAIL_ERROR['errors'], failure) |
| 2172 | + for k, v in failure.args[0].items(): |
| 2173 | + self.assertIn(k, STATUS_EMAIL_ERROR['errors']) |
| 2174 | + self.assertEqual(v, "\n".join(STATUS_EMAIL_ERROR['errors'][k])) |
| 2175 | + |
| 2176 | + def test_validate_email_if_status_error_with_string_message(self): |
| 2177 | + """Proper error is raised if register fails.""" |
| 2178 | + self.login_kwargs['email_token'] = EMAIL_ALREADY_REGISTERED |
| 2179 | + failure = self.assertRaises(EmailTokenError, |
| 2180 | + self.processor.validate_email, |
| 2181 | + **self.login_kwargs) |
| 2182 | + for k, v in failure.args[0].items(): |
| 2183 | + self.assertIn(k, {'email': 'Email already registered'}) |
| 2184 | + self.assertEqual(v, 'Email already registered') |
| 2185 | |
| 2186 | def test_validate_email_if_status_unknown(self): |
| 2187 | """Proper error is raised if email validation returns unknown.""" |
| 2188 | @@ -413,8 +444,11 @@ |
| 2189 | """Assert over token and app_name.""" |
| 2190 | self.assertEqual(k, APP_NAME) |
| 2191 | self.assertEqual(v, TOKEN) |
| 2192 | + self.keyring_was_set = True |
| 2193 | + self.keyring_values = k, v |
| 2194 | |
| 2195 | self.patch(ubuntu_sso.main, "keyring_store_credentials", ksc) |
| 2196 | + self.keyring_was_set = False |
| 2197 | |
| 2198 | def tearDown(self): |
| 2199 | """Verify the mocking bus and shut it down.""" |
| 2200 | @@ -427,8 +461,12 @@ |
| 2201 | |
| 2202 | def fake_err_blocking(self, f, a, cb, eb): |
| 2203 | """A fake blocking function that fails.""" |
| 2204 | - f() |
| 2205 | - eb(a, except_to_errdict(BlockingSampleException())) |
| 2206 | + try: |
| 2207 | + f() |
| 2208 | + except Exception, e: |
| 2209 | + eb(a, except_to_errdict(e)) |
| 2210 | + else: |
| 2211 | + eb(a, except_to_errdict(BlockingSampleException())) |
| 2212 | |
| 2213 | def test_creation(self): |
| 2214 | """Test that the object creation is successful.""" |
| 2215 | @@ -544,6 +582,7 @@ |
| 2216 | def verify(app_name, result): |
| 2217 | self.assertEqual(result, EMAIL) |
| 2218 | self.assertEqual(app_name, APP_NAME) |
| 2219 | + self.assertTrue(self.keyring_was_set, "The keyring should be set") |
| 2220 | d.callback(result) |
| 2221 | |
| 2222 | client = SSOLogin(self.mockbusname, |
| 2223 | @@ -556,14 +595,20 @@ |
| 2224 | def test_login_error(self): |
| 2225 | """Test that the login method fails as expected.""" |
| 2226 | d = Deferred() |
| 2227 | - self.create_mock_processor().login(EMAIL, PASSWORD, TOKEN_NAME) |
| 2228 | - self.mocker.result(TOKEN) |
| 2229 | + self.mockprocessorclass = self.mocker.mock() |
| 2230 | self.patch(ubuntu_sso.main, "blocking", self.fake_err_blocking) |
| 2231 | + |
| 2232 | + def fake_gtn(*args): |
| 2233 | + """A fake get_token_name that fails.""" |
| 2234 | + raise BlockingSampleException() |
| 2235 | + |
| 2236 | + self.patch(ubuntu_sso.main, "get_token_name", fake_gtn) |
| 2237 | self.mocker.replay() |
| 2238 | |
| 2239 | def verify(app_name, errdict): |
| 2240 | self.assertEqual(app_name, APP_NAME) |
| 2241 | self.assertEqual(errdict["errtype"], "BlockingSampleException") |
| 2242 | + self.assertFalse(self.keyring_was_set, "Keyring should not be set") |
| 2243 | d.callback("Ok") |
| 2244 | |
| 2245 | client = SSOLogin(self.mockbusname, |
| 2246 | @@ -578,13 +623,14 @@ |
| 2247 | d = Deferred() |
| 2248 | self.create_mock_processor().validate_email(EMAIL, PASSWORD, |
| 2249 | EMAIL_TOKEN, TOKEN_NAME) |
| 2250 | - self.mocker.result(EMAIL) |
| 2251 | + self.mocker.result(TOKEN) |
| 2252 | self.patch(ubuntu_sso.main, "blocking", self.fake_ok_blocking) |
| 2253 | self.mocker.replay() |
| 2254 | |
| 2255 | def verify(app_name, result): |
| 2256 | self.assertEqual(result, EMAIL) |
| 2257 | self.assertEqual(app_name, APP_NAME) |
| 2258 | + self.assertTrue(self.keyring_was_set, "The keyring should be set") |
| 2259 | d.callback(result) |
| 2260 | |
| 2261 | client = SSOLogin(self.mockbusname, |
| 2262 | @@ -597,17 +643,20 @@ |
| 2263 | def test_validate_email_error(self): |
| 2264 | """Test that the validate_email method fails as expected.""" |
| 2265 | d = Deferred() |
| 2266 | - expected_result = "expected result" |
| 2267 | - |
| 2268 | - self.create_mock_processor().validate_email(EMAIL, PASSWORD, |
| 2269 | - EMAIL_TOKEN, TOKEN_NAME) |
| 2270 | - self.mocker.result(expected_result) |
| 2271 | + self.mockprocessorclass = self.mocker.mock() |
| 2272 | self.patch(ubuntu_sso.main, "blocking", self.fake_err_blocking) |
| 2273 | + |
| 2274 | + def fake_gtn(*args): |
| 2275 | + """A fake get_token_name that fails.""" |
| 2276 | + raise BlockingSampleException() |
| 2277 | + |
| 2278 | + self.patch(ubuntu_sso.main, "get_token_name", fake_gtn) |
| 2279 | self.mocker.replay() |
| 2280 | |
| 2281 | def verify(app_name, errdict): |
| 2282 | self.assertEqual(app_name, APP_NAME) |
| 2283 | self.assertEqual(errdict["errtype"], "BlockingSampleException") |
| 2284 | + self.assertFalse(self.keyring_was_set, "Keyring should not be set") |
| 2285 | d.callback("Ok") |
| 2286 | |
| 2287 | client = SSOLogin(self.mockbusname, |
| 2288 | @@ -794,7 +843,6 @@ |
| 2289 | e = TestExceptToErrdictException(*sample_args) |
| 2290 | result = except_to_errdict(e) |
| 2291 | self.assertEqual(result["errtype"], e.__class__.__name__) |
| 2292 | - self.assertEqual(result["errargs"], repr(sample_args)) |
| 2293 | |
| 2294 | |
| 2295 | class KeyringCredentialsTestCase(MockerTestCase): |
| 2296 | @@ -838,58 +886,6 @@ |
| 2297 | token = keyring_get_credentials(APP_NAME) |
| 2298 | self.assertEqual(token, None) |
| 2299 | |
| 2300 | - def test_keyring_get_old_cred_found(self): |
| 2301 | - """The method returns a new set of creds if old creds are found.""" |
| 2302 | - sample_oauth_token = "sample oauth token" |
| 2303 | - sample_oauth_secret = "sample oauth secret" |
| 2304 | - old_creds = { |
| 2305 | - "oauth_token": sample_oauth_token, |
| 2306 | - "oauth_token_secret": sample_oauth_secret, |
| 2307 | - } |
| 2308 | - |
| 2309 | - mockKeyringClass = self.mocker.replace("ubuntu_sso.keyring.Keyring") |
| 2310 | - mockKeyringClass(U1_APP_NAME) |
| 2311 | - mockKeyring = self.mocker.mock() |
| 2312 | - self.mocker.result(mockKeyring) |
| 2313 | - mockKeyring.get_ubuntusso_attr() |
| 2314 | - self.mocker.result(None) |
| 2315 | - |
| 2316 | - mockKeyringClass(OLD_KEY_NAME) |
| 2317 | - mockKeyring2 = self.mocker.mock() |
| 2318 | - self.mocker.result(mockKeyring2) |
| 2319 | - mockKeyring2.get_ubuntusso_attr() |
| 2320 | - self.mocker.result(old_creds) |
| 2321 | - |
| 2322 | - self.mocker.replay() |
| 2323 | - |
| 2324 | - new_creds = keyring_get_credentials(U1_APP_NAME) |
| 2325 | - self.assertIn("token", new_creds) |
| 2326 | - self.assertEqual(new_creds["token"], sample_oauth_token) |
| 2327 | - self.assertIn("token_secret", new_creds) |
| 2328 | - self.assertEqual(new_creds["token_secret"], sample_oauth_secret) |
| 2329 | - self.assertIn("token_name", new_creds) |
| 2330 | - self.assertEqual(new_creds["token_name"], OLD_KEY_NAME) |
| 2331 | - |
| 2332 | - def test_keyring_get_old_cred_not_found(self): |
| 2333 | - """The method returns None if no old nor new credentials found.""" |
| 2334 | - mockKeyringClass = self.mocker.replace("ubuntu_sso.keyring.Keyring") |
| 2335 | - mockKeyringClass(U1_APP_NAME) |
| 2336 | - mockKeyring = self.mocker.mock() |
| 2337 | - self.mocker.result(mockKeyring) |
| 2338 | - mockKeyring.get_ubuntusso_attr() |
| 2339 | - self.mocker.result(None) |
| 2340 | - |
| 2341 | - mockKeyringClass(OLD_KEY_NAME) |
| 2342 | - mockKeyring2 = self.mocker.mock() |
| 2343 | - self.mocker.result(mockKeyring2) |
| 2344 | - mockKeyring2.get_ubuntusso_attr() |
| 2345 | - self.mocker.result(None) |
| 2346 | - |
| 2347 | - self.mocker.replay() |
| 2348 | - |
| 2349 | - token = keyring_get_credentials(U1_APP_NAME) |
| 2350 | - self.assertEqual(token, None) |
| 2351 | - |
| 2352 | |
| 2353 | class RegisterSampleException(Exception): |
| 2354 | """A mock exception thrown just when testing.""" |

