Merge lp:~josharenson/unity8/settings_wizard_tests into lp:unity8

Proposed by Josh Arenson on 2015-05-19
Status: Merged
Approved by: Albert Astals Cid on 2015-07-02
Approved revision: 1792
Merged at revision: 1859
Proposed branch: lp:~josharenson/unity8/settings_wizard_tests
Merge into: lp:unity8
Diff against target: 802 lines (+762/-0)
5 files modified
debian/control (+2/-0)
tests/autopilot/unity8/settings_wizard/__init__.py (+507/-0)
tests/autopilot/unity8/settings_wizard/fixture_setup.py (+58/-0)
tests/autopilot/unity8/settings_wizard/ofono_helper.py (+116/-0)
tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py (+79/-0)
To merge this branch: bzr merge lp:~josharenson/unity8/settings_wizard_tests
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) xvfb is fine for testing Approve on 2015-07-02
PS Jenkins bot continuous-integration Needs Fixing on 2015-06-08
Richard Huddie (community) Approve on 2015-05-29
Ubuntu Unity PS integration team debian packaging 2015-05-19 Pending
Leo Arias 2015-05-19 Pending
Review via email: mp+259537@code.launchpad.net

Commit Message

Add a basic autopilot test for the SettingsWizard

Description of the Change

* Are there any related MPs required for this MP to build/function as expected? Please list.
No

 * Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Yes
   Adds ofono-phonesim and xvfb to unity8-autopilot dependencies. These will be used in a future branch, but are currently required for ofono_helper to function.

To post a comment you must log in.
1784. By Josh Arenson on 2015-05-19

Remove debug code

1785. By Josh Arenson on 2015-05-19

Add license

1786. By Josh Arenson on 2015-05-20

Add license

Richard Huddie (rhuddie) wrote :

This looks good. I've got a question below about checking the state of the network connections to check the button state, rather than just pressing it regardless. I haven't had a chance to run it yet, but I'll give that a try later.

Thanks!

review: Needs Fixing
Josh Arenson (josharenson) wrote :

> This looks good. I've got a question below about checking the state of the
> network connections to check the button state, rather than just pressing it
> regardless. I haven't had a chance to run it yet, but I'll give that a try
> later.
>
> Thanks!

I agree with you, and I'll implement this tomorrow. I also am working on adding a LocationPage to the emulator and code to handle the wizard if the location page is present.

Richard Huddie (rhuddie) wrote :

Also, it would be better to remove the emulators folder and move the contents of settings_wizard.py into:

tests/autopilot/unity8/settings_wizard/__init__.py

Then you can easily import the helpers in the test by doing:

from unity8.settings_wizard import Wizard

We are trying to remove use of the word 'emulators' from the tests.

review: Needs Fixing
1787. By Josh Arenson on 2015-05-20

Merge upstream

1788. By Josh Arenson on 2015-05-21

