Merge lp:~canonical-platform-qa/uoa-integration-tests/python-testability into lp:uoa-integration-tests
- python-testability
- Merge into trunk
Proposed by
Leo Arias
Status: | Merged |
---|---|
Merged at revision: | 15 |
Proposed branch: | lp:~canonical-platform-qa/uoa-integration-tests/python-testability |
Merge into: | lp:uoa-integration-tests |
Diff against target: |
365 lines (+346/-0) 3 files modified
python/uoa_integration_tests/evernote.py (+41/-0) python/uoa_integration_tests/onlineaccounts.py (+233/-0) python/uoa_integration_tests/tests/test_evernote_online_accounts.py (+72/-0) |
To merge this branch: | bzr merge lp:~canonical-platform-qa/uoa-integration-tests/python-testability |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Online Accounts | Pending | ||
Review via email: mp+241815@code.launchpad.net |
Commit message
Description of the change
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 | === added directory 'python' |
2 | === added directory 'python/uoa_integration_tests' |
3 | === added file 'python/uoa_integration_tests/__init__.py' |
4 | === added file 'python/uoa_integration_tests/evernote.py' |
5 | --- python/uoa_integration_tests/evernote.py 1970-01-01 00:00:00 +0000 |
6 | +++ python/uoa_integration_tests/evernote.py 2014-11-14 14:59:44 +0000 |
7 | @@ -0,0 +1,41 @@ |
8 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
9 | +# |
10 | +# Copyright (C) 2014 Canonical Ltd. |
11 | +# |
12 | +# This program is free software; you can redistribute it and/or modify |
13 | +# it under the terms of the GNU General Public License version 3, as published |
14 | +# by the Free Software Foundation. |
15 | +# |
16 | +# This program is distributed in the hope that it will be useful, |
17 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | +# GNU General Public License for more details. |
20 | +# |
21 | +# You should have received a copy of the GNU General Public License |
22 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
23 | + |
24 | +import logging |
25 | + |
26 | +from uoa_integration_tests import onlineaccounts |
27 | + |
28 | + |
29 | +logger = logging.getLogger(__name__) |
30 | + |
31 | + |
32 | +class EvernoteOnlineAccounts(): |
33 | + |
34 | + @classmethod |
35 | + def add_evernote_sandbox_account_with_oauth_token( |
36 | + cls, user_name, password, oauth_token): |
37 | + """Add an Evernote Sandbox account . |
38 | + |
39 | + :param user_name: The user name of the account. |
40 | + :param password: The password of the account. |
41 | + :param oauth_token: The oauth token of the account. |
42 | + |
43 | + """ |
44 | + accounts_manager = onlineaccounts.AccountsManager() |
45 | + provider_id = 'com.ubuntu.reminders_evernote-account-plugin-sandbox' |
46 | + service_id = 'com.ubuntu.reminders_reminders-sandbox' |
47 | + return accounts_manager.add_account_with_oauth_token( |
48 | + provider_id, service_id, user_name, password, oauth_token) |
49 | |
50 | === added file 'python/uoa_integration_tests/onlineaccounts.py' |
51 | --- python/uoa_integration_tests/onlineaccounts.py 1970-01-01 00:00:00 +0000 |
52 | +++ python/uoa_integration_tests/onlineaccounts.py 2014-11-14 14:59:44 +0000 |
53 | @@ -0,0 +1,233 @@ |
54 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
55 | +# |
56 | +# Copyright (C) 2014 Canonical Ltd. |
57 | +# |
58 | +# This program is free software; you can redistribute it and/or modify |
59 | +# it under the terms of the GNU General Public License version 3, as published |
60 | +# by the Free Software Foundation. |
61 | +# |
62 | +# This program is distributed in the hope that it will be useful, |
63 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
64 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
65 | +# GNU General Public License for more details. |
66 | +# |
67 | +# You should have received a copy of the GNU General Public License |
68 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
69 | + |
70 | +import logging |
71 | +import time |
72 | +import threading |
73 | + |
74 | +from gi.repository import Accounts, GLib, Signon |
75 | + |
76 | + |
77 | +logger = logging.getLogger(__name__) |
78 | + |
79 | + |
80 | +class CredentialsException(Exception): |
81 | + |
82 | + """Exception for credentials problems.""" |
83 | + |
84 | + |
85 | +class AccountsManager(object): |
86 | + |
87 | + """Manager for online accounts.""" |
88 | + |
89 | + def __init__(self): |
90 | + self._manager = Accounts.Manager.new() |
91 | + |
92 | + def _start_main_loop(self): |
93 | + self.error = None |
94 | + self._main_loop = GLib.MainLoop() |
95 | + self._main_loop_thread = threading.Thread( |
96 | + target=self._main_loop.run) |
97 | + self._main_loop_thread.start() |
98 | + |
99 | + def _join_main_loop(self): |
100 | + self._main_loop_thread.join() |
101 | + if self.error is not None: |
102 | + raise CredentialsException(self.error) |
103 | + |
104 | + def add_account_with_oauth_token( |
105 | + self, provider_id, service_id, user_name, password, oauth_token): |
106 | + """Add an account with an oauth token. |
107 | + |
108 | + :param provider_id: The identifier of the account provider. |
109 | + :param servide_id: The identifier of the service that will use the |
110 | + account. |
111 | + :param user_name: The user name of the account. |
112 | + :param password: The password of the account. |
113 | + :param oauth_token: The oauth token of the account. |
114 | + |
115 | + """ |
116 | + logger.info('Add an account for provider {} and service {}.'.format( |
117 | + provider_id, service_id)) |
118 | + logger.info('user name: {}, password: {}, oauth_token: {}.'.format( |
119 | + user_name, password, oauth_token)) |
120 | + self._start_main_loop() |
121 | + |
122 | + account = self._create_account(provider_id) |
123 | + logger.debug('account %s' % account.get_settings_dict()) |
124 | + |
125 | + if not account.get_settings_dict(): |
126 | + self._delete_account_on_error(account) |
127 | + self._quit_main_loop_on_error('account is blank', 'add account') |
128 | + |
129 | + info = self._get_identity_info(user_name, password) |
130 | + |
131 | + identity = Signon.Identity.new() |
132 | + identity.store_credentials_with_info( |
133 | + info, self._set_credentials_id_to_account, |
134 | + {'account': account, 'oauth_token': oauth_token}) |
135 | + logger.debug('identity %s' % identity.list_properties()) |
136 | + |
137 | + logger.debug('Joining loop') |
138 | + |
139 | + self._join_main_loop() |
140 | + |
141 | + # XXX Sometimes, the account fails to be enabled. This sleep seems to |
142 | + # fix it but we haven't yet found the reason. --elopio - 2014-06-25 |
143 | + time.sleep(10) |
144 | + self._enable_service(account, service_id) |
145 | + |
146 | + logger.info('Created the account with id: {}.'.format(account.id)) |
147 | + self._log_accounts_info() |
148 | + return account |
149 | + |
150 | + def _create_account(self, provider_id): |
151 | + logger.debug('Creating the Evernote account.') |
152 | + account = self._manager.create_account(provider_id) |
153 | + account.set_enabled(True) |
154 | + account.store(self._on_account_created, None) |
155 | + return account |
156 | + |
157 | + def _on_account_created(self, account, error, _): |
158 | + if error: |
159 | + self._quit_main_loop_on_error(error, 'storing account') |
160 | + |
161 | + def _delete_account_on_error(self, account): |
162 | + # attempt to clean up after ourselves, since normal |
163 | + # addCleanups will not run in this case |
164 | + try: |
165 | + logger.debug('Cleaning up account %s' % account.id) |
166 | + account.delete() |
167 | + account.store(self._on_account_deleted, None) |
168 | + except: |
169 | + logger.warn('Failed to cleanup account') |
170 | + |
171 | + def _quit_main_loop_on_error(self, error, step): |
172 | + logger.error('Error {}.'.format(step)) |
173 | + self.error = error |
174 | + self._main_loop.quit() |
175 | + raise CredentialsException(error) |
176 | + |
177 | + def _get_identity_info(self, user_name, password): |
178 | + info = Signon.IdentityInfo.new() |
179 | + info.set_username(user_name) |
180 | + info.set_caption(user_name) |
181 | + info.set_secret(password, True) |
182 | + return info |
183 | + |
184 | + def _set_credentials_id_to_account( |
185 | + self, identity, id_, error, account_dict): |
186 | + if error: |
187 | + self._quit_main_loop_on_error( |
188 | + error, 'storing credentials with info') |
189 | + |
190 | + logger.debug('Setting credentials to account.') |
191 | + account = account_dict.get('account') |
192 | + oauth_token = account_dict.get('oauth_token') |
193 | + account.set_variant('CredentialsId', GLib.Variant('u', id_)) |
194 | + account.store(self._process_session, oauth_token) |
195 | + logger.debug('Account stored') |
196 | + |
197 | + def _process_session(self, account, error, oauth_token): |
198 | + if error: |
199 | + self._quit_main_loop_on_error( |
200 | + error, 'setting credentials id to account') |
201 | + |
202 | + logger.debug('Processing session.') |
203 | + account_service = Accounts.AccountService.new(account, None) |
204 | + logger.debug('account_service %s' % account_service.list_properties()) |
205 | + auth_data = account_service.get_auth_data() |
206 | + logger.debug('auth_data %s' % auth_data.get_parameters()) |
207 | + identity = auth_data.get_credentials_id() |
208 | + method = auth_data.get_method() |
209 | + if method is None: |
210 | + self._delete_account_on_error(account) |
211 | + self._quit_main_loop_on_error('Method is none', |
212 | + 'processing auth data') |
213 | + mechanism = auth_data.get_mechanism() |
214 | + session_data = auth_data.get_parameters() |
215 | + session_data['ProvidedTokens'] = GLib.Variant('a{sv}', { |
216 | + 'TokenSecret': GLib.Variant('s', 'dummy'), |
217 | + 'AccessToken': GLib.Variant('s', oauth_token), |
218 | + }) |
219 | + logger.debug('session_data %s' % session_data) |
220 | + logger.debug('Authenticating session %s, %s' % (identity, method)) |
221 | + session = Signon.AuthSession.new(identity, method) |
222 | + logger.debug('Send session %s' % session) |
223 | + session.process( |
224 | + session_data, mechanism, self._on_login_processed, None) |
225 | + logger.debug('Session processed') |
226 | + |
227 | + def _on_login_processed(self, session, reply, error, userdata): |
228 | + if error: |
229 | + self._quit_main_loop_on_error(error, 'processing session') |
230 | + |
231 | + else: |
232 | + self._main_loop.quit() |
233 | + |
234 | + def _enable_service(self, account, service_id): |
235 | + logger.debug('Enabling evernote service.') |
236 | + service = self._manager.get_service(service_id) |
237 | + account.select_service(service) |
238 | + account.set_enabled(True) |
239 | + account.store(self._on_service_enabled, None) |
240 | + |
241 | + def _on_service_enabled(self, account, error, _): |
242 | + if error: |
243 | + self._quit_main_loop_on_error(error, 'enabling service') |
244 | + |
245 | + def _log_accounts_info(self): |
246 | + account_ids = self._manager.list() |
247 | + logger.debug('Existing accounts: {}.'.format(account_ids)) |
248 | + for id_ in account_ids: |
249 | + account = self._manager.get_account(id_) |
250 | + self._log_account_info(account) |
251 | + |
252 | + def _log_account_info(self, account): |
253 | + logger.debug('Account info:') |
254 | + logger.debug('id: {}'.format(account.id)) |
255 | + logger.debug('provider: {}'.format(account.get_provider_name())) |
256 | + logger.debug('enabled: {}'.format(account.get_enabled())) |
257 | + logger.debug('Account services:') |
258 | + for service in account.list_services(): |
259 | + logger.debug('name: {}'.format(service.get_name())) |
260 | + account_service = Accounts.AccountService.new(account, service) |
261 | + logger.debug('enabled: {}'.format(account_service.get_enabled())) |
262 | + |
263 | + def get_accounts_list(self): |
264 | + return self._manager.list() |
265 | + |
266 | + def delete_account(self, account): |
267 | + """Delete an account. |
268 | + |
269 | + :param account: The account to delete. |
270 | + |
271 | + """ |
272 | + logger.info('Deleting the account with id {}.'.format(account.id)) |
273 | + self._start_main_loop() |
274 | + # XXX There seems to be a problem when we try to delete the account too |
275 | + # soon after starting the main loop. |
276 | + # Reported as bug http://pad.lv/1363604. --elopio - 2014-09-01 |
277 | + time.sleep(10) |
278 | + account.delete() |
279 | + account.store(self._on_account_deleted, None) |
280 | + self._join_main_loop() |
281 | + |
282 | + def _on_account_deleted(self, account, error, _): |
283 | + if error: |
284 | + self._quit_main_loop_on_error(error, 'deleting account') |
285 | + else: |
286 | + self._main_loop.quit() |
287 | |
288 | === added directory 'python/uoa_integration_tests/tests' |
289 | === added file 'python/uoa_integration_tests/tests/__init__.py' |
290 | === added file 'python/uoa_integration_tests/tests/test_evernote_online_accounts.py' |
291 | --- python/uoa_integration_tests/tests/test_evernote_online_accounts.py 1970-01-01 00:00:00 +0000 |
292 | +++ python/uoa_integration_tests/tests/test_evernote_online_accounts.py 2014-11-14 14:59:44 +0000 |
293 | @@ -0,0 +1,72 @@ |
294 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
295 | +# |
296 | +# Copyright (C) 2014 Canonical Ltd |
297 | +# |
298 | +# This program is free software: you can redistribute it and/or modify |
299 | +# it under the terms of the GNU General Public License version 3 as |
300 | +# published by the Free Software Foundation. |
301 | +# |
302 | +# This program is distributed in the hope that it will be useful, |
303 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
304 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
305 | +# GNU General Public License for more details. |
306 | +# |
307 | +# You should have received a copy of the GNU General Public License |
308 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
309 | + |
310 | +import logging |
311 | + |
312 | +import testtools |
313 | +from gi.repository import Accounts |
314 | +from testtools.matchers import HasLength |
315 | + |
316 | +from uoa_integration_tests import onlineaccounts, evernote |
317 | + |
318 | + |
319 | +logger = logging.getLogger(__name__) |
320 | + |
321 | + |
322 | +class EvernoteCredentialsTestCase(testtools.TestCase): |
323 | + |
324 | + def setUp(self): |
325 | + super(EvernoteCredentialsTestCase, self).setUp() |
326 | + self.accounts_manager = onlineaccounts.AccountsManager() |
327 | + |
328 | + def add_evernote_sandbox_account(self): |
329 | + accounts = evernote.EvernoteOnlineAccounts |
330 | + add_account = accounts.add_evernote_sandbox_account_with_oauth_token |
331 | + account = add_account('dummy', 'dummy', 'dummy') |
332 | + self.addCleanup(self.delete_account, account) |
333 | + return account |
334 | + |
335 | + def delete_account(self, account): |
336 | + if account.id in self.account_manager.get_accounts_list(): |
337 | + self.accounts_manager.delete_account(account) |
338 | + |
339 | + def test_add_evernote_sandbox_account_must_enable_it(self): |
340 | + account = self.add_evernote_sandbox_account() |
341 | + |
342 | + self.assertTrue(account.get_enabled()) |
343 | + |
344 | + def test_add_evernote_sandbox_account_must_set_provider(self): |
345 | + account = self.add_evernote_sandbox_account() |
346 | + |
347 | + provider_id = 'com.ubuntu.reminders_evernote-account-plugin-sandbox' |
348 | + self.assertEqual(account.get_provider_name(), provider_id) |
349 | + |
350 | + def test_add_evernote_sandbox_account_must_enable_evernote_service(self): |
351 | + account = self.add_evernote_sandbox_account() |
352 | + services = account.list_services() |
353 | + |
354 | + self.assertThat(services, HasLength(1)) |
355 | + service_id = 'com.ubuntu.reminders_reminders-sandbox' |
356 | + self.assertEqual(services[0].get_name(), service_id) |
357 | + service = Accounts.AccountService.new(account, services[0]) |
358 | + self.assertTrue(service.get_enabled()) |
359 | + |
360 | + def test_delete_evernote_sandbox_account_must_remove_it(self): |
361 | + account = self.add_evernote_sandbox_account() |
362 | + self.assertThat(self.account_manager._manager.list(), HasLength(1)) |
363 | + |
364 | + self.account_manager.delete_account(account) |
365 | + self.assertThat(self.account_manager._manager.list(), HasLength(0)) |