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

Proposed by Sergio Cazzolato
Status: Work in progress
Proposed branch: lp:~canonical-platform-qa/ubuntu-system-tests/device_monitoring
Merge into: lp:ubuntu-system-tests
Diff against target: 820 lines (+503/-29)
15 files modified
debian/control (+3/-0)
debian/tests/control (+1/-0)
ubuntu_system_tests/command_line.py (+5/-0)
ubuntu_system_tests/config.py (+11/-0)
ubuntu_system_tests/helpers/data.py (+14/-2)
ubuntu_system_tests/helpers/file_system.py (+1/-0)
ubuntu_system_tests/helpers/monitoring.py (+61/-0)
ubuntu_system_tests/helpers/sdcard.py (+5/-0)
ubuntu_system_tests/results.py (+51/-0)
ubuntu_system_tests/tests/base.py (+42/-26)
ubuntu_system_tests/tests/data/perf/metadata.json (+8/-0)
ubuntu_system_tests/tests/data/perf/plot.json (+12/-0)
ubuntu_system_tests/tests/perf/__init__.py (+91/-0)
ubuntu_system_tests/tests/perf/test_apps.py (+197/-0)
ubuntu_system_tests/tests/test_sdcard.py (+1/-1)
To merge this branch: bzr merge lp:~canonical-platform-qa/ubuntu-system-tests/device_monitoring
Reviewer Review Type Date Requested Status
platform-qa-bot continuous-integration Needs Fixing
Brendan Donegan (community) Needs Information
PS Jenkins bot continuous-integration Approve
Richard Huddie (community) Needs Fixing
prod-platform-qa continuous-integration Pending
Sergio Cazzolato Pending
Review via email: mp+280167@code.launchpad.net

Commit message

Enable the device monitoring used to visualize the resources usage in the device during tests execution

To post a comment you must log in.
Revision history for this message
Brendan Donegan (brendan-donegan) wrote :

Do you think the plotting of the data should be coupled to ubuntu-system-tests? I suppose it's a nice to have but really the plotting should be done externally so we have a choice of which tool to use, how to configure it etc.

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
288. By Sergio Cazzolato

Adding test case to open 100 time several apps

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

Adding new test to open all the apps

290. By Sergio Cazzolato

Adding new test case

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

Flake8 fix

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

Improving webapps start

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

> Do you think the plotting of the data should be coupled to ubuntu-system-
> tests? I suppose it's a nice to have but really the plotting should be done
> externally so we have a choice of which tool to use, how to configure it etc.

Agree with that, I just added the visualization as part of the branch to make easy to see if the results are what we need, after that I could remove it.

293. By Sergio Cazzolato

Adding config parameter for nmon

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

Removing clock app

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

Adding new test case to maname apps in a cicle

296. By Sergio Cazzolato

Minor improvements for new test

297. By Sergio Cazzolato

Adding fixtures for test

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

Minor fixes

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

Moving test configuration to json file

300. By Sergio Cazzolato

Merge with trunk

301. By Sergio Cazzolato

Adding comments

302. By Sergio Cazzolato

Adding missing file

303. By Sergio Cazzolato

Minor fix in name

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

Fixing camera actions

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

Adding config file with plotting directives

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

Getting this error from jenkins http://paste.ubuntu.com/14120530/

306. By Sergio Cazzolato

Moving dependencies and increasing iterations

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, some minor comments below. I had this problem when running test_open_apps: http://pastebin.ubuntu.com/14161943/

The other test was running, but I've not had a chance to run it until completion yet.

review: Needs Fixing
307. By Sergio Cazzolato

Fixes based on PM comments

308. By Sergio Cazzolato

Minor fix

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 got the following error when running test_open_apps: http://pastebin.ubuntu.com/14419424/

