Merge lp:~elopio/ubuntu-sso-client/autopilot into lp:ubuntu-sso-client

Proposed by Leo Arias
Status: Work in progress
Proposed branch: lp:~elopio/ubuntu-sso-client/autopilot
Merge into: lp:ubuntu-sso-client
Diff against target: 195 lines (+189/-0)
1 file modified
ubuntu_sso/tests/acceptance/test_ubuntu_sso_client.py (+189/-0)
To merge this branch: bzr merge lp:~elopio/ubuntu-sso-client/autopilot
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Vincent Ladeuil Pending
Review via email: mp+150260@code.launchpad.net

Description of the change

Run with:
autopilot ubuntu_sso.tests.acceptance

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) wrote :

Looks good to me (code review) did not have a chance to run it, sorry :-(

review: Approve

Unmerged revisions

1024. By Leo Arias

Second pass to the autopilot acceptance test.

1023. By Leo Arias

Merged with trunk.

1022. By Leo Arias

Added an autopilot acceptance test.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'ubuntu_sso/tests/acceptance'
2=== added file 'ubuntu_sso/tests/acceptance/__init__.py'
3=== added file 'ubuntu_sso/tests/acceptance/test_ubuntu_sso_client.py'
4--- ubuntu_sso/tests/acceptance/test_ubuntu_sso_client.py 1970-01-01 00:00:00 +0000
5+++ ubuntu_sso/tests/acceptance/test_ubuntu_sso_client.py 2013-02-25 04:12:21 +0000
6@@ -0,0 +1,189 @@
7+import time
8+import os
9+import uuid
10+
11+import dbus
12+from dbus.mainloop.glib import DBusGMainLoop
13+
14+from autopilot import introspection, testcase
15+from autopilot.emulators import X11
16+from testtools.matchers import Equals, Contains
17+
18+
19+# This should be an emulator. But it seems that the only way to make an
20+# emulator is if the application's bus has well-known name.
21+# TODO ask on #qa.
22+class Page(object):
23+
24+ def __init__(self, application, page_type):
25+ self.application = application
26+ self.page = self.application.select_single(page_type)
27+ self.keyboard = X11.Keyboard()
28+ self.mouse = X11.Mouse()
29+
30+ def wait_for_action_to_complete(self):
31+ """Wait for the last action to complete.
32+
33+ This method waits for the loading overlay to dissapear.
34+
35+ """
36+ # If autopilot executes too fast, we might look for the loading overlay
37+ # before it is shown. We should wait a little to give it time to
38+ # appear, but it's not possible to wait for it, because if autopilot
39+ # executes too slow, we might look for it after it dissapears.
40+ # Thus, the only solution that comes to mind is a sleep. -- Leo
41+ time.sleep(3)
42+ loading_overlay = self.application.select_single('LoadingOverlay')
43+ loading_overlay.visible.wait_for(False)
44+
45+ # TODO propose this to autopilot.
46+ def get_child_by_type(self, desired_type, **kwargs):
47+ children = self.page.get_children_by_type(desired_type, **kwargs)
48+ assert len(children) > 0, 'No child found.'
49+ assert len(children) == 1, 'More than one child found.'
50+ return children[0]
51+
52+
53+class SignUpPage(Page):
54+
55+ def __init__(self, application):
56+ super(SignUpPage, self).__init__(application, 'SetupAccountPage')
57+
58+ def go_to_log_in(self):
59+ sign_in_label = self.get_child_by_type(
60+ 'QLabel', objectName='sign_in_label')
61+ self.mouse.move_to_object(sign_in_label)
62+ self.mouse.click()
63+ self.wait_for_action_to_complete()
64+ return LogInPage(self.application)
65+
66+
67+class LogInPage(Page):
68+
69+ def __init__(self, application):
70+ super(LogInPage, self).__init__(application, 'CurrentUserSignInPage')
71+
72+ def log_in_with_successful_authentication(self, email, password):
73+ self._log_in(email, password)
74+ assert self.get_form_errors() is None
75+ return SuccessPage(self.application)
76+
77+ def _log_in(self, email, password):
78+ self._fill_log_in_form(email, password)
79+ sign_in_button = self.get_child_by_type(
80+ 'QPushButton', objectName='sign_in_button')
81+ self.mouse.move_to_object(sign_in_button)
82+ self.mouse.click()
83+ self.wait_for_action_to_complete()
84+
85+ def log_in_with_failed_authentication(self, email, password):
86+ self._log_in(email, password)
87+ return self.page
88+
89+ def _fill_log_in_form(self, email, password):
90+ email_edit = self.get_child_by_type(
91+ 'QLineEdit', objectName='email_edit')
92+ self.mouse.move_to_object(email_edit)
93+ self.mouse.click()
94+ self.keyboard.type(email)
95+ password_edit = self.get_child_by_type(
96+ 'QLineEdit', objectName='password_edit')
97+ self.mouse.move_to_object(password_edit)
98+ self.mouse.click()
99+ self.keyboard.type(password)
100+
101+ def get_form_errors(self):
102+ form_errors = self.get_child_by_type(
103+ 'QLabel', objectName='form_errors')
104+ if form_errors.visible:
105+ return form_errors.text
106+ else:
107+ return None
108+
109+
110+class SuccessPage(Page):
111+
112+ def __init__(self, application):
113+ super(SuccessPage, self).__init__(application, 'SuccessPage')
114+
115+ def get_message(self):
116+ label = self.get_child_by_type(
117+ 'QLabel', objectName='success_message_body')
118+ return label.text
119+
120+ def finish(self):
121+ # TODO when we have the emulator, this should be on the wizard, not the
122+ # page.
123+ # TODO file a bug to QWizard because the buttons don't have objectName.
124+ finish_button = self.application.select_single(
125+ 'QPushButton', text='&Finish')
126+ self.mouse.move_to_object(finish_button)
127+ self.mouse.click()
128+
129+
130+class NoEnvironmentIntrospectionTestMixin(
131+ introspection.ApplicationIntrospectionTestMixin):
132+
133+ def prepare_environment(self, app_path, arguments):
134+ return app_path, arguments
135+
136+
137+class TestUbuntuSSOClient(
138+ testcase.AutopilotTestCase, NoEnvironmentIntrospectionTestMixin):
139+
140+ def setUp(self):
141+ super(TestUbuntuSSOClient, self).setUp()
142+ os.environ['TESTABILITY'] = '1'
143+ # TODO we shouldn't start the application this way. We should call
144+ # the register or login method through dbus.
145+ # There are two problems with this. First, the TESTABILITY variable
146+ # is not passed as True. Second, I haven't found an easy way to get
147+ # the autopilot dbus proxy.
148+ self.app_name = 'App {0}'.format(str(uuid.uuid1()))
149+ self.application = self.launch_test_application(
150+ 'bin/ubuntu-sso-login-qt',
151+ '--app_name={0}'.format(self.app_name))
152+
153+ def _clear_credentials(self):
154+ DBusGMainLoop(set_as_default=True)
155+ session_bus = dbus.SessionBus()
156+ proxy = session_bus.get_object(
157+ 'com.ubuntu.sso', '/com/ubuntu/sso/credentials')
158+ interface = dbus.Interface(
159+ proxy, dbus_interface='com.ubuntu.sso.CredentialsManagement')
160+ interface.clear_credentials(self.app_name, {})
161+
162+ def _log_in_with_successful_authentication(self, email, password):
163+ log_in_page = self._go_to_log_in_page()
164+ return log_in_page.log_in_with_successful_authentication(
165+ email, password)
166+
167+ def _go_to_log_in_page(self):
168+ sign_up_page = SignUpPage(self.application)
169+ sign_up_page.wait_for_action_to_complete()
170+ return sign_up_page.go_to_log_in()
171+
172+ def _log_in_with_failed_authentication(self, email, password):
173+ log_in_page = self._go_to_log_in_page()
174+ log_in_page.log_in_with_failed_authentication(email, password)
175+ self.assertTrue(log_in_page.page.visible)
176+ return log_in_page
177+
178+ def test_authentication_failed(self):
179+ log_in_page = self._log_in_with_failed_authentication(
180+ 'wrong-email@canonical.com', 'wrong password')
181+ self.assertThat(
182+ log_in_page.get_form_errors(),
183+ Contains('The authentication failed.'))
184+
185+ def test_successful_log_in(self):
186+ self.skipTest('This is a public project, so we need a way to store '
187+ 'real user credentials on a private way.')
188+ self.addCleanup(self._clear_credentials)
189+ success_page = self._log_in_with_successful_authentication(
190+ 'u1test+sso@canonical.com', 'some-password')
191+ self.assertThat(
192+ success_page.get_message(),
193+ Equals('You are now logged into {0}.'.format(self.app_name)))
194+ success_page.finish()
195+ # TODO assert that the application is closed.

Subscribers

People subscribed via source and target branches