Merge lp:~elopio/u1-test-utils/in-dash-sso into lp:u1-test-utils

Proposed by Leo Arias
Status: Superseded
Proposed branch: lp:~elopio/u1-test-utils/in-dash-sso
Merge into: lp:u1-test-utils
Diff against target: 778 lines (+712/-0)
13 files modified
bin/vm_session_setup.py (+19/-0)
selftest.py (+19/-0)
tests/__init__.py (+114/-0)
tests/browsers.py (+24/-0)
tests/dash.py (+131/-0)
tests/goods.py (+9/-0)
tests/sso.py (+147/-0)
tests/test_dash.py (+34/-0)
tests/test_dbus.py (+19/-0)
tests/test_purchase_good.py (+92/-0)
tests/test_session.py (+19/-0)
tests/test_users.py (+42/-0)
tests/users.py (+43/-0)
To merge this branch: bzr merge lp:~elopio/u1-test-utils/in-dash-sso
Reviewer Review Type Date Requested Status
Canonical ISD hackers Pending
Review via email: mp+162634@code.launchpad.net

This proposal has been superseded by a proposal from 2013-05-06.

Commit message

Added the code to create a user and log in to Ubuntu SSO.

To post a comment you must log in.
Revision history for this message
Leo Arias (elopio) wrote :
lp:~elopio/u1-test-utils/in-dash-sso updated
32. By Leo Arias

Implemented the log out with a call to the sso dbus.

33. By Leo Arias

Implemented the is_log_in with the sso dbus.

34. By Leo Arias

Moved the sso helpers to the sso module.

35. By Leo Arias

Use the django config.

36. By Leo Arias

Added the missing settings and schema.

37. By Leo Arias

Cleanup.

38. By Leo Arias

Clean up after login, keep the system clean.

39. By Leo Arias

Cleaned the log in and log out test.

40. By Leo Arias

Some remainders of the failed config version.

41. By Leo Arias

Updated to the latests u1testutils version.

42. By Leo Arias

Use the async find credentials.

43. By Leo Arias

Import os instead of os.path.

44. By Leo Arias

Moved the mainloop call to the methods that use it.

45. By Leo Arias

Added a sso server parameter to create account.

46. By Leo Arias

Added an assertion that the user is not logged in.

47. By Leo Arias

Pass the sso url to the login method, added a FIXME on the django config import.

48. By Leo Arias

Comment about the user without payment method.

49. By Leo Arias

Pass the test to log in to make sure the user is logged out afterwards.

50. By Leo Arias

Added a comment about deleting users.

51. By Leo Arias

Added fixme comments to django imports.

52. By Leo Arias

Moved the async method to sso, and added to assertion methods to users.

53. By Leo Arias

Missing parameter.

54. By Leo Arias

Extra parameter.

55. By Leo Arias

Wrong assertion.

56. By Leo Arias

Also pass the ubuntu server url from the test to the helpers.

57. By Leo Arias

Refactored is_logged_in to be synchronous.

58. By Leo Arias

Renamed the sso is_loged_in function.

59. By Leo Arias

We need to make sure that the SSO service is running.

60. By Leo Arias

We need to make sure that the SSO service is running.

61. By Leo Arias

We need to make sure that the SSO service is running.

62. By Leo Arias

Set the urls as instance attributes.

Unmerged revisions

62. By Leo Arias

Set the urls as instance attributes.

61. By Leo Arias

We need to make sure that the SSO service is running.

60. By Leo Arias

We need to make sure that the SSO service is running.

59. By Leo Arias

We need to make sure that the SSO service is running.

58. By Leo Arias

Renamed the sso is_loged_in function.

57. By Leo Arias

Refactored is_logged_in to be synchronous.

56. By Leo Arias

Also pass the ubuntu server url from the test to the helpers.

55. By Leo Arias

Wrong assertion.

54. By Leo Arias

Extra parameter.

53. By Leo Arias

Missing parameter.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'bin'
2=== added file 'bin/vm_session_setup.py'
3--- bin/vm_session_setup.py 1970-01-01 00:00:00 +0000
4+++ bin/vm_session_setup.py 2013-05-06 17:45:31 +0000
5@@ -0,0 +1,19 @@
6+#!/usr/bin/env python
7+"""
8+Setup the gnome session environment to suit test needs.
9+"""
10+
11+from gi.repository import Gio, Gtk
12+
13+
14+def run(args=None):
15+ session = Gio.Settings('org.gnome.desktop.session')
16+ # Never sleep, we're in a vm
17+ session.set_uint('idle-delay', 0)
18+ # Never lock the screen either
19+ screen_saver = Gio.Settings('org.gnome.desktop.screensaver')
20+ screen_saver.set_boolean('lock-enabled', False)
21+
22+
23+if __name__ == "__main__":
24+ run()
25
26=== added file 'selftest.py'
27--- selftest.py 1970-01-01 00:00:00 +0000
28+++ selftest.py 2013-05-06 17:45:31 +0000
29@@ -0,0 +1,19 @@
30+#!/usr/bin/env python
31+
32+import sys
33+
34+import tests
35+
36+# load tests
37+# filter tests
38+# order tests
39+# run tests
40+
41+
42+# We discover tests under './tests', the python 'load_test' protocol can be
43+# used in test modules for more fancy stuff.
44+discover_args = ['discover',
45+ '--start-directory', './tests',
46+ ]
47+tests.TestProgram(__name__, argv=[sys.argv[0]] + discover_args + sys.argv[1:])
48+
49
50=== added directory 'tests'
51=== added file 'tests/__init__.py'
52--- tests/__init__.py 1970-01-01 00:00:00 +0000
53+++ tests/__init__.py 2013-05-06 17:45:31 +0000
54@@ -0,0 +1,114 @@
55+import os
56+import selenium
57+from selenium.webdriver.firefox import (
58+ firefox_binary,
59+ webdriver as ff_webdriver,
60+ )
61+
62+from sst import runtests as stests
63+import testtools
64+from testtools import (
65+ run,
66+ testcase,
67+ )
68+import unittest
69+import unity.tests as utests
70+
71+
72+class TestCase(testcase.TestCase):
73+ pass
74+
75+
76+class FirefoxNoRemote(firefox_binary.FirefoxBinary):
77+ """A firefox that can be called by all apps.
78+
79+ Selelnium provides a firefox instance working in isolation. While that's
80+ the most common case, we need a variant here as we don't control how the
81+ dash or any lens will call the web browser.
82+ """
83+
84+ def __init__(self, firefox_path=None):
85+ super(FirefoxNoRemote, self).__init__(firefox_path)
86+ if self._firefox_env.get('MOZ_NO_REMOTE', None) is not None:
87+ del self._firefox_env['MOZ_NO_REMOTE']
88+
89+ if selenium.__version__ < '2.32':
90+ # FIXME: The constructor above is all that is needed for selenium 2.32,
91+ # but it hasn't been pushed in all places so far so the method below
92+ # achieve the same trick for previous selenium releases
93+ def _start_from_profile_path(self, path):
94+ import platform
95+ from subprocess import Popen, PIPE, STDOUT
96+ self._firefox_env["XRE_PROFILE_PATH"] = path
97+ self._firefox_env["MOZ_CRASHREPORTER_DISABLE"] = "1"
98+ self._firefox_env["NO_EM_RESTART"] = "1"
99+
100+ if platform.system().lower() == 'linux':
101+ self._modify_link_library_path()
102+ command = [self._start_cmd, "-silent"]
103+ if self.command_line is not None:
104+ for cli in self.command_line:
105+ command.append(cli)
106+
107+ Popen(command, stdout=PIPE, stderr=STDOUT,
108+ env=self._firefox_env).communicate()
109+ command[1] = '-foreground'
110+ self.process = Popen(
111+ command, stdout=PIPE, stderr=STDOUT,
112+ env=self._firefox_env)
113+
114+
115+class WebDriverNoRemote(ff_webdriver.WebDriver):
116+ """A selenium webdriver using FirefoxNoRemote.
117+
118+ See FirefoxNoRemote for rationale.
119+ """
120+
121+ def __init__(self, firefox_profile=None, firefox_binary=None, timeout=30,
122+ capabilities=None, proxy=None):
123+ super(WebDriverNoRemote, self).__init__(
124+ firefox_profile, FirefoxNoRemote(), timeout, capabilities, proxy)
125+
126+
127+class FirefoxNoRemoteFactory(stests.FirefoxFactory):
128+ """A browser factory using FirefoxNoRemote.
129+
130+ See FirefoxNoRemote for rationale.
131+ """
132+
133+ webdriver_class = WebDriverNoRemote
134+
135+
136+class UnitySSTestcase(utests.UnityTestCase, stests.SSTTestCase):
137+
138+ def setUp(self):
139+ # We need to setup a firefox instance that capture all web connections
140+ self.browser_factory = FirefoxNoRemoteFactory()
141+ utests.UnityTestCase.setUp(self)
142+ # FIXME: Urgh, for an unclear reason, the following occurs in
143+ # autopilot.testcase.LoggedTestCase.setUp when super(LoggedTestCase,
144+ # self).setUp() is called. The joy of multiple inheritance... One more
145+ # reason to avoid it but sst doesn't provide a way to compose instead
146+ # of inheriting in our case. If we leave the following call in place,
147+ # we end up calling SSTTestCase.setUp twice which is utterly wrong. One
148+ # workaround may be to make SSTTestCase detect double calls and avoid
149+ # them but that's even dirtier than the actual behavior and may lead to
150+ # even more obscure failures -- vila 2013-03-27
151+ # stests.SSTTestCase.setUp(self)
152+
153+ # Check that the browser started with a single window opened
154+ self.assertEqual(1, len(self.browser.window_handles))
155+ self.assertEqual('about:blank', self.browser.current_url)
156+
157+ # FIXME: sst overrides testtools definition, that breaks autopilot
158+ # assumption that shortDescription can be used to generate a unique log
159+ # file. -- vila 2013-03-27
160+ shortDescription = testcase.TestCase.shortDescription
161+
162+class TestProgram(testtools.run.TestProgram):
163+
164+ def __init__(self, module, argv, stdout=None, testRunner=None, exit=True):
165+ if testRunner is None:
166+ testRunner = unittest.TextTestRunner
167+ super(TestProgram, self).__init__(module, argv=argv, stdout=stdout,
168+ testRunner=testRunner, exit=exit)
169
170=== added file 'tests/browsers.py'
171--- tests/browsers.py 1970-01-01 00:00:00 +0000
172+++ tests/browsers.py 2013-05-06 17:45:31 +0000
173@@ -0,0 +1,24 @@
174+from sst import actions
175+
176+
177+class Browser(object):
178+
179+ def __init__(self, test):
180+ super(Browser, self).__init__()
181+ self.browser = test.browser
182+ self.nb_windows = len(self.browser.window_handles)
183+
184+ def switch_to_new_window(self, test):
185+ def new_window_appeared():
186+ return len(self.browser.window_handles) > 1
187+ actions.wait_for(new_window_appeared)
188+ test.assertEqual(2, len(self.browser.window_handles))
189+ self.browser.switch_to_window(self.browser.window_handles[1])
190+
191+ @property
192+ def url(self):
193+ return self.browser.current_url
194+
195+ @property
196+ def title(self):
197+ return self.browser.title
198
199=== added file 'tests/dash.py'
200--- tests/dash.py 1970-01-01 00:00:00 +0000
201+++ tests/dash.py 2013-05-06 17:45:31 +0000
202@@ -0,0 +1,131 @@
203+from autopilot.matchers import Eventually
204+from testtools.matchers import (
205+ Equals,
206+ GreaterThan,
207+ NotEquals,
208+)
209+from unity.emulators import dash as udash
210+
211+
212+def wait_for_category(test, scope, category_name):
213+ get_category = lambda: scope.get_category_by_name(category_name)
214+ test.assertThat(get_category, Eventually(NotEquals(None)))
215+ return get_category()
216+
217+
218+class Window(object):
219+ """A dash window with a content, including buttons and links."""
220+
221+ def __init__(self, user):
222+ self.user = user
223+
224+class Home(Window):
225+ """The first window opened when the dash is activated."""
226+
227+ def get_result(self, test):
228+ lens = test.unity.dash.get_current_lens()
229+ # Wait for the category we care about to appear (that's the one where
230+ # goods can be bought).
231+ category = lens.get_category_by_name('More suggestions')
232+
233+ refresh_results_fn = lambda: len(category.get_results())
234+ test.assertThat(refresh_results_fn, Eventually(GreaterThan(0)))
235+ # Select first result as soon as it appears
236+ return category.get_results()[0]
237+
238+ def get_preview(self, test, good):
239+ test.unity.dash.ensure_visible()
240+ test.addCleanup(test.unity.dash.ensure_hidden)
241+ if test.lens_name == 'music':
242+ test.unity.dash.reveal_music_lens()
243+ # Start the search
244+ test.keyboard.type(good.search)
245+ result = self.get_result(test)
246+ # The name of the result is different between home lens and music lens
247+ # :-/ -- vila 2013-04-04
248+ test.assertTrue(good.name in result.name)
249+ # We got the right one, preview it
250+ result.preview()
251+ test.assertThat(test.unity.dash.view.preview_displaying,
252+ Eventually(Equals(True)))
253+ test.assertThat(test.unity.dash.view.get_preview_container,
254+ Eventually(NotEquals(None)))
255+ container = test.unity.dash.view.get_preview_container()
256+ # We have the preview now
257+ return Preview(self.user, good, container)
258+
259+
260+class WindowWithGood(Window):
261+
262+ def __init__(self, user, good):
263+ super(WindowWithGood, self).__init__(user)
264+ self.good = good
265+
266+ def good_displayed(self):
267+ # FIXME: There should be a way to fail ;) -- vila 2013-03-26
268+ return True
269+
270+
271+class Preview(WindowWithGood):
272+
273+ def __init__(self, user, good, container):
274+ super(Preview, self).__init__(user, good)
275+ self.container = container
276+
277+
278+ def get_dash_preview(self):
279+ content = self.container.get_children_by_type(udash.PreviewContent)[0]
280+ preview = content.get_current_preview()
281+ return preview
282+
283+ def good_displayed(self):
284+ preview = self.get_dash_preview()
285+ # FIXME: At some point, self.good.name == preview.text_boxes[0].text
286+ # used to be True... we need some other way now -- vila 2013-04-03
287+ return True
288+
289+ def get_download_button(self):
290+ preview = self.get_dash_preview()
291+ download = preview.get_action_by_id('download_album')
292+ return download
293+
294+ def click_download(self, test):
295+ download = self.get_download_button()
296+ # FIXME: MusicPreview should allow executing the action but it's
297+ # currently broken (http://pad.lv/1163930) -- vila 2013-04-03
298+ mouse = udash.Mouse()
299+ mouse.move(download.x, download.y)
300+ mouse.click()
301+ # FIXME: The current implementation diverges from the design spec by
302+ # going straight to the web without presenting a window explaining why
303+ # the good can't be bought while also displaying the good. As of today,
304+ # the workaround is to display a message instead of the button. But
305+ # this is only implemented for the music lens, not the home
306+ # lens. -- vila 2013-03-28
307+ return GotoU1(self.user, self.good)
308+
309+
310+class GotoU1(WindowWithGood):
311+
312+ def __init__(self, user, good):
313+ super(GotoU1, self).__init__(user, good)
314+ if self.user.logged_in:
315+ if self.user.payment_method == 'expired':
316+ self.message = ('Your card has expired.'
317+ 'To add a new payment method, please visit...')
318+ else:
319+ self.message = 'To add a payment method, please visit...'
320+ else:
321+ self.message = ("You don't have an Ubuntu One account,"
322+ " or you are not logged in.")
323+
324+ def click_goto_u1(self):
325+ from tests import browsers
326+ browser = browsers.get_default()
327+ # Fake the app response by forcing the url in the browser
328+ if self.user.logged_in:
329+ browser.current_url = 'https://pay.ubuntu.com'
330+ else:
331+ browser.current_url = 'https://one.ubuntu.com'
332+ return browser
333+
334
335=== added file 'tests/goods.py'
336--- tests/goods.py 1970-01-01 00:00:00 +0000
337+++ tests/goods.py 2013-05-06 17:45:31 +0000
338@@ -0,0 +1,9 @@
339+class Good(object):
340+
341+ def __init__(self, name, search):
342+ # Name is used to lightly check the result we get from the
343+ # search. Lightly here means that we ensure that the result name
344+ # contains the good name.
345+ self.name = name
346+ # How to search for this good from the dash
347+ self.search = search
348
349=== added file 'tests/sso.py'
350--- tests/sso.py 1970-01-01 00:00:00 +0000
351+++ tests/sso.py 2013-05-06 17:45:31 +0000
352@@ -0,0 +1,147 @@
353+import os
354+import subprocess
355+import time
356+
357+from autopilot.emulators import input
358+from autopilot import introspection
359+from u1testutils import settings
360+
361+
362+class UbuntuSSO(object):
363+
364+ def launch_application(self):
365+ self._prepare_environment()
366+ process = subprocess.Popen(
367+ '/usr/lib/ubuntu-sso-client/ubuntu-sso-login-qt')
368+ self.application = (
369+ introspection.get_autopilot_proxy_object_for_process(process))
370+
371+ def _prepare_environment(self):
372+ os.environ['TESTABILITY'] = '1'
373+ os.environ['USSOC_SERVICE_URL'] = '{0}/api/1.0/'.format(
374+ settings.OPENID_SSO_SERVER_URL)
375+ os.environ['SSO_AUTH_BASE_URL'] = settings.OPENID_SSO_SERVER_URL
376+ os.environ['SSO_UONE_BASE_URL'] = settings.UBUNTUONE_SERVER_URL
377+ os.system('pkill ubuntu-sso')
378+ subprocess.Popen('/usr/lib/ubuntu-sso-client/ubuntu-sso-login')
379+
380+ def log_in(self, user):
381+ self.launch_application()
382+ log_in_page = self._go_to_log_in_page()
383+ success_page = log_in_page.log_in_with_successful_authentication(user)
384+ assert (success_page.get_message() ==
385+ 'You are now logged into Ubuntu One.')
386+ success_page.finish()
387+
388+ def _go_to_log_in_page(self):
389+ sign_up_page = SignUpPage(self.application)
390+ sign_up_page.wait_for_action_to_complete()
391+ return sign_up_page.go_to_log_in()
392+
393+
394+class Page(object):
395+
396+ def __init__(self, application, page_type):
397+ self.application = application
398+ self.page = self.application.select_single(page_type)
399+ self.keyboard = input.get_keyboard()
400+ self.mouse = input.get_mouse()
401+
402+ def wait_for_action_to_complete(self):
403+ """Wait for the last action to complete.
404+
405+ This method waits for the loading overlay to dissapear.
406+
407+ """
408+ # If autopilot executes too fast, we might look for the loading overlay
409+ # before it is shown. We should wait a little to give it time to
410+ # appear, but it's not possible to wait for it, because if autopilot
411+ # executes too slow, we might look for it after it dissapears.
412+ # Thus, the only solution that comes to mind is a sleep.
413+ # -- elopio - 2013-05-03
414+ time.sleep(3)
415+ loading_overlay = self.application.select_single('LoadingOverlay')
416+ loading_overlay.visible.wait_for(False)
417+
418+ # TODO propose this to autopilot. -- elopio - 2013-05-03
419+ def get_child_by_type(self, desired_type, **kwargs):
420+ children = self.page.get_children_by_type(desired_type, **kwargs)
421+ assert len(children) > 0, 'No child found.'
422+ assert len(children) == 1, 'More than one child found.'
423+ return children[0]
424+
425+
426+class SignUpPage(Page):
427+
428+ def __init__(self, application):
429+ super(SignUpPage, self).__init__(application, 'SetupAccountPage')
430+
431+ def go_to_log_in(self):
432+ self.wait_for_action_to_complete()
433+ sign_in_label = self.get_child_by_type(
434+ 'QLabel', objectName='sign_in_label')
435+ self.mouse.move_to_object(sign_in_label)
436+ self.mouse.click()
437+ self.wait_for_action_to_complete()
438+ return LogInPage(self.application)
439+
440+
441+class LogInPage(Page):
442+
443+ def __init__(self, application):
444+ super(LogInPage, self).__init__(application, 'CurrentUserSignInPage')
445+
446+ def log_in_with_successful_authentication(self, user):
447+ self._log_in(user.email, user.password)
448+ assert self.get_form_errors() is None
449+ return SuccessPage(self.application)
450+
451+ def _log_in(self, email, password):
452+ self._fill_log_in_form(email, password)
453+ sign_in_button = self.get_child_by_type(
454+ 'QPushButton', objectName='sign_in_button')
455+ self.mouse.move_to_object(sign_in_button)
456+ self.mouse.click()
457+ self.wait_for_action_to_complete()
458+
459+ def _fill_log_in_form(self, email, password):
460+ email_edit = self.get_child_by_type(
461+ 'QLineEdit', objectName='email_edit')
462+ self.mouse.move_to_object(email_edit)
463+ self.mouse.click()
464+ self.keyboard.type(email)
465+ password_edit = self.get_child_by_type(
466+ 'QLineEdit', objectName='password_edit')
467+ self.mouse.move_to_object(password_edit)
468+ self.mouse.click()
469+ self.keyboard.type(password)
470+
471+ def get_form_errors(self):
472+ form_errors = self.get_child_by_type(
473+ 'QLabel', objectName='form_errors')
474+ if form_errors.visible:
475+ return form_errors.text
476+ else:
477+ return None
478+
479+
480+class SuccessPage(Page):
481+
482+ def __init__(self, application):
483+ super(SuccessPage, self).__init__(application, 'SuccessPage')
484+
485+ def get_message(self):
486+ label = self.get_child_by_type(
487+ 'QLabel', objectName='success_message_body')
488+ return label.text
489+
490+ def finish(self):
491+ # TODO when we have the emulator, this should be on the wizard, not the
492+ # page. -- elopio - 2013-05-03
493+ # Bug reported to QWizard because the buttons don't have objectName:
494+ # https://bugreports.qt-project.org/browse/QTBUG-29924
495+ # TODO update when the bug is fixed. -- elopio - 2013-05-03
496+ finish_button = self.application.select_single(
497+ 'QPushButton', text='&Finish')
498+ self.mouse.move_to_object(finish_button)
499+ self.mouse.click()
500
501=== added file 'tests/test_dash.py'
502--- tests/test_dash.py 1970-01-01 00:00:00 +0000
503+++ tests/test_dash.py 2013-05-06 17:45:31 +0000
504@@ -0,0 +1,34 @@
505+import autopilot
506+from autopilot.matchers import Eventually
507+from testtools.matchers import Contains, Equals, GreaterThan
508+import unity.tests as utests
509+
510+
511+class TestDash(utests.UnityTestCase):
512+
513+ # This test needs to be upgraded to catch up with autopilot and unity
514+ # recent versions.
515+ def xtest_select_preview(self):
516+ self.unity.dash.ensure_visible()
517+ self.addCleanup(self.unity.dash.ensure_hidden)
518+ lens = self.unity.dash.get_current_lens()
519+ self.keyboard.type("hendrix")
520+ results_category = lens.get_category_by_name("More suggestions")
521+ refresh_results_fn = lambda: len(results_category.get_results())
522+ self.assertThat(refresh_results_fn, Eventually(GreaterThan(1)))
523+ # Select first result
524+ self.keyboard.press_and_release('Enter')
525+ # We have the preview now
526+ self.keyboard.press_and_release('Enter')
527+ self.assertTrue(self.bamf.wait_until_application_is_running(
528+ 'firefox.desktop', 10.0))
529+ firefox = self.bamf.get_running_applications_by_desktop_file(
530+ 'firefox.desktop')[0]
531+ self.addCleanup(firefox.get_windows()[0].close)
532+ # FIXME: We can't get the right title as we receive the window too
533+ # soon. -- vila 2013-02-21
534+# for w in firefox.get_windows():
535+# print 'title: %s' % (w.title)
536+# import pdb; pdb.set_trace()
537+# self.assertEqual('Log in - Mozilla Firefox',
538+# firefox.get_windows()[0].title)
539
540=== added file 'tests/test_dbus.py'
541--- tests/test_dbus.py 1970-01-01 00:00:00 +0000
542+++ tests/test_dbus.py 2013-05-06 17:45:31 +0000
543@@ -0,0 +1,19 @@
544+import tests
545+
546+import dbus
547+from gi.repository import Gio, Gtk
548+
549+class TestDBUS(tests.TestCase):
550+
551+ def setUp(self):
552+ super(TestDBUS, self).setUp()
553+ self.bus = dbus.SessionBus()
554+ # Register and clean up our own bus.
555+ self.bus.request_name('canonical.online-services.selftest')
556+ self.addCleanup(self.bus.release_name,
557+ 'canonical.online-services.selftest')
558+
559+ def test_it(self):
560+ # FIXME: We need some real tests :0) But the setUp above will be
561+ # exercised even by an eempty test and represent useful knowledge.
562+ pass
563
564=== added file 'tests/test_purchase_good.py'
565--- tests/test_purchase_good.py 1970-01-01 00:00:00 +0000
566+++ tests/test_purchase_good.py 2013-05-06 17:45:31 +0000
567@@ -0,0 +1,92 @@
568+import unity.tests as utests
569+
570+from sst import actions as sactions
571+
572+import tests
573+from tests import (
574+ browsers,
575+ dash,
576+ goods,
577+ users,
578+)
579+
580+# Command to use different servers for in-dash purchases
581+# pkill unity-music; G_MESSAGES_DEBUG=all U1_STAGING_WEBAPI=https://staging.one.ubuntu.com/ U1_STAGING_AUTHENTICATION=https://login.staging.ubuntu.com/ /usr/lib/x86_64-linux-gnu/unity-lens-music/unity-musicstore-daemon
582+
583+# Command to use the local servers for in-dash purchases
584+# pkill unity-music; G_MESSAGES_DEBUG=all U1_STAGING_WEBAPI=http://u1.local:8003/ U1_STAGING_AUTHENTICATION=http://sso.local:8001/ /usr/lib/x86_64-linux-gnu/unity-lens-music/unity-musicstore-daemon
585+
586+
587+class TestPurchaseGood(tests.UnitySSTestcase):
588+
589+
590+ def setUp(self):
591+ super(TestPurchaseGood, self).setUp()
592+ # A user will purchase a good
593+ self.user = users.User.make_unique()
594+ # Arbitrarily using a good that is known to work
595+ self.good = goods.Good(u'Jimi Hendrix', 'hendrix')
596+
597+ def preview_good(self):
598+ home = dash.Home(self.user)
599+ self.preview = home.get_preview(self, self.good)
600+ # user get a preview screen and a button to click on
601+ self.assertTrue(self.preview.good_displayed())
602+
603+ def purchase_good(self):
604+ # Attempt to purchase the good
605+ return self.preview.click_download(self)
606+
607+
608+class TestUserCannotPay(TestPurchaseGood):
609+
610+ scenarios = [(name, {'lens_name': name}) for name in ('home', 'music',)]
611+
612+ def test_user_not_logged_in(self):
613+ # User not logged in
614+ self.user.logout()
615+ self.preview_good()
616+ if self.lens_name == 'music':
617+ # There is a workaround in place for the music lens only that
618+ # forbids testing the rest of the workflow
619+ self.assertIs(None, self.preview.get_download_button())
620+ # FIXME: It would be nice to check the message displayed when the
621+ # button is not available but it's not exposed -- vila 2013-04-04
622+ return
623+ goto_u1 = self.purchase_good()
624+ # diverges from the design spec, we go directly to the web
625+ # self.assertTrue(goto_u1.good_displayed())
626+ browser = browsers.Browser(self)
627+ # We've been redirected to the web
628+ browser.switch_to_new_window(self)
629+ sactions.wait_for(sactions.assert_url_contains,
630+ 'https://login.ubuntu.com')
631+ self.assertEqual('Log in', browser.title)
632+
633+ def test_no_payment_method_stored(self):
634+ # User has no payment method
635+ self.user.login()
636+ self.user.payment_method = None
637+ goto_u1 = self.purchase_good()
638+ self.assertTrue(goto_u1.good_displayed())
639+ self.assertIn('add a payment method', goto_u1.message)
640+ # The default browser is launched to propose paying
641+ browser = goto_u1.click_goto_u1()
642+ # User is sent to the web
643+ self.assertTrue(browser.is_running())
644+ self.assertEqual('https://pay.ubuntu.com', browser.current_url)
645+
646+ def test_pay_method_expired(self):
647+ # Uesrs's payment has expired
648+ self.user.login()
649+ self.user.payment_method = 'expired'
650+ goto_u1 = self.purchase_good()
651+ self.assertTrue(goto_u1.good_displayed())
652+ self.assertIn('card has expired', goto_u1.message)
653+ # The default browser is launched to propose paying
654+ browser = goto_u1.click_goto_u1()
655+ # User is sent to the web
656+ self.assertTrue(browser.is_running())
657+ self.assertEqual('https://pay.ubuntu.com', browser.current_url)
658+
659+
660
661=== added file 'tests/test_session.py'
662--- tests/test_session.py 1970-01-01 00:00:00 +0000
663+++ tests/test_session.py 2013-05-06 17:45:31 +0000
664@@ -0,0 +1,19 @@
665+import tests
666+
667+from gi.repository import Gio, Gtk
668+
669+class TestGSettings(tests.TestCase):
670+
671+ def test_session(self):
672+ s = Gio.Settings('org.gnome.desktop.session')
673+ orig = s.get_uint('idle-delay')
674+ self.addCleanup(s.set_uint, 'idle-delay', orig)
675+ s.set_uint('idle-delay', orig + 2)
676+ self.assertEqual(orig + 2, s.get_uint('idle-delay'))
677+
678+ def test_screensaver(self):
679+ s = Gio.Settings('org.gnome.desktop.screensaver')
680+ orig = s.get_boolean('lock-enabled')
681+ self.addCleanup(s.set_boolean, 'lock-enabled', orig)
682+ s.set_boolean('lock-enabled', not orig)
683+ self.assertEqual(not orig, s.get_boolean('lock-enabled'))
684
685=== added file 'tests/test_users.py'
686--- tests/test_users.py 1970-01-01 00:00:00 +0000
687+++ tests/test_users.py 2013-05-06 17:45:31 +0000
688@@ -0,0 +1,42 @@
689+import mock
690+
691+import tests
692+from tests import users
693+
694+
695+class UsersTest(tests.TestCase):
696+
697+ def _patch_u1testutils_settings(self, **kwargs):
698+ for setting, new_value in kwargs.items():
699+ name = 'u1testutils.settings.{0}'.format(setting)
700+ patcher = mock.patch(name, new_value)
701+ self.addCleanup(patcher.stop)
702+ patcher.start()
703+
704+ def test_make_unique(self):
705+ self._patch_u1testutils_settings(
706+ EMAIL_ADDRESS_PATTERN='emailconf+%s@example.com',
707+ SSO_TEST_ACCOUNT_PASSWORD='password from configuration')
708+ with mock.patch('uuid.uuid1') as mock_uuid:
709+ mock_uuid.return_value = 'test_uuid'
710+ user = users.User.make_unique()
711+
712+ self.assertEqual(user.user_data.full_name, 'Test user test_uuid')
713+ self.assertEqual(
714+ user.user_data.email, 'emailconf+test_uuid@example.com')
715+ self.assertEqual(
716+ user.user_data.password, 'password from configuration')
717+ self.assertEqual(user.is_logged_in(), False)
718+ self.assertEqual(user.payment_method, None)
719+
720+ def test_log_in(self):
721+ user = users.User.make_unique()
722+ user.login()
723+ self.assertEqual(user.is_logged_in(), True)
724+
725+ def test_log_out(self):
726+ user = users.User.make_unique()
727+ user.logged_in = True
728+ user.logout()
729+ self.assertEqual(user.is_logged_in(), False)
730+
731
732=== added file 'tests/users.py'
733--- tests/users.py 1970-01-01 00:00:00 +0000
734+++ tests/users.py 2013-05-06 17:45:31 +0000
735@@ -0,0 +1,43 @@
736+import dbus
737+from dbus.mainloop.glib import DBusGMainLoop
738+
739+from u1testutils.sso import data, client
740+
741+from tests import sso
742+
743+
744+class User(object):
745+
746+ def __init__(self, user_data):
747+ self.user_data = user_data
748+ self.logged_in = False
749+ self.payment_method = None
750+
751+ @classmethod
752+ def make_unique(cls):
753+ user_data = data.User.make_from_configuration(new_user=True)
754+ return cls(user_data)
755+
756+ def is_logged_in(self):
757+ # TODO make this work.
758+ #DBusGMainLoop(set_as_default=True)
759+ #session_bus = dbus.SessionBus()
760+ #proxy = session_bus.get_object(
761+ # 'com.ubuntu.sso', '/com/ubuntu/sso/credentials')
762+ #interface = dbus.Interface(
763+ # proxy, dbus_interface='com.ubuntu.sso.CredentialsManagement')
764+ #proxy.connect_to_signal('CredentialsFound', credentials_found)
765+ #proxy.connect_to_signal('CredentialsNotFound', credentials_not_found)
766+ #proxy.connect_to_signal('CredentialsError', credentials_error)
767+ #interface.find_credentials('Ubuntu One', {})
768+ return self.logged_in
769+
770+ def login(self):
771+ client.create_new_account(
772+ self.user_data, captcha_id='Not used', captcha_solution='Not used')
773+ ubuntu_sso = sso.UbuntuSSO()
774+ ubuntu_sso.log_in(self.user_data)
775+ self.logged_in = True
776+
777+ def logout(self):
778+ self.logged_in = False

Subscribers

People subscribed via source and target branches

to all changes: