Merge lp:~elopio/u1-test-utils/dash-tests into lp:~canonical-isd-hackers/u1-test-utils/test-in-dash-payments

Proposed by Leo Arias
Status: Merged
Approved by: Leo Arias
Approved revision: 64
Merged at revision: 64
Proposed branch: lp:~elopio/u1-test-utils/dash-tests
Merge into: lp:~canonical-isd-hackers/u1-test-utils/test-in-dash-payments
Diff against target: 386 lines (+147/-127)
5 files modified
tests/dash.py (+83/-65)
tests/schema.py (+3/-0)
tests/test_dash.py (+34/-28)
tests/test_purchase_good.py (+26/-33)
tests/test_session.py (+1/-1)
To merge this branch: bzr merge lp:~elopio/u1-test-utils/dash-tests
Reviewer Review Type Date Requested Status
Vincent Ladeuil (community) Approve
Review via email: mp+164760@code.launchpad.net

This proposal supersedes a proposal from 2013-05-20.

Commit message

Added tests for the dash functions we use, cleaned the purchase tests and make sure they will work with the local servers.

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

44 + # TODO We should check if the result is visible, instead of checking if
45 + # there are visible categories. I don't know how to do it, I'll ask
46 + # --elopio - 2013-05-19

I thought the following was doing that:

91 - refresh_results_fn = lambda: len(category.get_results())
92 - test.assertThat(refresh_results_fn, Eventually(GreaterThan(0)))
93 - # Select first result as soon as it appears
94 - return category.get_results()[0]

This also ensures that there is at least one result which the following
doesn't seem to care about:

40 + return category.get_results()[0]

I'm not sure about why you thunk some methods to functions but as long as
daughter classes can still redefine the methods, I don't have strong
objections either.

review: Approve
lp:~elopio/u1-test-utils/dash-tests updated
64. By Leo Arias

Assert that there is at least one result displayed.

Revision history for this message
Leo Arias (elopio) wrote :

> 44 + # TODO We should check if the result is visible, instead of checking
> if
> 45 + # there are visible categories. I don't know how to do it, I'll ask
> 46 + # --elopio - 2013-05-19
>
> I thought the following was doing that:
>
> 91 - refresh_results_fn = lambda: len(category.get_results())
> 92 - test.assertThat(refresh_results_fn, Eventually(GreaterThan(0)))
> 93 - # Select first result as soon as it appears
> 94 - return category.get_results()[0]
>
> This also ensures that there is at least one result which the following
> doesn't seem to care about:
>
> 40 + return category.get_results()[0]

You are right. I copied that part of the code. Thanks.

> I'm not sure about why you thunk some methods to functions but as long as
> daughter classes can still redefine the methods, I don't have strong
> objections either.

My goal is to put this in a custom autopilot emulator that inherits from the one in unity. We still need a little work from the autopilot team for that.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'tests/dash.py'
2--- tests/dash.py 2013-05-17 16:24:59 +0000
3+++ tests/dash.py 2013-06-19 20:36:26 +0000
4@@ -4,13 +4,69 @@
5 GreaterThan,
6 NotEquals,
7 )
8-from unity.emulators import dash as udash
9-
10-
11-def wait_for_category(test, scope, category_name):
12- get_category = lambda: scope.get_category_by_name(category_name)
13- test.assertThat(get_category, Eventually(NotEquals(None)))
14- return get_category()
15+
16+
17+def search_music_scope(test, query):
18+ test.addCleanup(test.unity.dash.ensure_hidden)
19+ test.unity.dash.reveal_music_scope()
20+ test.addCleanup(clear_music_scope_search, test)
21+ test.keyboard.type(query)
22+ music_scope = test.unity.dash.get_current_scope()
23+ # Wait for a category to appear.
24+ test.assertThat(
25+ music_scope.get_num_visible_categories,
26+ Eventually(GreaterThan(0)))
27+
28+
29+def clear_music_scope_search(test):
30+ dash = test.unity.dash
31+ if (not dash.visible) or (dash.get_current_scope() != 'music.scope'):
32+ dash.reveal_music_scope()
33+ dash.clear_search()
34+
35+
36+def get_first_result_from_category(test, category_name):
37+ current_scope = test.unity.dash.get_current_scope()
38+ category = current_scope.get_category_by_name(category_name)
39+ test.assertTrue(category.is_visible)
40+ get_number_of_results = lambda: len(category.get_results())
41+ test.assertThat(get_number_of_results, Eventually(GreaterThan(0)))
42+ return category.get_results()[0]
43+
44+
45+def preview_result(test, result):
46+ current_scope = test.unity.dash.get_current_scope()
47+ test.assertThat(current_scope.get_num_visible_categories(), GreaterThan(0))
48+ result.preview()
49+ _wait_for_preview_animation(test)
50+
51+
52+def _wait_for_preview_animation(test):
53+ test.assertThat(
54+ test.unity.dash.view.get_preview_container,
55+ Eventually(NotEquals(None)))
56+ preview_container = test.unity.dash.view.get_preview_container()
57+ test.assertThat(
58+ preview_container.animating, Eventually(Equals(False)))
59+
60+
61+def ensure_preview_closed(test):
62+ if test.unity.dash.preview_displaying:
63+ close_preview(test)
64+
65+
66+def close_preview(test):
67+ test.assertTrue(test.unity.dash.preview_displaying)
68+ test.keyboard.press_and_release('Escape')
69+
70+
71+def get_current_preview(test):
72+ test.assertThat(
73+ test.unity.dash.view.get_preview_container,
74+ Eventually(NotEquals(None)))
75+ container = test.unity.dash.view.get_preview_container()
76+ test.assertThat(container.waiting_preview, Eventually(Equals(False)))
77+ return container.current_preview
78
79
80 class Window(object):
81@@ -23,37 +79,17 @@
82 """The first window opened when the dash is activated."""
83
84 def get_result(self, test):
85- scope = test.unity.dash.get_current_scope()
86- # Wait for the category we care about to appear (that's the one where
87- # goods can be bought).
88- category = scope.get_category_by_name('More suggestions')
89-
90- refresh_results_fn = lambda: len(category.get_results())
91- test.assertThat(refresh_results_fn, Eventually(GreaterThan(0)))
92- # Select first result as soon as it appears
93- return category.get_results()[0]
94+ # XXX Currently we can't force the Music Store to return a result,
95+ # so for now we will just use the first one. --elopio - 2013-05-19
96+ return get_first_result_from_category(test, 'More suggestions')
97
98 def get_preview(self, test, good):
99- test.unity.dash.ensure_visible()
100- test.addCleanup(test.unity.dash.ensure_hidden)
101- # Use the scope required by the test
102- if test.scope_name == 'music':
103- test.unity.dash.reveal_music_scope()
104- # Start the search
105- test.keyboard.type(good.search)
106+ search_music_scope(test, good.search)
107 result = self.get_result(test)
108- # The name of the result is different between home scope and music scope
109- # :-/ -- vila 2013-04-04
110- test.assertTrue(good.name in result.name)
111- # We got the right one, preview it
112- result.preview()
113- test.assertThat(test.unity.dash.view.preview_displaying,
114- Eventually(Equals(True)))
115- test.assertThat(test.unity.dash.view.get_preview_container,
116- Eventually(NotEquals(None)))
117- container = test.unity.dash.view.get_preview_container()
118+ test.addCleanup(ensure_preview_closed, test)
119+ preview_result(test, result)
120 # We have the preview now
121- return Preview(self.user, good, container)
122+ return Preview(self.user, good)
123
124
125 class WindowWithGood(Window):
126@@ -69,24 +105,13 @@
127
128 class Preview(WindowWithGood):
129
130- def __init__(self, user, good, container):
131+ _DOWNLOAD_BUTTON_ID = 'show_purchase_preview'
132+
133+ def __init__(self, user, good):
134 super(Preview, self).__init__(user, good)
135- self.container = container
136-
137-
138- def get_dash_preview(self):
139- content = self.container.get_children_by_type(udash.PreviewContent)[0]
140- preview = content.get_current_preview()
141- return preview
142-
143- def good_displayed(self):
144- preview = self.get_dash_preview()
145- # FIXME: At some point, self.good.name == preview.text_boxes[0].text
146- # used to be True... we need some other way now -- vila 2013-04-03
147- return True
148-
149- def get_message_replacing_action(self):
150- preview = self.get_dash_preview()
151+
152+ def get_message_replacing_action(self, test):
153+ preview = get_current_preview()
154 # FIXME: Far from pretty but at least we can get it. There are two
155 # issues below: [2] may break if more StaticCairoTexts are added and
156 # the 'get_properties()['text'] may be brittle (but that would mean
157@@ -96,21 +121,14 @@
158 message = preview.text_boxes[2].get_properties()['text']
159 return message
160
161- def get_download_button(self):
162- preview = self.get_dash_preview()
163- # FIXME: Urgh, we can't access the action button by name anymore,
164- # relying on the fact that there is only one button for now. -- vila
165- # 2013-05-17
166- download = preview.get_children_by_type(udash.ActionButton)[0]
167+ def get_download_button(self, test):
168+ preview = get_current_preview(test)
169+ download = preview.get_action_by_id(self._DOWNLOAD_BUTTON_ID)
170 return download
171
172 def click_download(self, test):
173- download = self.get_download_button()
174- # FIXME: MusicPreview should allow executing the action but it's
175- # currently broken (http://pad.lv/1163930) -- vila 2013-04-03
176- mouse = udash.get_mouse()
177- mouse.move(download.x, download.y)
178- mouse.click()
179+ preview = get_current_preview(test)
180+ preview.execute_action_by_id(self._DOWNLOAD_BUTTON_ID)
181 # FIXME: The current implementation diverges from the design spec by
182 # going straight to the web without presenting a window explaining why
183 # the good can't be bought while also displaying the good. As of today,
184@@ -124,8 +142,8 @@
185
186 def __init__(self, user, good):
187 super(GotoU1, self).__init__(user, good)
188- if self.user.logged_in:
189- if self.user.payment_method == 'expired':
190+ if self.user.is_logged_in():
191+ if self.user.get_payment_type() == 'expired':
192 self.message = ('Your card has expired.'
193 'To add a new payment method, please visit...')
194 else:
195
196=== modified file 'tests/schema.py'
197--- tests/schema.py 2013-05-10 06:21:41 +0000
198+++ tests/schema.py 2013-06-19 20:36:26 +0000
199@@ -15,5 +15,8 @@
200 class ubuntuone(schema.Section):
201 ubuntuone_server_url = schema.StringOption()
202
203+ class musicsearch(schema.Section):
204+ musicsearch_server_url = schema.StringOption()
205+
206
207 schema = InDashPaymentsSchema
208
209=== modified file 'tests/test_dash.py'
210--- tests/test_dash.py 2013-05-17 13:00:48 +0000
211+++ tests/test_dash.py 2013-06-19 20:36:26 +0000
212@@ -1,34 +1,40 @@
213-import autopilot
214+import unity.tests as utests
215+
216 from autopilot.matchers import Eventually
217-from testtools.matchers import Contains, Equals, GreaterThan
218-import unity.tests as utests
219+from testtools.matchers import Equals
220+
221+from tests import dash
222
223
224 class TestDash(utests.UnityTestCase):
225
226- # This test needs to be upgraded to catch up with autopilot and unity
227- # recent versions.
228- def xtest_select_preview(self):
229- self.unity.dash.ensure_visible()
230+ def setUp(self):
231+ super(TestDash, self).setUp()
232 self.addCleanup(self.unity.dash.ensure_hidden)
233- scope = self.unity.dash.get_current_scope()
234- self.keyboard.type("hendrix")
235- results_category = scope.get_category_by_name("More suggestions")
236- refresh_results_fn = lambda: len(results_category.get_results())
237- self.assertThat(refresh_results_fn, Eventually(GreaterThan(1)))
238- # Select first result
239- self.keyboard.press_and_release('Enter')
240- # We have the preview now
241- self.keyboard.press_and_release('Enter')
242- self.assertTrue(self.bamf.wait_until_application_is_running(
243- 'firefox.desktop', 10.0))
244- firefox = self.bamf.get_running_applications_by_desktop_file(
245- 'firefox.desktop')[0]
246- self.addCleanup(firefox.get_windows()[0].close)
247- # FIXME: We can't get the right title as we receive the window too
248- # soon. -- vila 2013-02-21
249-# for w in firefox.get_windows():
250-# print 'title: %s' % (w.title)
251-# import pdb; pdb.set_trace()
252-# self.assertEqual('Log in - Mozilla Firefox',
253-# firefox.get_windows()[0].title)
254+
255+ def test_open_music_scope(self):
256+ self.unity.dash.reveal_music_scope()
257+ current_scope = self.unity.dash.get_current_scope()
258+ self.assertEquals(current_scope.name, 'music.scope')
259+
260+ def test_search_music_scope(self):
261+ dash.search_music_scope(self, 'Hendrix')
262+ first_result = dash.get_first_result_from_category(
263+ self, 'More suggestions')
264+ self.assertIn('Hendrix', first_result.name)
265+
266+ def test_open_and_close_music_result(self):
267+ dash.search_music_scope(self, 'Hendrix')
268+ first_result = dash.get_first_result_from_category(
269+ self, 'More suggestions')
270+ dash.preview_result(self, first_result)
271+ self.assertThat(
272+ self.unity.dash.preview_displaying, Eventually(Equals(True)))
273+ preview = dash.get_current_preview(self)
274+ self.assertIn('Hendrix', preview.text_boxes[0].text)
275+ self.assertEquals(preview.get_num_actions(), 1)
276+ download_button = preview.get_action_by_id('show_purchase_preview')
277+ self.assertEqual(download_button.label, 'Download')
278+ dash.close_preview(self)
279+ self.assertThat(
280+ self.unity.dash.preview_displaying, Eventually(Equals(False)))
281
282=== modified file 'tests/test_purchase_good.py'
283--- tests/test_purchase_good.py 2013-05-17 13:00:48 +0000
284+++ tests/test_purchase_good.py 2013-06-19 20:36:26 +0000
285@@ -1,3 +1,6 @@
286+import os
287+import subprocess
288+
289 from sst import actions as sactions
290
291 # FIXME do not use django config to get the server settings.
292@@ -22,9 +25,24 @@
293 # Set the urls of the servers that will be used by the user.
294 self.user.set_servers_data(
295 sso_server_url=conf.settings.OPENID_SSO_SERVER_URL,
296+ pay_server_url=conf.settings.PAY_SERVER_URL,
297+ consumer_id=conf.settings.CONSUMER_ID,
298 ubuntuone_server_url=conf.settings.UBUNTUONE_SERVER_URL)
299 # Arbitrarily using a good that is known to work
300 self.good = goods.Good(u'Jimi Hendrix', 'hendrix')
301+ self._run_music_lens()
302+
303+ def _run_music_lens(self):
304+ os.environ['MUSICSTORE_URI'] = (
305+ conf.settings.MUSICSEARCH_SERVER_URL + '/v1/')
306+ os.environ['U1_STAGING_AUTHENTICATION'] = (
307+ conf.settings.OPENID_SSO_SERVER_URL + '/')
308+ os.environ['U1_STAGING_WEBAPI'] = (
309+ conf.settings.UBUNTUONE_SERVER_URL + '/')
310+ os.system('pkill unity-music')
311+ subprocess.Popen(
312+ '/usr/lib/x86_64-linux-gnu/unity-lens-music/'
313+ 'unity-musicstore-daemon')
314
315 def preview_good(self):
316 home = dash.Home(self.user)
317@@ -39,22 +57,10 @@
318
319 class TestUserCannotPay(TestPurchaseGood):
320
321- scenarios = [(name, {'scope_name': name}) for name in ('home', 'music',)]
322-
323 def test_user_not_logged_in(self):
324 self.assertFalse(self.user.is_logged_in())
325 self.preview_good()
326- if self.scope_name == 'music':
327- # There is a workaround in place for the music scope only that
328- # forbids testing the rest of the workflow
329- self.assertIs(None, self.preview.get_download_button())
330- message = self.preview.get_message_replacing_action()
331- self.assertEqual('Before you can purchase music you need'
332- ' to log in to the Ubuntu One app', message)
333- return
334- goto_u1 = self.purchase_good()
335- # diverges from the design spec, we go directly to the web
336- # self.assertTrue(goto_u1.good_displayed())
337+ self.purchase_good()
338 browser = browsers.Browser(self)
339 # We've been redirected to the web
340 browser.switch_to_new_window(self)
341@@ -65,27 +71,14 @@
342 def test_no_payment_method_stored(self):
343 # Log in with a newly created user, and set no payment method to him.
344 self.user.login(self)
345- self.user.payment_method = None
346+ self.assertIs(self.user.get_payment_type(), None)
347 self.preview_good()
348 goto_u1 = self.purchase_good()
349 self.assertTrue(goto_u1.good_displayed())
350 self.assertIn('add a payment method', goto_u1.message)
351- # The default browser is launched to propose paying
352- browser = goto_u1.click_goto_u1()
353- # User is sent to the web
354- self.assertTrue(browser.is_running())
355- self.assertEqual('https://pay.ubuntu.com', browser.current_url)
356-
357- def test_pay_method_expired(self):
358- # Users's payment has expired
359- self.user.login(self)
360- self.user.payment_method = 'expired'
361- self.preview_good()
362- goto_u1 = self.purchase_good()
363- self.assertTrue(goto_u1.good_displayed())
364- self.assertIn('card has expired', goto_u1.message)
365- # The default browser is launched to propose paying
366- browser = goto_u1.click_goto_u1()
367- # User is sent to the web
368- self.assertTrue(browser.is_running())
369- self.assertEqual('https://pay.ubuntu.com', browser.current_url)
370+ self.skipTest('We are blocked at this point because of bug #1185486.')
371+ # The default browser is launched to propose paying
372+ #browser = goto_u1.click_goto_u1()
373+ # User is sent to the web
374+ #self.assertTrue(browser.is_running())
375+ #self.assertEqual(conf.settings.PAY_SERVER_URL, browser.current_url)
376
377=== modified file 'tests/test_session.py'
378--- tests/test_session.py 2013-02-20 15:53:53 +0000
379+++ tests/test_session.py 2013-06-19 20:36:26 +0000
380@@ -1,6 +1,6 @@
381 import tests
382
383-from gi.repository import Gio, Gtk
384+from gi.repository import Gio
385
386 class TestGSettings(tests.TestCase):
387

Subscribers

People subscribed via source and target branches