I was able to create an HTML graph for statistics using nmonchart (http://nmon.sourceforge.net/pmwiki.php?n=Site.Nmonchart), is this correct usage? It would be useful to add a section to README to explain how to generate graphs from the .nmon result file.

Other question, when I ran on Arale with no SD card, the exception is raised which gets reported as error: http://pastebin.ubuntu.com/14419431/
This is not an error, but just unsupported feature. Could this just be logged, rather than raising exception?

Also, it would be useful if the the error message ("testtools.matchers._impl.MismatchError: 0 != 5: Errors found 5") could give a summary of the reported errors. Otherwise it could be long job to go through the logs to understand what has happened.

review: Needs Fixing
Revision history for this message
Selene ToyKeeper (toykeeper) wrote :

To get this working at all, I had to rename a couple functions:
--- ubuntu_system_tests/tests/data/perf/metadata.json 2015-12-23 21:54:32 +0000
+++ ubuntu_system_tests/tests/data/perf/metadata.json 2016-01-15 07:53:46 +0000
@@ -2,7 +2,7 @@
     "test_open_apps": {
         "iterations": 100,
         "apps": ["camera-app", "webbrowser-app", "messaging-app",
- "address-book-app", "ubuntu-calculator-app", "dialer-app"]
+ "address-book", "calculator-app", "dialer-app"]
     },
     "test_do_actions": {
         "iterations": 2,

... and to run on arale, I had to disable _validate_sd_card() in ubuntu_system_tests/tests/perf/__init__.py .

I'm still getting 4 errors in test_do_actions() though, which I haven't finished tracing.

What is the recommended way to get pyNmonAnalyzer?

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

> To get this working at all, I had to rename a couple functions:
> --- ubuntu_system_tests/tests/data/perf/metadata.json 2015-12-23 21:54:32
> +0000
> +++ ubuntu_system_tests/tests/data/perf/metadata.json 2016-01-15 07:53:46
> +0000
> @@ -2,7 +2,7 @@
> "test_open_apps": {
> "iterations": 100,
> "apps": ["camera-app", "webbrowser-app", "messaging-app",
> - "address-book-app", "ubuntu-calculator-app", "dialer-app"]
> + "address-book", "calculator-app", "dialer-app"]
> },
> "test_do_actions": {
> "iterations": 2,

I am working on that, I think I am going to remove this test and will add actions to close the apps so we will be able to manage everything in the test test_do_actions
>
>
>
> ... and to run on arale, I had to disable _validate_sd_card() in
> ubuntu_system_tests/tests/perf/__init__.py .

This is fixed in the next commit. When you want to use the sdcard and it is not inserted in the device, this action will be skipped and logged as a warning

>
> I'm still getting 4 errors in test_do_actions() though, which I haven't
> finished tracing.
>
> What is the recommended way to get pyNmonAnalyzer?

You need to have installed pip as a prerequisite. Then:
  sudo apt-get install python-numpy python-matplotlib
  sudo pip install pyNmonAnalyzer

In the meantime I am analyzing other tools to plot the nmon information. Here you have an example graphic that I took https://drive.google.com/open?id=0B2R7lqeEPdMUU1p0Mlhhc2FxbTA

Thanks for the review

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

> I got the following error when running test_open_apps:
> http://pastebin.ubuntu.com/14419424/

I am going to remove this test and adding some actions to close apps so this test will be included in the test_do_actions.

>
> I was able to create an HTML graph for statistics using nmonchart
> (http://nmon.sourceforge.net/pmwiki.php?n=Site.Nmonchart), is this correct
> usage? It would be useful to add a section to README to explain how to
> generate graphs from the .nmon result file.

Nice, taking a look now

>
> Other question, when I ran on Arale with no SD card, the exception is raised
> which gets reported as error: http://pastebin.ubuntu.com/14419431/
> This is not an error, but just unsupported feature. Could this just be logged,
> rather than raising exception?

Done, When you want to use the sdcard and it is not inserted in the device, this action will be skipped and logged as a warning
>
> Also, it would be useful if the the error message
> ("testtools.matchers._impl.MismatchError: 0 != 5: Errors found 5") could give
> a summary of the reported errors. Otherwise it could be long job to go through
> the logs to understand what has happened.

WIP

309. By Sergio Cazzolato

Changes based on comments in review

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

adding wait action

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

Merge from trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Brendan Donegan (brendan-donegan) wrote :

From a code point of view this is fine, but I would look for some early feedback from jibel to make sure this is what is wanted. In my opinion this solution could do with being a bit more flexible. Rather than writing tests specifically for performance, it might be a better idea to re-use existing tests and have a way to get the metrics at certain points (in between tests, after all the tests are completed, etc). It might also be possible to granularise the test approach, so rather than gathering all the metrics for all tests, have a specific set of tests for memory usage, a specific set for CPU usage and a specific set for network usage. It really depends on what the intent is - is it to emulate real usage or is it to provoke specific bugs?

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

Showing some conflicts on this branch:
Text conflict in ubuntu_system_tests/config.py
Text conflict in ubuntu_system_tests/tests/base.py
2 conflicts encountered.

Could you update?

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)

Unmerged revisions

311. By Sergio Cazzolato

Merge from trunk

310. By Sergio Cazzolato

adding wait action

309. By Sergio Cazzolato

Changes based on comments in review

308. By Sergio Cazzolato

Minor fix

307. By Sergio Cazzolato

Fixes based on PM comments

306. By Sergio Cazzolato

Moving dependencies and increasing iterations

305. By Sergio Cazzolato

Adding config file with plotting directives

304. By Sergio Cazzolato

Fixing camera actions

303. By Sergio Cazzolato

Minor fix in name

302. By Sergio Cazzolato

Adding missing file

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-06-26 22:41:14 +0000
3+++ debian/control 2016-01-20 15:40:48 +0000
4@@ -22,7 +22,10 @@
5 Architecture: all
6 Depends: ${misc:Depends},
7 ${python3:Depends},
8+ pyNmonAnalyzer,
9 python3-dbus,
10+ python3-matplotlib,
11+ python3-numpy,
12 python3-testtools,
13 python3-uci-config,
14 subunit,
15
16=== modified file 'debian/tests/control'
17--- debian/tests/control 2015-11-25 15:04:04 +0000
18+++ debian/tests/control 2016-01-20 15:40:48 +0000
19@@ -14,6 +14,7 @@
20 mediaplayer-app-autopilot,
21 messaging-app,
22 messaging-app-autopilot, # TMPINSTALL
23+ nmon,
24 oxideqt-chromedriver,
25 python3-autopilot,
26 python3-dbus,
27
28=== modified file 'ubuntu_system_tests/command_line.py'
29--- ubuntu_system_tests/command_line.py 2015-12-03 20:15:55 +0000
30+++ ubuntu_system_tests/command_line.py 2016-01-20 15:40:48 +0000
31@@ -456,6 +456,11 @@
32 def generate_user_report(config_stack):
33 """Create a human readable report from the subunit results."""
34 artifacts_directory = results.get_artifacts_directory(config_stack)
35+ if config_stack.get('profiling_statistics'):
36+ serial = config_stack.get('device_serial')
37+ data_file = results.copy_monitor_data(artifacts_directory, serial)
38+ if config_stack.get('plot_statistics'):
39+ results.generate_statistics_report(artifacts_directory, data_file)
40 results.convert_subunit_results_to_pyunit(artifacts_directory)
41 results.print_results(artifacts_directory)
42
43
44=== modified file 'ubuntu_system_tests/config.py'
45--- ubuntu_system_tests/config.py 2015-11-05 17:35:49 +0000
46+++ ubuntu_system_tests/config.py 2016-01-20 15:40:48 +0000
47@@ -109,6 +109,17 @@
48 'max_unity8_retry_delay', default=30000,
49 help_string='The boundary for how long we should be retrying until '
50 'unity8 is started'),
51+ options.Option(
52+ 'profiling_statistics',
53+ help_string="Enable performance profiling. CPU, Disk usage, Memory, "
54+ "Network and other statistics will be measured and stored "
55+ "as part of the test results. If empty, statistics won't "
56+ "be taken from the device."),
57+ options.Option(
58+ 'plot_statistics',
59+ help_string="Enable performance plotting. A report will be generated "
60+ "as part of the test results. If empty, statistics won't "
61+ "be plotted."),
62 ]
63 """Options for tests in external debian and click packages."""
64
65
66=== modified file 'ubuntu_system_tests/helpers/data.py'
67--- ubuntu_system_tests/helpers/data.py 2015-09-23 21:12:39 +0000
68+++ ubuntu_system_tests/helpers/data.py 2016-01-20 15:40:48 +0000
69@@ -28,7 +28,7 @@
70 """ Class used to decode a dict into a AttrDict object """
71
72 def __init__(self, *args, **kargs):
73- JSONDecoder.__init__(self, object_hook=dict_to_attr_dict)
74+ JSONDecoder.__init__(self, object_hook=_dict_to_attr_dict)
75
76
77 class AttrDict(dict):
78@@ -51,7 +51,7 @@
79 return file
80
81
82-def dict_to_attr_dict(d):
83+def _dict_to_attr_dict(d):
84 try:
85 return AttrDict(**d)
86 except:
87@@ -91,3 +91,15 @@
88
89 _full_dict = _load_metadata_list(fs.DIR_TEST_DATA)
90 return _full_dict
91+
92+
93+def load_data_file(file):
94+ """ Load in a AttrDict the data stored in the specific json file
95+ :param file: the path to the json file
96+ :return: A AttrDict with the data stored in the specific json file
97+ """
98+ if not path.isfile(file):
99+ raise RuntimeError('Json data file does not exist')
100+
101+ with open(file) as data_file:
102+ return load(data_file, cls=AttrDictDecoder)
103
104=== modified file 'ubuntu_system_tests/helpers/file_system.py'
105--- ubuntu_system_tests/helpers/file_system.py 2015-12-22 23:21:51 +0000
106+++ ubuntu_system_tests/helpers/file_system.py 2016-01-20 15:40:48 +0000
107@@ -91,6 +91,7 @@
108 DIR_TEST_DATA_VIDEO = os.path.join(DIR_TEST_DATA, 'video')
109 DIR_TEST_DATA_DEVICES = os.path.join(DIR_TEST_DATA, 'devices')
110 DIR_TEST_DATA_DATABASES = os.path.join(DIR_TEST_DATA, 'databases')
111+DIR_TEST_DATA_PERF = os.path.join(DIR_TEST_DATA, 'perf')
112
113 # Media dirs
114 DIR_MEDIA = '/media'
115
116=== added file 'ubuntu_system_tests/helpers/monitoring.py'
117--- ubuntu_system_tests/helpers/monitoring.py 1970-01-01 00:00:00 +0000
118+++ ubuntu_system_tests/helpers/monitoring.py 2016-01-20 15:40:48 +0000
119@@ -0,0 +1,61 @@
120+
121+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
122+
123+# Ubuntu System Tests
124+# Copyright (C) 2015 Canonical
125+#
126+# This program is free software: you can redistribute it and/or modify
127+# it under the terms of the GNU General Public License as published by
128+# the Free Software Foundation, either version 3 of the License, or
129+# (at your option) any later version.
130+#
131+# This program is distributed in the hope that it will be useful,
132+# but WITHOUT ANY WARRANTY; without even the implied warranty of
133+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
134+# GNU General Public License for more details.
135+#
136+# You should have received a copy of the GNU General Public License
137+# along with this program. If not, see <http://www.gnu.org/licenses/>.
138+
139+import logging
140+import os
141+import subprocess
142+
143+from ubuntu_system_tests import config
144+from ubuntu_system_tests.helpers import file_system as fs
145+
146+logger = logging.getLogger(__name__)
147+
148+
149+MONITOR = 'nmon'
150+NAME = 'monitoring_data.nmon'
151+OUTPUT_DIR = '/tmp/monitor_data'
152+
153+
154+def is_monitoring_enabled():
155+ """ Determine if the monitoring was requested in the config file """
156+ return bool(config.get_device_config_stack().get('profiling_statistics'))
157+
158+
159+def get_output_file():
160+ """ Retrieve the .nmon file for current/last execution """
161+ return os.path.join(OUTPUT_DIR, NAME)
162+
163+
164+def start(interval=2, counts=50000):
165+ """ Start the monitoring tool with defined parameters
166+ :param interval: time in seconds between snap shots
167+ :param counts: number of snapshots before nmon stops
168+ """
169+ fs.create_directory_if_not_exists(OUTPUT_DIR)
170+ fs.clean_files(OUTPUT_DIR)
171+ cmd = '{mon} -F {name} -s {interval} -t -c {counts}'
172+ vars = dict(mon=MONITOR, interval=interval, name=get_output_file(),
173+ counts=counts)
174+
175+ subprocess.call(cmd.format(**vars), shell=True)
176+
177+
178+def stop():
179+ """ Stop the nmon process """
180+ subprocess.call('pkill {}'.format(MONITOR), shell=True)
181
182=== modified file 'ubuntu_system_tests/helpers/sdcard.py'
183--- ubuntu_system_tests/helpers/sdcard.py 2015-11-03 21:03:37 +0000
184+++ ubuntu_system_tests/helpers/sdcard.py 2016-01-20 15:40:48 +0000
185@@ -106,3 +106,8 @@
186 :param dst_name: The filename in the sd card
187 """
188 return copy_file(src_path, fs.DIR_PICTURES, dst_name)
189+
190+
191+def is_sdcard_mounted():
192+ """ Indicate if the sd card is mounted in the device """
193+ return fs.is_media_folder_dir(fs.DIR_PICTURES)
194
195=== modified file 'ubuntu_system_tests/results.py'
196--- ubuntu_system_tests/results.py 2015-05-21 18:15:40 +0000
197+++ ubuntu_system_tests/results.py 2016-01-20 15:40:48 +0000
198@@ -18,9 +18,16 @@
199 # along with this program. If not, see <http://www.gnu.org/licenses/>.
200 #
201
202+import logging
203 import os
204 import subprocess
205
206+from ubuntu_system_tests.helpers import data
207+from ubuntu_system_tests.helpers import file_system as fs
208+from ubuntu_system_tests.helpers import monitoring
209+
210+logger = logging.getLogger(__name__)
211+
212
213 def convert_subunit_results_to_pyunit(artifacts_directory):
214 subunit_source_file_path = os.path.join(
215@@ -48,3 +55,47 @@
216 """Return the path to the directory in which artifacts are stored."""
217 output_dir = config_stack.get('output_dir')
218 return os.path.join(output_dir, 'artifacts')
219+
220+
221+def copy_monitor_data(artifacts_directory, device=None):
222+ """ Copy the monitoring data from the device to the test results dir
223+ :param artifacts_directory: the path where the artifacts are stored
224+ :param device: the serial for the desired device
225+ """
226+ from_file = monitoring.get_output_file()
227+ to_file = os.path.join(artifacts_directory, os.path.basename(from_file))
228+ if device:
229+ cmd = 'adb -s {} pull {} {}'.format(device, from_file, to_file)
230+ else:
231+ cmd = 'adb pull {} {}'.format(from_file, to_file)
232+ subprocess.call(cmd, shell=True)
233+ return to_file
234+
235+
236+def _write_statistics_config_file(config_file, directives):
237+ """ Create the config file used to plot the monitoring data """
238+ fs.delete_file(config_file)
239+ with open(config_file, 'w') as f:
240+ for directive in directives:
241+ f.write(directive + '\n')
242+
243+
244+def generate_statistics_report(artifacts_directory, data_file):
245+ """ Generate the html report with the statistics usage
246+ :param artifacts_directory: the path where the artifacts are stored
247+ :param data_file: file with monitoring raw data copied from the device
248+ """
249+ plot_data = data.load_data_file(os.path.join(fs.DIR_TEST_DATA_PERF,
250+ 'plot.json'))
251+
252+ output_report_dir = os.path.join(artifacts_directory, plot_data.output_dir)
253+ config_file = os.path.join(artifacts_directory, plot_data.config_file_name)
254+ _write_statistics_config_file(config_file, plot_data.directives)
255+
256+ cmd = 'pyNmonAnalyzer -x -b -o {} -i {} -t static -r {}'.format(
257+ output_report_dir, data_file, config_file)
258+ try:
259+ subprocess.call(cmd, shell=True)
260+ except OSError:
261+ logger.error("Statistics not generated. Error to call "
262+ "pyNmonAnalyzer")
263
264=== modified file 'ubuntu_system_tests/tests/base.py'
265--- ubuntu_system_tests/tests/base.py 2016-01-11 11:06:16 +0000
266+++ ubuntu_system_tests/tests/base.py 2016-01-20 15:40:48 +0000
267@@ -48,6 +48,7 @@
268 from ubuntu_system_tests.helpers import click
269 from ubuntu_system_tests.helpers import images
270 from ubuntu_system_tests.helpers import mir
271+from ubuntu_system_tests.helpers import monitoring
272 from ubuntu_system_tests.helpers import processes
273 from ubuntu_system_tests.helpers import screen
274 from ubuntu_system_tests.helpers import unity8
275@@ -61,9 +62,21 @@
276 # Any test name ending with this will leave device locked
277 TEST_ID_DEVICE_LOCKED = 'device_locked'
278
279+logger = logging.getLogger(__name__)
280+
281+# Apps and cleanup names
282+ADDRESS_BOOK_APP = 'address-book-app'
283 CALCULATOR_APP = 'ubuntu-calculator-app'
284-
285-logger = logging.getLogger(__name__)
286+CAMERA_APP = 'camera-app'
287+CLOCK_APP = 'ubuntu-clock-app'
288+DIALER_APP = 'dialer-app'
289+GALLERY_APP = 'gallery-app'
290+MEDIA_PLAYER_APP = 'mediaplayer-app'
291+MESSAGING_APP = 'messaging-app'
292+SYSTEM_SETTINGS = 'system-settings'
293+SYSTEM_SETTINGS_CLEANUP = 'ubuntu-system-settings'
294+UNITY_8 = 'unity8'
295+WEB_BROWSER_APP = 'webbrowser-app'
296
297
298 class BaseUbuntuSystemTestCase(testcase.AutopilotTestCase):
299@@ -72,11 +85,15 @@
300 def setUpClass(cls):
301 unity8.ensure_unity_stopped()
302 super().setUpClass()
303+ if monitoring.is_monitoring_enabled():
304+ monitoring.start()
305
306 @classmethod
307 def tearDownClass(cls):
308 super().tearDownClass()
309 unity8.ensure_unity_running_and_greeter_hidden()
310+ if monitoring.is_monitoring_enabled():
311+ monitoring.stop()
312
313 def setUp(self):
314 super().setUp()
315@@ -106,7 +123,7 @@
316 else:
317 self._start_unity_with_testability()
318
319- unity = self.get_job_proxy_object('unity8')
320+ unity = self.get_job_proxy_object(UNITY_8)
321 unity.wait_for_greeter_content()
322 self._reset_keyboard()
323 # Workaround for bug lp:1474444
324@@ -115,7 +132,7 @@
325 return unity
326
327 def _start_unity_with_testability(self):
328- process_helpers.start_job('unity8', 'QT_LOAD_TESTABILITY=1')
329+ process_helpers.start_job(UNITY_8, 'QT_LOAD_TESTABILITY=1')
330
331 # Retry added until fix for bug 1427946 in QtMir is landed
332 @retry(stop_max_delay=30000,
333@@ -153,7 +170,7 @@
334 def _create_sensors(self):
335 """Create fake sensors for testing"""
336 Eventually(Equals(True)).match(
337- lambda: process_helpers.is_job_running('unity8')
338+ lambda: process_helpers.is_job_running(UNITY_8)
339 )
340 unity_pid = process_helpers._get_unity_pid()
341 fifo_path = '/tmp/sensor-fifo-{}'.format(unity_pid)
342@@ -200,7 +217,7 @@
343
344 def _get_screenshot_size(self, x, y, width, height):
345 """ Calculate the screenshot size """
346- unity = self.get_job_proxy_object('unity8')
347+ unity = self.get_job_proxy_object(UNITY_8)
348 if width and height:
349 return width, height
350 else:
351@@ -240,7 +257,7 @@
352 :param app_name: Name of the displayed application.
353
354 """
355- unity = self.get_job_proxy_object('unity8')
356+ unity = self.get_job_proxy_object(UNITY_8)
357 unity.main_window.launch_application(app_name)
358
359 def _get_proxy_object_for_existing_app(
360@@ -332,7 +349,7 @@
361
362 """
363 from ubuntu_system_tests.helpers.addressbook import _cpo # NOQA
364- proxy = self._get_proxy_object_for_existing_app('address-book-app')
365+ proxy = self._get_proxy_object_for_existing_app(ADDRESS_BOOK_APP)
366 return proxy.main_window
367
368 def launch_camera_app(self):
369@@ -360,7 +377,7 @@
370 """
371 from ubuntu_system_tests.helpers.camera._cpo import MainWindow
372 proxy = self._get_proxy_object_for_existing_app(
373- 'camera-app',
374+ CAMERA_APP,
375 cleanup_process=click.get_click_app_identifier('com.ubuntu.camera')
376 )
377 return MainWindow(proxy)
378@@ -383,7 +400,7 @@
379
380 """
381 from ubuntu_system_tests.helpers.dialer_app import _cpo # NOQA
382- proxy = self._get_proxy_object_for_existing_app('dialer-app')
383+ proxy = self._get_proxy_object_for_existing_app(DIALER_APP)
384 return proxy.main_view
385
386 def launch_gallery_app(self):
387@@ -404,9 +421,9 @@
388 :return: Proxy object for gallery application.
389
390 """
391- proxy = self._get_proxy_object_for_existing_app('gallery-app')
392+ proxy = self._get_proxy_object_for_existing_app(GALLERY_APP)
393 # ubuntu-app-stop does not work with gallery app, use process helper
394- self.addCleanup(processes.stop_process, 'gallery-app')
395+ self.addCleanup(processes.stop_process, GALLERY_APP)
396 return proxy
397
398 def get_gallery_events_view(self):
399@@ -427,7 +444,7 @@
400
401 """
402 from ubuntu_system_tests.helpers.mediaplayer._cpo import MainWindow
403- proxy = self._get_proxy_object_for_existing_app('mediaplayer-app')
404+ proxy = self._get_proxy_object_for_existing_app(MEDIA_PLAYER_APP)
405 return MainWindow(proxy)
406
407 def launch_messaging_app(self):
408@@ -453,7 +470,7 @@
409 base=base)
410
411 from ubuntu_system_tests.helpers.messaging._cpo import MainView
412- proxy = self._get_proxy_object_for_existing_app('messaging-app')
413+ proxy = self._get_proxy_object_for_existing_app(MESSAGING_APP)
414 return proxy.wait_select_single(MainView)
415
416 def launch_system_settings(self):
417@@ -475,7 +492,7 @@
418 """
419 from ubuntu_system_tests.helpers.system_settings import _cpo # NOQA
420 proxy = self._get_proxy_object_for_existing_app(
421- 'system-settings', cleanup_process='ubuntu-system-settings')
422+ SYSTEM_SETTINGS, cleanup_process=SYSTEM_SETTINGS_CLEANUP)
423 return proxy.main_view
424
425 def launch_webbrowser_app(self):
426@@ -496,7 +513,7 @@
427
428 """
429 from ubuntu_system_tests.helpers.webbrowser import _cpo # NOQA
430- proxy = self._get_proxy_object_for_existing_app('webbrowser-app')
431+ proxy = self._get_proxy_object_for_existing_app(WEB_BROWSER_APP)
432 return proxy.main_window
433
434 def launch_calendar_app(self):
435@@ -530,14 +547,9 @@
436 """
437 self._launch_application_from_apps_scope('Clock')
438 wait_until(processes.is_qmlscene_running_with_qmlfile,
439- 'ubuntu-clock-app')
440+ CLOCK_APP)
441 return self.get_clock_app_proxy()
442
443- def launch_webbrowser_from_launcher(self):
444- """Start webbrowser from the launcher."""
445- self._launch_application_from_launcher('webbrowser-app')
446- return self.get_webbrowser_app_proxy()
447-
448 def get_clock_app_proxy(self):
449 """
450 Return clock app proxy object from existing process.
451@@ -546,18 +558,22 @@
452
453 """
454 from ubuntu_system_tests.helpers.clock import _cpo # NOQA
455- proxy = self._get_proxy_object_for_existing_qmlscene_process(
456- 'ubuntu-clock-app')
457+ proxy = self._get_proxy_object_for_existing_qmlscene_process(CLOCK_APP)
458 return proxy.main_view
459
460+ def launch_webbrowser_from_launcher(self):
461+ """Start webbrowser from the launcher."""
462+ self._launch_application_from_launcher(WEB_BROWSER_APP)
463+ return self.get_webbrowser_app_proxy()
464+
465 def launch_messaging_app_from_launcher(self):
466 """Drag out the launcher and tap the messaging app icon to start it."""
467- self._launch_application_from_launcher('messaging-app')
468+ self._launch_application_from_launcher(MESSAGING_APP)
469 return self.get_messaging_app_proxy()
470
471 def launch_dialer_app_from_launcher(self):
472 """Drag out the launcher and tap the dialer app icon to start it."""
473- self._launch_application_from_launcher('dialer-app')
474+ self._launch_application_from_launcher(DIALER_APP)
475 return self.get_dialer_app_proxy()
476
477 def get_webapp_proxy(self, web_app_package):
478
479=== added directory 'ubuntu_system_tests/tests/data/perf'
480=== added file 'ubuntu_system_tests/tests/data/perf/metadata.json'
481--- ubuntu_system_tests/tests/data/perf/metadata.json 1970-01-01 00:00:00 +0000
482+++ ubuntu_system_tests/tests/data/perf/metadata.json 2016-01-20 15:40:48 +0000
483@@ -0,0 +1,8 @@
484+{
485+ "test_perform_actions": {
486+ "setup_actions": ["start_all_webapps"],
487+ "iterations": 2,
488+ "test_actions": ["take_photo", "open_two_urls", "add_random_contact",
489+ "add_random_numbers", "remove_add_sdcard", "record_video"]
490+ }
491+}
492
493=== added file 'ubuntu_system_tests/tests/data/perf/plot.json'
494--- ubuntu_system_tests/tests/data/perf/plot.json 1970-01-01 00:00:00 +0000
495+++ ubuntu_system_tests/tests/data/perf/plot.json 2016-01-20 15:40:48 +0000
496@@ -0,0 +1,12 @@
497+{
498+ "output_dir": "monitoring_report",
499+ "config_file_name": "report.config",
500+ "directives": [
501+ "CPU_ALL={stackedGraph: true, fillGraph: true}",
502+ "MEM={}",
503+ "NET=wlan0{}",
504+ "DISKBUSY=mmcblk0,mmcblk0p1,mmcblk0p2,mmcblk0p3,mmcblk0p4,mmcblk0p5,mmcblk0p6,mmcblk0p7,mmcblk0boot1,mmcblk0boot0,mmcblk1,mmcblk1p1{}",
505+ "DISKREAD=mmcblk0,mmcblk0p1,mmcblk0p2,mmcblk0p3,mmcblk0p4,mmcblk0p5,mmcblk0p6,mmcblk0p7,mmcblk0boot1,mmcblk0boot0,mmcblk1,mmcblk1p1{}",
506+ "DISKWRITE=mmcblk0,mmcblk0p1,mmcblk0p2,mmcblk0p3,mmcblk0p4,mmcblk0p5,mmcblk0p6,mmcblk0p7,mmcblk0boot1,mmcblk0boot0,mmcblk1,mmcblk1p1{}"
507+ ]
508+}
509
510=== added directory 'ubuntu_system_tests/tests/perf'
511=== added file 'ubuntu_system_tests/tests/perf/__init__.py'
512--- ubuntu_system_tests/tests/perf/__init__.py 1970-01-01 00:00:00 +0000
513+++ ubuntu_system_tests/tests/perf/__init__.py 2016-01-20 15:40:48 +0000
514@@ -0,0 +1,91 @@
515+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
516+
517+#
518+# Ubuntu System Tests
519+# Copyright (C) 2015 Canonical
520+#
521+# This program is free software: you can redistribute it and/or modify
522+# it under the terms of the GNU General Public License as published by
523+# the Free Software Foundation, either version 3 of the License, or
524+# (at your option) any later version.
525+#
526+# This program is distributed in the hope that it will be useful,
527+# but WITHOUT ANY WARRANTY; without even the implied warranty of
528+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
529+# GNU General Public License for more details.
530+#
531+# You should have received a copy of the GNU General Public License
532+# along with this program. If not, see <http://www.gnu.org/licenses/>.
533+#
534+
535+import logging
536+import traceback
537+
538+from ubuntu_system_tests.helpers.addressbook import (
539+ fixture_setup as addressbook_fixtures)
540+from ubuntu_system_tests.helpers import autopilot
541+from ubuntu_system_tests.helpers.backup_restore_fixture import (
542+ BackupRestoreFixture)
543+from ubuntu_system_tests.helpers.camera.fixture_setup import (
544+ SetCameraAccessRequests)
545+from ubuntu_system_tests.helpers.clock.fixture_setup import (
546+ SetClockAccessRequests)
547+from ubuntu_system_tests.helpers import file_system as fs
548+from ubuntu_system_tests.helpers.location.fixture_setup import (
549+ SetLocationAccessRequests)
550+from ubuntu_system_tests.helpers import media
551+from ubuntu_system_tests.helpers.scopes import go_to_apps_scope
552+from ubuntu_system_tests.helpers.webbrowser.fixture_setup import (
553+ WebbrowserTestEnvironment)
554+
555+from ubuntu_system_tests.tests import base
556+
557+logger = logging.getLogger(__name__)
558+
559+WEB_APPS = ['Gmail', 'Facebook', 'Twitter', 'Amazon', 'eBay', 'HERE Maps']
560+
561+
562+class BasePerfTestCase(base.BaseUbuntuSystemTestCase):
563+
564+ def setUp(self):
565+ super().setUp()
566+
567+ self.useFixture(SetCameraAccessRequests())
568+ self.useFixture(SetClockAccessRequests())
569+ self.useFixture(SetLocationAccessRequests('com.nokia.heremaps_here'))
570+
571+ self.useFixture(BackupRestoreFixture(fs.DIR_HOME_CAMERA_CONFIG))
572+ self.useFixture(BackupRestoreFixture(fs.DIR_HOME_CAMERA_THUMBNAILS))
573+ self.useFixture(media.BackupRestoreLocalMediaFixture())
574+
575+ self.useFixture(addressbook_fixtures.AddressBookTestEnvironment())
576+ self.useFixture(WebbrowserTestEnvironment())
577+
578+ self.errors = 0
579+ self.errors_msg = []
580+ self.addCleanup(self._print_errors)
581+
582+ def _manage_app(self, method, *args):
583+ try:
584+ method(*args)
585+ except Exception as e:
586+ self.errors += 1
587+ self.errors_msg.append(traceback.format_exc())
588+ logger.error(e)
589+
590+ def _start_webapp(self, app_name):
591+ apps_scope = go_to_apps_scope()
592+ apps_scope.click_scope_item('local', app_name)
593+
594+ def _validate_camera_app(self):
595+ if not autopilot.is_camera_supported():
596+ raise RuntimeError("Camera-app required")
597+
598+ def _print_errors(self):
599+ print('*' * 100)
600+ print('ERRORS FOUND')
601+ print('*' * 100)
602+ for error in self.errors_msg:
603+ print(error)
604+ print('-' * 50)
605+ print('*' * 100)
606
607=== added file 'ubuntu_system_tests/tests/perf/test_apps.py'
608--- ubuntu_system_tests/tests/perf/test_apps.py 1970-01-01 00:00:00 +0000
609+++ ubuntu_system_tests/tests/perf/test_apps.py 2016-01-20 15:40:48 +0000
610@@ -0,0 +1,197 @@
611+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
612+
613+#
614+# Ubuntu System Tests
615+# Copyright (C) 2015 Canonical
616+#
617+# This program is free software: you can redistribute it and/or modify
618+# it under the terms of the GNU General Public License as published by
619+# the Free Software Foundation, either version 3 of the License, or
620+# (at your option) any later version.
621+#
622+# This program is distributed in the hope that it will be useful,
623+# but WITHOUT ANY WARRANTY; without even the implied warranty of
624+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
625+# GNU General Public License for more details.
626+#
627+# You should have received a copy of the GNU General Public License
628+# along with this program. If not, see <http://www.gnu.org/licenses/>.
629+#
630+
631+import logging
632+import subprocess
633+import random
634+import os
635+from testtools import skipUnless
636+
637+from address_book_app.address_book.data import Phone, Contact
638+
639+from ubuntu_system_tests.helpers import camera
640+from ubuntu_system_tests.helpers.data import load_test_metadata
641+from ubuntu_system_tests.helpers import monitoring
642+from ubuntu_system_tests.helpers import processes
643+from ubuntu_system_tests.helpers import sdcard
644+from ubuntu_system_tests.helpers import wait_until
645+
646+from ubuntu_system_tests.tests import base
647+from ubuntu_system_tests.tests import perf
648+
649+logger = logging.getLogger(__name__)
650+
651+
652+class AppsTestCase(perf.BasePerfTestCase):
653+ """ This Class tests performance aspects open and closing apps """
654+
655+ @skipUnless(monitoring.is_monitoring_enabled(), 'Perf test skipped')
656+ def setUp(self):
657+ super().setUp()
658+ self.unity_proxy = self.restart_unity()
659+ self.test_metadata = load_test_metadata().perf
660+ self.pic = 0
661+
662+ def _start_action(self, action):
663+ getattr(self, '_action_{}'.format(action))()
664+
665+ def _action_open_webbrowser(self):
666+ self.launch_webbrowser_app()
667+
668+ def _action_close_webbrowser(self):
669+ self.ensure_application_closed(base.WEB_BROWSER_APP)
670+
671+ def _action_open_dialer(self):
672+ self.launch_dialer_app()
673+
674+ def _action_close_dialer(self):
675+ self.ensure_application_closed(base.DIALER_APP)
676+
677+ def _action_open_messaging(self):
678+ self.launch_messaging_app()
679+
680+ def _action_close_messaging(self):
681+ self.ensure_application_closed(base.MESSAGING_APP)
682+
683+ def _action_open_clock(self):
684+ self.launch_clock_app()
685+
686+ def _action_close_clock(self):
687+ self.ensure_application_closed(base.CLOCK_APP)
688+
689+ def _action_open_address_book(self):
690+ self.launch_address_book()
691+
692+ def _action_close_address_book(self):
693+ self.ensure_application_closed(base.ADDRESS_BOOK_APP)
694+
695+ def _action_open_camera(self):
696+ self.launch_calendar_app()
697+
698+ def _action_close_camera(self):
699+ self.ensure_application_closed(base.CAMERA_APP)
700+
701+ def _action_open_calculator(self):
702+ self.launch_calculator_app()
703+
704+ def _action_close_calculator(self):
705+ processes.stop_qmlscene_process(base.CALCULATOR_APP)
706+
707+ def _action_open_system_settings(self):
708+ self.launch_system_settings()
709+
710+ def _action_close_system_settings(self):
711+ processes.ensure_application_closed(base.SYSTEM_SETTINGS_CLEANUP)
712+
713+ def _action_start_all_webapps(self):
714+ # Open apps that will be open during the whole tests
715+ self._manage_app(self._start_webapp, 'Gmail')
716+ self._manage_app(self._start_webapp, 'Facebook')
717+ self._manage_app(self._start_webapp, 'Twitter')
718+ self._manage_app(self._start_webapp, 'Amazon')
719+ self._manage_app(self._start_webapp, 'eBay')
720+ self._manage_app(self._start_webapp, 'HERE Maps')
721+ self.addCleanup(self._action_close_all_webapps)
722+
723+ def _action_close_all_webapps(self):
724+ cmd = 'pkill -ef --signal SIGKILL webapp-container'
725+ subprocess.call(cmd, shell=True)
726+
727+ def _action_open_two_urls(self):
728+ """ Open two pages """
729+ browser = self.launch_webbrowser_app()
730+ browser.go_to_url('launchpad.net')
731+ browser.wait_page_loaded()
732+ browser.go_to_url('canonical.com')
733+ browser.wait_page_loaded()
734+
735+ def _action_add_random_contact(self):
736+ # Add a random contact
737+ address_book = self.launch_address_book()
738+
739+ first_name = 'first_name_{}'.format(random.randint(0, 999999))
740+ last_name = 'last_name_{}'.format(random.randint(0, 999999))
741+ phone = Phone(type_='Mobile', number='818616313')
742+ test_contact = Contact(first_name=first_name, last_name=last_name,
743+ phones=[phone])
744+ contact_editor = address_book.go_to_add_contact()
745+ contact_editor.fill_form(test_contact)
746+ address_book.save()
747+
748+ def _action_add_random_numbers(self):
749+ """ Add two numbers """
750+ calculator = self.launch_calculator_app()
751+ calculator.calculate('{}+{}').format(random.randint(0, 999),
752+ random.randint(0, 999))
753+
754+ def _action_remove_add_sdcard(self):
755+ # Remove and insert the sd card
756+ if sdcard.is_sdcard_mounted():
757+ device = sdcard.remove()
758+ sdcard.insert(device)
759+ else:
760+ logging.warning('Action Remove Add sdcard skipped')
761+
762+ def _action_take_photo(self):
763+ self._validate_camera_app()
764+ camera_app = self.launch_camera_app()
765+ config = camera.get_config(mode='camera')
766+ camera.config_camera(camera_app, config)
767+ photoroll_hint = camera_app.take_photo(self.pic == 0)
768+ self.pic += 1
769+ if photoroll_hint:
770+ gallery = photoroll_hint.swipe_to_dismiss()
771+ gallery.go_back()
772+
773+ def _action_record_video(self):
774+ self._validate_camera_app()
775+ camera_app = self.launch_camera_app()
776+ config = camera.get_config(mode='video')
777+ camera.config_camera(camera_app, config)
778+ camera_app.record_video(2, random_focus=False)
779+ if self.pic == 0:
780+ camera_app.swipe_to_gallery(self)
781+ camera_app.start_playback()
782+
783+ def _action_wait_for_stop_test_file(self):
784+ file = os.path.join('/', 'home', 'stop_test')
785+ timeout = 60 * 60 * 12
786+ if wait_until(os.path.isfile, file, timeout=timeout, period=5):
787+ os.remove(file)
788+
789+ def test_perform_actions(self):
790+ """ Perform all the actions defined in the input test data repeatedly.
791+ The test first read the test_perform_actions test data and based on
792+ that execute all the setup actions first, then it performs
793+ iteratively based on the iterations parameter the test_actions.
794+ The cleanup has to be set through the standard cleanup method.
795+ The test passes when all the actions finished successfully. The
796+ exceptions raise during the execution are printed in stdout.
797+ """
798+ test_data = self.test_metadata.test_perform_actions
799+
800+ for action in test_data.setup_actions:
801+ self._manage_app(self._start_action, action)
802+
803+ for i in range(test_data.iterations):
804+ for action in test_data.test_actions:
805+ self._manage_app(self._start_action, action)
806+
807+ self.assertEqual(0, self.errors, 'Errors found {}'.format(self.errors))
808
809=== modified file 'ubuntu_system_tests/tests/test_sdcard.py'
810--- ubuntu_system_tests/tests/test_sdcard.py 2015-12-23 13:30:00 +0000
811+++ ubuntu_system_tests/tests/test_sdcard.py 2016-01-20 15:40:48 +0000
812@@ -62,7 +62,7 @@
813 class SDCardSystemTest(base.BaseUbuntuSystemTestCase):
814 """This Class tests the sd card"""
815
816- @skipUnless(fs.is_media_folder_dir(fs.DIR_PICTURES), SKIP_REASON)
817+ @skipUnless(sdcard.is_sdcard_mounted(), SKIP_REASON)
818 def setUp(self):
819 super().setUp()
820 self.useFixture(ScopesHints())

Subscribers

People subscribed via source and target branches

to all changes: