Merge lp:~alecu/ubuntu-sso-client/keyring-api-change into lp:ubuntu-sso-client

Proposed by Alejandro J. Cura
Status: Merged
Approved by: Rodrigo Moya
Approved revision: 593
Merged at revision: 599
Proposed branch: lp:~alecu/ubuntu-sso-client/keyring-api-change
Merge into: lp:ubuntu-sso-client
Diff against target: 526 lines (+219/-152)
4 files modified
ubuntu_sso/keyring.py (+89/-38)
ubuntu_sso/main.py (+1/-28)
ubuntu_sso/tests/test_keyring.py (+125/-29)
ubuntu_sso/tests/test_main.py (+4/-57)
To merge this branch: bzr merge lp:~alecu/ubuntu-sso-client/keyring-api-change
Reviewer Review Type Date Requested Status
Rodrigo Moya (community) Approve
John Lenton (community) Approve
Review via email: mp+33840@code.launchpad.net

Commit message

Use the keyring unlocking gnomekeyring APIs (LP: #623622)
Search all keyrings for the credentials (LP: #624033)

Description of the change

Use the keyring unlocking gnomekeyring apis and search all keyrings for the credentials

To post a comment you must log in.
Revision history for this message
John Lenton (chipaca) wrote :

tests are delicious!

review: Approve
Revision history for this message
Rodrigo Moya (rodrigo-moya) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'ubuntu_sso/keyring.py'
--- ubuntu_sso/keyring.py 2010-08-19 13:39:50 +0000
+++ ubuntu_sso/keyring.py 2010-08-26 21:18:42 +0000
@@ -19,77 +19,128 @@
1919
20"""Handle keys in the gnome kerying."""20"""Handle keys in the gnome kerying."""
2121
22import socket
23import urllib
24import urlparse
25
22import gnomekeyring26import gnomekeyring
2327
24from urllib import urlencode28from ubuntu_sso.logger import setupLogging
25from urlparse import parse_qsl29logger = setupLogging("ubuntu_sso.main")
30
31U1_APP_NAME = "Ubuntu One"
32U1_KEY_NAME = "UbuntuOne token for https://ubuntuone.com"
33U1_KEY_ATTR = {
34 "oauth-consumer-key": "ubuntuone",
35 "ubuntuone-realm": "https://ubuntuone.com",
36}
37
38
39def get_token_name(app_name):
40 """Build the token name."""
41 quoted_app_name = urllib.quote(app_name)
42 computer_name = socket.gethostname()
43 quoted_computer_name = urllib.quote(computer_name)
44 return "%s - %s" % (quoted_app_name, quoted_computer_name)
2645
2746
28class Keyring(object):47class Keyring(object):
2948 """A Keyring for a given application name."""
30 KEYRING_NAME = "login"49 KEYRING_NAME = "login"
3150
32 def __init__(self, app_name):51 def __init__(self, app_name):
52 """Initialize this instance given the app_name."""
33 if not gnomekeyring.is_available():53 if not gnomekeyring.is_available():
34 raise gnomekeyring.NoKeyringDaemonError54 raise gnomekeyring.NoKeyringDaemonError
35 self.app_name = app_name55 self.app_name = app_name
56 self.token_name = get_token_name(self.app_name)
3657
37 def _create_keyring(self, name):58 def _create_keyring(self, name):
38 """Creates a keyring, if it already exists, do nothing."""59 """Creates a keyring, or if it already exists, it does nothing."""
39 keyring_names = gnomekeyring.list_keyring_names_sync()60 keyring_names = gnomekeyring.list_keyring_names_sync()
40 if not name in keyring_names:61 if not name in keyring_names:
41 gnomekeyring.create_sync(name)62 gnomekeyring.create_sync(name)
4263
43 def _get_item_id_from_name(self, sync, name):64 def _find_keyring_item(self):
44 """Return the ID for a named item."""65 """Return the keyring item or None if not found."""
45 for item_id in gnomekeyring.list_item_ids_sync(sync):66 try:
46 item_info = gnomekeyring.item_get_info_sync(sync, item_id)67 items = gnomekeyring.find_items_sync(
47 display_name = item_info.get_display_name()68 gnomekeyring.ITEM_GENERIC_SECRET,
48 if display_name == name:69 self._get_keyring_attr())
49 return item_id70 except gnomekeyring.NoMatchError:
5071 # if no items found, return None
51 def _get_item_info_from_name(self, sync, name):72 return None
52 """Return the ID for a named item."""73
53 for item_id in gnomekeyring.list_item_ids_sync(sync):74 # we priorize the item in the "login" keyring
54 item_info = gnomekeyring.item_get_info_sync(sync, item_id)75 for item in items:
55 display_name = item_info.get_display_name()76 if item.keyring == "login":
56 if display_name == name:77 return item
57 return item_info78
79 # if not on the "login" keyring, we return the first item
80 return items[0]
81
82 def _get_keyring_attr(self):
83 """Build the keyring attributes for this credentials."""
84 attr = {"key-type": "Ubuntu SSO credentials",
85 "token-name": self.token_name}
86 return attr
5887
59 def set_ubuntusso_attr(self, cred):88 def set_ubuntusso_attr(self, cred):
60 """Set the credentials of the Ubuntu SSO item."""89 """Set the credentials of the Ubuntu SSO item."""
61 # Creates the secret from the credentials90 # Creates the secret from the credentials
62 secret = urlencode(cred)91 secret = urllib.urlencode(cred)
6392
64 # Create the keyring93 # Create the keyring if it does not exists
65 self._create_keyring(self.KEYRING_NAME)94 self._create_keyring(self.KEYRING_NAME)
6695
67 # No need to delete the item if it already exists
68
69 # A set of attributes for this credentials
70 attr = {"key-type": "Ubuntu SSO credentials",
71 "token-name": cred["name"].encode("utf8")}
72
73 # Add our SSO credentials to the keyring96 # Add our SSO credentials to the keyring
74 gnomekeyring.item_create_sync(self.KEYRING_NAME,97 gnomekeyring.item_create_sync(self.KEYRING_NAME,
75 gnomekeyring.ITEM_GENERIC_SECRET, self.app_name, attr,98 gnomekeyring.ITEM_GENERIC_SECRET, self.app_name,
76 secret, True)99 self._get_keyring_attr(), secret, True)
77100
78 def get_ubuntusso_attr(self):101 def get_ubuntusso_attr(self):
79 """Return the secret of the SSO item in a dictionary."""102 """Return the secret of the SSO item in a dictionary."""
80 # If we have no attributes, return None103 # If we have no attributes, return None
81 exist = self._get_item_info_from_name(self.KEYRING_NAME, self.app_name)104 item = self._find_keyring_item()
82 if exist is not None:105 if item is not None:
83 secret = self._get_item_info_from_name(self.KEYRING_NAME,106 return dict(urlparse.parse_qsl(item.secret))
84 self.app_name).get_secret()107 else:
85 return dict(parse_qsl(secret))108 # if no item found, try getting the old credentials
109 if self.app_name == U1_APP_NAME:
110 return try_old_credentials(self.app_name)
111 # nothing was found
112 return None
86113
87 def delete_ubuntusso_attr(self):114 def delete_ubuntusso_attr(self):
88 """Delete a set of credentials from the keyring."""115 """Delete a set of credentials from the keyring."""
89 item_id = self._get_item_id_from_name(self.KEYRING_NAME,116 item = self._find_keyring_item()
90 self.app_name)117 if item is not None:
91 if item_id is not None:118 gnomekeyring.item_delete_sync(item.keyring, item.item_id)
92 gnomekeyring.item_delete_sync(self.KEYRING_NAME, item_id)119
120
121class UbuntuOneOAuthKeyring(Keyring):
122
123 def _get_keyring_attr(self):
124 """Build the keyring attributes for this credentials."""
125 return U1_KEY_ATTR
126
127
128def try_old_credentials(app_name):
129 """Try to get old U1 credentials and format them as new."""
130 logger.debug('trying to get old credentials.')
131 old_creds = UbuntuOneOAuthKeyring(U1_KEY_NAME).get_ubuntusso_attr()
132 if old_creds is not None:
133 # Old creds found, build a new credentials dict with them
134 creds = {
135 'consumer_key': "ubuntuone",
136 'consumer_secret': "hammertime",
137 'name': U1_KEY_NAME,
138 'token': old_creds["oauth_token"],
139 'token_secret': old_creds["oauth_token_secret"],
140 }
141 logger.debug('found old credentials')
142 return creds
143 logger.debug('try_old_credentials: No old credentials for this app.')
93144
94145
95if __name__ == "__main__":146if __name__ == "__main__":
96147
=== modified file 'ubuntu_sso/main.py'
--- ubuntu_sso/main.py 2010-08-26 13:43:31 +0000
+++ ubuntu_sso/main.py 2010-08-26 21:18:42 +0000
@@ -28,11 +28,9 @@
28"""28"""
2929
30import re30import re
31import socket
32import time31import time
33import threading32import threading
34import traceback33import traceback
35import urllib
36import urllib234import urllib2
37import urlparse35import urlparse
3836
@@ -49,7 +47,7 @@
49from ubuntu_sso import (DBUS_IFACE_AUTH_NAME, DBUS_IFACE_USER_NAME,47from ubuntu_sso import (DBUS_IFACE_AUTH_NAME, DBUS_IFACE_USER_NAME,
50 DBUS_IFACE_CRED_NAME, DBUS_CRED_PATH, DBUS_BUS_NAME, gui)48 DBUS_IFACE_CRED_NAME, DBUS_CRED_PATH, DBUS_BUS_NAME, gui)
51from ubuntu_sso.config import get_config49from ubuntu_sso.config import get_config
52from ubuntu_sso.keyring import Keyring50from ubuntu_sso.keyring import Keyring, get_token_name, U1_APP_NAME
53from ubuntu_sso.logger import setupLogging51from ubuntu_sso.logger import setupLogging
54logger = setupLogging("ubuntu_sso.main")52logger = setupLogging("ubuntu_sso.main")
5553
@@ -57,8 +55,6 @@
57# Disable the invalid name warning, as we have a lot of DBus style names55# Disable the invalid name warning, as we have a lot of DBus style names
58# pylint: disable-msg=C010356# pylint: disable-msg=C0103
5957
60OLD_KEY_NAME = "UbuntuOne token for https://ubuntuone.com"
61U1_APP_NAME = "Ubuntu One"
62PING_URL = "http://edge.one.ubuntu.com/oauth/sso-finished-so-get-tokens/"58PING_URL = "http://edge.one.ubuntu.com/oauth/sso-finished-so-get-tokens/"
6359
6460
@@ -113,32 +109,9 @@
113 creds = Keyring(app_name).get_ubuntusso_attr()109 creds = Keyring(app_name).get_ubuntusso_attr()
114 logger.debug('keyring_get_credentials: Keyring returned credentials? %r',110 logger.debug('keyring_get_credentials: Keyring returned credentials? %r',
115 creds is not None)111 creds is not None)
116 if creds is None and app_name == U1_APP_NAME:
117 logger.debug('keyring_get_credentials: trying for old service.')
118 # No new creds, try to get old credentials
119 old_creds = Keyring(OLD_KEY_NAME).get_ubuntusso_attr()
120 if old_creds is not None:
121 # Old creds found, build a new credentials dict with them
122 creds = {
123 'consumer_key': "ubuntuone",
124 'consumer_secret': "hammertime",
125 'token_name': OLD_KEY_NAME,
126 'token': old_creds["oauth_token"],
127 'token_secret': old_creds["oauth_token_secret"],
128 }
129 else:
130 logger.debug('keyring_get_credentials: Keyring returned credentials.')
131 return creds112 return creds
132113
133114
134def get_token_name(app_name):
135 """Build the token name."""
136 quoted_app_name = urllib.quote(app_name)
137 computer_name = socket.gethostname()
138 quoted_computer_name = urllib.quote(computer_name)
139 return "%s - %s" % (quoted_app_name, quoted_computer_name)
140
141
142class SSOLoginProcessor(object):115class SSOLoginProcessor(object):
143 """Login and register users using the Ubuntu Single Sign On service."""116 """Login and register users using the Ubuntu Single Sign On service."""
144117
145118
=== modified file 'ubuntu_sso/tests/test_keyring.py'
--- ubuntu_sso/tests/test_keyring.py 2010-08-19 05:50:41 +0000
+++ ubuntu_sso/tests/test_keyring.py 2010-08-26 21:18:42 +0000
@@ -17,24 +17,39 @@
17# with this program. If not, see <http://www.gnu.org/licenses/>.17# with this program. If not, see <http://www.gnu.org/licenses/>.
18"""Tests for the keyring.py module."""18"""Tests for the keyring.py module."""
1919
20import itertools
21import socket
22import urllib
23
20import gnomekeyring24import gnomekeyring
21from twisted.trial.unittest import TestCase25from twisted.trial.unittest import TestCase
2226
23from ubuntu_sso import keyring27from ubuntu_sso import keyring
2428
2529
26class MockInfoSync(object):30def build_fake_gethostname(fake_hostname):
27 """A mock object that represents a fake key."""31 """Return a fake hostname getter."""
2832 return lambda *a: fake_hostname
29 def __init__(self, (key, key_name, secret)):33
34
35class MockKeyringItem(object):
36 """A mock object that fakes an item found in a keyring search."""
37
38 def __init__(self, item_id, keyring, attributes, secret):
30 """Initialize this instance."""39 """Initialize this instance."""
31 self.key = key40 self.item_id = item_id
32 self.key_name = key_name41 self.keyring = keyring
42 self.attributes = attributes
33 self.secret = secret43 self.secret = secret
3444
35 def get_display_name(self):45 def matches(self, search_attr):
36 """Return info on the mocked object."""46 """See if this item matches a given search."""
37 return self.key_name47 for k, v in search_attr.items():
48 if k not in self.attributes:
49 return False
50 if self.attributes[k] != v:
51 return False
52 return True
3853
3954
40class MockGnomeKeyring(object):55class MockGnomeKeyring(object):
@@ -43,28 +58,33 @@
43 def __init__(self):58 def __init__(self):
44 """Initialize this instance."""59 """Initialize this instance."""
45 self.keyrings = set()60 self.keyrings = set()
46 self.store = []61 self.id_counter = itertools.count()
62 self.store = {}
47 self.deleted = []63 self.deleted = []
4864
65 def _get_next_id(self):
66 """Return the next keyring id."""
67 return self.id_counter.next()
68
49 def item_create_sync(self, keyring_name, item_type, key_name, attr,69 def item_create_sync(self, keyring_name, item_type, key_name, attr,
50 secret, update_if_exists):70 secret, update_if_exists):
51 """Sets a value in the keyring."""71 """Add a key to a keyring."""
52 # we'll use the attr as the dict key, so make it a tuple72 new_id = self._get_next_id()
53 key = tuple(attr.items())73 i = MockKeyringItem(new_id, keyring_name, attr, secret)
54 self.store.append((key, key_name, secret))74 self.store[new_id] = i
5575
56 def item_delete_sync(self, keyring_name, item_id):76 def item_delete_sync(self, keyring_name, item_id):
57 """Makes a list of deleted items."""77 """Delete a key from a keyring, and keep a list of deleted keys."""
58 key, key_name, secret = self.store.pop(item_id)78 item = self.store.pop(item_id)
59 self.deleted.append(key_name)79 assert keyring_name == item.keyring
6080 self.deleted.append(item)
61 def list_item_ids_sync(self, keyring_name):81
62 """Return a list of ids for all the items."""82 def find_items_sync(self, item_type, attr):
63 return [n for n, v in enumerate(self.store)]83 """Find all keys that match the given attributes."""
6484 items = [i for i in self.store.values() if i.matches(attr)]
65 def item_get_info_sync(self, keyring_name, item_id):85 if len(items) == 0:
66 """Return an info sync object for the item."""86 raise gnomekeyring.NoMatchError()
67 return MockInfoSync(self.store[item_id])87 return items
6888
69 def list_keyring_names_sync(self):89 def list_keyring_names_sync(self):
70 """The keyring you are looking for may be here."""90 """The keyring you are looking for may be here."""
@@ -79,6 +99,32 @@
79 return True99 return True
80100
81101
102class TestTokenNameBuilder(TestCase):
103 """Test the method that builds the token name."""
104
105 def test_get_simple_token_name(self):
106 """A simple token name is built right."""
107 sample_app_name = "UbuntuTwo"
108 sample_hostname = "Darkstar"
109 expected_result = "UbuntuTwo - Darkstar"
110
111 fake_gethostname = build_fake_gethostname(sample_hostname)
112 self.patch(socket, "gethostname", fake_gethostname)
113 result = keyring.get_token_name(sample_app_name)
114 self.assertEqual(result, expected_result)
115
116 def test_get_complex_token_name(self):
117 """A complex token name is built right too."""
118 sample_app_name = "Ubuntu Eleven"
119 sample_hostname = "Mate+Cocido"
120 expected_result = "Ubuntu%20Eleven - Mate%2BCocido"
121
122 fake_gethostname = build_fake_gethostname(sample_hostname)
123 self.patch(socket, "gethostname", fake_gethostname)
124 result = keyring.get_token_name(sample_app_name)
125 self.assertEqual(result, expected_result)
126
127
82class TestKeyring(TestCase):128class TestKeyring(TestCase):
83 """Test the gnome keyring related functions."""129 """Test the gnome keyring related functions."""
84 def setUp(self):130 def setUp(self):
@@ -89,11 +135,10 @@
89 self.patch(gnomekeyring, "create_sync", self.mgk.create_sync)135 self.patch(gnomekeyring, "create_sync", self.mgk.create_sync)
90 self.patch(gnomekeyring, "list_keyring_names_sync",136 self.patch(gnomekeyring, "list_keyring_names_sync",
91 self.mgk.list_keyring_names_sync)137 self.mgk.list_keyring_names_sync)
92 self.patch(gnomekeyring, "list_item_ids_sync",138 self.patch(gnomekeyring, "find_items_sync", self.mgk.find_items_sync)
93 self.mgk.list_item_ids_sync)
94 self.patch(gnomekeyring, "item_get_info_sync",
95 self.mgk.item_get_info_sync)
96 self.patch(gnomekeyring, "item_delete_sync", self.mgk.item_delete_sync)139 self.patch(gnomekeyring, "item_delete_sync", self.mgk.item_delete_sync)
140 fake_gethostname = build_fake_gethostname("darkstar")
141 self.patch(socket, "gethostname", fake_gethostname)
97142
98 def test_set_ubuntusso(self):143 def test_set_ubuntusso(self):
99 """Test that the set method does not erase previous keys."""144 """Test that the set method does not erase previous keys."""
@@ -113,3 +158,54 @@
113158
114 self.assertEqual(len(self.mgk.store), 0)159 self.assertEqual(len(self.mgk.store), 0)
115 self.assertEqual(len(self.mgk.deleted), 1)160 self.assertEqual(len(self.mgk.deleted), 1)
161
162 def test_get_credentials(self):
163 """Test that credentials are properly retrieved."""
164 sample_creds = {"name": "sample creds name"}
165 keyring.Keyring("appname").set_ubuntusso_attr(sample_creds)
166
167 result = keyring.Keyring("appname").get_ubuntusso_attr()
168 self.assertEqual(result, sample_creds)
169
170 def test_get_old_cred_found(self):
171 """The method returns a new set of creds if old creds are found."""
172 sample_oauth_token = "sample oauth token"
173 sample_oauth_secret = "sample oauth secret"
174 old_creds = {
175 "oauth_token": sample_oauth_token,
176 "oauth_token_secret": sample_oauth_secret,
177 }
178 secret = urllib.urlencode(old_creds)
179 self.mgk.item_create_sync(keyring.U1_APP_NAME, None,
180 keyring.Keyring.KEYRING_NAME,
181 keyring.U1_KEY_ATTR,
182 secret, True)
183
184 result = keyring.Keyring(keyring.U1_APP_NAME).get_ubuntusso_attr()
185
186 self.assertIn("token", result)
187 self.assertEqual(result["token"], sample_oauth_token)
188 self.assertIn("token_secret", result)
189 self.assertEqual(result["token_secret"], sample_oauth_secret)
190
191 def test_get_old_cred_found_but_not_asked_for(self):
192 """Returns None if old creds are present but the appname is not U1"""
193 sample_oauth_token = "sample oauth token"
194 sample_oauth_secret = "sample oauth secret"
195 old_creds = {
196 "oauth_token": sample_oauth_token,
197 "oauth_token_secret": sample_oauth_secret,
198 }
199 secret = urllib.urlencode(old_creds)
200 self.mgk.item_create_sync(keyring.U1_APP_NAME, None,
201 keyring.Keyring.KEYRING_NAME,
202 keyring.U1_KEY_ATTR,
203 secret, True)
204
205 result = keyring.Keyring("Software Center").get_ubuntusso_attr()
206 self.assertEqual(result, None)
207
208 def test_get_old_cred_not_found(self):
209 """The method returns None if no old nor new credentials found."""
210 result = keyring.Keyring(keyring.U1_APP_NAME).get_ubuntusso_attr()
211 self.assertEqual(result, None)
116212
=== modified file 'ubuntu_sso/tests/test_main.py'
--- ubuntu_sso/tests/test_main.py 2010-08-26 13:43:31 +0000
+++ ubuntu_sso/tests/test_main.py 2010-08-26 21:18:42 +0000
@@ -35,15 +35,14 @@
3535
36from contrib.testing.testcase import MementoHandler36from contrib.testing.testcase import MementoHandler
37from ubuntu_sso import config, gui37from ubuntu_sso import config, gui
38from ubuntu_sso.keyring import get_token_name, U1_APP_NAME
38from ubuntu_sso.main import (39from ubuntu_sso.main import (
39 AuthenticationError, BadRealmError, blocking, EmailTokenError,40 AuthenticationError, BadRealmError, blocking, EmailTokenError,
40 except_to_errdict, get_token_name,41 except_to_errdict, InvalidEmailError, InvalidPasswordError,
41 InvalidEmailError, InvalidPasswordError,
42 keyring_get_credentials, keyring_store_credentials, logger,42 keyring_get_credentials, keyring_store_credentials, logger,
43 LoginProcessor, NewPasswordError, OLD_KEY_NAME, PING_URL,43 LoginProcessor, NewPasswordError, PING_URL,
44 RegistrationError, ResetPasswordTokenError,44 RegistrationError, ResetPasswordTokenError,
45 SSOCredentials, SSOLogin, SSOLoginProcessor,45 SSOCredentials, SSOLogin, SSOLoginProcessor)
46 U1_APP_NAME)
4746
4847
49APP_NAME = 'The Coolest App Ever'48APP_NAME = 'The Coolest App Ever'
@@ -842,58 +841,6 @@
842 token = keyring_get_credentials(APP_NAME)841 token = keyring_get_credentials(APP_NAME)
843 self.assertEqual(token, None)842 self.assertEqual(token, None)
844843
845 def test_keyring_get_old_cred_found(self):
846 """The method returns a new set of creds if old creds are found."""
847 sample_oauth_token = "sample oauth token"
848 sample_oauth_secret = "sample oauth secret"
849 old_creds = {
850 "oauth_token": sample_oauth_token,
851 "oauth_token_secret": sample_oauth_secret,
852 }
853
854 mockKeyringClass = self.mocker.replace("ubuntu_sso.keyring.Keyring")
855 mockKeyringClass(U1_APP_NAME)
856 mockKeyring = self.mocker.mock()
857 self.mocker.result(mockKeyring)
858 mockKeyring.get_ubuntusso_attr()
859 self.mocker.result(None)
860
861 mockKeyringClass(OLD_KEY_NAME)
862 mockKeyring2 = self.mocker.mock()
863 self.mocker.result(mockKeyring2)
864 mockKeyring2.get_ubuntusso_attr()
865 self.mocker.result(old_creds)
866
867 self.mocker.replay()
868
869 new_creds = keyring_get_credentials(U1_APP_NAME)
870 self.assertIn("token", new_creds)
871 self.assertEqual(new_creds["token"], sample_oauth_token)
872 self.assertIn("token_secret", new_creds)
873 self.assertEqual(new_creds["token_secret"], sample_oauth_secret)
874 self.assertIn("token_name", new_creds)
875 self.assertEqual(new_creds["token_name"], OLD_KEY_NAME)
876
877 def test_keyring_get_old_cred_not_found(self):
878 """The method returns None if no old nor new credentials found."""
879 mockKeyringClass = self.mocker.replace("ubuntu_sso.keyring.Keyring")
880 mockKeyringClass(U1_APP_NAME)
881 mockKeyring = self.mocker.mock()
882 self.mocker.result(mockKeyring)
883 mockKeyring.get_ubuntusso_attr()
884 self.mocker.result(None)
885
886 mockKeyringClass(OLD_KEY_NAME)
887 mockKeyring2 = self.mocker.mock()
888 self.mocker.result(mockKeyring2)
889 mockKeyring2.get_ubuntusso_attr()
890 self.mocker.result(None)
891
892 self.mocker.replay()
893
894 token = keyring_get_credentials(U1_APP_NAME)
895 self.assertEqual(token, None)
896
897844
898class RegisterSampleException(Exception):845class RegisterSampleException(Exception):
899 """A mock exception thrown just when testing."""846 """A mock exception thrown just when testing."""

Subscribers

People subscribed via source and target branches