[ Albert Astals Cid ]
* Add overrides to override functions
* Implement "rating-edit" preview widget (LP: #1318144)
* Make the DashContent::test_mainNavigation test more stable (LP:
  #1450809)
* Use art height as implicitHeight when the header is overlayed and
  there's no summary
[ CI Train Bot ]
* New rebuild forced.
* Resync trunk.
[ Daniel d'Andrada ]
* Introducing FloatingFlickable
* Make Ubuntu.Gestures components install TouchRegistry by themselves
[ Michael Terry ]
* Fix a possible crash in our PAM threading code. (LP: #1425362) (LP:
  #1425362)
* Fix the lockscreen becoming unresponsive after testing an app on the
  device from QtCreator. (LP: #1435364)
[ Nick Dedekind ]
* Fixed desktop stage app focus.
* Fixed issue in laggy indicator autpilot tests (LP: #1446846)

1789. By Josh Arenson on 2015-05-21

Make settings wizard test smarter when clicking through the wifi page

1790. By Josh Arenson on 2015-05-21

Move emulator code into module

Josh Arenson (josharenson) wrote :

WifiPage test checks for network connection/availability to determine which button to look for.

> Also, it would be better to remove the emulators folder and move the contents
> of settings_wizard.py into:
>
> tests/autopilot/unity8/settings_wizard/__init__.py

Done.

1791. By Josh Arenson on 2015-05-21

Remove unused methods

Richard Huddie (rhuddie) wrote :

This looks great. I ran the test locally and it passed. I understand that the ofono_helpers are for future use. So, approving.

review: Approve
Michael Terry (mterry) wrote :

Josh asked me to ACK the packaging changes. As mentioned on IRC, I'd like to avoid using xvfb if we can (feels weird to rely on it for phone stuff).

So Josh will test without using xvfb-run and see if phonesim really does require it. If so, fine. We can dep on it. But if it doesn't, let's drop the xvfb dep.

Michael Terry (mterry) wrote :

(Other than that, the packaging changes are trivial and fine.)

1792. By Josh Arenson on 2015-06-02

Find home dirctory regardless of platform

This allows for correctly deleting the wizard-has-run file on any platform

Josh Arenson (josharenson) wrote :

After a lot of playing around, it seems that ofono-phonesim does require xvfb to run, even when the -gui option is not specified (default is false). While this is unfortunate, mterry and I talked on IRC and agreed that it isn't harmful to install xvfb for testing, even though it only increases code coverage by a marginal amount. Can someone top level approve this?

Leo Arias (elopio) wrote :

You should mention on the commit message that you are adding the dependency. Otherwise ogra will go mad and start yelling ;)
Please mention there that it's only for testing and because the phonesim needs it. Maybe also report a bug for ofono-phonesim? I don't know the details, but maybe they can bundle a more simple wrapper.

Albert Astals Cid (aacid) wrote :

Yes, someone should investigate why ofono-phonesim needs xvfb but there's no reason to stall this perfectly valid MR to land.

We can fine-tune-improve it when/if the thing gets fixed.

Top approving.

review: Approve (xvfb is fine for testing)
1793. By Josh Arenson on 2015-07-09

[ Albert Astals Cid ]
* Make the card sizes a bit dependant on the total of gu of the dash
[ Albert Astals Cid ]
* Save screenshots of suspended apps to disk
* Set width of title label when inside the title row (LP: #1461979)
* qmluitests was renamed to uitests
[ CI Train Bot ]
* Resync trunk.
[ Daniel d'Andrada ]
* Fix tst_OrientedShell and tst_Tutorial (LP: #1469761, #1466947)
[ Leo Arias ]
* Reorganized the python test helper modules. Deprecated the
  unity8.shell.emulators namespace. (LP: #1306340)
[ Leonardo Arias Fonseca ]
* Reorganized the python test helper modules. Deprecated the
  unity8.shell.emulators namespace. (LP: #1306340)
[ Lukáš Tinkl ]
* fix PO files extraction
[ Michael Zanetti ]
* Make use of QInputDeviceInfo in order to automatically switch
  between usage modes and hide the OSK.
[ Nick Dedekind ]
* Fixed qtmultimedia mock which was generating errors in tests
[ Richard Huddie ]
* Reorganized the python test helper modules. Deprecated the
  unity8.shell.emulators namespace. (LP: #1306340)
[ Albert Astals Cid ]
* Refactor QmlTest.cmake module so that all tests can go through it.
  Also a bit of cleanup around tests.
* Support fallback images for dash card and preview widgets (LP:
  #1324142)
[ CI Train Bot ]
* New rebuild forced.
* Resync trunk.
[ Daniel d'Andrada ]
* Fix Shell tests
[ Josh Arenson ]
* Refactor greeter emulator to unlock the greeter via dbus
[ Lukáš Tinkl ]
* respect target window's devicePixelRatio in MouseTouchAdaptor
[ Michael Zanetti ]
* Refactor QmlTest.cmake module so that all tests can go through it.
  Also a bit of cleanup around tests.
[ Michał Sawicz ]
* Refactor QmlTest.cmake module so that all tests can go through it.
  Also a bit of cleanup around tests.
[ handsome_feng ]
* Forbid closing apps during the edge gesture. (LP: #1445572)
* Removed the horizonal rule on pin unlock screen. (LP: #1368798)
[ handsome_feng<email address hidden> ]
* Forbid closing apps during the edge gesture. (LP: #1445572)
* No-change rebuild against Qt 5.4.2.
[ Michał Sawicz ]
* Implement full-shell rotation (LP: #1210199)
[ CI Train Bot ]
* New rebuild forced.
* Resync trunk.
[ Daniel d'Andrada ]
* Implemented autopilot-test and fake-sensors for shell-rotation.
[ Mirco Müller ]
* Implemented autopilot-test and fake-sensors for shell-rotation.
* Implement full-shell rotation (LP: #1210199)
[ CI Train Bot ]
* New rebuild forced.
* Resync trunk.
[ Renato Araujo Oliveira Filho ]
* Set the device led color to green. (LP: #1450894)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2015-07-02 16:09:27 +0000
3+++ debian/control 2015-07-09 20:23:14 +0000
4@@ -148,6 +148,7 @@
5 gir1.2-notify-0.7,
6 libqt5test5,
7 libqt5widgets5,
8+ ofono-phonesim,
9 python3-autopilot,
10 python3-evdev,
11 python3-fixtures,
12@@ -158,6 +159,7 @@
13 unity8 (= ${source:Version}),
14 unity8-fake-env (= ${source:Version}),
15 url-dispatcher-tools,
16+ xvfb,
17 ${misc:Depends},
18 ${python3:Depends},
19 ${shlibs:Depends},
20
21=== added directory 'tests/autopilot/unity8/settings_wizard'
22=== added file 'tests/autopilot/unity8/settings_wizard/__init__.py'
23--- tests/autopilot/unity8/settings_wizard/__init__.py 1970-01-01 00:00:00 +0000
24+++ tests/autopilot/unity8/settings_wizard/__init__.py 2015-07-09 20:23:14 +0000
25@@ -0,0 +1,507 @@
26+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
27+#
28+# Unity Autopilot Test Suite
29+# Copyright (C) 2015 Canonical
30+#
31+# This program is free software: you can redistribute it and/or modify
32+# it under the terms of the GNU General Public License as published by
33+# the Free Software Foundation, either version 3 of the License, or
34+# (at your option) any later version.
35+#
36+# This program is distributed in the hope that it will be useful,
37+# but WITHOUT ANY WARRANTY; without even the implied warranty of
38+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39+# GNU General Public License for more details.
40+#
41+# You should have received a copy of the GNU General Public License
42+# along with this program. If not, see <http://www.gnu.org/licenses/>.
43+#
44+
45+import logging
46+import re
47+
48+import autopilot
49+from autopilot import introspection
50+from ubuntuuitoolkit import UbuntuUIToolkitCustomProxyObjectBase
51+
52+from contextlib import contextmanager
53+
54+
55+logger = logging.getLogger(__name__)
56+
57+
58+@contextmanager
59+def override_proxy_timeout(proxy, timeout_seconds):
60+ original_timeout = proxy._poll_time
61+ try:
62+ proxy._poll_time = timeout_seconds
63+ yield proxy
64+ finally:
65+ proxy._poll_time = original_timeout
66+
67+
68+def get_wizard(current_page):
69+ return current_page.get_root_instance().select_single(Wizard)
70+
71+
72+class Wizard(UbuntuUIToolkitCustomProxyObjectBase):
73+ """High-level helper to navigate through the pages of the wizard"""
74+
75+ def get_language_page(self):
76+ return self.wait_select_single(
77+ objectName='languagePage', visible='True')
78+
79+ def get_current_page(self):
80+ return self.wait_select_single('Page', visible='True')
81+
82+ def get_sim_page(self):
83+ return self.wait_select_single(
84+ objectName='simPage', visible='True')
85+
86+ def get_password_page(self):
87+ return self.wait_select_single(
88+ objectName='passwdPage', visible='True')
89+
90+ def get_password_entry_page(self):
91+ return self.wait_select_single(
92+ objectName='passwdSetPage', visible='True')
93+
94+ def get_confirm_password_page(self):
95+ return self.wait_select_single(
96+ objectName='passwdConfirmPage', visible='True')
97+
98+ def get_wifi_connect_page(self):
99+ return self.wait_select_single(
100+ objectName='wifiPage', visible='True')
101+
102+ def get_reporting_page(self):
103+ return self.wait_select_single(
104+ objectName='reportingPage', visible='True')
105+
106+ def get_finished_page(self):
107+ return self.wait_select_single(
108+ objectName='finishedPage', visible='True')
109+
110+
111+class WizardLanguagePage(UbuntuUIToolkitCustomProxyObjectBase):
112+ """Helper class to interact with the language welcome page"""
113+
114+ # This class was renamed from LanguagePage to WizardLanguagePage because
115+ # there is a class with the same name in the system settings custom proxy
116+ # objects. Reported in http://pad.lv/1422904. --elopio - 2015-02-17
117+
118+ @classmethod
119+ def validate_dbus_object(cls, path, state):
120+ name = introspection.get_classname_from_path(path)
121+ if name == b'Page':
122+ if state['objectName'][1] == 'languagePage':
123+ return True
124+ return False
125+
126+ def _get_language_button(self):
127+ return self.select_single(
128+ 'ComboButton', objectName='languageCombo')
129+
130+ def _get_continue_button(self):
131+ return self.select_single('StackButton', text='Continue')
132+
133+ def _swipe_to_language(self, list, language):
134+ """Swipe to the chosen language in the given list"""
135+ list.swipe_to_top()
136+ while not list.atYEnd:
137+ try:
138+ item = list.select_single(
139+ 'LabelVisual', text=language, visible='True')
140+ item.swipe_into_view()
141+ return item
142+ except introspection.dbus.StateNotFoundError:
143+ list.swipe_to_show_more_below()
144+ # item could not be found
145+ raise introspection.dbus.StateNotFoundError
146+
147+ @autopilot.logging.log_action(logger.info)
148+ def select_language(self, language):
149+ """Select a different language from the list"""
150+ combo_button = self._get_language_button()
151+ self.pointing_device.click_object(combo_button)
152+ language_list = combo_button.wait_select_single(
153+ 'UbuntuListView11', visible='True')
154+ item = self._swipe_to_language(language_list, language)
155+ self.pointing_device.click_object(item)
156+
157+ def get_selected_language(self):
158+ return self._get_language_button().get_properties()['text']
159+
160+ @autopilot.logging.log_action(logger.info)
161+ def continue_(self):
162+ self.pointing_device.click_object(self._get_continue_button())
163+ wizard = get_wizard(self)
164+ next_page = wizard.get_current_page()
165+ sim_inserted = True
166+ if next_page.objectName == 'simPage':
167+ # no sim is inserted
168+ next_page = wizard.get_sim_page()
169+ sim_inserted = False
170+ else:
171+ # sim is inserted
172+ next_page = wizard.get_password_page()
173+ return sim_inserted, next_page
174+
175+
176+class SimPage(UbuntuUIToolkitCustomProxyObjectBase):
177+ """Helper class to interact with the no sim notification page"""
178+
179+ @classmethod
180+ def validate_dbus_object(cls, path, state):
181+ name = introspection.get_classname_from_path(path)
182+ if name == b'Page':
183+ if state['objectName'][1] == 'simPage':
184+ return True
185+ return False
186+
187+ def _get_back_button(self):
188+ return self.select_single('StackButton', text='Back')
189+
190+ def _get_skip_button(self):
191+ return self.select_single('StackButton', text='Skip')
192+
193+ @autopilot.logging.log_action(logger.info)
194+ def back(self):
195+ self.pointing_device.click_object(self._get_back_button())
196+ return get_wizard(self).get_languge_page()
197+
198+ @autopilot.logging.log_action(logger.info)
199+ def skip(self):
200+ self.pointing_device.click_object(self._get_skip_button())
201+ return get_wizard(self).get_password_page()
202+
203+
204+class PasswordPage(UbuntuUIToolkitCustomProxyObjectBase):
205+ """Helper class to interact with the password security page"""
206+
207+ SECURITY_SWIPE = 'Swipe'
208+ SECURITY_PASSCODE = 'Passcode'
209+ SECURITY_PASSPHRASE = 'Passphrase'
210+
211+ @classmethod
212+ def validate_dbus_object(cls, path, state):
213+ name = introspection.get_classname_from_path(path)
214+ if name == b'Page':
215+ if state['objectName'][1] == 'passwdPage':
216+ return True
217+ return False
218+
219+ def _get_option_name(self, formatted_name):
220+ # the option name is formatted as follows:
221+ # need to read the name between bold tags
222+ # '<b>Passcode</b> (4 digits only)'
223+ formatted_pattern = re.compile(r'<b>(.*?)</b>.*',
224+ re.IGNORECASE | re.DOTALL)
225+ name = None
226+ match = formatted_pattern.search(formatted_name)
227+ if match:
228+ name = match.group(1)
229+ return name
230+
231+ def _get_all_options(self):
232+ return self.select_many('OptionSelectorDelegate')
233+
234+ def _get_continue_button(self):
235+ return self.select_single('StackButton', text='Continue')
236+
237+ def _get_back_button(self):
238+ return self.select_single('StackButton', text='Back')
239+
240+ def _get_selected_option(self):
241+ return self.select_single(
242+ 'OptionSelectorDelegate', visible='True', selected='True')
243+
244+ def get_selected_security_option(self):
245+ name_fmt = self._get_selected_option().get_properties()['subText']
246+ return self._get_option_name(name_fmt)
247+
248+ @autopilot.logging.log_action(logger.info)
249+ def select_security_option(self, selected_option):
250+ options = self._get_all_options()
251+ for option in options:
252+ name = self._get_option_name(option.get_properties()['subText'])
253+ if name == selected_option:
254+ self.pointing_device.click_object(option)
255+
256+ @autopilot.logging.log_action(logger.info)
257+ def back(self, sim_inserted):
258+ self.pointing_device.click_object(self._get_back_button())
259+ wizard = get_wizard(self)
260+ if sim_inserted:
261+ page = wizard.get_languge_page()
262+ else:
263+ page = wizard.get_sim_page()
264+ return page
265+
266+ @autopilot.logging.log_action(logger.info)
267+ def continue_(self):
268+ option = self.get_selected_security_option()
269+ self.pointing_device.click_object(self._get_continue_button())
270+ wizard = get_wizard(self)
271+ if option == self.SECURITY_SWIPE:
272+ next_page = wizard.get_wifi_connect_page()
273+ else:
274+ next_page = wizard.get_password_entry_page()
275+ return next_page
276+
277+
278+class PasswordEntryPage(UbuntuUIToolkitCustomProxyObjectBase):
279+ """Helper class to interact with the pin entry page"""
280+
281+ @classmethod
282+ def validate_dbus_object(cls, path, state):
283+ name = introspection.get_classname_from_path(path)
284+ if name == b'Page':
285+ if state['objectName'][1] == 'passwdSetPage':
286+ return True
287+ return False
288+
289+ def _get_pinpad_button(self, char):
290+ return self.select_single('PinPadButton', text=char)
291+
292+ def _get_continue_button(self):
293+ return self.select_single('StackButton', text='Continue')
294+
295+ def _get_back_button(self):
296+ return self.select_single('StackButton', text='Back')
297+
298+ def _get_text_field(self):
299+ return self.select_single('QQuickTextInput')
300+
301+ @autopilot.logging.log_action(logger.info)
302+ def enter_pin(self, pin):
303+ for char in pin:
304+ self.pointing_device.click_object(self._get_pinpad_button(char))
305+ return get_wizard(self).get_confirm_password_page()
306+
307+ @autopilot.logging.log_action(logger.info)
308+ def enter_text(self, text):
309+ self.pointing_device.click_object(self._get_text_field())
310+ autopilot.input.Keyboard.create().type(text)
311+
312+ @autopilot.logging.log_action(logger.info)
313+ def back(self):
314+ self.pointing_device.click_object(self._get_back_button())
315+ return get_wizard(self).get_password_page()
316+
317+ @autopilot.logging.log_action(logger.info)
318+ def continue_(self):
319+ autopilot.input.Keyboard.create().press_and_release('Enter')
320+ return get_wizard(self).get_confirm_password_page()
321+
322+
323+class ConfirmPasswordPage(UbuntuUIToolkitCustomProxyObjectBase):
324+ """Helper class to interact with the pin confirmation page"""
325+
326+ @classmethod
327+ def validate_dbus_object(cls, path, state):
328+ name = introspection.get_classname_from_path(path)
329+ if name == b'Page':
330+ if state['objectName'][1] == 'passwdConfirmPage':
331+ return True
332+ return False
333+
334+ def _get_pinpad_button(self, char):
335+ return self.select_single('PinPadButton', text=char)
336+
337+ def _get_continue_button(self):
338+ return self.select_single('StackButton', text='Continue')
339+
340+ def _get_back_button(self):
341+ return self.select_single('StackButton', text='Back')
342+
343+ def _get_text_field(self):
344+ return self.select_single('QQuickTextInput')
345+
346+ @autopilot.logging.log_action(logger.info)
347+ def enter_pin(self, pin):
348+ for char in pin:
349+ self.pointing_device.click_object(self._get_pinpad_button(char))
350+ return get_wizard(self).get_wifi_connect_page()
351+
352+ @autopilot.logging.log_action(logger.info)
353+ def enter_text(self, text):
354+ self.pointing_device.click_object(self._get_text_field())
355+ autopilot.input.Keyboard.create().type(text)
356+
357+ @autopilot.logging.log_action(logger.info)
358+ def back(self):
359+ self.pointing_device.click_object(self._get_back_button())
360+ return get_wizard(self).get_password_page()
361+
362+ @autopilot.logging.log_action(logger.info)
363+ def continue_(self):
364+ autopilot.input.Keyboard.create().press_and_release('Enter')
365+ return get_wizard(self).get_wifi_connect_page()
366+
367+
368+class WifiConnectPage(UbuntuUIToolkitCustomProxyObjectBase):
369+ """Helper class to interact with the Wi-Fi network list page"""
370+
371+ @classmethod
372+ def validate_dbus_object(cls, path, state):
373+ name = introspection.get_classname_from_path(path)
374+ if name == b'Page':
375+ if state['objectName'][1] == 'wifiPage':
376+ return True
377+ return False
378+
379+ def _get_all_networks(self):
380+ try:
381+ networks = self.select_many('Standard', objectName='accessPoint',
382+ visible='True')
383+ except:
384+ networks = []
385+ return networks
386+
387+ def _get_network(self, ssid):
388+ return self.wait_select_single(
389+ 'Standard', objectName='accessPoint', text=ssid, visible='True')
390+
391+ def _get_network_checkbox(self, ssid):
392+ return self._get_network(ssid).select_single(
393+ 'CheckBox', visible='True')
394+
395+ def _get_notification(self, unity):
396+ logger.info('Waiting longer for notification object')
397+ with override_proxy_timeout(unity, 30):
398+ return unity.wait_select_single(
399+ Notification, objectName='notification1', visible='True')
400+
401+ def _get_back_button(self):
402+ return self.wait_select_single(
403+ 'StackButton', text='Back', visible='True')
404+
405+ def _get_skip_button(self):
406+ return self.wait_select_single(
407+ 'StackButton', text='Skip', visible='True')
408+
409+ def _get_continue_button(self):
410+ return self.wait_select_single(
411+ 'StackButton', text='Continue', visible='True')
412+
413+ def is_any_network_checked(self):
414+ networks = self._get_all_networks()
415+ for network in networks:
416+ checkbox = network.select_single('CheckBox', visible='True')
417+ if checkbox.get_properties()['checked']:
418+ return True
419+ return False
420+
421+ def is_any_network_found(self):
422+ num_neworks = len(self._get_all_networks())
423+ return True if num_neworks > 0 else False
424+
425+ def is_network_checked(self, ssid):
426+ return self._get_network_checkbox(ssid).get_properties()['checked']
427+
428+ @autopilot.logging.log_action(logger.info)
429+ def select_network(self, unity, ssid):
430+ self.pointing_device.click_object(self._get_network_checkbox(ssid))
431+ return PasswordNotification(self._get_notification(unity))
432+
433+ @autopilot.logging.log_action(logger.info)
434+ def back(self):
435+ self.pointing_device.click_object(self._get_back_button())
436+ return get_wizard(self).get_password_page()
437+
438+ @autopilot.logging.log_action(logger.info)
439+ def skip(self):
440+ self.pointing_device.click_object(self._get_skip_button())
441+ return get_wizard(self).get_reporting_page()
442+
443+ @autopilot.logging.log_action(logger.info)
444+ def continue_(self):
445+ self.pointing_device.click_object(self._get_continue_button())
446+ return get_wizard(self).get_reporting_page()
447+
448+
449+class Notification(UbuntuUIToolkitCustomProxyObjectBase):
450+ """Base class for notification objects"""
451+ pass
452+
453+
454+class PasswordNotification(Notification):
455+ """Helper class to interact with the password entry notification"""
456+
457+ def __init__(self, notification):
458+ self.notification = notification
459+
460+ def _get_connect_button(self):
461+ return self.notification.wait_select_single(
462+ 'Button', text='Connect', objectName='notify_button0')
463+
464+ def _get_cancel_buttoon(self):
465+ return self.notification.wait_select_single(
466+ 'Button', text='Cancel', objectName='notify_button1')
467+
468+ def _get_text_field(self):
469+ return self.notification.wait_select_single('TextField')
470+
471+ @autopilot.logging.log_action(logger.info)
472+ def enter_text(self, text):
473+ self._get_text_field().write(text)
474+
475+ @autopilot.logging.log_action(logger.info)
476+ def connect(self):
477+ self.notification.pointing_device.click_object(
478+ self._get_connect_button())
479+
480+ @autopilot.logging.log_action(logger.info)
481+ def cancel(self):
482+ self.notification.pointing_device.click_object(
483+ self._get_cancel_buttoon())
484+
485+
486+class ReportingPage(UbuntuUIToolkitCustomProxyObjectBase):
487+ """Helper class to interact with the reporting page"""
488+
489+ @classmethod
490+ def validate_dbus_object(cls, path, state):
491+ name = introspection.get_classname_from_path(path)
492+ if name == b'Page':
493+ if state['objectName'][1] == 'reportingPage':
494+ return True
495+ return False
496+
497+ def _get_continue_button(self):
498+ return self.select_single('StackButton', text='Continue')
499+
500+ def _get_back_button(self):
501+ return self.select_single('StackButton', text='Back')
502+
503+ @autopilot.logging.log_action(logger.info)
504+ def back(self):
505+ self.pointing_device.click_object(self._get_back_button())
506+ return get_wizard(self).get_wifi_connect_page()
507+
508+ @autopilot.logging.log_action(logger.info)
509+ def continue_(self):
510+ self.pointing_device.click_object(self._get_continue_button())
511+ return get_wizard(self).get_finished_page()
512+
513+
514+class FinishedPage(UbuntuUIToolkitCustomProxyObjectBase):
515+ """Helper class to interact with the finished page"""
516+
517+ @classmethod
518+ def validate_dbus_object(cls, path, state):
519+ name = introspection.get_classname_from_path(path)
520+ if name == b'Page':
521+ if state['objectName'][1] == 'finishedPage':
522+ return True
523+ return False
524+
525+ def _get_finish_button(self):
526+ return self.wait_select_single(
527+ 'StackButton', text='Finish', visible='True')
528+
529+ @autopilot.logging.log_action(logger.info)
530+ def finish(self):
531+ self.pointing_device.click_object(self._get_finish_button())
532+ self.wait_until_destroyed()
533
534=== added file 'tests/autopilot/unity8/settings_wizard/fixture_setup.py'
535--- tests/autopilot/unity8/settings_wizard/fixture_setup.py 1970-01-01 00:00:00 +0000
536+++ tests/autopilot/unity8/settings_wizard/fixture_setup.py 2015-07-09 20:23:14 +0000
537@@ -0,0 +1,58 @@
538+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
539+#
540+# Unity Autopilot Test Suite
541+# Copyright (C) 2015 Canonical
542+#
543+# This program is free software: you can redistribute it and/or modify
544+# it under the terms of the GNU General Public License as published by
545+# the Free Software Foundation, either version 3 of the License, or
546+# (at your option) any later version.
547+#
548+# This program is distributed in the hope that it will be useful,
549+# but WITHOUT ANY WARRANTY; without even the implied warranty of
550+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
551+# GNU General Public License for more details.
552+#
553+# You should have received a copy of the GNU General Public License
554+# along with this program. If not, see <http://www.gnu.org/licenses/>.
555+#
556+
557+"""Set up and clean up fixtures for the Unity SettingsWizard tests."""
558+
559+import fixtures
560+import os
561+
562+from os.path import expanduser
563+
564+
565+class SettingsWizard(fixtures.Fixture):
566+ WIZARD_FILE = expanduser("~") + \
567+ '/.config/ubuntu-system-settings/wizard-has-run'
568+
569+ def __init__(self, enable):
570+ super().__init__()
571+ self.enable = enable
572+
573+ def setUp(self):
574+ super().setUp()
575+ original_state = self.is_settings_wizard_enabled()
576+ self.addCleanup(self.set_settings_wizard, original_state)
577+ if self.enable != original_state:
578+ self.set_settings_wizard(self.enable)
579+
580+ def is_settings_wizard_enabled(self):
581+ return not os.path.exists(self.WIZARD_FILE)
582+
583+ def set_settings_wizard(self, enabled):
584+ if enabled:
585+ self.enable_settings_wizard()
586+ else:
587+ self.disable_settings_wizard()
588+
589+ def enable_settings_wizard(self):
590+ if os.path.exists(self.WIZARD_FILE):
591+ os.remove(self.WIZARD_FILE)
592+
593+ def disable_settings_wizard(self):
594+ if not os.path.exists(self.WIZARD_FILE):
595+ open(self.WIZARD_FILE, 'a').close()
596
597=== added file 'tests/autopilot/unity8/settings_wizard/ofono_helper.py'
598--- tests/autopilot/unity8/settings_wizard/ofono_helper.py 1970-01-01 00:00:00 +0000
599+++ tests/autopilot/unity8/settings_wizard/ofono_helper.py 2015-07-09 20:23:14 +0000
600@@ -0,0 +1,116 @@
601+#!/usr/bin/python -tt
602+
603+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
604+#
605+# Unity Indicators Autopilot Test Suite
606+# Copyright (C) 2014, 2015 Canonical
607+#
608+# This program is free software: you can redistribute it and/or modify
609+# it under the terms of the GNU General Public License as published by
610+# the Free Software Foundation, either version 3 of the License, or
611+# (at your option) any later version.
612+#
613+# This program is distributed in the hope that it will be useful,
614+# but WITHOUT ANY WARRANTY; without even the implied warranty of
615+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
616+# GNU General Public License for more details.
617+#
618+# You should have received a copy of the GNU General Public License
619+# along with this program. If not, see <http://www.gnu.org/licenses/>.
620+
621+
622+from __future__ import absolute_import
623+
624+import dbus
625+import subprocess
626+from time import sleep
627+
628+
629+class OfonoManager(object):
630+
631+ def __init__(self):
632+ self.system_bus = dbus.SystemBus()
633+ self.ofono = self.system_bus.get_object('org.ofono', '/')
634+
635+ self.real_manager = dbus.Interface(
636+ self.ofono,
637+ 'org.ofono.Manager'
638+ )
639+
640+ def _get_sim_manager(self):
641+ modems = self.real_manager.GetModems()
642+ path = modems[0][0]
643+ return dbus.Interface(self.system_bus.get_object('org.ofono', path),
644+ 'org.ofono.SimManager')
645+
646+ def physical_sim_is_present(self):
647+ sim_manager = self._get_sim_manager()
648+ properties = sim_manager.GetProperties()
649+ return properties["Present"] == 1
650+
651+
652+class PhonesimManager(object):
653+
654+ def __init__(self, sims, exe=None):
655+ if exe is None:
656+ self.phonesim_exe = '/usr/bin/ofono-phonesim'
657+ else:
658+ self.phonesim_exe = exe
659+ self.sims = sims
660+ self.sim_processes = {}
661+ self.system_bus = dbus.SystemBus()
662+ self.ofono = self.system_bus.get_object('org.ofono', '/')
663+
664+ self.phonesim_manager = dbus.Interface(
665+ self.ofono,
666+ 'org.ofono.phonesim.Manager'
667+ )
668+
669+ def start_phonesim_processes(self):
670+ for simname, simport, conffile in self.sims:
671+ cmd = ['/usr/bin/xvfb-run',
672+ '-a',
673+ self.phonesim_exe,
674+ '-p',
675+ str(simport),
676+ conffile]
677+
678+ p = subprocess.Popen(cmd)
679+ self.sim_processes[simname] = p
680+ # give the processes some time to start
681+ sleep(3)
682+
683+ def shutdown(self):
684+ for p in self.sim_processes.values():
685+ p.kill()
686+ self.sim_processes = {}
687+
688+ def reset_ofono(self):
689+ self.phonesim_manager.Reset()
690+
691+ def remove_all_ofono(self):
692+ self.phonesim_manager.RemoveAll()
693+
694+ def add_ofono(self, name):
695+ for simname, simport, _ in self.sims:
696+ if name == simname:
697+ self.phonesim_manager.Add(simname, '127.0.0.1', str(simport))
698+ return
699+ raise RuntimeError('Tried to add unknown modem %s.' % name)
700+
701+ def power_on(self, sim_name):
702+ sim = self.system_bus.get_object('org.ofono', '/'+sim_name)
703+ modem = dbus.Interface(sim, dbus_interface='org.ofono.Modem')
704+ modem.SetProperty('Powered', True)
705+ sleep(1)
706+
707+ def power_off(self, sim_name):
708+ sim = self.system_bus.get_object('org.ofono', '/'+sim_name)
709+ modem = dbus.Interface(sim, dbus_interface='org.ofono.Modem')
710+ modem.SetProperty('Powered', False)
711+ sleep(1)
712+
713+ def get_required_pin(self, sim_name):
714+ sim = self.system_bus.get_object('org.ofono', '/'+sim_name)
715+ interface = dbus.Interface(sim, dbus_interface='org.ofono.SimManager')
716+ return str(interface.GetProperties()['PinRequired'])
717
718=== added directory 'tests/autopilot/unity8/settings_wizard/tests'
719=== added file 'tests/autopilot/unity8/settings_wizard/tests/__init__.py'
720=== added file 'tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py'
721--- tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py 1970-01-01 00:00:00 +0000
722+++ tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py 2015-07-09 20:23:14 +0000
723@@ -0,0 +1,79 @@
724+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
725+#
726+# Unity Autopilot Test Suite
727+# Copyright (C) 2015 Canonical
728+#
729+# This program is free software: you can redistribute it and/or modify
730+# it under the terms of the GNU General Public License as published by
731+# the Free Software Foundation, either version 3 of the License, or
732+# (at your option) any later version.
733+#
734+# This program is distributed in the hope that it will be useful,
735+# but WITHOUT ANY WARRANTY; without even the implied warranty of
736+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
737+# GNU General Public License for more details.
738+#
739+# You should have received a copy of the GNU General Public License
740+# along with this program. If not, see <http://www.gnu.org/licenses/>.
741+#
742+
743+from unity8.settings_wizard import fixture_setup, Wizard
744+from unity8.shell import tests
745+
746+DEFAULT_LANGUAGE = 'English (United States)'
747+DEFAULT_PHONESIM_CONFIG_FILE = '/usr/share/phonesim/default.xml'
748+DEFAULT_SECURITY_METHOD = 'Passcode'
749+
750+
751+class SkipThroughSettingsWizardTestCase(tests.UnityTestCase):
752+ """ Autopilot test for completing settings wizard """
753+
754+ def setUp(self):
755+ super().setUp()
756+ self.wizard_helper = self.useFixture(
757+ fixture_setup.SettingsWizard(True))
758+ self.unity = self.launch_unity()
759+ self.wizard = self._get_settings_wizard()
760+
761+ def _get_settings_wizard(self):
762+ return self.unity.wait_select_single(Wizard)
763+
764+ def _test_language_page(self):
765+ """ Get the language page, check the default language and continue """
766+ language_page = self.wizard.get_language_page()
767+ default_selection = language_page.get_selected_language()
768+ self.assertEqual(default_selection, DEFAULT_LANGUAGE)
769+ return language_page.continue_()
770+
771+ def _test_password_page(self, password_page):
772+ """ Check default selection for password type and change
773+ password type to swipe to keep this test as uncomplicated
774+ as possible """
775+ default_selection = password_page.get_selected_security_option()
776+ self.assertEqual(default_selection, DEFAULT_SECURITY_METHOD)
777+ password_page.select_security_option('Swipe')
778+ return password_page.continue_()
779+
780+ def _test_reporting_page(self, reporting_page):
781+ return reporting_page.continue_()
782+
783+ def _test_wifi_connect_page(self, wifi_connect_page):
784+ if wifi_connect_page.is_any_network_checked() or not \
785+ wifi_connect_page.is_any_network_found():
786+ return wifi_connect_page.continue_()
787+ else:
788+ return wifi_connect_page.skip()
789+
790+ def test_skipping_through_wizard(self):
791+ """ Most basic test of the settings wizard. Skip all skipable pages """
792+ sim_inserted, next_page = self._test_language_page()
793+ if sim_inserted:
794+ password_page = next_page
795+ else:
796+ password_page = next_page.skip()
797+ wifi_connect_page = self._test_password_page(password_page)
798+ reporting_page = self._test_wifi_connect_page(wifi_connect_page)
799+ finish_page = self._test_reporting_page(reporting_page)
800+ finish_page.finish()
801+ self.assertFalse(
802+ self.wizard_helper.is_settings_wizard_enabled())

Subscribers

People subscribed via source and target branches