Merge lp:~canonical-platform-qa/ubuntu-system-tests/app_startup_poc into lp:ubuntu-system-tests

Proposed by Sergio Cazzolato
Status: Merged
Approved by: Richard Huddie
Approved revision: 302
Merged at revision: 327
Proposed branch: lp:~canonical-platform-qa/ubuntu-system-tests/app_startup_poc
Merge into: lp:ubuntu-system-tests
Diff against target: 892 lines (+523/-41)
14 files modified
ubuntu_system_tests/config.py (+8/-0)
ubuntu_system_tests/helpers/autopilot.py (+18/-5)
ubuntu_system_tests/helpers/music.py (+0/-4)
ubuntu_system_tests/helpers/scopes/base.py (+6/-0)
ubuntu_system_tests/helpers/timer.py (+53/-0)
ubuntu_system_tests/helpers/webbrowser/__init__.py (+0/-5)
ubuntu_system_tests/tests/app_startup/__init__.py (+19/-0)
ubuntu_system_tests/tests/app_startup/test_application_startup.py (+212/-0)
ubuntu_system_tests/tests/base.py (+202/-13)
ubuntu_system_tests/tests/scopes/test_music_scope.py (+1/-1)
ubuntu_system_tests/tests/scopes/test_video_scope.py (+1/-1)
ubuntu_system_tests/tests/test_sdcard.py (+1/-1)
ubuntu_system_tests/tests/webapps/test_ebay.py (+1/-6)
ubuntu_system_tests/tests/webapps/test_here.py (+1/-5)
To merge this branch: bzr merge lp:~canonical-platform-qa/ubuntu-system-tests/app_startup_poc
Reviewer Review Type Date Requested Status
Richard Huddie (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+283699@code.launchpad.net

Commit message

Run app_startup tests. Running these tests, the elapsed times to start apps are saved to be processed.

Run the tests by doing:
./run-system-tests ubuntu_system_tests.tests.app_startup.test_application_startup

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Richard Huddie (rhuddie) wrote :

I've made some minor comments below.

Also a question regarding best approach to stop the apps. By using the ubuntu-app-stop or process killing mechanism, we are not stopping the app in the way it would be done by user, so could potentially lead to data being left in bad state, or app doesn't get time to save data etc. So, as we now have the task switcher cpo which allows apps to be closed the correct way, should we use that? Perhaps not for cleanup actions where we just want to close the process, but when running performance tests in a loop I think it makes senses to do it the way a user would through the UI. What do you think?

I did a test run with a couple of failure results:
http://pastebin.ubuntu.com/14662564/

review: Needs Fixing
290. By Sergio Cazzolato

Split runs by run type and improve the cache cleanup

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sergio Cazzolato (sergio-j-cazzolato) wrote :

> I've made some minor comments below.
>
> Also a question regarding best approach to stop the apps. By using the ubuntu-
> app-stop or process killing mechanism, we are not stopping the app in the way
> it would be done by user, so could potentially lead to data being left in bad
> state, or app doesn't get time to save data etc. So, as we now have the task
> switcher cpo which allows apps to be closed the correct way, should we use
> that? Perhaps not for cleanup actions where we just want to close the process,
> but when running performance tests in a loop I think it makes senses to do it
> the way a user would through the UI. What do you think?
>
> I did a test run with a couple of failure results:
> http://pastebin.ubuntu.com/14662564/

I have implemented a close_app method in the base class following the method done for AppSwitcherTestCase

291. By Sergio Cazzolato

Stop apps method replaced by close apps method using the task switcher

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
292. By Sergio Cazzolato

Adding exception management for tests execution

293. By Sergio Cazzolato

Update exception message logged

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
294. By Sergio Cazzolato

Waiting until the app is started to get its proxy when the app is launched

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Richard Huddie (rhuddie) wrote :

Running tests currently. App switcher closing is working well, 1 comment below where HERE is not dismissing the location request prompt.

review: Needs Fixing
Revision history for this message
Richard Huddie (rhuddie) wrote :

Also seeing some CPO failures getting the CPO for some apps:
http://pastebin.ubuntu.com/14679028/

Using the patched_wait_select_single() method might help to resolve this.

295. By Sergio Cazzolato

Creating new test class for here app

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Richard Huddie (rhuddie) wrote :

I came across following failure when running on Arale and trying to launch the music app: http://pastebin.ubuntu.com/14688909/

See comment below.

review: Needs Fixing
Revision history for this message
Richard Huddie (rhuddie) wrote :

I've made an MP which will allow to get the category name for an app, so it should fix the issue I saw earlier where the category changed on different devices.

https://code.launchpad.net/~canonical-platform-qa/ubuntu-system-tests/get-app-category/+merge/284326

This could be added directly to this branch or used as pre-requisite branch.

Revision history for this message
Sergio Cazzolato (sergio-j-cazzolato) wrote :

Great, thanks Richard, so the idea should be autodetect the category and remove the category from the method signature. Do you agree with that?

296. By Sergio Cazzolato

Moving config to the config file and making run_id the same for all the times during the same run

297. By Sergio Cazzolato

Minor fix to cast the runs

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
298. By Sergio Cazzolato

merge with get-app-category branch

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
299. By Sergio Cazzolato

merge with trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Richard Huddie (rhuddie) wrote :

Currently getting this config error: http://pastebin.ubuntu.com/14856649/

review: Needs Fixing
300. By Sergio Cazzolato

Adding config values to config file

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
301. By Sergio Cazzolato

Merge with dependency branch

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Richard Huddie (rhuddie) wrote :

I did a test run, there were a few times the apps didn't load, but this was logged accordingly. No CPO errors now.

I've added a few minor comments below.

review: Needs Fixing
Revision history for this message
Sergio Cazzolato (sergio-j-cazzolato) wrote :

Changes implemented

302. By Sergio Cazzolato

Updating changes based on code reviews

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Richard Huddie (rhuddie) wrote :

Looks good and tests working well, approving.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ubuntu_system_tests/config.py'
2--- ubuntu_system_tests/config.py 2015-11-05 17:35:49 +0000
3+++ ubuntu_system_tests/config.py 2016-02-05 13:59:58 +0000
4@@ -109,6 +109,14 @@
5 'max_unity8_retry_delay', default=30000,
6 help_string='The boundary for how long we should be retrying until '
7 'unity8 is started'),
8+ options.Option(
9+ 'app_startup_cold_runs', default=5,
10+ help_string='How many iterations to run for the cold start app '
11+ 'performance tests?'),
12+ options.Option(
13+ 'app_startup_hot_runs', default=5,
14+ help_string='How many iterations to run for the hot start app '
15+ 'performance tests?'),
16 ]
17 """Options for tests in external debian and click packages."""
18
19
20=== modified file 'ubuntu_system_tests/helpers/autopilot.py'
21--- ubuntu_system_tests/helpers/autopilot.py 2016-02-02 17:23:05 +0000
22+++ ubuntu_system_tests/helpers/autopilot.py 2016-02-05 13:59:58 +0000
23@@ -262,17 +262,30 @@
24
25
26 def get_channel_name():
27- """
28- Return the build channel name. In case there is not channel defined, it
29- returns the default value
30+ """ Return the build channel name. In case there is not channel defined, it
31+ return the default value
32+ """
33+ default = 'ubuntu-touch/rc-proposed/bq-aquaris.en'
34+ return _get_image_info('service', 'channel', default)
35+
36+
37+def get_build_number():
38+ """ Return the build number. In case there is not channel defined, it
39+ return the default value
40+ """
41+ return _get_image_info('service', 'build_number', '0')
42+
43+
44+def _get_image_info(category, item, default):
45+ """ Return the image item requested. In case it is not defined, it return
46+ the default value
47 """
48 file = '/etc/system-image/channel.ini'
49- default = 'ubuntu-touch/rc-proposed/bq-aquaris.en'
50 if not os.path.isfile(file):
51 return default
52 parser = configparser.ConfigParser()
53 parser.read(file)
54- return parser['service']['channel']
55+ return parser[category][item]
56
57
58 def is_agps_supported():
59
60=== modified file 'ubuntu_system_tests/helpers/music.py'
61--- ubuntu_system_tests/helpers/music.py 2015-11-06 22:35:54 +0000
62+++ ubuntu_system_tests/helpers/music.py 2016-02-05 13:59:58 +0000
63@@ -24,10 +24,6 @@
64 QML = 'music-app.qml'
65
66
67-def is_music_app_running():
68- return processes.is_qmlscene_running_with_qmlfile(QML)
69-
70-
71 def stop_music_app():
72 processes.stop_qmlscene_process(QML)
73
74
75=== modified file 'ubuntu_system_tests/helpers/scopes/base.py'
76--- ubuntu_system_tests/helpers/scopes/base.py 2016-01-05 15:28:08 +0000
77+++ ubuntu_system_tests/helpers/scopes/base.py 2016-02-05 13:59:58 +0000
78@@ -18,6 +18,8 @@
79 # along with this program. If not, see <http://www.gnu.org/licenses/>.
80 #
81
82+import logging
83+
84 from autopilot import exceptions
85 from collections import namedtuple
86 from unity8 import dash as unity8_dash
87@@ -26,6 +28,7 @@
88 from ubuntu_system_tests.helpers.ubuntuuitoolkit.pageheader import (
89 DashPageHeader
90 )
91+from ubuntu_system_tests.helpers import timer
92 from ubuntu_system_tests.helpers.unity8 import get_dash
93 from ubuntu_system_tests.helpers.url_dispatcher import go_to_url
94
95@@ -33,6 +36,8 @@
96
97 IMAGE_TYPES = ['QQuickImage', 'CroppedImageMinimumSourceSize']
98
99+logger = logging.getLogger(__name__)
100+
101
102 class GenericScopeView(unity8_dash.GenericScopeView):
103 """
104@@ -70,6 +75,7 @@
105 x, y, width, height = icon.globalRect
106 self.pointing_device.move(x + 1, y + 1)
107 self.pointing_device.click(press_duration=press_duration)
108+ timer.start(timer.LAUNCH_ID)
109
110 def _get_data_from_object(self, object):
111 """
112
113=== added file 'ubuntu_system_tests/helpers/timer.py'
114--- ubuntu_system_tests/helpers/timer.py 1970-01-01 00:00:00 +0000
115+++ ubuntu_system_tests/helpers/timer.py 2016-02-05 13:59:58 +0000
116@@ -0,0 +1,53 @@
117+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
118+#
119+# Ubuntu System Tests
120+# Copyright (C) 2016 Canonical
121+#
122+# This program is free software: you can redistribute it and/or modify
123+# it under the terms of the GNU General Public License as published by
124+# the Free Software Foundation, either version 3 of the License, or
125+# (at your option) any later version.
126+#
127+# This program is distributed in the hope that it will be useful,
128+# but WITHOUT ANY WARRANTY; without even the implied warranty of
129+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
130+# GNU General Public License for more details.
131+#
132+# You should have received a copy of the GNU General Public License
133+# along with this program. If not, see <http://www.gnu.org/licenses/>.
134+#
135+
136+from datetime import datetime
137+
138+start_times = {}
139+
140+LAUNCH_ID = 'launch'
141+
142+
143+def start(id):
144+ """ Start the timer identified with the id """
145+ global start_times
146+ start_times[id] = datetime.now()
147+
148+
149+def _get_elapsed_time(id):
150+ global start_times
151+ end_time = datetime.now()
152+ if id not in start_times:
153+ raise RuntimeError('Timer with id {} not initialized'.format(id))
154+
155+ elapsed_time = end_time - start_times[id]
156+ return elapsed_time.total_seconds()
157+
158+
159+def stop(id):
160+ """ Retrieve the elapsed time in seconds from the id was started and stop
161+ the counter """
162+ elapsed_time = _get_elapsed_time(id)
163+ start_times.pop(id)
164+ return elapsed_time
165+
166+
167+def get_elaspsed_time(id):
168+ """ Retrieve the elapsed time in seconds from the id was started """
169+ return _get_elapsed_time(id)
170
171=== modified file 'ubuntu_system_tests/helpers/webbrowser/__init__.py'
172--- ubuntu_system_tests/helpers/webbrowser/__init__.py 2015-11-23 05:00:48 +0000
173+++ ubuntu_system_tests/helpers/webbrowser/__init__.py 2016-02-05 13:59:58 +0000
174@@ -23,11 +23,6 @@
175 APP = 'webbrowser-app'
176
177
178-def is_webbrowser_running():
179- """ Indicate if the webbrowser is running """
180- return processes.is_process_running(APP)
181-
182-
183 def get_webbrowser_process_id():
184 """ Retrieve the webbrowser process id """
185 return processes.get_process_id(APP)
186
187=== added directory 'ubuntu_system_tests/tests/app_startup'
188=== added file 'ubuntu_system_tests/tests/app_startup/__init__.py'
189--- ubuntu_system_tests/tests/app_startup/__init__.py 1970-01-01 00:00:00 +0000
190+++ ubuntu_system_tests/tests/app_startup/__init__.py 2016-02-05 13:59:58 +0000
191@@ -0,0 +1,19 @@
192+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
193+
194+#
195+# Ubuntu System Tests
196+# Copyright (C) 2015, 2016 Canonical
197+#
198+# This program is free software: you can redistribute it and/or modify
199+# it under the terms of the GNU General Public License as published by
200+# the Free Software Foundation, either version 3 of the License, or
201+# (at your option) any later version.
202+#
203+# This program is distributed in the hope that it will be useful,
204+# but WITHOUT ANY WARRANTY; without even the implied warranty of
205+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
206+# GNU General Public License for more details.
207+#
208+# You should have received a copy of the GNU General Public License
209+# along with this program. If not, see <http://www.gnu.org/licenses/>.
210+#
211
212=== added file 'ubuntu_system_tests/tests/app_startup/test_application_startup.py'
213--- ubuntu_system_tests/tests/app_startup/test_application_startup.py 1970-01-01 00:00:00 +0000
214+++ ubuntu_system_tests/tests/app_startup/test_application_startup.py 2016-02-05 13:59:58 +0000
215@@ -0,0 +1,212 @@
216+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
217+
218+#
219+# Ubuntu System Tests
220+# Copyright (C) 2015, 2016 Canonical
221+#
222+# This program is free software: you can redistribute it and/or modify
223+# it under the terms of the GNU General Public License as published by
224+# the Free Software Foundation, either version 3 of the License, or
225+# (at your option) any later version.
226+#
227+# This program is distributed in the hope that it will be useful,
228+# but WITHOUT ANY WARRANTY; without even the implied warranty of
229+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
230+# GNU General Public License for more details.
231+#
232+# You should have received a copy of the GNU General Public License
233+# along with this program. If not, see <http://www.gnu.org/licenses/>.
234+#
235+
236+import logging
237+import os
238+import traceback
239+
240+from ubuntu_system_tests import config
241+from ubuntu_system_tests.helpers import autopilot
242+from ubuntu_system_tests.helpers.camera.fixture_setup import (
243+ SetCameraAccessRequests
244+)
245+from ubuntu_system_tests.helpers.clock.fixture_setup import (
246+ SetClockAccessRequests)
247+from ubuntu_system_tests.helpers import file_system as fs
248+from ubuntu_system_tests.helpers.location.fixture_setup import (
249+ SetLocationAccessRequests)
250+from ubuntu_system_tests.helpers.testbed import run_command_with_sudo
251+from ubuntu_system_tests.helpers import timer
252+from ubuntu_system_tests.helpers.webbrowser.fixture_setup import (
253+ WebbrowserTestEnvironment
254+)
255+from ubuntu_system_tests.tests.base import BaseUbuntuSystemTestCase
256+
257+logger = logging.getLogger(__name__)
258+
259+HOT = 'hot'
260+COLD = 'cold'
261+COLD_RUNS_KEY = 'app_startup_cold_runs'
262+HOT_RUNS_KEY = 'app_startup_hot_runs'
263+RUN_ID = fs.get_random_string()
264+
265+
266+class BaseAppStartupTestCase(BaseUbuntuSystemTestCase):
267+
268+ def setUp(self):
269+ super().setUp()
270+ self.shell = self.restart_unity()
271+ self.addCleanup(self._clear_qml_cache)
272+ self._log_global_info()
273+
274+ def _clear_qml_cache(self):
275+ fs.clean_dir(os.path.join(fs.DIR_HOME_CACHE, 'QML'))
276+ run_command_with_sudo('sysctl -w vm.drop_caches=3')
277+
278+ def _load_config_values(self, key, default=None):
279+ config_stack = config.get_device_config_stack()
280+ try:
281+ return config_stack.get(key)
282+ except KeyError:
283+ return default
284+
285+ def _log_started(self, app, type):
286+ started = {"app": app, "time": timer.stop(timer.LAUNCH_ID),
287+ "type": type}
288+ logger.info("Started => {}".format(started))
289+
290+ def _log_global_info(self):
291+ global_info = {"run_id": RUN_ID,
292+ "device": autopilot.get_device_name(),
293+ "channel": autopilot.get_channel_name(),
294+ "build_number": autopilot.get_build_number()}
295+
296+ logger.info("Global Info <= {}".format(global_info))
297+
298+ def _run(self, runs, app_name, run_type, launch_method,
299+ close_method, loaded_method=None, setup_method=None):
300+ runs_passed = 0
301+ for i in range(runs):
302+ try:
303+ if setup_method:
304+ setup_method()
305+ launch_method()
306+ if loaded_method:
307+ loaded_method()
308+ self._log_started(app_name, run_type)
309+ runs_passed += 1
310+ except:
311+ logger.error('Unexpected error: {}'.format(
312+ traceback.format_exc()))
313+ finally:
314+ close_method()
315+ return runs_passed
316+
317+ def _run_test(self, app_name, launch_method, close_method,
318+ loaded_method=None):
319+ cold_runs = int(self._load_config_values(COLD_RUNS_KEY, 1))
320+ res_cold = self._run(cold_runs, app_name, COLD,
321+ launch_method, close_method,
322+ loaded_method=loaded_method,
323+ setup_method=self._clear_qml_cache)
324+ hot_runs = int(self._load_config_values(HOT_RUNS_KEY, 1))
325+ res_hot = self._run(hot_runs, app_name, HOT,
326+ launch_method, close_method,
327+ loaded_method=loaded_method)
328+
329+ msg = 'Not all the runs worked properly for app {}. Cold runs ' \
330+ 'passed {}/{}. Hot runs passed {}/{}'
331+ self.assertTrue(cold_runs == res_cold and hot_runs == res_hot,
332+ msg.format(app_name, res_cold, cold_runs, res_hot,
333+ hot_runs))
334+
335+
336+class AppStartupTestCase(BaseAppStartupTestCase):
337+
338+ def test_dialer_startup(self):
339+ self._run_test('dialer', self.launch_dialer_app,
340+ self.close_dialer_app,
341+ loaded_method=self.shell.ensure_app_loaded)
342+
343+ def test_calculator_startup(self):
344+ self._run_test('calculator', self.launch_calculator_app,
345+ self.close_calculator_app,
346+ loaded_method=self.shell.ensure_app_loaded)
347+
348+ def test_address_book_startup(self):
349+ self._run_test('address_book', self.launch_address_book,
350+ self.close_address_book,
351+ loaded_method=self.shell.ensure_app_loaded)
352+
353+ def test_messaging_startup(self):
354+ self._run_test('messaging', self.launch_messaging_app,
355+ self.close_messaging_app,
356+ loaded_method=self.shell.ensure_app_loaded)
357+
358+ def test_ebay_startup(self):
359+ self._run_test('ebay', self.launch_ebay_webapp,
360+ self.close_ebay_webapp,
361+ loaded_method=self.shell.ensure_app_loaded)
362+
363+ def test_system_settings_startup(self):
364+ self._run_test('system_settings', self.launch_system_settings,
365+ self.close_system_settings,
366+ loaded_method=self.shell.ensure_app_loaded)
367+
368+ def test_gallery_startup(self):
369+ self._run_test('gallery', self.launch_gallery_app_from_launcher,
370+ self.close_gallery_app,
371+ loaded_method=self.shell.ensure_app_loaded)
372+
373+ def test_music_startup(self):
374+ self._run_test('music', self.launch_music_app,
375+ self.close_music_app,
376+ loaded_method=self.shell.ensure_app_loaded)
377+
378+
379+class CameraAppStartupTestCase(BaseAppStartupTestCase):
380+
381+ def setUp(self):
382+ self.useFixture(SetCameraAccessRequests())
383+ super().setUp()
384+
385+ def _launch_camera_app(self):
386+ camera = self.launch_camera_app()
387+ camera.ensure_camera_ready()
388+
389+ def test_camera_startup(self):
390+ self._run_test('camera', self._launch_camera_app,
391+ self.close_camera_app)
392+
393+
394+class WebBrowserAppStartupTestCase(BaseAppStartupTestCase):
395+
396+ def setUp(self):
397+ self.useFixture(WebbrowserTestEnvironment())
398+ super().setUp()
399+
400+ def test_webbrowser_startup(self):
401+ self._run_test('webbrowser', self.launch_webbrowser_app,
402+ self.close_webbrowser_app,
403+ loaded_method=self.shell.ensure_app_loaded)
404+
405+
406+class ClockAppStartupTestCase(BaseAppStartupTestCase):
407+
408+ def setUp(self):
409+ self.useFixture(SetClockAccessRequests())
410+ super().setUp()
411+
412+ def test_clock_startup(self):
413+ self._run_test('clock', self.launch_clock_app,
414+ self.close_clock_app,
415+ loaded_method=self.shell.ensure_app_loaded)
416+
417+
418+class HereAppStartupTestCase(BaseAppStartupTestCase):
419+
420+ def setUp(self):
421+ self.useFixture(SetLocationAccessRequests('com.nokia.heremaps_here'))
422+ super().setUp()
423+
424+ def test_here_startup(self):
425+ self._run_test('here', self.launch_here_webapp,
426+ self.close_here_webapp,
427+ loaded_method=self.shell.ensure_app_loaded)
428
429=== modified file 'ubuntu_system_tests/tests/base.py'
430--- ubuntu_system_tests/tests/base.py 2016-01-29 12:10:01 +0000
431+++ ubuntu_system_tests/tests/base.py 2016-02-05 13:59:58 +0000
432@@ -50,6 +50,7 @@
433 from ubuntu_system_tests.helpers import mir
434 from ubuntu_system_tests.helpers import processes
435 from ubuntu_system_tests.helpers import screen
436+from ubuntu_system_tests.helpers import timer
437 from ubuntu_system_tests.helpers import unity8
438 from ubuntu_system_tests.helpers import wait_until
439 from ubuntu_system_tests.helpers import webapp
440@@ -61,6 +62,7 @@
441 # Any test name ending with this will leave device locked
442 TEST_ID_DEVICE_LOCKED = 'device_locked'
443
444+# Apps and cleanup names
445 CALCULATOR_APP = 'ubuntu-calculator-app'
446
447 CATEGORY_LOCAL = 'local'
448@@ -246,6 +248,7 @@
449
450 """
451 unity = self.get_job_proxy_object('unity8')
452+ timer.start(timer.LAUNCH_ID)
453 unity.main_window.launch_application(app_name)
454
455 def _get_proxy_object_for_existing_app(
456@@ -325,6 +328,15 @@
457 'Contacts', CATEGORY_PREDEFINED)
458 return self.get_address_book_app_proxy()
459
460+ def close_address_book(self):
461+ """ Close the address book app using task switcher """
462+ if self.is_address_book_app_running():
463+ self._close_app('address-book-app')
464+
465+ def is_address_book_app_running(self):
466+ """ Indicate if the address book app is currently running """
467+ return processes.is_process_running('address-book-app')
468+
469 def launch_address_book_from_launcher(self):
470 """Drag out the launcher and tap the address book icon to start it."""
471 self._launch_application_from_launcher('address-book-app')
472@@ -338,6 +350,7 @@
473
474 """
475 from ubuntu_system_tests.helpers.addressbook import _cpo # NOQA
476+ wait_until(self.is_address_book_app_running, period=0.5)
477 proxy = self._get_proxy_object_for_existing_app('address-book-app')
478 return proxy.main_window
479
480@@ -351,6 +364,15 @@
481 self._launch_application_from_apps_scope('Camera', CATEGORY_PREDEFINED)
482 return self.get_camera_app_proxy()
483
484+ def close_camera_app(self):
485+ """ Close the camera app using task switcher """
486+ if self.is_camera_app_running():
487+ self._close_app('com.ubuntu.camera_camera')
488+
489+ def is_camera_app_running(self):
490+ """ Indicate if the camera app is currently running """
491+ return processes.is_process_running('camera-app')
492+
493 def launch_camera_app_from_launcher(self):
494 """Drag out the launcher and tap the camera icon to start it."""
495 self._launch_application_from_launcher('com.ubuntu.camera_camera')
496@@ -365,6 +387,7 @@
497
498 """
499 from ubuntu_system_tests.helpers.camera._cpo import MainWindow
500+ wait_until(self.is_camera_app_running, period=0.5)
501 proxy = self._get_proxy_object_for_existing_app(
502 'camera-app',
503 cleanup_process=click.get_click_app_identifier('com.ubuntu.camera')
504@@ -381,6 +404,15 @@
505 self._launch_application_from_apps_scope('Phone', CATEGORY_PREDEFINED)
506 return self.get_dialer_app_proxy()
507
508+ def close_dialer_app(self):
509+ """ Close the dialer app using task switcher """
510+ if self.is_dialer_app_running():
511+ self._close_app('dialer-app')
512+
513+ def is_dialer_app_running(self):
514+ """ Indicate if the dialer app is currently running """
515+ return processes.is_process_running('dialer-app')
516+
517 def get_dialer_app_proxy(self):
518 """
519 Return dialer app proxy object from existing process.
520@@ -389,6 +421,7 @@
521
522 """
523 from ubuntu_system_tests.helpers.dialer_app import _cpo # NOQA
524+ wait_until(self.is_dialer_app_running, period=0.5)
525 proxy = self._get_proxy_object_for_existing_app('dialer-app')
526 return proxy.main_view
527
528@@ -403,6 +436,15 @@
529 self._launch_application_from_apps_scope('Gallery', CATEGORY_LOCAL)
530 return EventsView(self.get_gallery_app_proxy())
531
532+ def close_gallery_app(self):
533+ """ Close the gallery app using task switcher """
534+ if self.is_gallery_app_running():
535+ self._close_app('com.ubuntu.gallery_gallery')
536+
537+ def is_gallery_app_running(self):
538+ """ Indicate if the gallery app is currently running """
539+ return processes.is_process_running('gallery-app')
540+
541 def get_gallery_app_proxy(self):
542 """
543 Return gallery app proxy object from existing process.
544@@ -410,9 +452,11 @@
545 :return: Proxy object for gallery application.
546
547 """
548- proxy = self._get_proxy_object_for_existing_app('gallery-app')
549- # ubuntu-app-stop does not work with gallery app, use process helper
550- self.addCleanup(processes.stop_process, 'gallery-app')
551+ wait_until(self.is_gallery_app_running, period=0.5)
552+ proxy = self._get_proxy_object_for_existing_app(
553+ 'gallery-app',
554+ cleanup_process=click.get_click_app_identifier(
555+ 'com.ubuntu.gallery'))
556 return proxy
557
558 def get_gallery_events_view(self):
559@@ -447,6 +491,15 @@
560 'Messaging', CATEGORY_PREDEFINED)
561 return self.get_messaging_app_proxy()
562
563+ def close_messaging_app(self):
564+ """ Close the messaging app using task switcher """
565+ if self.is_messaging_app_running():
566+ self._close_app('messaging-app')
567+
568+ def is_messaging_app_running(self):
569+ """ Indicate if the messaging app is currently running """
570+ return processes.is_process_running('messaging-app')
571+
572 def get_messaging_app_proxy(
573 self, base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
574 """
575@@ -455,6 +508,7 @@
576 :return: Proxy object for messaging application.
577
578 """
579+ wait_until(self.is_messaging_app_running, period=0.5)
580 if not base:
581 return self._get_proxy_object_for_existing_app('messaging-app',
582 base=base)
583@@ -474,6 +528,15 @@
584 'System Settings', CATEGORY_LOCAL)
585 return self.get_system_settings_proxy()
586
587+ def close_system_settings(self):
588+ """ Close the system settings app using task switcher """
589+ if self.is_system_settings_running():
590+ self._close_app('ubuntu-system-settings')
591+
592+ def is_system_settings_running(self):
593+ """ Indicate if the system settings is currently running """
594+ return processes.is_process_running('system-settings')
595+
596 def get_system_settings_proxy(self):
597 """
598 Return system settings proxy object from existing process.
599@@ -482,6 +545,7 @@
600
601 """
602 from ubuntu_system_tests.helpers.system_settings import _cpo # NOQA
603+ wait_until(self.is_system_settings_running, period=0.5)
604 proxy = self._get_proxy_object_for_existing_app(
605 'system-settings', cleanup_process='ubuntu-system-settings')
606 return proxy.main_view
607@@ -497,6 +561,15 @@
608 'Browser', CATEGORY_PREDEFINED)
609 return self.get_webbrowser_app_proxy()
610
611+ def close_webbrowser_app(self):
612+ """ Close the webbrowser app using task switcher """
613+ if self.is_webbrowser_app_running():
614+ self._close_app('webbrowser-app')
615+
616+ def is_webbrowser_app_running(self):
617+ """ Indicate if the webbrowser app is currently running """
618+ return processes.is_process_running('webbrowser-app')
619+
620 def get_webbrowser_app_proxy(self):
621 """
622 Return webbrowser app proxy object from existing process.
623@@ -505,6 +578,7 @@
624
625 """
626 from ubuntu_system_tests.helpers.webbrowser import _cpo # NOQA
627+ wait_until(self.is_webbrowser_app_running, period=0.5)
628 proxy = self._get_proxy_object_for_existing_app('webbrowser-app')
629 return proxy.main_window
630
631@@ -515,11 +589,20 @@
632 :return: Proxy object for calendar application.
633
634 """
635- self._launch_application_from_apps_scope(
636- 'Calendar', CATEGORY_LOCAL)
637- wait_until(processes.is_qmlscene_running_with_qmlfile, 'calendar')
638+ self._launch_application_from_apps_scope('Calendar', CATEGORY_LOCAL)
639+ wait_until(self.is_calendar_app_running, period=0.5)
640+
641 return self.get_calendar_app_proxy()
642
643+ def close_calendar_app(self):
644+ """ Close the calendar app using task switcher """
645+ if self.is_calendar_app_running():
646+ self._close_app('calendar')
647+
648+ def is_calendar_app_running(self):
649+ """ Indicate if the calendar app is currently running """
650+ return processes.is_qmlscene_running_with_qmlfile('calendar')
651+
652 def get_calendar_app_proxy(self):
653 """
654 Return calendar app proxy object from existing process.
655@@ -539,14 +622,17 @@
656
657 """
658 self._launch_application_from_apps_scope('Clock', CATEGORY_PREDEFINED)
659- wait_until(processes.is_qmlscene_running_with_qmlfile,
660- 'ubuntu-clock-app')
661+ wait_until(self.is_clock_app_running, period=0.5)
662 return self.get_clock_app_proxy()
663
664- def launch_webbrowser_from_launcher(self):
665- """Start webbrowser from the launcher."""
666- self._launch_application_from_launcher('webbrowser-app')
667- return self.get_webbrowser_app_proxy()
668+ def close_clock_app(self):
669+ """ Close the calendar app using task switcher """
670+ if self.is_clock_app_running():
671+ self._close_app('com.ubuntu.clock_clock')
672+
673+ def is_clock_app_running(self):
674+ """ Indicate if the clock app is currently running """
675+ return processes.is_qmlscene_running_with_qmlfile('ubuntu-clock-app')
676
677 def get_clock_app_proxy(self):
678 """
679@@ -560,6 +646,11 @@
680 'ubuntu-clock-app')
681 return proxy.main_view
682
683+ def launch_webbrowser_from_launcher(self):
684+ """Start webbrowser from the launcher."""
685+ self._launch_application_from_launcher('webbrowser-app')
686+ return self.get_webbrowser_app_proxy()
687+
688 def launch_messaging_app_from_launcher(self):
689 """Drag out the launcher and tap the messaging app icon to start it."""
690 self._launch_application_from_launcher('messaging-app')
691@@ -570,6 +661,11 @@
692 self._launch_application_from_launcher('dialer-app')
693 return self.get_dialer_app_proxy()
694
695+ def launch_gallery_app_from_launcher(self):
696+ """Drag out the launcher and tap the gallery app icon to start it."""
697+ self._launch_application_from_launcher('com.ubuntu.gallery_gallery')
698+ return self.get_gallery_app_proxy()
699+
700 def get_webapp_proxy(self, web_app_package):
701 """ Return webapp proxy object from existing process.
702 :param web_app_package: The package name
703@@ -612,9 +708,19 @@
704 """
705 self._launch_application_from_apps_scope(
706 'Calculator', CATEGORY_LOCAL)
707- wait_until(processes.is_qmlscene_running_with_qmlfile, CALCULATOR_APP)
708+ wait_until(self.is_calculator_app_running, period=0.5)
709 return self.get_calculator_app_proxy()
710
711+ def close_calculator_app(self):
712+ """ Close the calculator app using task switcher """
713+ if self.is_calculator_app_running():
714+ self._close_app('com.ubuntu.calculator_calculator')
715+
716+ def is_calculator_app_running(self):
717+ """ Indicate if the calculator app is currently running """
718+ return processes.is_qmlscene_running_with_qmlfile(
719+ 'ubuntu-calculator-app')
720+
721 def get_calculator_app_proxy(self):
722 """Return the proxy object of the calculator app."""
723 from ubuntu_system_tests.helpers.calculator import _cpo # NOQA
724@@ -625,3 +731,86 @@
725 def get_ubuntu_keyboard_proxy(self):
726 from ubuntu_system_tests.helpers.ubuntu_keyboard import _cpo # NOQA
727 return self._get_proxy_object_for_existing_app('maliit-server')
728+
729+ def launch_ebay_webapp(self):
730+ """ Launch the Ebay webapp from apps scope and return its proxy object
731+ """
732+ webapp_name = 'eBay'
733+ webapp_package = 'com.ubuntu.developer.webapps.webapp-ebay'
734+ return self.launch_webapp(webapp_name, webapp_package)
735+
736+ def close_ebay_webapp(self):
737+ """ Close the ebay webapp using task switcher """
738+ if self.is_ebay_webapp_running():
739+ self._close_app(
740+ 'com.ubuntu.developer.webapps.webapp-ebay_webapp-ebay')
741+
742+ def is_ebay_webapp_running(self):
743+ """ Indicate if the ebay webapp is currently running """
744+ webapp_package = 'com.ubuntu.developer.webapps.webapp-ebay'
745+ return webapp.is_webapp_runing(webapp_package)
746+
747+ def launch_here_webapp(self):
748+ """ Launch the Here webapp from apps scope and return its proxy object
749+ """
750+ webapp_name = 'HERE Maps'
751+ webapp_package = 'com.nokia.heremaps'
752+ return self.launch_webapp(webapp_name, webapp_package)
753+
754+ def close_here_webapp(self):
755+ """ Close the here webapp using task switcher """
756+ if self.is_here_webapp_running():
757+ self._close_app('com.nokia.heremaps_here')
758+
759+ def is_here_webapp_running(self):
760+ """ Indicate if the here webapp is currently running """
761+ webapp_package = 'com.nokia.heremaps'
762+ return webapp.is_webapp_runing(webapp_package)
763+
764+ def launch_music_app(self):
765+ """
766+ Launch the music app from apps scope and return proxy object.
767+
768+ :return: Proxy object for music application.
769+
770+ """
771+ self._launch_application_from_apps_scope('Music')
772+ wait_until(self.is_music_app_running, period=0.5)
773+ return self.get_music_app_proxy()
774+
775+ def close_music_app(self):
776+ """ Close the music app using task switcher """
777+ if self.is_music_app_running():
778+ self._close_app('com.ubuntu.music_music')
779+
780+ def is_music_app_running(self):
781+ """ Indicate if the music app is currently running """
782+ return processes.is_qmlscene_running_with_qmlfile('music-app')
783+
784+ def get_music_app_proxy(self):
785+ """
786+ Return music app proxy object from existing process.
787+
788+ :return: Proxy object for music application.
789+
790+ """
791+ proxy = self._get_proxy_object_for_existing_qmlscene_process(
792+ 'music-app')
793+ return proxy.wait_select_single(ubuntuuitoolkit.MainView)
794+
795+ def _close_app(self, app_name):
796+ """Close an app using task switcher and check process is stopped."""
797+ unity_proxy = self.get_job_proxy_object('unity8')
798+
799+ # Get the windows name
800+ stage = unity_proxy.main_window.swipe_to_show_app_switcher()
801+ app_window_name = 'appWindow_' + app_name
802+ app_windows = stage.get_app_window_names()
803+ count = len(app_windows)
804+ self.assertTrue(app_window_name in app_windows)
805+
806+ # Close the windows and assert that it is closed
807+ stage.close_app(app_name)
808+ app_windows = stage.get_app_window_names()
809+ self.assertFalse(app_window_name in app_windows)
810+ self.assertEqual(len(app_windows), count - 1)
811
812=== modified file 'ubuntu_system_tests/tests/scopes/test_music_scope.py'
813--- ubuntu_system_tests/tests/scopes/test_music_scope.py 2016-01-26 14:03:27 +0000
814+++ ubuntu_system_tests/tests/scopes/test_music_scope.py 2016-02-05 13:59:58 +0000
815@@ -62,7 +62,7 @@
816
817 # Verify the music app is playing the selected song
818 track_preview.play_in_music_app()
819- self.assertTrue(wait_until(music_helper.is_music_app_running))
820+ self.assertTrue(wait_until(self.is_music_app_running))
821 self.addCleanup(music_helper.stop_music_app)
822 self.assertEqual(
823 test_data.LOCAL_AUDIO_FILE_2, music_helper.get_current_song())
824
825=== modified file 'ubuntu_system_tests/tests/scopes/test_video_scope.py'
826--- ubuntu_system_tests/tests/scopes/test_video_scope.py 2015-11-17 20:15:59 +0000
827+++ ubuntu_system_tests/tests/scopes/test_video_scope.py 2016-02-05 13:59:58 +0000
828@@ -131,7 +131,7 @@
829
830 # Validate the webbrowser is launched by clicking in the play button
831 preview.play_video()
832- self.assertTrue(wait_until(webbrowser.is_webbrowser_running))
833+ self.assertTrue(wait_until(self.is_webbrowser_app_running))
834
835 # Validate the url opened in the webbrowser is youtube
836 browser = self.get_webbrowser_app_proxy()
837
838=== modified file 'ubuntu_system_tests/tests/test_sdcard.py'
839--- ubuntu_system_tests/tests/test_sdcard.py 2016-01-27 11:39:06 +0000
840+++ ubuntu_system_tests/tests/test_sdcard.py 2016-02-05 13:59:58 +0000
841@@ -240,7 +240,7 @@
842 # Play the album in the music app and verify the desired album is
843 # being reproduced
844 preview.play_in_music_app()
845- self.assertTrue(wait_until(music.is_music_app_running, timeout=20))
846+ self.assertTrue(wait_until(self.is_music_app_running, timeout=20))
847 self.addCleanup(music.stop_music_app)
848 song_path = os.path.join(
849 fs.DIR_MEDIA_ROOT, sdcard.get_sd_card_dir_name(), 'Music',
850
851=== modified file 'ubuntu_system_tests/tests/webapps/test_ebay.py'
852--- ubuntu_system_tests/tests/webapps/test_ebay.py 2015-10-21 05:52:09 +0000
853+++ ubuntu_system_tests/tests/webapps/test_ebay.py 2016-02-05 13:59:58 +0000
854@@ -29,14 +29,9 @@
855
856 class EbayTestCase(BaseWebAppTestCase):
857
858- WEB_APP_NAME = 'eBay'
859- WEB_APP_PACKAGE = 'com.ubuntu.developer.webapps.webapp-ebay'
860-
861 def setUp(self):
862 super().setUp()
863- self.unity_proxy = self.restart_unity()
864- self.webapp = self.launch_webapp(self.WEB_APP_NAME,
865- self.WEB_APP_PACKAGE)
866+ self.web_app = self.launch_ebay_webapp()
867 self.driver = webapp.get_webdriver(self.addCleanup)
868
869 def test_open_and_view_content(self):
870
871=== modified file 'ubuntu_system_tests/tests/webapps/test_here.py'
872--- ubuntu_system_tests/tests/webapps/test_here.py 2015-10-23 14:12:44 +0000
873+++ ubuntu_system_tests/tests/webapps/test_here.py 2016-02-05 13:59:58 +0000
874@@ -35,17 +35,13 @@
875 class HereTestCase(BaseWebAppTestCase):
876
877 PARIS = 'Paris'
878-
879- WEB_APP_NAME = 'HERE Maps'
880- WEB_APP_PACKAGE = 'com.nokia.heremaps'
881 LOCATION_APP = 'com.nokia.heremaps_here'
882
883 def setUp(self):
884 self.useFixture(DummyLocation(*EIFFEL_TOWER))
885 super().setUp()
886 self.useFixture(SetLocationAccessRequests(self.LOCATION_APP))
887- self.webapp = self.launch_webapp(self.WEB_APP_NAME,
888- self.WEB_APP_PACKAGE)
889+ self.webapp = self.launch_here_webapp()
890 self.driver = webapp.get_webdriver(self.addCleanup)
891
892 def test_retrieve_location(self):

Subscribers

People subscribed via source and target branches

to all changes: