Merge lp:~achiang/ubuntu-test-cases/savilerow into lp:ubuntu-test-cases
- savilerow
- Merge into trunk
Proposed by
Alex Chiang
Status: | Merged |
---|---|
Merge reported by: | Andy Doan |
Merged at revision: | not available |
Proposed branch: | lp:~achiang/ubuntu-test-cases/savilerow |
Merge into: | lp:ubuntu-test-cases |
Diff against target: |
6972 lines (+5984/-0) (has conflicts) 185 files modified
README-cli.rst (+76/-0) jenkins/production.py (+77/-0) jenkins/setup_jenkins.py (+213/-0) jenkins/staging.py (+26/-0) jenkins/templates/touch-autopilot-base.xml.jinja2 (+31/-0) jenkins/templates/touch-base.xml.jinja2 (+79/-0) jenkins/templates/touch-click_image_tests.xml.jinja2 (+8/-0) jenkins/templates/touch-customizations.xml.jinja2 (+6/-0) jenkins/templates/touch-default.xml.jinja2 (+9/-0) jenkins/templates/touch-eventstat.xml.jinja2 (+20/-0) jenkins/templates/touch-install-and-boot.xml.jinja2 (+29/-0) jenkins/templates/touch-master-free.xml.jinja2 (+20/-0) jenkins/templates/touch-master.xml.jinja2 (+84/-0) jenkins/templates/touch-memevent.xml.jinja2 (+10/-0) jenkins/templates/touch-sdk.xml.jinja2 (+9/-0) jenkins/templates/touch-security.xml.jinja2 (+9/-0) jenkins/templates/touch-setup.xml.jinja2 (+18/-0) jenkins/templates/touch-smem.xml.jinja2 (+22/-0) jenkins/templates/touch-smoke.xml.jinja2 (+147/-0) jenkins/templates/touch-upgrade.xml.jinja2 (+28/-0) jenkins/testconfig.py (+171/-0) scripts/assert-image (+25/-0) scripts/combine_results (+94/-0) scripts/device (+191/-0) scripts/get-adb-id (+39/-0) scripts/jenkins.sh (+186/-0) scripts/provision.sh (+126/-0) scripts/reboot-and-wait (+41/-0) scripts/run-autopilot-tests.sh (+185/-0) scripts/run-smoke (+221/-0) scripts/run-touch-upgrade.sh (+46/-0) scripts/statsd.py (+35/-0) selftests/test_reboot_and_wait.py (+66/-0) selftests/test_run_smoke.py (+141/-0) selftests/test_statsd.py (+64/-0) tests/address-book-app-autopilot/master.run (+15/-0) tests/address-book-app-autopilot/ts_control (+1/-0) tests/address-book-app-autopilot/tslist.auto (+4/-0) tests/calendar-app-autopilot/master.run (+15/-0) tests/calendar-app-autopilot/ts_control (+1/-0) tests/calendar-app-autopilot/tslist.auto (+4/-0) tests/camera-app-autopilot/master.run (+15/-0) tests/camera-app-autopilot/ts_control (+1/-0) tests/camera-app-autopilot/tslist.auto (+4/-0) tests/click_image_tests/check_preinstalled_list/check_preinstalled_list.py (+61/-0) tests/click_image_tests/check_preinstalled_list/tc_control (+10/-0) tests/click_image_tests/master.run (+5/-0) tests/click_image_tests/tslist.run (+1/-0) tests/customizations/master.run (+5/-0) tests/customizations/setup.sh (+10/-0) tests/customizations/ts_control (+1/-0) tests/customizations/tslist.auto (+4/-0) tests/default/ifconfig/tc_control (+13/-0) tests/default/install/tc_control (+12/-0) tests/default/master.run (+5/-0) tests/default/netstat/tc_control (+12/-0) tests/default/ping/pingtest.sh (+12/-0) tests/default/ping/tc_control (+12/-0) tests/default/pwd/tc_control (+9/-0) tests/default/pwd/test.sh (+18/-0) tests/default/route/tc_control (+12/-0) tests/default/systemsettle/systemsettle.sh (+120/-0) tests/default/systemsettle/tc_control (+9/-0) tests/default/ts_control (+3/-0) tests/default/tslist.run (+10/-0) tests/default/uname/tc_control (+12/-0) tests/default/unity8/tc_control (+9/-0) tests/default/vmstat/tc_control (+12/-0) tests/dialer-app-autopilot/master.run (+15/-0) tests/dialer-app-autopilot/ts_control (+1/-0) tests/dialer-app-autopilot/tslist.auto (+4/-0) tests/dropping-letters-app-autopilot/master.run (+15/-0) tests/dropping-letters-app-autopilot/ts_control (+1/-0) tests/dropping-letters-app-autopilot/tslist.auto (+4/-0) tests/eventstat/eventstat/eventstat.sh (+5/-0) tests/eventstat/eventstat/setup.sh (+7/-0) tests/eventstat/eventstat/tc_control (+12/-0) tests/eventstat/master.run (+5/-0) tests/eventstat/tslist.run (+1/-0) tests/friends-app-autopilot/master.run (+15/-0) tests/friends-app-autopilot/ts_control (+1/-0) tests/friends-app-autopilot/tslist.auto (+4/-0) tests/gallery-app-autopilot/master.run (+15/-0) tests/gallery-app-autopilot/ts_control (+1/-0) tests/gallery-app-autopilot/tslist.auto (+4/-0) tests/install-and-boot/boot/tc_control (+9/-0) tests/install-and-boot/master.run (+5/-0) tests/install-and-boot/tslist.run (+1/-0) tests/mediaplayer-app-autopilot/master.run (+15/-0) tests/mediaplayer-app-autopilot/ts_control (+1/-0) tests/mediaplayer-app-autopilot/tslist.auto (+4/-0) tests/memevent/master.run (+5/-0) tests/memevent/setup.sh (+8/-0) tests/memevent/ts_control (+1/-0) tests/memevent/tslist.auto (+7/-0) tests/memevent/ubuntu_test_cases/__init__.py (+6/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/__init__.py (+1/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/__init__.py (+21/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/browser.py (+103/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/camera.py (+58/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/gallery.py (+41/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/media_player.py (+53/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/matchers.py (+37/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/probes.py (+170/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/smem-tabs (+687/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/__init__.py (+1/-0) tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_memory_usage.py (+80/-0) tests/messaging-app-autopilot/master.run (+15/-0) tests/messaging-app-autopilot/ts_control (+1/-0) tests/messaging-app-autopilot/tslist.auto (+4/-0) tests/music-app-autopilot/master.run (+15/-0) tests/music-app-autopilot/ts_control (+1/-0) tests/music-app-autopilot/tslist.auto (+4/-0) tests/notes-app-autopilot/master.run (+15/-0) tests/notes-app-autopilot/ts_control (+1/-0) tests/notes-app-autopilot/tslist.auto (+4/-0) tests/sdk/master.run (+5/-0) tests/sdk/run_test.sh (+20/-0) tests/sdk/setup.sh (+12/-0) tests/sdk/ts_control (+1/-0) tests/sdk/tslist.auto (+3/-0) tests/security/master.run (+5/-0) tests/security/run_test.sh (+25/-0) tests/security/setup.sh (+12/-0) tests/security/ts_control (+1/-0) tests/security/tslist.auto (+6/-0) tests/smem/master.run (+15/-0) tests/smem/smem/smem-tabs (+687/-0) tests/smem/smem/smem.sh (+12/-0) tests/smem/smem/tc_control (+11/-0) tests/smem/tslist.run (+1/-0) tests/systemsettle/systemsettle-after/tc_control (+9/-0) tests/systemsettle/systemsettle-before/tc_control (+9/-0) tests/systemsettle/systemsettle.sh (+119/-0) tests/systemsettle/tslist.run (+2/-0) tests/ubuntu-calculator-app-autopilot/master.run (+15/-0) tests/ubuntu-calculator-app-autopilot/ts_control (+1/-0) tests/ubuntu-calculator-app-autopilot/tslist.auto (+4/-0) tests/ubuntu-clock-app-autopilot/master.run (+15/-0) tests/ubuntu-clock-app-autopilot/ts_control (+1/-0) tests/ubuntu-clock-app-autopilot/tslist.auto (+4/-0) tests/ubuntu-docviewer-app-autopilot/master.run (+15/-0) tests/ubuntu-docviewer-app-autopilot/ts_control (+1/-0) tests/ubuntu-docviewer-app-autopilot/tslist.auto (+4/-0) tests/ubuntu-filemanager-app-autopilot/master.run (+15/-0) tests/ubuntu-filemanager-app-autopilot/ts_control (+1/-0) tests/ubuntu-filemanager-app-autopilot/tslist.auto (+4/-0) tests/ubuntu-rssreader-app-autopilot/master.run (+15/-0) tests/ubuntu-rssreader-app-autopilot/ts_control (+1/-0) tests/ubuntu-rssreader-app-autopilot/tslist.auto (+4/-0) tests/ubuntu-system-settings-online-accounts-autopilot/master.run (+15/-0) tests/ubuntu-system-settings-online-accounts-autopilot/ts_control (+1/-0) tests/ubuntu-system-settings-online-accounts-autopilot/tslist.auto (+4/-0) tests/ubuntu-terminal-app-autopilot/master.run (+15/-0) tests/ubuntu-terminal-app-autopilot/ts_control (+1/-0) tests/ubuntu-terminal-app-autopilot/tslist.auto (+4/-0) tests/ubuntu-ui-toolkit-autopilot/master.run (+15/-0) tests/ubuntu-ui-toolkit-autopilot/ts_control (+1/-0) tests/ubuntu-ui-toolkit-autopilot/tslist.auto (+4/-0) tests/ubuntu-weather-app-autopilot/master.run (+15/-0) tests/ubuntu-weather-app-autopilot/ts_control (+1/-0) tests/ubuntu-weather-app-autopilot/tslist.auto (+4/-0) tests/unity8-autopilot/master.run (+15/-0) tests/unity8-autopilot/setup.sh (+6/-0) tests/unity8-autopilot/ts_control (+2/-0) tests/unity8-autopilot/tslist.auto (+4/-0) tests/upgrade/README (+3/-0) tests/upgrade/install_old/run.sh (+27/-0) tests/upgrade/install_old/tc_control (+9/-0) tests/upgrade/master.run (+5/-0) tests/upgrade/tslist.run (+2/-0) tests/upgrade/upgrade/tc_control (+9/-0) tests/upgrade/upgrade/upgrade.sh (+79/-0) tests/webbrowser-app-autopilot/master.run (+15/-0) tests/webbrowser-app-autopilot/ts_control (+1/-0) tests/webbrowser-app-autopilot/tslist.auto (+4/-0) utils/host/adb-shell (+23/-0) utils/host/autopilot-list (+18/-0) utils/host/autopilot-run (+7/-0) utils/host/prepare-autopilot-test.sh (+5/-0) utils/target/autopilot-list (+13/-0) utils/target/autopilot-run (+6/-0) utils/target/prepare-autopilot-test.sh (+17/-0) utils/target/unlock_screen.py (+98/-0) utils/target/unlock_screen.sh (+8/-0) Conflict adding file scripts. Moved existing file to scripts.moved. |
To merge this branch: | bzr merge lp:~achiang/ubuntu-test-cases/savilerow |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Test Case Developers | Pending | ||
Review via email: mp+201849@code.launchpad.net |
Commit message
Description of the change
We have fixed a long-standing typo in the savilerow project (was sevilerow).
Pull tests from the proper source branch.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'README-cli.rst' |
2 | --- README-cli.rst 1970-01-01 00:00:00 +0000 |
3 | +++ README-cli.rst 2014-01-15 20:49:07 +0000 |
4 | @@ -0,0 +1,76 @@ |
5 | +Touch Testing From the CLI |
6 | +========================== |
7 | + |
8 | +The touch testing execution framework was written so that its very easy to |
9 | +run tests from home in the exact same way test are run in the lab. The only |
10 | +thigs you need are: |
11 | + |
12 | + * This bzr branch |
13 | + * The phablet-tools_ package |
14 | + * An Ubuntu Touch supported_ device |
15 | + |
16 | +.. _phablet-tools: http://launchpad.net/phablet-tools |
17 | +.. _supported: http://wiki.ubuntu.com/Touch/Devices |
18 | + |
19 | +There are two pieces to touch testing, provisioning and test execution. These |
20 | +functions are independent of one another. eg, If your device already |
21 | +has the proper image/configuration, you can simply use the test-runner. |
22 | + |
23 | +Provisioning |
24 | +------------ |
25 | + |
26 | +The provisioning script is a simple wrapper to commands from phablet-tools |
27 | +to get a device ready for testing. Provisioning is performed with the |
28 | +scripts/provision.sh command. Running:: |
29 | + |
30 | + ./scripts/provision.sh -h |
31 | + |
32 | +will list supported options. |
33 | + |
34 | +Executing Tests |
35 | +--------------- |
36 | + |
37 | +The touch testing repository supports both autopilot and UTAH test definitions. |
38 | + |
39 | +Executing Autopilot Tests |
40 | +~~~~~~~~~~~~~~~~~~~~~~~~~ |
41 | + |
42 | +One or more autopilot tests can be run on the target device using the command:: |
43 | + |
44 | + ./scripts/run-autopilot-tests.sh |
45 | + |
46 | +This is a small wrapper that uses phablet-tools to drive the tests. The |
47 | +script can run one or more autopilot tests. By default it will reboot the |
48 | +device between each test and ensure the device is settled using the |
49 | +*system-settle* script. Both of those options can be disabled via command |
50 | +line options. By default the script will create a directory named |
51 | +*clientlogs* and then a subdirectory for each testsuite with result files. |
52 | +These sub-directories include a xUnit XML formatted file, *test_results.xml*, |
53 | +as well as several log files from the device to help with debugging failures. |
54 | + |
55 | +An example testing two applications:: |
56 | + |
57 | + ./scripts/run-autopilot-tests.sh -a dropping_letters_app -a music_app |
58 | + |
59 | +Executing UTAH Tests |
60 | +~~~~~~~~~~~~~~~~~~~~ |
61 | + |
62 | +Executing UTAH tests locally will require you to install the UTAH client |
63 | +package from a PPA:: |
64 | + |
65 | + sudo add-apt-repository ppa:utah/stable |
66 | + sudo apt-get update |
67 | + sudo apt-get install utah-client |
68 | + |
69 | +With that package installed UTAH tests can be run with:: |
70 | + |
71 | + ./scripts/jenkins.sh |
72 | + |
73 | +This script runs one test at a time and will put its test artifacts under the |
74 | +*clientlogs* directory similar to the autopilot runner. The UTAH result file |
75 | +will be named clientlogs/utah.yaml. |
76 | + |
77 | +An example of running the sdk test suite:: |
78 | + |
79 | + ./scripts/jenkins.sh -a sdk |
80 | + |
81 | |
82 | === added directory 'jenkins' |
83 | === added file 'jenkins/production.py' |
84 | --- jenkins/production.py 1970-01-01 00:00:00 +0000 |
85 | +++ jenkins/production.py 2014-01-15 20:49:07 +0000 |
86 | @@ -0,0 +1,77 @@ |
87 | +# The configuration matrix of our production device testing |
88 | + |
89 | +JENKINS = 'http://q-jenkins:8080' |
90 | + |
91 | + |
92 | +def _url(channel, device): |
93 | + return 'http://system-image.ubuntu.com/%s/%s/index.json' \ |
94 | + % (channel, device) |
95 | + |
96 | + |
97 | +TRUSTY_MATRIX = [ |
98 | + { |
99 | + 'image-type': 'touch_sf4p', |
100 | + 'node-label': 'touch-daily', |
101 | + 'devices': [ |
102 | + { |
103 | + 'name': 'mako-05', |
104 | + 'trigger_url': _url('trusty-proposed', 'mako'), |
105 | + }, |
106 | + { |
107 | + 'name': 'maguro-02', |
108 | + 'trigger_url': _url('trusty-proposed', 'maguro'), |
109 | + }, |
110 | + ], |
111 | + }, |
112 | + { |
113 | + 'image-type': 'touch', |
114 | + 'node-label': 'touch-daily', |
115 | + 'devices': [ |
116 | + { |
117 | + 'name': 'mako-02', |
118 | + 'trigger_url': _url('trusty-proposed', 'mako'), |
119 | + }, |
120 | + { |
121 | + 'name': 'maguro-01', |
122 | + 'trigger_url': _url('trusty-proposed', 'maguro'), |
123 | + }, |
124 | + ], |
125 | + }, |
126 | + { |
127 | + 'image-type': 'touch_custom', |
128 | + 'node-label': 'touch-daily', |
129 | + 'devices': [ |
130 | + { |
131 | + 'name': 'mako-10', |
132 | + 'trigger_url': _url('trusty-proposed-customized', 'mako'), |
133 | + }, |
134 | + ], |
135 | + 'IMAGE_OPT': 'export IMAGE_OPT="ubuntu-system -b ' |
136 | + '--channel trusty-proposed-customized"' |
137 | + }, |
138 | +] |
139 | + |
140 | +SAUCY_MATRIX = [ |
141 | + { |
142 | + 'image-type': 'touch_mir', |
143 | + 'node-label': 'touch-daily', |
144 | + 'devices': [ |
145 | + { |
146 | + # mako-11 should be the least utilized trusty device |
147 | + 'name': 'mako-11', |
148 | + 'trigger_url': _url('saucy-proposed', 'mako'), |
149 | + }, |
150 | + { |
151 | + 'name': 'maguro-03', |
152 | + 'trigger_url': _url('saucy-proposed', 'maguro'), |
153 | + }, |
154 | + ], |
155 | + 'IMAGE_OPT': 'export IMAGE_OPT="ubuntu-system -b ' |
156 | + '--channel saucy-proposed"' |
157 | + }, |
158 | +] |
159 | + |
160 | +MATRIX = { |
161 | + 'trusty': TRUSTY_MATRIX, |
162 | + 'saucy': SAUCY_MATRIX, |
163 | +} |
164 | |
165 | === added file 'jenkins/setup_jenkins.py' |
166 | --- jenkins/setup_jenkins.py 1970-01-01 00:00:00 +0000 |
167 | +++ jenkins/setup_jenkins.py 2014-01-15 20:49:07 +0000 |
168 | @@ -0,0 +1,213 @@ |
169 | +#!/usr/bin/env python |
170 | + |
171 | +# Ubuntu Testing Automation Harness |
172 | +# Copyright 2013 Canonical Ltd. |
173 | + |
174 | +# This program is free software: you can redistribute it and/or modify it |
175 | +# under the terms of the GNU General Public License version 3, as published |
176 | +# by the Free Software Foundation. |
177 | + |
178 | +# This program is distributed in the hope that it will be useful, but |
179 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
180 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
181 | +# PURPOSE. See the GNU General Public License for more details. |
182 | + |
183 | +# You should have received a copy of the GNU General Public License along |
184 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
185 | + |
186 | +import argparse |
187 | +import imp |
188 | +import jenkins |
189 | +import jinja2 |
190 | +import logging |
191 | +import os |
192 | + |
193 | +from distro_info import UbuntuDistroInfo |
194 | +DEV_SERIES = UbuntuDistroInfo().devel() |
195 | + |
196 | +import testconfig |
197 | + |
198 | +DEFINE_MEGA = os.environ.get('MEGA', False) |
199 | + |
200 | + |
201 | +def _get_parser(): |
202 | + """Create and return command line parser. |
203 | + |
204 | + :returns: command line parser |
205 | + :rtype: argparse.ArgumentParser |
206 | + |
207 | + """ |
208 | + parser = argparse.ArgumentParser( |
209 | + description='Create/Update upgrade testing jenkins jobs.') |
210 | + parser.add_argument("-d", "--dryrun", action="store_true", |
211 | + help="Dry run mode. Don't execute jenkins commands.") |
212 | + parser.add_argument("-u", "--username", |
213 | + help="username to use when logging into Jenkins.") |
214 | + parser.add_argument("-p", "--password", |
215 | + help="username to use when logging into Jenkins") |
216 | + parser.add_argument("-b", "--branch", default="lp:ubuntu-test-cases/touch", |
217 | + help="The branch this is located. default=%(default)s") |
218 | + parser.add_argument("-c", "--config", required=True, |
219 | + type=argparse.FileType('r'), |
220 | + help="The job config to use.") |
221 | + parser.add_argument("-P", "--publish", action="store_true", |
222 | + help="Publish at the end of the job") |
223 | + parser.add_argument("--prefix", |
224 | + help="Prefix to add to the beginning of the job name") |
225 | + parser.add_argument("-s", "--series", default=DEV_SERIES, |
226 | + help=("series of Ubuntu to download " |
227 | + "(default=%(default)s)")) |
228 | + parser.add_argument("-w", "--wait", type=int, default=300, |
229 | + help=("How long to wait after jenkins triggers the" |
230 | + "install-and-boot job (default=%(default)d)")) |
231 | + return parser |
232 | + |
233 | + |
234 | +def _get_jenkins(url, username, password): |
235 | + logging.info('Attempting to login to jenkins at %s', url) |
236 | + if username is not None: |
237 | + logging.info('...with authentication as user: %s', username) |
238 | + instance = jenkins.Jenkins(url, username=username, password=password) |
239 | + else: |
240 | + logging.info('...without authentication') |
241 | + instance = jenkins.Jenkins(url) |
242 | + |
243 | + return instance |
244 | + |
245 | + |
246 | +def _get_environment(): |
247 | + base = os.path.join(os.path.dirname(__file__), 'templates') |
248 | + return jinja2.Environment( |
249 | + loader=jinja2.FileSystemLoader(base), |
250 | + undefined=jinja2.StrictUndefined, |
251 | + trim_blocks=True) |
252 | + |
253 | + |
254 | +def _publish(instance, env, args, template, jobname, **params): |
255 | + tmpl = env.get_template(template) |
256 | + cfg = tmpl.render(**params) |
257 | + if args.dryrun: |
258 | + _dryrun_func(jobname, cfg) |
259 | + return |
260 | + if instance.job_exists(jobname): |
261 | + logging.info('reconfiguring job %s', jobname) |
262 | + instance.reconfig_job(jobname, cfg) |
263 | + else: |
264 | + logging.info('creating job %s', jobname) |
265 | + instance.create_job(jobname, cfg) |
266 | + |
267 | + |
268 | +if DEFINE_MEGA: |
269 | + def _get_job_name(args, device_type, image_type): |
270 | + prefix = "" |
271 | + if(args.prefix): |
272 | + prefix = args.prefix + "-" |
273 | + |
274 | + return '{}{}-{}-{}-smoke'.format( |
275 | + prefix, args.series, image_type, device_type) |
276 | + |
277 | + def _configure_jobs(instance, env, args, config_item, device, tests): |
278 | + name = device['name'] |
279 | + defserial = '$(${BZRDIR}/scripts/get-adb-id ${NODE_NAME})' |
280 | + |
281 | + params = { |
282 | + 'name': name, |
283 | + 'serial': device.get('serial', defserial), |
284 | + 'publish': args.publish, |
285 | + 'branch': args.branch, |
286 | + 'trigger_url': device['trigger_url'], |
287 | + 'imagetype': config_item['image-type'], |
288 | + 'image_opt': config_item.get('IMAGE_OPT', ''), |
289 | + 'statsd_key': config_item.get('statsd-key', ''), |
290 | + } |
291 | + |
292 | + job = _get_job_name(args, name, config_item['image-type']) |
293 | + _publish(instance, env, args, 'touch-smoke.xml.jinja2', job, **params) |
294 | +else: |
295 | + def _get_job_name(args, device, test, image_type): |
296 | + prefix = "" |
297 | + if(args.prefix): |
298 | + prefix = args.prefix + "-" |
299 | + return test.fmt.format(prefix=prefix, |
300 | + series=args.series, |
301 | + testname=test.name, |
302 | + imagetype=image_type, |
303 | + type=device[:device.index("-")]) |
304 | + |
305 | + def _configure_job(instance, env, args, config_item, device, test): |
306 | + tmpl_name = 'touch-{}.xml.jinja2'.format(test.name) |
307 | + if type(test) == testconfig.APTest: |
308 | + tmpl_name = 'touch-autopilot-base.xml.jinja2' |
309 | + defserial = '$(${BZRDIR}/scripts/get-adb-id %s)' % device['name'] |
310 | + params = { |
311 | + 'host': config_item['node-label'], |
312 | + 'name': device['name'], |
313 | + 'serial': device.get('serial', defserial), |
314 | + 'publish': args.publish, |
315 | + 'branch': args.branch, |
316 | + 'wait': args.wait, |
317 | + 'imagetype': config_item['image-type'], |
318 | + 'image_opt': config_item.get('IMAGE_OPT', ''), |
319 | + 'testname': test.name, |
320 | + } |
321 | + job = _get_job_name(args, params['name'], test, params['imagetype']) |
322 | + _publish(instance, env, args, tmpl_name, job, **params) |
323 | + return job |
324 | + |
325 | + def _configure_master(instance, env, args, projects, config_item, device): |
326 | + params = { |
327 | + 'host': config_item['node-label'], |
328 | + 'name': device['name'], |
329 | + 'publish': args.publish, |
330 | + 'branch': args.branch, |
331 | + 'projects': projects, |
332 | + 'trigger_url': device['trigger_url'], |
333 | + } |
334 | + image_type = config_item['image-type'] |
335 | + test = testconfig.Test('master') |
336 | + job = _get_job_name(args, device['name'], test, image_type) |
337 | + _publish(instance, env, args, 'touch-master.xml.jinja2', job, **params) |
338 | + |
339 | + job = 'smoke-master-free' |
340 | + _publish(instance, env, args, |
341 | + 'touch-master-free.xml.jinja2', job, **params) |
342 | + |
343 | + def _configure_jobs(instance, env, args, config_item, device, tests): |
344 | + projects = [] |
345 | + for test in tests: |
346 | + logging.debug("configuring %s job for %s", |
347 | + device['name'], test.name) |
348 | + p = _configure_job(instance, env, args, config_item, device, test) |
349 | + projects.append(p) |
350 | + _configure_master(instance, env, args, projects, config_item, device) |
351 | + |
352 | + |
353 | +def _dryrun_func(jobname, config): |
354 | + logging.debug(jobname) |
355 | + logging.debug(config) |
356 | + |
357 | + |
358 | +def main(): |
359 | + logging.basicConfig(level=logging.DEBUG) |
360 | + args = _get_parser().parse_args() |
361 | + |
362 | + config = imp.load_source('', 'config.py', args.config) |
363 | + if args.series not in config.MATRIX: |
364 | + print('"%s" series is not supported by this config.' % args.series) |
365 | + exit(1) |
366 | + |
367 | + jenkins_inst = _get_jenkins(config.JENKINS, args.username, args.password) |
368 | + if args.dryrun: |
369 | + jenkins_inst.create_job = _dryrun_func |
370 | + jenkins_inst.reconfig_job = _dryrun_func |
371 | + |
372 | + env = _get_environment() |
373 | + |
374 | + for item in config.MATRIX[args.series]: |
375 | + for device in item['devices']: |
376 | + tests = testconfig.TESTSUITES |
377 | + tests = testconfig.filter_tests(tests, item['image-type']) |
378 | + _configure_jobs(jenkins_inst, env, args, item, device, tests) |
379 | + |
380 | +if __name__ == '__main__': |
381 | + main() |
382 | |
383 | === added file 'jenkins/staging.py' |
384 | --- jenkins/staging.py 1970-01-01 00:00:00 +0000 |
385 | +++ jenkins/staging.py 2014-01-15 20:49:07 +0000 |
386 | @@ -0,0 +1,26 @@ |
387 | +# The configuration matrix of our staging device testing |
388 | + |
389 | +import os |
390 | + |
391 | +if not os.environ.get('MEGA', False): |
392 | + raise RuntimeError('staging server only supports MEGA jobs') |
393 | + |
394 | +JENKINS = 'http://jenkins-dev-image-test:8080/' |
395 | + |
396 | +TRUSTY_MATRIX = [ |
397 | + { |
398 | + 'image-type': 'touch', |
399 | + 'node-label': 'touch-dev', |
400 | + 'statsd-key': 'ubuntu-ci.test-execution-service.staging', |
401 | + 'devices': [ |
402 | + { |
403 | + 'name': 'mako', |
404 | + 'trigger_url': 'http://system-image.ubuntu.com/trusty-proposed/mako/index.json' |
405 | + } |
406 | + ], |
407 | + }, |
408 | +] |
409 | + |
410 | +MATRIX = { |
411 | + 'trusty': TRUSTY_MATRIX, |
412 | +} |
413 | |
414 | === added directory 'jenkins/templates' |
415 | === added file 'jenkins/templates/touch-autopilot-base.xml.jinja2' |
416 | --- jenkins/templates/touch-autopilot-base.xml.jinja2 1970-01-01 00:00:00 +0000 |
417 | +++ jenkins/templates/touch-autopilot-base.xml.jinja2 2014-01-15 20:49:07 +0000 |
418 | @@ -0,0 +1,31 @@ |
419 | +{% extends "touch-base.xml.jinja2" %} |
420 | +<?xml version='1.0' encoding='UTF-8'?> |
421 | +{% block triggers %} |
422 | + <triggers class="vector"/> |
423 | +{% endblock %} |
424 | +{% block timeout %} |
425 | + <timeoutMinutes>30</timeoutMinutes> |
426 | +{% endblock timeout %} |
427 | + |
428 | +{% block shellcmds %} |
429 | + <command>set -e |
430 | +rm -rf * |
431 | +{% include "touch-setup.xml.jinja2" %} |
432 | + |
433 | +{% block apptest %}{% endblock %} |
434 | + |
435 | +${BZRDIR}/scripts/jenkins.sh -s $ANDROID_SERIAL -a {{testname}} $EXTRA_PULLS |
436 | + </command> |
437 | +{% endblock %} |
438 | + |
439 | +{% block junitresults %} |
440 | + <hudson.tasks.junit.JUnitResultArchiver> |
441 | + <testResults>clientlogs/*.xml</testResults> |
442 | + <keepLongStdio>true</keepLongStdio> |
443 | + <testDataPublishers/> |
444 | + </hudson.tasks.junit.JUnitResultArchiver> |
445 | +{% endblock %} |
446 | + |
447 | +{% block artifacts %} |
448 | + <artifacts>clientlogs/*, **/jenkins.sh</artifacts> |
449 | +{% endblock %} |
450 | |
451 | === added file 'jenkins/templates/touch-base.xml.jinja2' |
452 | --- jenkins/templates/touch-base.xml.jinja2 1970-01-01 00:00:00 +0000 |
453 | +++ jenkins/templates/touch-base.xml.jinja2 2014-01-15 20:49:07 +0000 |
454 | @@ -0,0 +1,79 @@ |
455 | +<?xml version='1.0' encoding='UTF-8'?> |
456 | +<project> |
457 | + <actions/> |
458 | + <description> |
459 | +<pre> |
460 | +#NOTE: Automatically created from a script as part of daily smoke testing
 |
461 | + {{branch}}
 |
462 | +</pre> |
463 | + </description> |
464 | + <keepDependencies>false</keepDependencies> |
465 | + <properties> |
466 | + <hudson.plugins.throttleconcurrents.ThrottleJobProperty> |
467 | + <maxConcurrentPerNode>0</maxConcurrentPerNode> |
468 | + <maxConcurrentTotal>0</maxConcurrentTotal> |
469 | + <throttleEnabled>false</throttleEnabled> |
470 | + <throttleOption>project</throttleOption> |
471 | + </hudson.plugins.throttleconcurrents.ThrottleJobProperty> |
472 | + <hudson.plugins.build__publisher.ExternalProjectProperty/> |
473 | + </properties> |
474 | + <scm class="hudson.scm.NullSCM"/> |
475 | + <assignedNode>{{ host }}</assignedNode> |
476 | + <canRoam>false</canRoam> |
477 | + <disabled>false</disabled> |
478 | + <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding> |
479 | + <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding> |
480 | +{% block triggers %}{% endblock %} |
481 | + <concurrentBuild>false</concurrentBuild> |
482 | + <builders> |
483 | +{% block shellblock %} |
484 | + <hudson.tasks.Shell> |
485 | +{% block shellcmds %}{% endblock %} |
486 | + </hudson.tasks.Shell> |
487 | +{% endblock %} |
488 | +{% block extrasteps %}{% endblock %} |
489 | + </builders> |
490 | + <publishers> |
491 | +{% block artifactblock %} |
492 | + <hudson.tasks.ArtifactArchiver> |
493 | +{% block artifacts %}{% endblock %} |
494 | + <latestOnly>false</latestOnly> |
495 | + </hudson.tasks.ArtifactArchiver> |
496 | +{% endblock %} |
497 | +{% block descriptionsetter %} |
498 | + <hudson.plugins.descriptionsetter.DescriptionSetterPublisher> |
499 | + <regexp>^= TOUCH IMAGE VERSION:([0-9]+.*)</regexp> |
500 | + <regexpForFailed>^= TOUCH IMAGE VERSION:([0-9]+.*)</regexpForFailed> |
501 | + <setForMatrix>false</setForMatrix> |
502 | + </hudson.plugins.descriptionsetter.DescriptionSetterPublisher> |
503 | +{% endblock %} |
504 | +{% block mailer %} |
505 | + <hudson.tasks.Mailer> |
506 | + <recipients>paul.larson@canonical.com para.siva@canonical.com</recipients> |
507 | + <dontNotifyEveryUnstableBuild>false</dontNotifyEveryUnstableBuild> |
508 | + <sendToIndividuals>false</sendToIndividuals> |
509 | + </hudson.tasks.Mailer> |
510 | +{% endblock %} |
511 | +{% if publish %} |
512 | +{% block buildpublisher %} |
513 | + <hudson.plugins.build__publisher.BuildPublisher> |
514 | + <publishUnstableBuilds>true</publishUnstableBuilds> |
515 | + <publishFailedBuilds>true</publishFailedBuilds> |
516 | + <postActions class="vector"/> |
517 | + </hudson.plugins.build__publisher.BuildPublisher> |
518 | +{% endblock %} |
519 | +{% endif %} |
520 | +{% block buildtrigger %}{% endblock %} |
521 | +{% block junitresults %}{% endblock %} |
522 | + </publishers> |
523 | + <buildWrappers> |
524 | + <hudson.plugins.build__timeout.BuildTimeoutWrapper> |
525 | + {% block timeout %}{% endblock %} |
526 | + <failBuild>true</failBuild> |
527 | + <writingDescription>false</writingDescription> |
528 | + <timeoutPercentage>0</timeoutPercentage> |
529 | + <timeoutType>absolute</timeoutType> |
530 | + <timeoutMinutesElasticDefault>3</timeoutMinutesElasticDefault> |
531 | + </hudson.plugins.build__timeout.BuildTimeoutWrapper> |
532 | + </buildWrappers> |
533 | +</project> |
534 | |
535 | === added file 'jenkins/templates/touch-click_image_tests.xml.jinja2' |
536 | --- jenkins/templates/touch-click_image_tests.xml.jinja2 1970-01-01 00:00:00 +0000 |
537 | +++ jenkins/templates/touch-click_image_tests.xml.jinja2 2014-01-15 20:49:07 +0000 |
538 | @@ -0,0 +1,8 @@ |
539 | +{% extends "touch-autopilot-base.xml.jinja2" %} |
540 | +<?xml version='1.0' encoding='UTF-8'?> |
541 | + |
542 | +{% block apptest %} |
543 | +export APP="click_image_tests" |
544 | +{% endblock %} |
545 | + |
546 | +{% block junitresults %}{% endblock %} |
547 | |
548 | === added file 'jenkins/templates/touch-customizations.xml.jinja2' |
549 | --- jenkins/templates/touch-customizations.xml.jinja2 1970-01-01 00:00:00 +0000 |
550 | +++ jenkins/templates/touch-customizations.xml.jinja2 2014-01-15 20:49:07 +0000 |
551 | @@ -0,0 +1,6 @@ |
552 | +{% extends "touch-autopilot-base.xml.jinja2" %} |
553 | +<?xml version='1.0' encoding='UTF-8'?> |
554 | + |
555 | +{% block apptest %} |
556 | +export APP="customizations" |
557 | +{% endblock %} |
558 | |
559 | === added file 'jenkins/templates/touch-default.xml.jinja2' |
560 | --- jenkins/templates/touch-default.xml.jinja2 1970-01-01 00:00:00 +0000 |
561 | +++ jenkins/templates/touch-default.xml.jinja2 2014-01-15 20:49:07 +0000 |
562 | @@ -0,0 +1,9 @@ |
563 | +{% extends "touch-autopilot-base.xml.jinja2" %} |
564 | +<?xml version='1.0' encoding='UTF-8'?> |
565 | + |
566 | +{% block apptest %} |
567 | +export APP="default" |
568 | +{% endblock %} |
569 | + |
570 | +{% block junitresults %}{% endblock %} |
571 | + |
572 | |
573 | === added file 'jenkins/templates/touch-eventstat.xml.jinja2' |
574 | --- jenkins/templates/touch-eventstat.xml.jinja2 1970-01-01 00:00:00 +0000 |
575 | +++ jenkins/templates/touch-eventstat.xml.jinja2 2014-01-15 20:49:07 +0000 |
576 | @@ -0,0 +1,20 @@ |
577 | +{% extends "touch-base.xml.jinja2" %} |
578 | + |
579 | +{% block timeout %} |
580 | + <timeoutMinutes>45</timeoutMinutes> |
581 | +{% endblock timeout %} |
582 | + |
583 | +{% block shellcmds %} |
584 | + <command>set -e |
585 | +rm -rf * |
586 | +{% include "touch-setup.xml.jinja2" %} |
587 | + |
588 | +export APP=eventstat |
589 | + |
590 | +${BZRDIR}/scripts/jenkins.sh -s $ANDROID_SERIAL -a $APP -p /tmp/results |
591 | + </command> |
592 | +{% endblock %} |
593 | + |
594 | +{% block artifacts %} |
595 | + <artifacts>clientlogs/*, **/jenkins.sh</artifacts> |
596 | +{% endblock %} |
597 | |
598 | === added file 'jenkins/templates/touch-install-and-boot.xml.jinja2' |
599 | --- jenkins/templates/touch-install-and-boot.xml.jinja2 1970-01-01 00:00:00 +0000 |
600 | +++ jenkins/templates/touch-install-and-boot.xml.jinja2 2014-01-15 20:49:07 +0000 |
601 | @@ -0,0 +1,29 @@ |
602 | +{% extends "touch-base.xml.jinja2" %} |
603 | +<?xml version='1.0' encoding='UTF-8'?> |
604 | +{% block triggers %} |
605 | + <triggers class="vector"/> |
606 | +{% endblock %} |
607 | +{% block timeout %} |
608 | + <timeoutMinutes>30</timeoutMinutes> |
609 | +{% endblock timeout %} |
610 | + |
611 | +{% block shellcmds %} |
612 | + <command>set -e |
613 | +apt-cache policy phablet-tools |
614 | +rm -rf * |
615 | +mkdir clientlogs |
616 | + |
617 | +{% include "touch-setup.xml.jinja2" %} |
618 | + |
619 | +#Wait for images to actually show up on cdimage |
620 | +sleep {{wait}} |
621 | +{{image_opt}} |
622 | +${BZRDIR}/scripts/provision.sh -s $ANDROID_SERIAL -i {{imagetype}} -w |
623 | + |
624 | +${BZRDIR}/scripts/jenkins.sh -s $ANDROID_SERIAL -a install-and-boot |
625 | + </command> |
626 | +{% endblock %} |
627 | + |
628 | +{% block artifacts %} |
629 | + <artifacts>clientlogs/*</artifacts> |
630 | +{% endblock %} |
631 | |
632 | === added file 'jenkins/templates/touch-master-free.xml.jinja2' |
633 | --- jenkins/templates/touch-master-free.xml.jinja2 1970-01-01 00:00:00 +0000 |
634 | +++ jenkins/templates/touch-master-free.xml.jinja2 2014-01-15 20:49:07 +0000 |
635 | @@ -0,0 +1,20 @@ |
636 | +{% extends "touch-base.xml.jinja2" %} |
637 | + |
638 | +{% block timeout %} |
639 | + <timeoutMinutes>10</timeoutMinutes> |
640 | +{% endblock timeout %} |
641 | + |
642 | +{% block shellcmds %} |
643 | + <command>set -e |
644 | +rm -rf * |
645 | +{% include "touch-setup.xml.jinja2" %} |
646 | + |
647 | +echo LOCK_FILE=$LOCK_FILE > device-lock |
648 | +${BZRDIR}/scripts/device free --tokenfile device-lock |
649 | + </command> |
650 | +{% endblock %} |
651 | + |
652 | +{% block artifactblock %}{% endblock %} |
653 | +{% block descriptionsetter %}{% endblock %} |
654 | +{% block buildpublisher %}{% endblock %} |
655 | +{% block mailer %}{% endblock %} |
656 | |
657 | === added file 'jenkins/templates/touch-master.xml.jinja2' |
658 | --- jenkins/templates/touch-master.xml.jinja2 1970-01-01 00:00:00 +0000 |
659 | +++ jenkins/templates/touch-master.xml.jinja2 2014-01-15 20:49:07 +0000 |
660 | @@ -0,0 +1,84 @@ |
661 | +{% extends "touch-base.xml.jinja2" %} |
662 | +{% block triggers %} |
663 | + <triggers class="vector"> |
664 | + <com.redfin.hudson.UrlChangeTrigger> |
665 | + <spec></spec> |
666 | + <url>{{trigger_url}}</url> |
667 | + </com.redfin.hudson.UrlChangeTrigger> |
668 | + </triggers> |
669 | +{% endblock %} |
670 | + |
671 | +{% block shellcmds %} |
672 | + <command>set -e |
673 | +rm -rf * |
674 | +{% include "touch-setup.xml.jinja2" %} |
675 | + |
676 | +mv .device.$$ device-lock |
677 | + </command> |
678 | +{% endblock %} |
679 | + |
680 | +{% block extrasteps %} |
681 | +{% for project in projects %} |
682 | + <hudson.plugins.parameterizedtrigger.TriggerBuilder> |
683 | + <configs> |
684 | + <hudson.plugins.parameterizedtrigger.BlockableBuildTriggerConfig> |
685 | + <configs> |
686 | + <hudson.plugins.parameterizedtrigger.FileBuildParameters> |
687 | + <propertiesFile>device-lock</propertiesFile> |
688 | + <failTriggerOnMissing>true</failTriggerOnMissing> |
689 | + </hudson.plugins.parameterizedtrigger.FileBuildParameters> |
690 | + </configs> |
691 | + <projects>{{project}}</projects> |
692 | + <condition>ALWAYS</condition> |
693 | + <triggerWithNoParameters>false</triggerWithNoParameters> |
694 | + <block> |
695 | +{% if "install-and-boot" in project %} |
696 | + <buildStepFailureThreshold> |
697 | + <name>FAILURE</name> |
698 | + <ordinal>2</ordinal> |
699 | + <color>RED</color> |
700 | + </buildStepFailureThreshold> |
701 | +{% endif %} |
702 | + <unstableThreshold> |
703 | + <name>UNSTABLE</name> |
704 | + <ordinal>1</ordinal> |
705 | + <color>YELLOW</color> |
706 | + </unstableThreshold> |
707 | +{% if "install-and-boot" in project or "default" in project %} |
708 | + <failureThreshold> |
709 | + <name>FAILURE</name> |
710 | + <ordinal>2</ordinal> |
711 | + <color>RED</color> |
712 | + </failureThreshold> |
713 | +{% endif %} |
714 | + </block> |
715 | + <buildAllNodesWithLabel>false</buildAllNodesWithLabel> |
716 | + </hudson.plugins.parameterizedtrigger.BlockableBuildTriggerConfig> |
717 | + </configs> |
718 | + </hudson.plugins.parameterizedtrigger.TriggerBuilder> |
719 | +{% endfor %} |
720 | +{% endblock %} |
721 | +{% block timeout %} |
722 | + <timeoutMinutes>300</timeoutMinutes> |
723 | +{% endblock timeout %} |
724 | +{% block artifactblock %}{% endblock %} |
725 | +{% block descriptionsetter %}{% endblock %} |
726 | +{% block buildpublisher %}{% endblock %} |
727 | +{% block mailer %}{% endblock %} |
728 | +{% block buildtrigger %} |
729 | + <hudson.plugins.parameterizedtrigger.BuildTrigger> |
730 | + <configs> |
731 | + <hudson.plugins.parameterizedtrigger.BuildTriggerConfig> |
732 | + <configs> |
733 | + <hudson.plugins.parameterizedtrigger.FileBuildParameters> |
734 | + <propertiesFile>device-lock</propertiesFile> |
735 | + <failTriggerOnMissing>true</failTriggerOnMissing> |
736 | + </hudson.plugins.parameterizedtrigger.FileBuildParameters> |
737 | + </configs> |
738 | + <projects>smoke-master-free</projects> |
739 | + <condition>ALWAYS</condition> |
740 | + <triggerWithNoParameters>false</triggerWithNoParameters> |
741 | + </hudson.plugins.parameterizedtrigger.BuildTriggerConfig> |
742 | + </configs> |
743 | + </hudson.plugins.parameterizedtrigger.BuildTrigger> |
744 | +{% endblock %} |
745 | |
746 | === added file 'jenkins/templates/touch-memevent.xml.jinja2' |
747 | --- jenkins/templates/touch-memevent.xml.jinja2 1970-01-01 00:00:00 +0000 |
748 | +++ jenkins/templates/touch-memevent.xml.jinja2 2014-01-15 20:49:07 +0000 |
749 | @@ -0,0 +1,10 @@ |
750 | +{% extends "touch-autopilot-base.xml.jinja2" %} |
751 | +<?xml version='1.0' encoding='UTF-8'?> |
752 | +{% block timeout %} |
753 | + <timeoutMinutes>30</timeoutMinutes> |
754 | +{% endblock timeout %} |
755 | + |
756 | +{% block apptest %} |
757 | +export APP="memevent" |
758 | +export EXTRA_PULLS="-p /tmp/memory_usage.json" |
759 | +{% endblock %} |
760 | |
761 | === added file 'jenkins/templates/touch-sdk.xml.jinja2' |
762 | --- jenkins/templates/touch-sdk.xml.jinja2 1970-01-01 00:00:00 +0000 |
763 | +++ jenkins/templates/touch-sdk.xml.jinja2 2014-01-15 20:49:07 +0000 |
764 | @@ -0,0 +1,9 @@ |
765 | +{% extends "touch-autopilot-base.xml.jinja2" %} |
766 | +<?xml version='1.0' encoding='UTF-8'?> |
767 | + |
768 | +{% block apptest %} |
769 | +export APP="sdk" |
770 | +{% endblock %} |
771 | + |
772 | +{% block junitresults %}{% endblock %} |
773 | + |
774 | |
775 | === added file 'jenkins/templates/touch-security.xml.jinja2' |
776 | --- jenkins/templates/touch-security.xml.jinja2 1970-01-01 00:00:00 +0000 |
777 | +++ jenkins/templates/touch-security.xml.jinja2 2014-01-15 20:49:07 +0000 |
778 | @@ -0,0 +1,9 @@ |
779 | +{% extends "touch-autopilot-base.xml.jinja2" %} |
780 | +<?xml version='1.0' encoding='UTF-8'?> |
781 | + |
782 | +{% block apptest %} |
783 | +export APP="security" |
784 | +{% endblock %} |
785 | + |
786 | +{% block junitresults %}{% endblock %} |
787 | + |
788 | |
789 | === added file 'jenkins/templates/touch-setup.xml.jinja2' |
790 | --- jenkins/templates/touch-setup.xml.jinja2 1970-01-01 00:00:00 +0000 |
791 | +++ jenkins/templates/touch-setup.xml.jinja2 2014-01-15 20:49:07 +0000 |
792 | @@ -0,0 +1,18 @@ |
793 | +BRANCH="{{branch}}" |
794 | +BZRDIR=`echo "$BRANCH" | awk -F/ '{ print $(NF) }'` |
795 | +BZRDIR=$(readlink -f $BZRDIR) |
796 | +bzr branch ${BRANCH} ${BZRDIR} |
797 | + |
798 | +device_free() { |
799 | + if [ -f .device.$$ ] ; then |
800 | + ${BZRDIR}/scripts/device free |
801 | + fi |
802 | +} |
803 | + |
804 | +if [ -z $ANDROID_SERIAL ] ; then |
805 | + echo No device lock found. Aquiring... |
806 | + ${BZRDIR}/scripts/device get --name {{name}} |
807 | + . ./.device.$$ # source in the device serial |
808 | + trap "exit -2" TERM INT |
809 | + trap device_free EXIT |
810 | +fi |
811 | |
812 | === added file 'jenkins/templates/touch-smem.xml.jinja2' |
813 | --- jenkins/templates/touch-smem.xml.jinja2 1970-01-01 00:00:00 +0000 |
814 | +++ jenkins/templates/touch-smem.xml.jinja2 2014-01-15 20:49:07 +0000 |
815 | @@ -0,0 +1,22 @@ |
816 | +{% extends "touch-base.xml.jinja2" %} |
817 | + |
818 | +{% block triggers %} |
819 | + <triggers class="vector"/> |
820 | +{% endblock %} |
821 | +{% block timeout %} |
822 | + <timeoutMinutes>60</timeoutMinutes> |
823 | +{% endblock timeout %} |
824 | + |
825 | +{% block shellcmds %} |
826 | + <command>rm -rf * |
827 | +{% include "touch-setup.xml.jinja2" %} |
828 | + |
829 | +export APP=smem |
830 | + |
831 | +${BZRDIR}/scripts/jenkins.sh -s $ANDROID_SERIAL -a $APP -p /tmp/results |
832 | +</command> |
833 | +{% endblock %} |
834 | + |
835 | +{% block artifacts %} |
836 | + <artifacts>clientlogs/**/*</artifacts> |
837 | +{% endblock %} |
838 | |
839 | === added file 'jenkins/templates/touch-smoke.xml.jinja2' |
840 | --- jenkins/templates/touch-smoke.xml.jinja2 1970-01-01 00:00:00 +0000 |
841 | +++ jenkins/templates/touch-smoke.xml.jinja2 2014-01-15 20:49:07 +0000 |
842 | @@ -0,0 +1,147 @@ |
843 | +<?xml version='1.0' encoding='UTF-8'?> |
844 | +<project> |
845 | + <actions/> |
846 | + <description> |
847 | +<![CDATA[ |
848 | +This job provides a flexible way to execute all the tests in our daily image |
849 | +testing process that contribute to the |
850 | +<a href="http://reports.qa.ubuntu.com/smokeng/">QA Dashboard</a>. |
851 | +The job is parameterized to give flexibility in what gets tested. A couple of |
852 | +common ways to run this job are: |
853 | +<dl> |
854 | + <dt>Full Test Run</dt> |
855 | + <dd>TESTS=ALL</dd> |
856 | + <dd>APPS=ALL</dd> |
857 | + <dd>PACKAGES=ALL</dd> |
858 | + <dt>Re-run a Failed Autopilot Test</dt> |
859 | + <dd>INSTALL_URL=http://jenkins-dev-image-test:8080/job/saucy-touch_ro-mako/9</dd> |
860 | + <dd>APPS=share_app</dd> |
861 | + <dt>Run Several Autopilot Tests on Latest Build</dt> |
862 | + <dd>APPS=share_app music_app</dd> |
863 | + <dd>PACKAGES=share-app-autopilot</dd> |
864 | + <dt>Run All Tests Under Utah</dt> |
865 | + <dd>TESTS=ALL_INCLUDING_AUTOPILOT</dd> |
866 | +</dl> |
867 | +<pre> |
868 | +#NOTE: Automatically created from a script as part of daily smoke testing |
869 | + {{branch}} |
870 | +</pre> |
871 | +{% if statsd_key %} |
872 | +<h3>Graphite Reports</h3> |
873 | +<ul> |
874 | + <li><a href="https://graphite.engineering.canonical.com/graphlot/?width=841&height=770&&target=alias%28scale%28statsd.{{statsd_key}}.{{imagetype}}.provision.mean%2C0.000016667%29%2C%22Provisioning%20Time(minutes)%22%29&target=alias%28scale%28statsd.{{statsd_key}}.{{imagetype}}.test_autopilot.mean%2C0.000016667%29%2C%22Autopilot%20Tests%20Time%22%29&target=alias%28scale%28statsd.{{statsd_key}}.{{imagetype}}.test_utah.mean%2C0.000016667%29%2C%22UTAH%20Tests%20Time%22%29&from=-1weeks">Timings (1 week)</a></li> |
875 | + <li><a href="https://graphite.engineering.canonical.com/graphlot/?width=841&height=770&&target=alias%28scale%28statsd.{{statsd_key}}.{{imagetype}}.provision.mean%2C0.000016667%29%2C%22Provisioning%20Time(minutes)%22%29&target=alias%28scale%28statsd.{{statsd_key}}.{{imagetype}}.test_autopilot.mean%2C0.000016667%29%2C%22Autopilot%20Tests%20Time%22%29&target=alias%28scale%28statsd.{{statsd_key}}.{{imagetype}}.test_utah.mean%2C0.000016667%29%2C%22UTAH%20Tests%20Time%22%29&from=-4weeks">Timings (4 weeks)</a></li> |
876 | +</ul> |
877 | +{% endif %} |
878 | +]]> |
879 | + </description> |
880 | + <keepDependencies>false</keepDependencies> |
881 | + <properties> |
882 | + <hudson.model.ParametersDefinitionProperty> |
883 | + <parameterDefinitions> |
884 | + <hudson.model.StringParameterDefinition> |
885 | + <name>INSTALL_URL</name> |
886 | + <description>A URL to the previous job. If provided this job will use the same install options as it used. If the device executing the job happens to have the exact same image, then provisioning can be skipped. |
887 | + </description> |
888 | + <defaultValue></defaultValue> |
889 | + </hudson.model.StringParameterDefinition> |
890 | + <hudson.model.StringParameterDefinition> |
891 | + <name>TESTS</name> |
892 | + <description>A space separated list of utah tests to run. "ALL" can be used to run all known tests. |
893 | + </description> |
894 | + <defaultValue></defaultValue> |
895 | + </hudson.model.StringParameterDefinition> |
896 | + <hudson.model.StringParameterDefinition> |
897 | + <name>APPS</name> |
898 | + <description>A space separated list of autopilot tests to run. "ALL" can be used to run all known tests. |
899 | + </description> |
900 | + <defaultValue></defaultValue> |
901 | + </hudson.model.StringParameterDefinition> |
902 | + <hudson.model.StringParameterDefinition> |
903 | + <name>PACKAGES</name> |
904 | + <description>A space separated list of packages to install. "ALL" can be used to install required packages for all known autopilot tests. |
905 | + </description> |
906 | + <defaultValue>ALL</defaultValue> |
907 | + </hudson.model.StringParameterDefinition> |
908 | + <hudson.model.StringParameterDefinition> |
909 | + <name>PPAS</name> |
910 | + <description>A space separated list of PPAs to configure on the device. |
911 | + </description> |
912 | + <defaultValue></defaultValue> |
913 | + </hudson.model.StringParameterDefinition> |
914 | + </parameterDefinitions> |
915 | + </hudson.model.ParametersDefinitionProperty> |
916 | + <com.sonyericsson.rebuild.RebuildSettings> |
917 | + <autoRebuild>false</autoRebuild> |
918 | + </com.sonyericsson.rebuild.RebuildSettings> |
919 | + </properties> |
920 | + <scm class="hudson.scm.NullSCM"/> |
921 | + <assignedNode>{{ name }}</assignedNode> |
922 | + <canRoam>false</canRoam> |
923 | + <disabled>false</disabled> |
924 | + <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding> |
925 | + <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding> |
926 | + <triggers class="vector"/> |
927 | + <concurrentBuild>true</concurrentBuild> |
928 | + <builders> |
929 | + <hudson.tasks.Shell> |
930 | + <command>set -e |
931 | +BRANCH="{{branch}}" |
932 | +BZRDIR=`echo "$BRANCH" | awk -F/ '{ print $(NF) }'` |
933 | +BZRDIR=$(readlink -f $BZRDIR) |
934 | +[ -d $BZRDIR ] && rm -rf $BZRDIR |
935 | +bzr branch ${BRANCH} ${BZRDIR} |
936 | + |
937 | +export ANDROID_SERIAL={{serial}} |
938 | +export IMAGE_TYPE={{imagetype}} |
939 | +{% if statsd_key %} |
940 | +export STATSD_KEY={{statsd_key}}.{{imagetype}} |
941 | +{% endif %} |
942 | + |
943 | +{{image_opt}} |
944 | +${BZRDIR}/scripts/run-smoke |
945 | + </command> |
946 | + </hudson.tasks.Shell> |
947 | + </builders> |
948 | + <publishers> |
949 | + <hudson.tasks.ArtifactArchiver> |
950 | + <artifacts>clientlogs/**</artifacts> |
951 | + <latestOnly>false</latestOnly> |
952 | + </hudson.tasks.ArtifactArchiver> |
953 | + <hudson.tasks.junit.JUnitResultArchiver> |
954 | + <testResults>clientlogs/**/test_results.xml</testResults> |
955 | + <keepLongStdio>true</keepLongStdio> |
956 | + <testDataPublishers> |
957 | + <hudson.plugins.junitattachments.AttachmentPublisher/> |
958 | + </testDataPublishers> |
959 | + </hudson.tasks.junit.JUnitResultArchiver> |
960 | + <hudson.plugins.descriptionsetter.DescriptionSetterPublisher> |
961 | + <regexp>^= TOUCH IMAGE VERSION:([0-9]+.*)</regexp> |
962 | + <regexpForFailed>^= TOUCH IMAGE VERSION:([0-9]+.*)</regexpForFailed> |
963 | + <setForMatrix>false</setForMatrix> |
964 | + </hudson.plugins.descriptionsetter.DescriptionSetterPublisher> |
965 | +{% if publish %} |
966 | + <hudson.tasks.Mailer> |
967 | + <recipients>paul.larson@canonical.com</recipients> |
968 | + <dontNotifyEveryUnstableBuild>false</dontNotifyEveryUnstableBuild> |
969 | + <sendToIndividuals>false</sendToIndividuals> |
970 | + </hudson.tasks.Mailer> |
971 | + <hudson.plugins.build__publisher.BuildPublisher> |
972 | + <publishUnstableBuilds>true</publishUnstableBuilds> |
973 | + <publishFailedBuilds>true</publishFailedBuilds> |
974 | + <postActions class="vector"/> |
975 | + </hudson.plugins.build__publisher.BuildPublisher> |
976 | +{% endif %} |
977 | + </publishers> |
978 | + <buildWrappers> |
979 | + <hudson.plugins.build__timeout.BuildTimeoutWrapper> |
980 | + <timeoutMinutes>180</timeoutMinutes> |
981 | + <failBuild>true</failBuild> |
982 | + <writingDescription>false</writingDescription> |
983 | + <timeoutPercentage>0</timeoutPercentage> |
984 | + <timeoutType>absolute</timeoutType> |
985 | + <timeoutMinutesElasticDefault>3</timeoutMinutesElasticDefault> |
986 | + </hudson.plugins.build__timeout.BuildTimeoutWrapper> |
987 | + </buildWrappers> |
988 | +</project> |
989 | + |
990 | |
991 | === added file 'jenkins/templates/touch-upgrade.xml.jinja2' |
992 | --- jenkins/templates/touch-upgrade.xml.jinja2 1970-01-01 00:00:00 +0000 |
993 | +++ jenkins/templates/touch-upgrade.xml.jinja2 2014-01-15 20:49:07 +0000 |
994 | @@ -0,0 +1,28 @@ |
995 | +{% extends "touch-base.xml.jinja2" %} |
996 | +<?xml version='1.0' encoding='UTF-8'?> |
997 | +{% block triggers %} |
998 | + <triggers class="vector"/> |
999 | +{% endblock %} |
1000 | +{% block timeout %} |
1001 | + <timeoutMinutes>30</timeoutMinutes> |
1002 | +{% endblock timeout %} |
1003 | + |
1004 | +{% block shellcmds %} |
1005 | + <command>rm -rf * |
1006 | +{% include "touch-setup.xml.jinja2" %} |
1007 | + |
1008 | +${BZRDIR}/scrips/run-touch-upgrade.sh |
1009 | +</command> |
1010 | +{% endblock %} |
1011 | + |
1012 | +{% block artifacts %} |
1013 | + <artifacts>clientlogs/*, **/jenkins.sh</artifacts> |
1014 | +{% endblock %} |
1015 | + |
1016 | +{% block descriptionsetter %} |
1017 | + <hudson.plugins.descriptionsetter.DescriptionSetterPublisher> |
1018 | + <regexp>^UPGRADED TO VERSION: (.*)</regexp> |
1019 | + <regexpForFailed>^UPGRADED TO VERSION: (.*)</regexpForFailed> |
1020 | + <setForMatrix>false</setForMatrix> |
1021 | + </hudson.plugins.descriptionsetter.DescriptionSetterPublisher> |
1022 | +{% endblock %} |
1023 | |
1024 | === added file 'jenkins/testconfig.py' |
1025 | --- jenkins/testconfig.py 1970-01-01 00:00:00 +0000 |
1026 | +++ jenkins/testconfig.py 2014-01-15 20:49:07 +0000 |
1027 | @@ -0,0 +1,171 @@ |
1028 | +#!/usr/bin/env python |
1029 | + |
1030 | +# Ubuntu Testing Automation Harness |
1031 | +# Copyright 2013 Canonical Ltd. |
1032 | + |
1033 | +# This program is free software: you can redistribute it and/or modify it |
1034 | +# under the terms of the GNU General Public License version 3, as published |
1035 | +# by the Free Software Foundation. |
1036 | + |
1037 | +# This program is distributed in the hope that it will be useful, but |
1038 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1039 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1040 | +# PURPOSE. See the GNU General Public License for more details. |
1041 | + |
1042 | +# You should have received a copy of the GNU General Public License along |
1043 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1044 | + |
1045 | +import argparse |
1046 | + |
1047 | +DEF_FMT = '{prefix}{series}-{imagetype}-{type}-smoke-{testname}' |
1048 | +IDLE_FMT = '{prefix}{testname}-{series}-{imagetype}-armhf-install-idle-{type}' |
1049 | + |
1050 | + |
1051 | +class Test(object): |
1052 | + def __init__(self, name, fmt=DEF_FMT): |
1053 | + self.name = name |
1054 | + self.fmt = fmt |
1055 | + |
1056 | + |
1057 | +class APTest(Test): |
1058 | + def __init__(self, name, app=None, pkgs=None): |
1059 | + Test.__init__(self, name) |
1060 | + self.pkgs = pkgs |
1061 | + if not app: |
1062 | + # convert share-app-autopilot to share_app |
1063 | + app = name.replace('-', '_').replace('_autopilot', '') |
1064 | + self.app = app |
1065 | + |
1066 | + |
1067 | +TESTSUITES = [ |
1068 | + Test('install-and-boot'), |
1069 | + Test('default'), |
1070 | +] |
1071 | +TESTSUITES += [ |
1072 | + APTest('friends-app-autopilot', pkgs=['friends-app-autopilot']), |
1073 | + APTest('mediaplayer-app-autopilot', pkgs=['mediaplayer-app-autopilot']), |
1074 | + APTest('gallery-app-autopilot', pkgs=['gallery-app-autopilot']), |
1075 | + APTest('webbrowser-app-autopilot', pkgs=['webbrowser-app-autopilot']), |
1076 | + APTest('unity8-autopilot', 'unity8', pkgs=['python-gi']), |
1077 | + APTest('notes-app-autopilot'), |
1078 | + APTest('camera-app-autopilot', pkgs=['camera-app-autopilot']), |
1079 | + APTest('dialer-app-autopilot', pkgs=['dialer-app-autopilot']), |
1080 | + APTest('messaging-app-autopilot', pkgs=['messaging-app-autopilot']), |
1081 | + APTest('address-book-app-autopilot', pkgs=['address-book-app-autopilot']), |
1082 | + APTest('calendar-app-autopilot'), |
1083 | + APTest('music-app-autopilot'), |
1084 | + APTest('dropping-letters-app-autopilot'), |
1085 | + APTest('ubuntu-calculator-app-autopilot'), |
1086 | + APTest('ubuntu-clock-app-autopilot'), |
1087 | + APTest('ubuntu-filemanager-app-autopilot'), |
1088 | + APTest('ubuntu-rssreader-app-autopilot'), |
1089 | + APTest('ubuntu-terminal-app-autopilot'), |
1090 | + APTest('ubuntu-weather-app-autopilot'), |
1091 | + APTest('ubuntu-ui-toolkit-autopilot', 'ubuntuuitoolkit', |
1092 | + ['ubuntu-ui-toolkit-autopilot']), |
1093 | + APTest('ubuntu-system-settings-online-accounts-autopilot', |
1094 | + 'online_accounts_ui', |
1095 | + ['ubuntu-system-settings-online-accounts-autopilot']), |
1096 | +] |
1097 | +TESTSUITES += [ |
1098 | + Test('click_image_tests'), |
1099 | + Test('sdk'), |
1100 | + Test('security'), |
1101 | + Test('eventstat', IDLE_FMT), |
1102 | + Test('smem', IDLE_FMT), |
1103 | + Test('memevent', |
1104 | + '{prefix}{testname}-{series}-{imagetype}-armhf-default-{type}'), |
1105 | +] |
1106 | + |
1107 | + |
1108 | +def filter_tests(tests, image_type): |
1109 | + if image_type: |
1110 | + func = globals().get('get_tests_%s' % image_type) |
1111 | + if func: |
1112 | + tests = func(tests) |
1113 | + elif image_type not in ['touch', 'touch_mir']: |
1114 | + print('Unsupported image type: %s' % image_type) |
1115 | + exit(1) |
1116 | + return tests |
1117 | + |
1118 | + |
1119 | +def _get_tests(test_type, image_type): |
1120 | + tests = [t for t in TESTSUITES if type(t) == test_type] |
1121 | + return filter_tests(tests, image_type) |
1122 | + |
1123 | + |
1124 | +def _handle_utah(args): |
1125 | + tests = _get_tests(Test, args.image_type) |
1126 | + if args.with_autopilot: |
1127 | + tests += _get_tests(APTest, args.image_type) |
1128 | + # NOTE: this is only called by MEGA jobs, so we can skip install-and-boot |
1129 | + print(' '.join([t.name for t in tests if t.name != 'install-and-boot'])) |
1130 | + |
1131 | + |
1132 | +def _handle_ap_apps(args): |
1133 | + tests = _get_tests(APTest, args.image_type) |
1134 | + print(' '.join([t.app for t in tests])) |
1135 | + |
1136 | + |
1137 | +def _handle_ap_packages(args): |
1138 | + pkgs = [] |
1139 | + tests = _get_tests(APTest, args.image_type) |
1140 | + for test in tests: |
1141 | + if not args.app or test.app in args.app: |
1142 | + if test.pkgs: |
1143 | + pkgs.extend(test.pkgs) |
1144 | + print(' '.join(pkgs)) |
1145 | + |
1146 | + |
1147 | +def get_tests_touch_sf4p(common_tests): |
1148 | + tests = [] |
1149 | + test_set = [ |
1150 | + 'install-and-boot', |
1151 | + 'default', |
1152 | + 'unity8-autopilot', |
1153 | + ] |
1154 | + |
1155 | + tests = [t for t in common_tests if t.name in test_set] |
1156 | + return tests |
1157 | + |
1158 | + |
1159 | +def get_tests_touch_custom(common_tests): |
1160 | + tests = common_tests |
1161 | + tests.insert(1, Test('customizations')) |
1162 | + return tests |
1163 | + |
1164 | + |
1165 | +def _get_parser(): |
1166 | + parser = argparse.ArgumentParser( |
1167 | + description='List information on configured tests for touch') |
1168 | + sub = parser.add_subparsers(title='Commands', metavar='') |
1169 | + |
1170 | + p = sub.add_parser('utah', help='List UTAH tests') |
1171 | + p.set_defaults(func=_handle_utah) |
1172 | + p.add_argument('-i', '--image-type', |
1173 | + help='Return list of test configured for an image type.') |
1174 | + p.add_argument('-a', '--with-autopilot', action='store_true', |
1175 | + help='Include autopilot tests that can be run under UTAH.') |
1176 | + |
1177 | + p = sub.add_parser('apps', help='List autopilot application names') |
1178 | + p.set_defaults(func=_handle_ap_apps) |
1179 | + p.add_argument('-i', '--image-type', |
1180 | + help='Return list of test configured for an image type.') |
1181 | + |
1182 | + p = sub.add_parser('packages', help='List packages required for autopilot') |
1183 | + p.set_defaults(func=_handle_ap_packages) |
1184 | + g = p.add_mutually_exclusive_group() |
1185 | + g.add_argument('-i', '--image-type', |
1186 | + help='''If no apps are listed, limit to tests for an |
1187 | + image type.''') |
1188 | + g.add_argument('-a', '--app', action='append', |
1189 | + help='Autopilot test application. eg share_app') |
1190 | + return parser |
1191 | + |
1192 | + |
1193 | +def main(): |
1194 | + args = _get_parser().parse_args() |
1195 | + return args.func(args) |
1196 | + |
1197 | +if __name__ == '__main__': |
1198 | + exit(main()) |
1199 | |
1200 | === added directory 'scripts' |
1201 | === renamed directory 'scripts' => 'scripts.moved' |
1202 | === added file 'scripts/assert-image' |
1203 | --- scripts/assert-image 1970-01-01 00:00:00 +0000 |
1204 | +++ scripts/assert-image 2014-01-15 20:49:07 +0000 |
1205 | @@ -0,0 +1,25 @@ |
1206 | +#!/bin/sh |
1207 | + |
1208 | +set -e |
1209 | + |
1210 | +BASEDIR=$(readlink -f $(dirname $0)/..) |
1211 | + |
1212 | +# a simple script to ensure the proper image is installed on the target |
1213 | + |
1214 | +[ -z $INSTALL_URL ] && echo "= INSTALL_URL not set. Using target as-is." && exit 0 |
1215 | + |
1216 | +echo "Ensuring target has proper image..." |
1217 | +REQUIRED_UUID=$(curl ${INSTALL_URL}/artifact/clientlogs/.ci-uuid) |
1218 | +ACTUAL_UUID=$(adb shell "cat /home/phablet/.ci-uuid | tr -d '\r\n'") |
1219 | +if [ "$REQUIRED_UUID" != "$ACTUAL_UUID" ] ; then |
1220 | + echo "= UUIDs $REQUIRED_UUID != $ACTUAL_UUID" |
1221 | + ARGS=$(curl ${INSTALL_URL}/artifact/clientlogs/.ci-flash-args | tr -d '\r\n') |
1222 | + CUST=$(curl ${INSTALL_URL}/artifact/clientlogs/.ci-customizations | tr -d '\r\n') |
1223 | + echo "reprovisioning device with: $ARGS" |
1224 | + echo "customizing device with: $CUST" |
1225 | + UUID=$REQUIRED_UUID IMAGE_OPT=$ARGS CUSTOMIZATIONS=$CUST \ |
1226 | + ${BASEDIR}/scripts/provision.sh |
1227 | +else |
1228 | + echo "= UUIDS match, reusing image on target" |
1229 | +fi |
1230 | + |
1231 | |
1232 | === added file 'scripts/combine_results' |
1233 | --- scripts/combine_results 1970-01-01 00:00:00 +0000 |
1234 | +++ scripts/combine_results 2014-01-15 20:49:07 +0000 |
1235 | @@ -0,0 +1,94 @@ |
1236 | +#!/usr/bin/env python3 |
1237 | + |
1238 | +""" |
1239 | +We always run the system-settle test before and after an autopilot test. This |
1240 | +script takes the results of the before/after results and combines them in with |
1241 | +the junit xml results from the autopilot test so we have one unified report. |
1242 | +""" |
1243 | + |
1244 | + |
1245 | +import os |
1246 | +import sys |
1247 | + |
1248 | +from xml.etree import ElementTree |
1249 | + |
1250 | + |
1251 | +def _build_node(classname, name, rcfile, stdout): |
1252 | + e = ElementTree.Element('testcase') |
1253 | + e.attrib['classname'] = classname |
1254 | + e.attrib['name'] = 'settle_%s' % name |
1255 | + rc = int(open(rcfile).read()) |
1256 | + if rc != 0: |
1257 | + f = ElementTree.Element('failure') |
1258 | + e.append(f) |
1259 | + f.attrib['type'] = 'testtools.testresult.real._StringException' |
1260 | + f.text = open(stdout).read() |
1261 | + return e, rc != 0 |
1262 | + |
1263 | + |
1264 | +def _get_results(apfile): |
1265 | + try: |
1266 | + tree = ElementTree.parse(apfile) |
1267 | + except Exception as ex: |
1268 | + e = ElementTree.Element('testsuite') |
1269 | + tree = ElementTree.ElementTree(e) |
1270 | + e.attrib['errors'] = '1' |
1271 | + e.attrib['failures'] = '0' |
1272 | + e.attrib['tests'] = '1' |
1273 | + |
1274 | + # make a guess at the classname: |
1275 | + classname = os.path.basename(os.path.dirname(apfile)) |
1276 | + |
1277 | + t = ElementTree.Element('testcase') |
1278 | + e.append(t) |
1279 | + t.attrib['classname'] = classname |
1280 | + t.attrib['name'] = 'phablet-test-run' |
1281 | + |
1282 | + f = ElementTree.Element('failure') |
1283 | + t.append(f) |
1284 | + f.attrib['type'] = 'testtools.testresult.real._StringException' |
1285 | + f.text = str(ex) |
1286 | + |
1287 | + return tree |
1288 | + |
1289 | + |
1290 | +def _get_classname(results): |
1291 | + return results[0].attrib.get('classname', '???').split('.')[0] |
1292 | + |
1293 | + |
1294 | +def combine(resdir): |
1295 | + ap_file = os.path.join(resdir, 'test_results.xml') |
1296 | + tree = _get_results(ap_file) |
1297 | + ap_results = tree.getroot() |
1298 | + |
1299 | + errors = int(ap_results.attrib['errors']) |
1300 | + |
1301 | + classname = _get_classname(ap_results) |
1302 | + |
1303 | + rc = os.path.join(resdir, 'settle_before.rc') |
1304 | + log = os.path.join(resdir, 'settle_before.log') |
1305 | + node, failed = _build_node(classname, 'before', rc, log) |
1306 | + ap_results.insert(0, node) |
1307 | + if failed: |
1308 | + errors += 1 |
1309 | + |
1310 | + rc = os.path.join(resdir, 'settle_after.rc') |
1311 | + log = os.path.join(resdir, 'settle_after.log') |
1312 | + node, failed = _build_node(classname, 'after', rc, log) |
1313 | + ap_results.append(node) |
1314 | + if failed: |
1315 | + errors += 1 |
1316 | + |
1317 | + num = int(ap_results.attrib['tests']) + 2 |
1318 | + ap_results.attrib['tests'] = str(num) |
1319 | + ap_results.attrib['errors'] = str(errors) |
1320 | + |
1321 | + tree.write(ap_file) |
1322 | + |
1323 | + |
1324 | +if __name__ == '__main__': |
1325 | + if len(sys.argv) != 2: |
1326 | + print('usage: {} <results directory>'.format(sys.argv[0])) |
1327 | + sys.exit(1) |
1328 | + |
1329 | + combine(sys.argv[1]) |
1330 | |
1331 | === added file 'scripts/device' |
1332 | --- scripts/device 1970-01-01 00:00:00 +0000 |
1333 | +++ scripts/device 2014-01-15 20:49:07 +0000 |
1334 | @@ -0,0 +1,191 @@ |
1335 | +#!/usr/bin/python |
1336 | + |
1337 | +import argparse |
1338 | +import contextlib |
1339 | +import fcntl |
1340 | +import imp |
1341 | +import logging |
1342 | +import os |
1343 | +import sys |
1344 | +import time |
1345 | + |
1346 | + |
1347 | +class DeviceException(Exception): |
1348 | + """Just a handy way to pass errors to the CLI.""" |
1349 | + pass |
1350 | + |
1351 | + |
1352 | +@contextlib.contextmanager |
1353 | +def _device_pool(args): |
1354 | + lockfile = os.path.join(args.device_pool, 'lockfile') |
1355 | + with open(lockfile, 'w') as f: |
1356 | + logging.debug('aquiring lock for device pool') |
1357 | + try: |
1358 | + fcntl.lockf(f, fcntl.LOCK_EX) |
1359 | + yield args.device_pool |
1360 | + finally: |
1361 | + fcntl.lockf(f, fcntl.LOCK_UN) |
1362 | + |
1363 | + |
1364 | +def _get_tokenfile(): |
1365 | + return '.device.%d' % os.getppid() |
1366 | + |
1367 | + |
1368 | +def _lock_device(device_file): |
1369 | + logging.info('locking file %s', device_file) |
1370 | + |
1371 | + name = os.path.basename(device_file) |
1372 | + lockfile = device_file + '.lck' |
1373 | + |
1374 | + with open(device_file) as f: |
1375 | + contents = f.read() |
1376 | + with open(_get_tokenfile(), 'w') as w: |
1377 | + w.write(contents) |
1378 | + if contents[-1] != '\n': |
1379 | + w.write('\n') |
1380 | + w.write('DEVICE_NAME=%s\n' % name) |
1381 | + w.write('LOCK_FILE=%s\n' % lockfile) |
1382 | + os.rename(device_file, lockfile) |
1383 | + |
1384 | + |
1385 | +def _get_by_name(args): |
1386 | + loops = 0 |
1387 | + while True: |
1388 | + with _device_pool(args) as pool: |
1389 | + f = os.path.join(pool, args.name) |
1390 | + if os.path.exists(f): |
1391 | + _lock_device(f) |
1392 | + break |
1393 | + elif os.path.exists(f + '.lck'): |
1394 | + # throttle back logging as time progresses |
1395 | + if (loops < 10) or \ |
1396 | + (loops < 100 and loops % 4 == 0) or \ |
1397 | + (loops % 12 == 0): |
1398 | + logging.info( |
1399 | + 'device is locked, waiting... attempts(%d)', loops) |
1400 | + else: |
1401 | + raise DeviceException('No such device exists.') |
1402 | + time.sleep(5) |
1403 | + loops += 1 |
1404 | + |
1405 | + |
1406 | +def _get_by_type(args): |
1407 | + while True: |
1408 | + with _device_pool(args) as pool: |
1409 | + match = False |
1410 | + for d in os.listdir(pool): |
1411 | + if args.type in d: |
1412 | + match = True |
1413 | + if not d.endswith('.lck'): |
1414 | + _lock_device(os.path.join(pool, d)) |
1415 | + return |
1416 | + if not match: |
1417 | + raise DeviceException( |
1418 | + 'No "%s" devices found in pool.' % args.type) |
1419 | + time.sleep(5) |
1420 | + |
1421 | + |
1422 | +def _get_by_env(args, jobname): |
1423 | + # find the device portion of a string like: |
1424 | + # saucy-touch_ro-DEVICETYPE-smoke-ubuntu-terminal-app-autopilot |
1425 | + parts = jobname.split('-') |
1426 | + if len(parts) < 3: |
1427 | + raise DeviceException('Invalid jobname: %s.' % jobname) |
1428 | + args.type = parts[2] |
1429 | + _get_by_type(args) |
1430 | + |
1431 | + |
1432 | +def _device_get(args): |
1433 | + job = os.environ.get('JOBNAME', False) |
1434 | + |
1435 | + if args.name: |
1436 | + _get_by_name(args) |
1437 | + elif args.type: |
1438 | + _get_by_type(args) |
1439 | + elif job: |
1440 | + _get_by_env(args, job) |
1441 | + else: |
1442 | + raise DeviceException('no device, type or $JOBNAME specified.') |
1443 | + |
1444 | + |
1445 | +def _device_free(args): |
1446 | + if not os.path.exists(args.tokenfile): |
1447 | + raise DeviceException('tokenfile(%s) does not exist.' % args.tokenfile) |
1448 | + |
1449 | + lockfile = None |
1450 | + with open(args.tokenfile) as f: |
1451 | + for line in f.readlines(): |
1452 | + if line.startswith('LOCK_FILE='): |
1453 | + lockfile = line.split('=', 2)[1].strip() |
1454 | + break |
1455 | + |
1456 | + device_file = os.path.splitext(lockfile)[0] |
1457 | + with _device_pool(args): |
1458 | + logging.info('releasing lock for %s', device_file) |
1459 | + os.rename(lockfile, device_file) |
1460 | + os.unlink(args.tokenfile) |
1461 | + |
1462 | + |
1463 | +def _populate(args): |
1464 | + if os.path.exists(args.device_pool): |
1465 | + raise DeviceException('pool(%s) already exists.' % args.device_pool) |
1466 | + os.makedirs(args.device_pool) |
1467 | + |
1468 | + # jump through some hoops to import this module since it has dashes |
1469 | + # and doesn't have a .py extension |
1470 | + module = 'get-adb-id' |
1471 | + fname = os.path.join(os.path.dirname(__file__), module) |
1472 | + adb = imp.load_source(module, fname) |
1473 | + |
1474 | + # import the config |
1475 | + config_module = imp.load_source('config', args.config) |
1476 | + for config in config_module.MATRIX.values(): |
1477 | + for item in config: |
1478 | + for device in item['devices']: |
1479 | + name = device['name'] |
1480 | + serial = device.get('serial', None) |
1481 | + if not serial: |
1482 | + serial = adb.DEVICES[name] |
1483 | + with open(os.path.join(args.device_pool, name), 'w') as f: |
1484 | + f.write('ANDROID_SERIAL=%s' % serial) |
1485 | + |
1486 | + |
1487 | +def _get_args(): |
1488 | + parser = argparse.ArgumentParser( |
1489 | + description='''Provides a mechanism to aquire a lock on a device in |
1490 | + a given resource pool. The lock info will be written in |
1491 | + the format .device.<calling pid>. This file can be sourced |
1492 | + by a shell script to get ANDROID_SERIAL etc.''') |
1493 | + parser.add_argument('--device-pool', default='/var/lib/jenkins/ci-devices', |
1494 | + help='location of the device pool. %(default)s') |
1495 | + |
1496 | + sub = parser.add_subparsers(title='Commands', metavar='') |
1497 | + p = sub.add_parser('get', help='Aquire a lock on an idle device.') |
1498 | + grp = p.add_mutually_exclusive_group() |
1499 | + grp.add_argument('--name', help='Get device by name') |
1500 | + grp.add_argument('--type', help='Get device by type') |
1501 | + p.set_defaults(func=_device_get) |
1502 | + |
1503 | + p = sub.add_parser('free', help='Release a lock on a device.') |
1504 | + p.add_argument('--tokenfile', default=_get_tokenfile(), |
1505 | + help='token file for device reservation. %(default)s') |
1506 | + p.set_defaults(func=_device_free) |
1507 | + |
1508 | + p = sub.add_parser('populate', help='Initialize a device pool for usage') |
1509 | + p.add_argument('-c', '--config', required=True, |
1510 | + help='The jenkins config to find devices in.') |
1511 | + p.set_defaults(func=_populate) |
1512 | + |
1513 | + return parser.parse_args() |
1514 | + |
1515 | + |
1516 | +if __name__ == '__main__': |
1517 | + logging.basicConfig(level=logging.INFO) |
1518 | + args = _get_args() |
1519 | + rc = 0 |
1520 | + try: |
1521 | + args.func(args) |
1522 | + except DeviceException as e: |
1523 | + rc = 1 |
1524 | + print('ERROR: %s' % e) |
1525 | + sys.exit(rc) |
1526 | |
1527 | === added file 'scripts/get-adb-id' |
1528 | --- scripts/get-adb-id 1970-01-01 00:00:00 +0000 |
1529 | +++ scripts/get-adb-id 2014-01-15 20:49:07 +0000 |
1530 | @@ -0,0 +1,39 @@ |
1531 | +#!/usr/bin/python |
1532 | + |
1533 | +import sys |
1534 | + |
1535 | +DEVICES = { |
1536 | + "maguro-01": "0149BD7E0A019003", |
1537 | + "maguro-02": "0149BD7E0200E00F", |
1538 | + "maguro-03": "0149C7A50A00C011", |
1539 | + "maguro-04": "0149BDCC0500701B", |
1540 | + "maguro-05": "0149BD3418014013", |
1541 | + "maguro-06": "014E058C0F00C013", |
1542 | + "maguro-07": "01498FE717002014", |
1543 | + "mako-01": "01aa3d7a5dcba4a2", |
1544 | + "mako-02": "01ade38b552014d4", |
1545 | + "mako-03": "04c6714ed7c863f2", |
1546 | + "mako-05": "01b22f82dc5cec63", |
1547 | + "mako-06": "04ed70928fdc13ba", |
1548 | + "mako-07": "01e2f64788556934", |
1549 | + "mako-08": "04ea16a163930769", |
1550 | + "mako-10": "01ce848e48dfa6a2", |
1551 | + "mako-11": "04ed727c929709ba", |
1552 | + "grouper-02": "015d1884951c020e", |
1553 | + "grouper-03": "015d18ad5c27f80d", |
1554 | + "grouper-04": "015d188445242611", |
1555 | + "grouper-05": "015d21d9151c0019", |
1556 | + "manta-01": "R32D102RPZL", |
1557 | + "manta-02": "R32D102RPPK", |
1558 | + "manta-04": "R32D203DDZR", |
1559 | + "manta-05": "R32D203DMBY", |
1560 | +} |
1561 | + |
1562 | +if __name__ == '__main__': |
1563 | + name = sys.argv[1] |
1564 | + |
1565 | + try: |
1566 | + print(DEVICES[name]) |
1567 | + except KeyError: |
1568 | + print("Unknown device name: '%s'" % name) |
1569 | + sys.exit(-1) |
1570 | |
1571 | === added file 'scripts/jenkins.sh' |
1572 | --- scripts/jenkins.sh 1970-01-01 00:00:00 +0000 |
1573 | +++ scripts/jenkins.sh 2014-01-15 20:49:07 +0000 |
1574 | @@ -0,0 +1,186 @@ |
1575 | +#!/bin/bash |
1576 | + |
1577 | +## This is the script jenkins should run to execute various touch applications |
1578 | + |
1579 | +set -e |
1580 | + |
1581 | +BASEDIR=$(dirname $(readlink -f $0))/.. |
1582 | + |
1583 | +RESDIR="${RESDIR-`pwd`/clientlogs}" |
1584 | +UTAHFILE=${RESDIR}/utah.yaml |
1585 | +UTAH_PHABLET_CMD="${UTAH_PHABLET_CMD-/usr/share/utah/examples/run_utah_phablet.py}" |
1586 | + |
1587 | + |
1588 | +usage() { |
1589 | + cat <<EOF |
1590 | +usage: $0 -a APP [-s ANDROID_SERIAL] [-p FILE -p FILE ...] [-Q] |
1591 | + |
1592 | +Provisions the given device with the latest build |
1593 | + |
1594 | +OPTIONS: |
1595 | + -h Show this message |
1596 | + -s Specify the serial of the device to install |
1597 | + -a The application under the "tests" directory to test |
1598 | + -p Extra file to pull from target (absolute path or relative to /home/phablet) |
1599 | + -Q "Quick" don't do a reboot of the device before running the test |
1600 | + |
1601 | +EOF |
1602 | +} |
1603 | + |
1604 | +PIDS="" |
1605 | + |
1606 | +cleanup() { |
1607 | + set +e |
1608 | + echo "killing child pids: $PIDS" |
1609 | + for p in $PIDS ; do |
1610 | + kill $p |
1611 | + done |
1612 | +} |
1613 | + |
1614 | +test_from_host() { |
1615 | + export PATH=${BASEDIR}/utils/host:${PATH} |
1616 | + |
1617 | + # allow for certain commands to run from host/target |
1618 | + # see unity8-autopilot/ts_control for example |
1619 | + export TARGET_PREFIX=adb-shell |
1620 | + |
1621 | + [ -z $ANDROID_SERIAL ] || ADBOPTS="-s $ANDROID_SERIAL" |
1622 | + |
1623 | + sudo TARGET_PREFIX=$TARGET_PREFIX PATH="${PATH}" ${UTAH_PHABLET_CMD} \ |
1624 | + ${ADBOPTS} \ |
1625 | + --from-host \ |
1626 | + --whoopsie \ |
1627 | + --results-dir ${RESDIR} \ |
1628 | + --skip-install --skip-network --skip-utah \ |
1629 | + --pull /var/crash \ |
1630 | + --pull /home/phablet/.cache/upstart \ |
1631 | + --pull /tmp/xmlresults \ |
1632 | + $EXTRA_PULL \ |
1633 | + -l ${TESTSUITE_HOST}/master.run |
1634 | + |
1635 | + # make sure the user running this script can remove its artifacts. |
1636 | + sudo chown -R `whoami` ${RESDIR} |
1637 | +} |
1638 | + |
1639 | +assert_image() { |
1640 | + [ -z $INSTALL_URL ] && return |
1641 | + echo "Ensuring target has proper image..." |
1642 | + REQUIRED_UUID=$(curl ${INSTALL_URL}/artifact/clientlogs/.ci-uuid) |
1643 | + ACTUAL_UUID=$(adb shell "cat /home/phablet/.ci-uuid | tr -d '\r\n'") |
1644 | + if [ "$REQUIRED_UUID" != "$ACTUAL_UUID" ] ; then |
1645 | + echo "UUIDs $REQUIRED_UUID != $ACTUAL_UUID, reprovisioning device..." |
1646 | + ARGS=$(curl ${INSTALL_URL}/artifact/clientlogs/.ci-utah-args | tr -d '\r\n') |
1647 | + UUID=$REQUIRED_UUID IMAGE_OPT=$ARGS ${BASEDIR}/scripts/provision.sh |
1648 | + else |
1649 | + echo "UUIDS match" |
1650 | + fi |
1651 | +} |
1652 | + |
1653 | +main() { |
1654 | + rm -rf $RESDIR |
1655 | + mkdir $RESDIR |
1656 | + |
1657 | + assert_image |
1658 | + |
1659 | + # print the build date so the jenkins job can use it as the |
1660 | + # build description |
1661 | + adb pull /var/log/installer/media-info ${RESDIR} |
1662 | + BUILDID=$(adb shell cat /home/phablet/.ci-version) |
1663 | + echo "= TOUCH IMAGE VERSION:$BUILDID" |
1664 | + |
1665 | + adb shell "top -n1 -b" > ${RESDIR}/top.log |
1666 | + |
1667 | + set -x |
1668 | + adb shell 'rm -f /var/crash/*' |
1669 | + if [ -z $QUICK ] ; then |
1670 | + # get the phone in sane place |
1671 | + adb reboot |
1672 | + # sometimes reboot doesn't happen fast enough, so add a little |
1673 | + # delay to help ensure its actually rebooted and we didn't just |
1674 | + # connect back to the device before it rebooted |
1675 | + adb wait-for-device |
1676 | + sleep 5 |
1677 | + adb wait-for-device |
1678 | + phablet-network --skip-setup -t 90s |
1679 | + adb shell powerd-cli active & |
1680 | + PIDS="$PIDS $!" |
1681 | + adb shell powerd-cli display on & |
1682 | + PIDS="$PIDS $!" |
1683 | + else |
1684 | + echo "SKIPPING phone reboot..." |
1685 | + fi |
1686 | + |
1687 | + ${BASEDIR}/utils/host/adb-shell "aa-clickhook -f --include=/usr/share/autopilot-touch/apparmor/click.rules" |
1688 | + |
1689 | + echo "launching test from the host...." |
1690 | + test_from_host |
1691 | + adb shell 'rm -f /var/crash/*' |
1692 | + |
1693 | + if ! `grep "^errors: [!0]" < $UTAHFILE >/dev/null` ; then |
1694 | + echo "errors found" |
1695 | + EXITCODE=1 |
1696 | + fi |
1697 | + if ! `grep "^failures: [!0]" < $UTAHFILE >/dev/null` ; then |
1698 | + echo "failures found" |
1699 | + EXITCODE=2 |
1700 | + fi |
1701 | + echo "Results Summary" |
1702 | + echo "---------------" |
1703 | + egrep '^(errors|failures|passes|fetch_errors):' $UTAHFILE |
1704 | + exit $EXITCODE |
1705 | +} |
1706 | + |
1707 | +while getopts p:s:a:Qh opt; do |
1708 | + case $opt in |
1709 | + h) |
1710 | + usage |
1711 | + exit 0 |
1712 | + ;; |
1713 | + s) |
1714 | + export ANDROID_SERIAL=$OPTARG |
1715 | + ;; |
1716 | + a) |
1717 | + APP=$OPTARG |
1718 | + ;; |
1719 | + p) |
1720 | + EXTRA_PULL_FILE=$OPTARG |
1721 | + |
1722 | + if [ ! -z $EXTRA_PULL_FILE ]; then |
1723 | + # relative paths are assumed to be relative to /home/phablet |
1724 | + E_P_START=`echo $EXTRA_PULL_FILE | cut -c1` |
1725 | + |
1726 | + if [ $E_P_START = '/' ]; then |
1727 | + EXTRA_PULL="$EXTRA_PULL --pull $EXTRA_PULL_FILE" |
1728 | + else |
1729 | + EXTRA_PULL="$EXTRA_PULL --pull /home/phablet/$EXTRA_PULL_FILE" |
1730 | + fi |
1731 | + fi |
1732 | + ;; |
1733 | + Q) |
1734 | + QUICK=1 |
1735 | + ;; |
1736 | + esac |
1737 | +done |
1738 | + |
1739 | +if [ -z $ANDROID_SERIAL ] ; then |
1740 | + # ensure we only have one device attached |
1741 | + lines=$(adb devices | wc -l) |
1742 | + if [ $lines -gt 3 ] ; then |
1743 | + echo "ERROR: More than one device attached, please use -s option" |
1744 | + echo |
1745 | + usage |
1746 | + exit 1 |
1747 | + fi |
1748 | +fi |
1749 | +if [ -z $APP ] ; then |
1750 | + echo "ERROR: No app specified" |
1751 | + usage |
1752 | + exit 1 |
1753 | +fi |
1754 | + |
1755 | +TESTSUITE_HOST=$(readlink -f ${BASEDIR}/tests/${APP}) |
1756 | +TESTSUITE_TARGET_BASE=/tmp/tests |
1757 | +TESTSUITE_TARGET=${TESTSUITE_TARGET_BASE}/$(basename ${TESTSUITE_HOST}) |
1758 | + |
1759 | +trap cleanup TERM INT EXIT |
1760 | +main |
1761 | |
1762 | === added file 'scripts/provision.sh' |
1763 | --- scripts/provision.sh 1970-01-01 00:00:00 +0000 |
1764 | +++ scripts/provision.sh 2014-01-15 20:49:07 +0000 |
1765 | @@ -0,0 +1,126 @@ |
1766 | +#!/bin/bash |
1767 | + |
1768 | +## This is the script jenkins should run to provision a device in the lab |
1769 | + |
1770 | +set -e |
1771 | + |
1772 | +BASEDIR=$(dirname $(readlink -f $0)) |
1773 | + |
1774 | +RESDIR=`pwd`/clientlogs |
1775 | + |
1776 | +NETWORK_FILE="${NETWORK_FILE-/home/ubuntu/magners-wifi}" |
1777 | + |
1778 | +IMAGE_OPT="${IMAGE_OPT-ubuntu-system -b --channel trusty-proposed}" |
1779 | +UUID="${UUID-$(uuidgen -r)}" |
1780 | + |
1781 | +usage() { |
1782 | +cat <<EOF |
1783 | +usage: $0 [-s ANDROID_SERIAL] [-n NETWORK_FILE] [-P ppa] [-p package] [-w] |
1784 | + |
1785 | +Provisions the given device with the latest build |
1786 | + |
1787 | +OPTIONS: |
1788 | + -h Show this message |
1789 | + -s Specify the serial of the device to install |
1790 | + -n Select network file |
1791 | + -P add the ppa to the target (can be repeated) |
1792 | + -p add the package to the target (can be repeated) |
1793 | + -w make the system writeable (implied with -p and -P arguments) |
1794 | + |
1795 | +EOF |
1796 | +} |
1797 | + |
1798 | +image_info() { |
1799 | + # mark the version we installed in /home/phablet/.ci-[uuid,flash-args] |
1800 | + # adb shell messes up \n's with \r\n's so do the whole of the regex on the target |
1801 | + IMAGEVER=$(adb shell "system-image-cli -i | sed -n -e 's/version version: \([0-9]*\)/\1/p' -e 's/version ubuntu: \([0-9]*\)/\1/p' -e 's/version device: \([0-9]*\)/\1/p' | paste -s -d:") |
1802 | + CHAN=$(adb shell "system-image-cli -i | sed -n -e 's/channel: \(.*\)/\1/p' | paste -s -d:") |
1803 | + REV=$(echo $IMAGEVER | cut -d: -f1) |
1804 | + echo "$IMAGE_OPT" | grep -q "\-\-revision" || IMAGE_OPT="${IMAGE_OPT} --revision $REV" |
1805 | + echo "$IMAGE_OPT" | grep -q "\-\-channel" || IMAGE_OPT="${IMAGE_OPT} --channel $CHAN" |
1806 | + adb shell "echo '${IMAGEVER}' > /home/phablet/.ci-version" |
1807 | + echo $UUID > $RESDIR/.ci-uuid |
1808 | + adb push $RESDIR/.ci-uuid /home/phablet/ |
1809 | + cat > $RESDIR/.ci-flash-args <<EOF |
1810 | +$IMAGE_OPT |
1811 | +EOF |
1812 | + adb push $RESDIR/.ci-flash-args /home/phablet/.ci-flash-args |
1813 | + echo $CUSTOMIZE > $RESDIR/.ci-customizations |
1814 | + adb push $RESDIR/.ci-customizations /home/phablet/.ci-customizations |
1815 | +} |
1816 | + |
1817 | +log() { |
1818 | + echo = $(date): $* |
1819 | +} |
1820 | + |
1821 | +while getopts i:s:n:P:p:wh opt; do |
1822 | + case $opt in |
1823 | + h) |
1824 | + usage |
1825 | + exit 0 |
1826 | + ;; |
1827 | + n) |
1828 | + NETWORK_FILE=$OPTARG |
1829 | + ;; |
1830 | + s) |
1831 | + export ANDROID_SERIAL=$OPTARG |
1832 | + ;; |
1833 | + i) |
1834 | + IMAGE_TYPE=$OPTARG |
1835 | + ;; |
1836 | + w) |
1837 | + # making this a non-zero length string enables the logic |
1838 | + CUSTOMIZE=" " |
1839 | + ;; |
1840 | + P) |
1841 | + CUSTOMIZE="$CUSTOMIZE --ppa $OPTARG" |
1842 | + ;; |
1843 | + p) |
1844 | + CUSTOMIZE="$CUSTOMIZE -p $OPTARG" |
1845 | + ;; |
1846 | + esac |
1847 | +done |
1848 | + |
1849 | +if [ -z $ANDROID_SERIAL ] ; then |
1850 | + # ensure we only have one device attached |
1851 | + lines=$(adb devices | wc -l) |
1852 | + if [ $lines -gt 3 ] ; then |
1853 | + echo "ERROR: More than one device attached, please use -s option" |
1854 | + echo |
1855 | + usage |
1856 | + exit 1 |
1857 | + fi |
1858 | +fi |
1859 | + |
1860 | +set -x |
1861 | +[ -d $RESDIR ] && rm -rf $RESDIR |
1862 | +mkdir -p $RESDIR |
1863 | + |
1864 | +log "FLASHING DEVICE" |
1865 | +phablet-flash $IMAGE_OPT |
1866 | +adb wait-for-device |
1867 | +sleep 20 #give the system a little time |
1868 | + |
1869 | +log "SETTING UP CLICK PACKAGES" |
1870 | +phablet-click-test-setup |
1871 | + |
1872 | +log "SETTING UP WIFI" |
1873 | +phablet-network -n $NETWORK_FILE |
1874 | + |
1875 | +if [ "$IMAGE_TYPE" = "touch_sf4p" ]; then |
1876 | + adb shell rm -f /home/phablet/.display-mir |
1877 | +fi |
1878 | + |
1879 | +phablet-config edges-intro --disable |
1880 | + |
1881 | +# get our target-based utilities into our PATH |
1882 | +adb push ${BASEDIR}/../utils/target /home/phablet/bin |
1883 | + |
1884 | +image_info |
1885 | + |
1886 | +if [ -n "$CUSTOMIZE" ] ; then |
1887 | + log "CUSTOMIZING IMAGE" |
1888 | + phablet-config writable-image $CUSTOMIZE |
1889 | + # Make sure whoopsie-upload-all can work (bug #1245524) |
1890 | + adb shell "sed -i '/Waiting for whoopsie/ a\ subprocess.call([\"restart\", \"whoopsie\"])' /usr/share/apport/whoopsie-upload-all" |
1891 | +fi |
1892 | |
1893 | === added file 'scripts/reboot-and-wait' |
1894 | --- scripts/reboot-and-wait 1970-01-01 00:00:00 +0000 |
1895 | +++ scripts/reboot-and-wait 2014-01-15 20:49:07 +0000 |
1896 | @@ -0,0 +1,41 @@ |
1897 | +#!/usr/bin/python |
1898 | + |
1899 | +import argparse |
1900 | +import logging |
1901 | +import time |
1902 | + |
1903 | +from phabletutils.device import AndroidBridge |
1904 | + |
1905 | + |
1906 | +def _get_arg_parser(): |
1907 | + parser = argparse.ArgumentParser( |
1908 | + description='Reboot device and waits for networking to become active.') |
1909 | + parser.add_argument('-s', '--serial', help='Device serial') |
1910 | + parser.add_argument('-n', '--num-tries', type=int, default=3, |
1911 | + help='''How many times to retry on failure. |
1912 | + default=%(default)d''') |
1913 | + return parser |
1914 | + |
1915 | + |
1916 | +def main(args): |
1917 | + device = AndroidBridge(args.serial) |
1918 | + device.wait_for_device() |
1919 | + for i in range(args.num_tries): |
1920 | + device.reboot() |
1921 | + device.wait_for_device() |
1922 | + time.sleep(5) |
1923 | + device.wait_for_device() |
1924 | + try: |
1925 | + device.wait_for_network() |
1926 | + return 0 |
1927 | + except: |
1928 | + pass # try the loop again |
1929 | + logging.error('device failed to start and activate networking') |
1930 | + return 1 |
1931 | + |
1932 | + |
1933 | +if __name__ == '__main__': |
1934 | + logging.basicConfig(level=logging.INFO) |
1935 | + logging.getLogger().name = 'reboot-and-wait' |
1936 | + args = _get_arg_parser().parse_args() |
1937 | + exit(main(args)) |
1938 | |
1939 | === added file 'scripts/run-autopilot-tests.sh' |
1940 | --- scripts/run-autopilot-tests.sh 1970-01-01 00:00:00 +0000 |
1941 | +++ scripts/run-autopilot-tests.sh 2014-01-15 20:49:07 +0000 |
1942 | @@ -0,0 +1,185 @@ |
1943 | +#!/bin/sh |
1944 | + |
1945 | +set -e |
1946 | + |
1947 | +BASEDIR=$(dirname $(readlink -f $0))/.. |
1948 | +RESDIR=`pwd`/clientlogs |
1949 | + |
1950 | +export PATH=${BASEDIR}/utils/host:${PATH} |
1951 | +export TARGET_PREFIX=adb-shell |
1952 | + |
1953 | + |
1954 | +usage() { |
1955 | + cat <<EOF |
1956 | +usage: $0 -a APP [-s ANDROID_SERIAL] [-Q] [-o results_dir] [-S] |
1957 | + |
1958 | +Runs a set of autopilot tests on the target |
1959 | + |
1960 | +OPTIONS: |
1961 | + -h Show this message |
1962 | + -s Specify the serial of the device to test |
1963 | + -a The application to test (can be repeated) |
1964 | + -o Specify the directory to place results in. |
1965 | + Default: $RESDIR |
1966 | + -Q "Quick" don't do a reboot of the device before/between testsuites. |
1967 | + -S Skip the system-settle tests that run before/after each testsuite. |
1968 | + |
1969 | +EOF |
1970 | +} |
1971 | + |
1972 | +log_error() { |
1973 | + echo ERROR: $* >> ${RESDIR}/runner-errors.txt |
1974 | +} |
1975 | + |
1976 | +system_settle() { |
1977 | + [ -z $NOSETTLE ] || return 0 |
1978 | + |
1979 | + label=$1 |
1980 | + odir=$2 |
1981 | + rc=0 |
1982 | + settle=${BASEDIR}/tests/systemsettle/systemsettle.sh |
1983 | + { |
1984 | + export UTAH_PROBE_DIR=${odir} # needed for log file location |
1985 | + timeout 120s $settle -c5 -d6 -p 97.5 -l $label || rc=1 |
1986 | + echo $rc > ${odir}/settle_${label}.rc |
1987 | + } 2>&1 | tee ${odir}/settle_${label}.log |
1988 | + |
1989 | + if [ "$label" = "after" ] ; then |
1990 | + ${BASEDIR}/scripts/combine_results ${odir} |
1991 | + fi |
1992 | +} |
1993 | + |
1994 | +test_app() { |
1995 | + app=$1 |
1996 | + |
1997 | + odir=${RESDIR}/${app} |
1998 | + [ -d $odir ] && rm -rf $odir |
1999 | + mkdir -p $odir || return 1 |
2000 | + |
2001 | + system_settle before $odir |
2002 | + phablet-config autopilot --dbus-probe enable || \ |
2003 | + (log_error "'autopilot dbus-probe enable' failed"; return 1) |
2004 | + |
2005 | + NOSHELL="" |
2006 | + [ "$app" = "unity8" ] && NOSHELL="-n" |
2007 | + |
2008 | + if adb-shell /home/phablet/bin/unlock_screen.sh ; then |
2009 | + phablet-test-run \ |
2010 | + $NOSHELL \ |
2011 | + -o ${odir} \ |
2012 | + -a /var/crash -a /home/phablet/.cache/upstart \ |
2013 | + -v $app || true |
2014 | + else |
2015 | + log_error "screen unlock failed, skipping $app" |
2016 | + fi |
2017 | + system_settle after $odir |
2018 | +} |
2019 | + |
2020 | +reboot_wait() { |
2021 | + if [ -z $QUICK ] ; then |
2022 | + ${BASEDIR}/scripts/reboot-and-wait |
2023 | + files="/var/crash/* /home/phablet/.cache/upstart/*.log" |
2024 | + if ! adb shell rm -rf "$FILES" ; then |
2025 | + log_error "unable to remove crash and log files, retrying" |
2026 | + adb wait-for-device |
2027 | + adb shell rm -rf "$FILES" |
2028 | + fi |
2029 | + else |
2030 | + echo "SKIPPING phone reboot..." |
2031 | + fi |
2032 | +} |
2033 | + |
2034 | +grab_powerd() { |
2035 | + echo "grabbing powerd cli locks..." |
2036 | + adb shell powerd-cli active & |
2037 | + PIDS="$!" |
2038 | + adb shell powerd-cli display on & |
2039 | + PIDS="$PIDS $!" |
2040 | +} |
2041 | + |
2042 | +release_powerd() { |
2043 | + if [ -n "$PIDS" ] ; then |
2044 | + echo "killing child pids: $PIDS" |
2045 | + for p in $PIDS ; do |
2046 | + kill $p || true |
2047 | + done |
2048 | + PIDS="" |
2049 | + fi |
2050 | +} |
2051 | + |
2052 | +main() { |
2053 | + # print the build date so the jenkins job can use it as the |
2054 | + # build description |
2055 | + BUILDID=$(adb shell cat /home/phablet/.ci-version) |
2056 | + echo "= TOUCH IMAGE VERSION:$BUILDID" |
2057 | + |
2058 | + [ -d $RESDIR ] || mkdir -p $RESDIR |
2059 | + |
2060 | + set -x |
2061 | + |
2062 | + for app in $APPS ; do |
2063 | + set +x |
2064 | + echo "========================================================" |
2065 | + echo "= testing $app" |
2066 | + echo "========================================================" |
2067 | + set -x |
2068 | + reboot_wait |
2069 | + |
2070 | + grab_powerd |
2071 | + |
2072 | + if ! test_app $app ; then |
2073 | + log_error "testing $app, retrying" |
2074 | + # we sometimes see sporatic adb failures that seem to |
2075 | + # related to MTP. This adds a retry for the test. |
2076 | + # test_app only fails on a device error (not a test |
2077 | + # case error) |
2078 | + adb wait-for-device |
2079 | + test_app $app |
2080 | + fi |
2081 | + |
2082 | + release_powerd |
2083 | + done |
2084 | +} |
2085 | + |
2086 | +while getopts s:a:o:QSh opt; do |
2087 | + case $opt in |
2088 | + h) |
2089 | + usage |
2090 | + exit 0 |
2091 | + ;; |
2092 | + s) |
2093 | + export ANDROID_SERIAL=$OPTARG |
2094 | + ;; |
2095 | + o) |
2096 | + RESDIR=$OPTARG |
2097 | + ;; |
2098 | + a) |
2099 | + APPS="$APPS $OPTARG" |
2100 | + ;; |
2101 | + Q) |
2102 | + QUICK=1 |
2103 | + ;; |
2104 | + S) |
2105 | + NOSETTLE=1 |
2106 | + ;; |
2107 | + esac |
2108 | +done |
2109 | + |
2110 | +if [ -z $ANDROID_SERIAL ] ; then |
2111 | + # ensure we only have one device attached |
2112 | + lines=$(adb devices | wc -l) |
2113 | + if [ $lines -gt 3 ] ; then |
2114 | + echo "ERROR: More than one device attached, please use -s option" |
2115 | + echo |
2116 | + usage |
2117 | + exit 1 |
2118 | + fi |
2119 | +fi |
2120 | +if [ -z "$APPS" ] ; then |
2121 | + echo "ERROR: No app specified" |
2122 | + usage |
2123 | + exit 1 |
2124 | +fi |
2125 | + |
2126 | +trap release_powerd TERM INT EXIT |
2127 | +main |
2128 | |
2129 | === added file 'scripts/run-smoke' |
2130 | --- scripts/run-smoke 1970-01-01 00:00:00 +0000 |
2131 | +++ scripts/run-smoke 2014-01-15 20:49:07 +0000 |
2132 | @@ -0,0 +1,221 @@ |
2133 | +#!/usr/bin/python |
2134 | + |
2135 | +import argparse |
2136 | +import logging |
2137 | +import os |
2138 | +import shutil |
2139 | +import subprocess |
2140 | + |
2141 | +import statsd |
2142 | + |
2143 | +log = logging.getLogger() |
2144 | +script_dir = os.path.dirname(__file__) |
2145 | +res_dir = os.path.join(os.getcwd(), 'clientlogs') |
2146 | + |
2147 | + |
2148 | +class SerialAction(argparse.Action): |
2149 | + def __call__(self, parser, namespace, values, option_string=None): |
2150 | + log.info('android serial: %s', values[0]) |
2151 | + os.environ['ANDROID_SERIAL'] = values[0] |
2152 | + |
2153 | + |
2154 | +class DebugAction(argparse.Action): |
2155 | + def __call__(self, parser, namespace, values, option_string=None): |
2156 | + log.setLevel(level=logging.DEBUG) |
2157 | + log.debug('debug logging enabled') |
2158 | + |
2159 | + |
2160 | +def _serial_required(): |
2161 | + required = 'ANDROID_SERIAL' not in os.environ |
2162 | + if required: |
2163 | + try: |
2164 | + out = subprocess.check_output(['adb', 'devices']) |
2165 | + required = (len(out.decode().split('\n')) != 4) |
2166 | + except subprocess.CalledProcessError as e: |
2167 | + logging.debug('error getting adb devices: %s', e) |
2168 | + return required |
2169 | + |
2170 | + |
2171 | +def _get_parser(): |
2172 | + parser = argparse.ArgumentParser( |
2173 | + description='Run the complete test-execution-service suite.') |
2174 | + |
2175 | + parser.add_argument('-s', '--serial', action=SerialAction, nargs=1, |
2176 | + required=_serial_required(), |
2177 | + help='Android serial if more than one device present') |
2178 | + parser.add_argument('--debug', action=DebugAction, nargs=0, |
2179 | + help='''Enable debug logging.''') |
2180 | + |
2181 | + parser.add_argument('--install-url', |
2182 | + help='''Flash with image from previous jenkins job. |
2183 | + This option will check if the device already has image |
2184 | + noted from this URL and will skip provisioning. The URL |
2185 | + should be the path the job like: |
2186 | + http://q-jenkins:8080/job/<your job>/<build number>''') |
2187 | + parser.add_argument('-p', '--package', action='append', |
2188 | + help='Additional packages to install on target.') |
2189 | + parser.add_argument('-P', '--ppa', action='append', |
2190 | + help='Additional PPA to configure on target.') |
2191 | + parser.add_argument('-a', '--app', action='append', |
2192 | + help='Autopilot tests tor run.') |
2193 | + parser.add_argument('-t', '--test', action='append', |
2194 | + help='UTAH tests tor run.') |
2195 | + parser.add_argument('--image-opt', |
2196 | + help='Options to pass to phablet-flash') |
2197 | + parser.add_argument('--image-type', default='touch', |
2198 | + help='''Image type being tested. This can be changed |
2199 | + to 'touch_sf4p' so that SurfaceFlinger will be used |
2200 | + instead of Mir. default=%(default)s''') |
2201 | + return parser |
2202 | + |
2203 | + |
2204 | +def _arg_from_env(args, attr, envkey, array): |
2205 | + val = os.environ.get(envkey, False) |
2206 | + if val: |
2207 | + if array: |
2208 | + setattr(args, attr, val.split()) |
2209 | + else: |
2210 | + setattr(args, attr, val) |
2211 | + del os.environ[envkey] |
2212 | + |
2213 | + |
2214 | +def _merge_env(args): |
2215 | + '''When run in Jenkins everything comes as environment variables. |
2216 | + |
2217 | + Its makes a much simpler job this way. While command line args are |
2218 | + much easier for a user. |
2219 | + ''' |
2220 | + _arg_from_env(args, 'app', 'APPS', True) |
2221 | + _arg_from_env(args, 'test', 'TESTS', True) |
2222 | + _arg_from_env(args, 'package', 'PACKAGES', True) |
2223 | + _arg_from_env(args, 'ppa', 'PPAS', True) |
2224 | + _arg_from_env(args, 'image_opt', 'IMAGE_OPT', False) |
2225 | + _arg_from_env(args, 'image_type', 'IMAGE_TYPE', False) |
2226 | + _arg_from_env(args, 'install_url', 'INSTALL_URL', False) |
2227 | + |
2228 | + |
2229 | +def _assert_args(args): |
2230 | + if args.install_url: |
2231 | + # this means you shouldn't specify packages, ppas, or image options |
2232 | + if args.package or args.ppa or args.image_opt: |
2233 | + msg = 'ERROR: --install-url can\'t be used with ' \ |
2234 | + '--package, -ppa, or --image_opt' |
2235 | + print(msg) |
2236 | + return False |
2237 | + |
2238 | + # don't bother the install_url check, a user might be copy/pasting and |
2239 | + # doesn't hurt. Its just good to not encourage it. |
2240 | + _merge_env(args) |
2241 | + |
2242 | + script = os.path.join(script_dir, '../jenkins/testconfig.py') |
2243 | + if args.package and args.package[0] == 'ALL': |
2244 | + logging.info('Discovering all required dependencies') |
2245 | + out = subprocess.check_output( |
2246 | + [script, 'packages', '-i', args.image_type]) |
2247 | + args.package = [x for x in out.decode().split()] |
2248 | + |
2249 | + if args.app and args.app[0] == 'ALL': |
2250 | + logging.info('Discovering all autopilot tests') |
2251 | + out = subprocess.check_output( |
2252 | + [script, 'apps', '-i', args.image_type]) |
2253 | + args.app = [x for x in out.decode().split()] |
2254 | + |
2255 | + if args.test and args.test[0].startswith('ALL'): |
2256 | + logging.info('Discovering all UTAH tests') |
2257 | + argv = [script, 'utah', '-i', args.image_type] |
2258 | + if args.test[0] == 'ALL_INCLUDING_AUTOPILOT': |
2259 | + argv.append('-a') |
2260 | + out = subprocess.check_output(argv) |
2261 | + args.test = [x for x in out.decode().split()] |
2262 | + |
2263 | + logging.debug('ARGS: %r', args) |
2264 | + |
2265 | + statsd.gauge_it('PACKAGES', args.package) |
2266 | + statsd.gauge_it('APPS', args.app) |
2267 | + statsd.gauge_it('TESTS', args.test) |
2268 | + |
2269 | + return True |
2270 | + |
2271 | + |
2272 | +def _run(args, ignore_error=False): |
2273 | + try: |
2274 | + logging.info('Running: %s', ' '.join(args)) |
2275 | + subprocess.check_call(args) |
2276 | + except subprocess.CalledProcessError: |
2277 | + if ignore_error: |
2278 | + logging.error('failed to run %r, continuing', args) |
2279 | + else: |
2280 | + exit(1) |
2281 | + |
2282 | + |
2283 | +def _assert_image(args): |
2284 | + log.info('checking if device has proper image ...') |
2285 | + os.environ['INSTALL_URL'] = args.install_url |
2286 | + _run([os.path.join(script_dir, 'assert-image')]) |
2287 | + |
2288 | + |
2289 | +def _provision(args): |
2290 | + log.info('provisioning device ...') |
2291 | + if args.image_opt: |
2292 | + log.debug('overriding IMAGE_OPT with: %s', args.image_opt) |
2293 | + os.environ['IMAGE_OPT'] = args.image_opt |
2294 | + |
2295 | + cargs = [os.path.join(script_dir, 'provision.sh'), '-i', args.image_type] |
2296 | + |
2297 | + if args.package: |
2298 | + for p in args.package: |
2299 | + cargs.extend(['-p', p]) |
2300 | + if args.ppa: |
2301 | + for p in args.ppa: |
2302 | + cargs.extend(['-P', p]) |
2303 | + |
2304 | + with statsd.time_it('provision'): |
2305 | + _run(cargs) |
2306 | + |
2307 | + |
2308 | +def _test_autopilot(args): |
2309 | + if args.app: |
2310 | + cargs = [os.path.join(script_dir, 'run-autopilot-tests.sh')] |
2311 | + for app in args.app: |
2312 | + cargs.extend(['-a', app]) |
2313 | + with statsd.time_it('APPS'): |
2314 | + _run(cargs) |
2315 | + |
2316 | + |
2317 | +def _test_utah(args): |
2318 | + if args.test: |
2319 | + cargs = [os.path.join(script_dir, 'jenkins.sh')] |
2320 | + with statsd.time_it('TESTS'): |
2321 | + for test in args.test: |
2322 | + os.environ['RESDIR'] = os.path.join(res_dir, test) |
2323 | + _run(cargs + ['-a', test], ignore_error=True) |
2324 | + |
2325 | + |
2326 | +def main(args): |
2327 | + with statsd.time_it('main'): |
2328 | + if os.path.exists(res_dir): |
2329 | + logging.info('deleting old result directory: %s', res_dir) |
2330 | + shutil.rmtree(res_dir) |
2331 | + os.mkdir(res_dir) |
2332 | + |
2333 | + if args.install_url: |
2334 | + _assert_image(args) |
2335 | + else: |
2336 | + _provision(args) |
2337 | + |
2338 | + _test_autopilot(args) |
2339 | + |
2340 | + _test_utah(args) |
2341 | + |
2342 | + return 0 |
2343 | + |
2344 | + |
2345 | +if __name__ == '__main__': |
2346 | + logging.basicConfig(level=logging.INFO) |
2347 | + log.name = 'run-smoke' |
2348 | + |
2349 | + args = _get_parser().parse_args() |
2350 | + if not _assert_args(args): |
2351 | + exit(1) |
2352 | + |
2353 | + exit(main(args)) |
2354 | |
2355 | === added file 'scripts/run-touch-upgrade.sh' |
2356 | --- scripts/run-touch-upgrade.sh 1970-01-01 00:00:00 +0000 |
2357 | +++ scripts/run-touch-upgrade.sh 2014-01-15 20:49:07 +0000 |
2358 | @@ -0,0 +1,46 @@ |
2359 | +#!/bin/bash |
2360 | + |
2361 | +## This is the script jenkins should run to test upgrading a system image |
2362 | +## in the lab. |
2363 | +## Intersting environment variables that must be set: |
2364 | +## ANDROID_SERIAL - specify another android device |
2365 | +## RUNLIST - the path the runlist |
2366 | +## NETWORK_FILE - specify an alternative network file (passed to runlist) |
2367 | +## UPGRADE_FROM - the revision to upgrade from, eg -1 (passed to runlist) |
2368 | + |
2369 | +set -eux |
2370 | + |
2371 | +BASEDIR=$(dirname $(readlink -f $0)) |
2372 | + |
2373 | +RESDIR=`pwd`/clientlogs |
2374 | + |
2375 | +UTAH_PHABLET_CMD="${UTAH_PHABLET_CMD-/usr/share/utah/examples/run_utah_phablet.py}" |
2376 | +RUNLIST=${RUNLIST-"`pwd`/smoke-touch-apps/upgrade/master.run"} |
2377 | +ANDROID_SERIAL="${ANDROID_SERIAL-015d1884b20c1c0f}" #doanac's nexus7 at home |
2378 | +NETWORK_FILE="${NETWORK_FILE-/home/ubuntu/magners-wifi}" |
2379 | + |
2380 | +rm -rf clientlogs |
2381 | +mkdir clientlogs |
2382 | + |
2383 | +export ANDROID_SERIAL=$ANDROID_SERIAL |
2384 | + |
2385 | +set +e |
2386 | +sudo NETWORK_FILE=$NETWORK_FILE \ |
2387 | + $UTAH_PHABLET_CMD -s $ANDROID_SERIAL \ |
2388 | + --from-host --skip-install --skip-utah --skip-network -l $RUNLIST \ |
2389 | + --results-dir=$RESDIR |
2390 | +EXITCODE=$? |
2391 | + |
2392 | +UTAHFILE=$RESDIR/utah.yaml |
2393 | +if ! `grep "^errors: [!0]" < $UTAHFILE >/dev/null` ; then |
2394 | + echo "errors found" |
2395 | + EXITCODE=1 |
2396 | +fi |
2397 | +if ! `grep "^failures: [!0]" < $UTAHFILE >/dev/null` ; then |
2398 | + echo "failures found" |
2399 | + EXITCODE=2 |
2400 | +fi |
2401 | +echo "Results Summary" |
2402 | +echo "---------------" |
2403 | +egrep '^(errors|failures|passes|fetch_errors):' $UTAHFILE |
2404 | +exit $EXITCODE |
2405 | |
2406 | === added file 'scripts/statsd.py' |
2407 | --- scripts/statsd.py 1970-01-01 00:00:00 +0000 |
2408 | +++ scripts/statsd.py 2014-01-15 20:49:07 +0000 |
2409 | @@ -0,0 +1,35 @@ |
2410 | +#!/usr/bin/python |
2411 | + |
2412 | +import os |
2413 | +import contextlib |
2414 | +import time |
2415 | + |
2416 | + |
2417 | +_namespace = os.environ.get('STATSD_KEY') |
2418 | +if _namespace: |
2419 | + from txstatsd.client import UdpStatsDClient |
2420 | + from txstatsd.metrics.timermetric import TimerMetric |
2421 | + from txstatsd.metrics.gaugemetric import GaugeMetric |
2422 | + _host = os.environ.get('SERVER', 'snakefruit.canonical.com') |
2423 | + _port = int(os.environ.get('PORT', '10041')) |
2424 | + _client = UdpStatsDClient(_host, _port) |
2425 | + _client.connect() |
2426 | + |
2427 | + |
2428 | +@contextlib.contextmanager |
2429 | +def time_it(key): |
2430 | + start = time.time() |
2431 | + try: |
2432 | + yield |
2433 | + finally: |
2434 | + if _namespace: |
2435 | + m = TimerMetric(_client, _namespace + '.' + key) |
2436 | + m.mark(time.time() - start) |
2437 | + |
2438 | + |
2439 | +def gauge_it(key, array): |
2440 | + val = 0 |
2441 | + if array: |
2442 | + val = len(array) |
2443 | + if _namespace: |
2444 | + GaugeMetric(_client, _namespace + '.' + key).mark(val) |
2445 | |
2446 | === added directory 'selftests' |
2447 | === added file 'selftests/test_reboot_and_wait.py' |
2448 | --- selftests/test_reboot_and_wait.py 1970-01-01 00:00:00 +0000 |
2449 | +++ selftests/test_reboot_and_wait.py 2014-01-15 20:49:07 +0000 |
2450 | @@ -0,0 +1,66 @@ |
2451 | +# Ubuntu Test Cases for Touch |
2452 | +# Copyright 2013 Canonical Ltd. |
2453 | + |
2454 | +# This program is free software: you can redistribute it and/or modify it |
2455 | +# under the terms of the GNU General Public License version 3, as published |
2456 | +# by the Free Software Foundation. |
2457 | + |
2458 | +# This program is distributed in the hope that it will be useful, but |
2459 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
2460 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2461 | +# PURPOSE. See the GNU General Public License for more details. |
2462 | + |
2463 | +# You should have received a copy of the GNU General Public License along |
2464 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
2465 | + |
2466 | +from __future__ import print_function |
2467 | + |
2468 | +import imp |
2469 | +import mock |
2470 | +import os |
2471 | +import unittest |
2472 | + |
2473 | + |
2474 | +class TestRebootAndWait(unittest.TestCase): |
2475 | + |
2476 | + """Simple set of tests to make sure the reboot-and-wait command works.""" |
2477 | + |
2478 | + def setUp(self): |
2479 | + # do some trickery to load this as module |
2480 | + module = 'reboot-and-wait' |
2481 | + fname = os.path.join(os.path.dirname(__file__), '../scripts', module) |
2482 | + m = imp.load_source(module, fname) |
2483 | + self._main = m.main |
2484 | + self._get_parser = m._get_arg_parser |
2485 | + |
2486 | + @mock.patch('phabletutils.device.AndroidBridge.reboot') |
2487 | + def testRebootFail(self, reboot): |
2488 | + reboot.side_effect = RuntimeError('foo') |
2489 | + args = self._get_parser().parse_args([]) |
2490 | + with self.assertRaisesRegexp(RuntimeError, 'foo'): |
2491 | + self._main(args) |
2492 | + |
2493 | + @mock.patch('phabletutils.device.AndroidBridge.reboot') |
2494 | + @mock.patch('phabletutils.device.AndroidBridge.wait_for_device') |
2495 | + def testWaitForDeviceFail(self, wait_for, reboot): |
2496 | + wait_for.side_effect = RuntimeError('foo') |
2497 | + args = self._get_parser().parse_args([]) |
2498 | + with self.assertRaisesRegexp(RuntimeError, 'foo'): |
2499 | + self._main(args) |
2500 | + reboot.assert_called_once_with() |
2501 | + |
2502 | + @mock.patch('phabletutils.device.AndroidBridge.reboot') |
2503 | + @mock.patch('phabletutils.device.AndroidBridge.wait_for_device') |
2504 | + @mock.patch('phabletutils.device.AndroidBridge.wait_for_network') |
2505 | + def testRetries(self, wait_for_net, wait_for_dev, reboot): |
2506 | + args = self._get_parser().parse_args([]) |
2507 | + wait_for_net.side_effect = RuntimeError('foo') |
2508 | + self.assertEquals(1, self._main(args)) |
2509 | + self.assertEquals(args.num_tries, reboot.call_count) |
2510 | + |
2511 | + # now make sure it can recover after a single network failure |
2512 | + reboot.reset_mock() |
2513 | + wait_for_net.reset_mock() |
2514 | + wait_for_net.side_effect = [RuntimeError('foo'), None] |
2515 | + self.assertEquals(0, self._main(args)) |
2516 | + self.assertEquals(2, reboot.call_count) |
2517 | |
2518 | === added file 'selftests/test_run_smoke.py' |
2519 | --- selftests/test_run_smoke.py 1970-01-01 00:00:00 +0000 |
2520 | +++ selftests/test_run_smoke.py 2014-01-15 20:49:07 +0000 |
2521 | @@ -0,0 +1,141 @@ |
2522 | +# Ubuntu Test Cases for Touch |
2523 | +# Copyright 2013 Canonical Ltd. |
2524 | + |
2525 | +# This program is free software: you can redistribute it and/or modify it |
2526 | +# under the terms of the GNU General Public License version 3, as published |
2527 | +# by the Free Software Foundation. |
2528 | + |
2529 | +# This program is distributed in the hope that it will be useful, but |
2530 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
2531 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2532 | +# PURPOSE. See the GNU General Public License for more details. |
2533 | + |
2534 | +# You should have received a copy of the GNU General Public License along |
2535 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
2536 | + |
2537 | +import imp |
2538 | +import mock |
2539 | +import os |
2540 | +import subprocess |
2541 | +import sys |
2542 | +import unittest |
2543 | + |
2544 | + |
2545 | +class TestRunSmoke(unittest.TestCase): |
2546 | + |
2547 | + """Simple set of tests to make sure the smoke-run command works.""" |
2548 | + |
2549 | + def setUp(self): |
2550 | + # load the module |
2551 | + module = 'run-smoke' |
2552 | + path = os.path.join(os.path.dirname(__file__), '../scripts') |
2553 | + sys.path.append(path) |
2554 | + fname = os.path.join(path, module) |
2555 | + self.run_smoke = imp.load_source(module, fname) |
2556 | + if 'ANDROID_SERIAL' in os.environ: |
2557 | + del os.environ['ANDROID_SERIAL'] |
2558 | + |
2559 | + @mock.patch.dict('os.environ') |
2560 | + @mock.patch('subprocess.check_output') |
2561 | + def testSerialRequired(self, check_output): |
2562 | + '''Ensure android serial is required when appropriate''' |
2563 | + check_output.return_value = '1'.encode() |
2564 | + self.assertTrue(self.run_smoke._serial_required()) |
2565 | + |
2566 | + check_output.return_value = '1\n2\n3\n4'.encode() |
2567 | + self.assertFalse(self.run_smoke._serial_required()) |
2568 | + |
2569 | + check_output.return_value = '1\n2\n3\n4\n5'.encode() |
2570 | + self.assertTrue(self.run_smoke._serial_required()) |
2571 | + |
2572 | + # make sure serial isn't required if specified in env |
2573 | + os.environ['ANDROID_SERIAL'] = 'foo' |
2574 | + check_output.return_value = '1\n2\n3\n4\n5'.encode() |
2575 | + self.assertFalse(self.run_smoke._serial_required()) |
2576 | + |
2577 | + @mock.patch('statsd.gauge_it') |
2578 | + def testAssertArgs(self, gauge): |
2579 | + '''Ensure install-url is used properly''' |
2580 | + patterns = [ |
2581 | + (['--install-url', 'x', '-p', 'x'], False), |
2582 | + (['--install-url', 'x', '-P', 'x'], False), |
2583 | + (['--install-url', 'x', '--image-opt', 'x'], False), |
2584 | + (['-p', 'x', '-P', 'x', '--image-opt', 'x'], True), |
2585 | + ] |
2586 | + for pat, val in patterns: |
2587 | + args = self.run_smoke._get_parser().parse_args(['-s', 'foo'] + pat) |
2588 | + self.assertEqual(val, self.run_smoke._assert_args(args)) |
2589 | + |
2590 | + # ensure the -p ALL pulls in all packages |
2591 | + gauge.reset_mock() |
2592 | + args = self.run_smoke._get_parser().parse_args(['-p', 'ALL']) |
2593 | + self.assertTrue(self.run_smoke._assert_args(args)) |
2594 | + self.assertTrue(len(args.package) > 1) |
2595 | + args = gauge.call_args_list[0][0] |
2596 | + self.assertEqual('PACKAGES', args[0]) |
2597 | + self.assertLess(1, len(args[1])) |
2598 | + |
2599 | + args = gauge.call_args_list[1][0] |
2600 | + self.assertEqual('APPS', args[0]) |
2601 | + self.assertIsNone(args[1]) |
2602 | + args = gauge.call_args_list[2][0] |
2603 | + self.assertEqual('TESTS', args[0]) |
2604 | + self.assertIsNone(args[1]) |
2605 | + |
2606 | + # don't bother checking gauge calls for the remaining "ALL" tests |
2607 | + |
2608 | + # ensure the -a ALL pulls in all APPS |
2609 | + args = self.run_smoke._get_parser().parse_args(['-a', 'ALL']) |
2610 | + self.assertTrue(self.run_smoke._assert_args(args)) |
2611 | + self.assertTrue(len(args.app) > 1) |
2612 | + |
2613 | + # ensure the -t ALL pulls in all TESTS |
2614 | + args = self.run_smoke._get_parser().parse_args(['-t', 'ALL']) |
2615 | + self.assertTrue(self.run_smoke._assert_args(args)) |
2616 | + self.assertTrue(len(args.test) > 1) |
2617 | + |
2618 | + def testAssertArgsEnv(self): |
2619 | + '''Ensure we pull in environment variables that jenkins uses.''' |
2620 | + with mock.patch.dict('os.environ'): |
2621 | + os.environ['APPS'] = 'apps' |
2622 | + os.environ['TESTS'] = 'tests' |
2623 | + os.environ['PACKAGES'] = 'packages' |
2624 | + os.environ['PPAS'] = 'ppas' |
2625 | + os.environ['IMAGE_TYPE'] = 'type' |
2626 | + os.environ['INSTALL_URL'] = 'url' |
2627 | + os.environ['IMAGE_OPT'] = 'opts opts' |
2628 | + os.environ['ANDROID_SERIAL'] = 'foo' |
2629 | + |
2630 | + args = self.run_smoke._get_parser().parse_args([]) |
2631 | + self.assertTrue(self.run_smoke._assert_args(args)) |
2632 | + |
2633 | + self.assertEqual(args.app, ['apps']) |
2634 | + self.assertEqual(args.test, ['tests']) |
2635 | + self.assertEqual(args.package, ['packages']) |
2636 | + self.assertEqual(args.ppa, ['ppas']) |
2637 | + self.assertEqual(args.image_type, 'type') |
2638 | + self.assertEqual(args.install_url, 'url') |
2639 | + self.assertEqual(args.image_opt, 'opts opts') |
2640 | + |
2641 | + def testProvision(self): |
2642 | + orig = os.environ.get('IMAGE_OPT', '') |
2643 | + with mock.patch.object(self.run_smoke, '_run') as run: |
2644 | + args = self.run_smoke._get_parser().parse_args( |
2645 | + ['-s', 'foo', '--image-opt', 'FOOBAR', '-p', '1', '-p', '2']) |
2646 | + self.run_smoke._provision(args) |
2647 | + self.assertTrue(run.called) |
2648 | + val = os.environ.get('IMAGE_OPT') |
2649 | + os.environ['IMAGE_OPT'] = orig |
2650 | + self.assertEqual('FOOBAR', val) |
2651 | + |
2652 | + def testUtahTests(self): |
2653 | + args = self.run_smoke._get_parser().parse_args( |
2654 | + ['-s', 'foo', '-t', 'a', '-t', 'b']) |
2655 | + with mock.patch.object(self.run_smoke, '_run') as run: |
2656 | + with mock.patch.dict('os.environ'): |
2657 | + run.side_effects = [subprocess.CalledProcessError, None] |
2658 | + self.run_smoke._test_utah(args) |
2659 | + p = os.path.join(self.run_smoke.res_dir, 'b') |
2660 | + # ensuring b ran means, that we handled the failure of test |
2661 | + # 'a' and that the environment is setup correctly |
2662 | + self.assertEqual(os.environ['RESDIR'], p) |
2663 | |
2664 | === added file 'selftests/test_statsd.py' |
2665 | --- selftests/test_statsd.py 1970-01-01 00:00:00 +0000 |
2666 | +++ selftests/test_statsd.py 2014-01-15 20:49:07 +0000 |
2667 | @@ -0,0 +1,64 @@ |
2668 | +# Ubuntu Test Cases for Touch |
2669 | +# Copyright 2013 Canonical Ltd. |
2670 | + |
2671 | +# This program is free software: you can redistribute it and/or modify it |
2672 | +# under the terms of the GNU General Public License version 3, as published |
2673 | +# by the Free Software Foundation. |
2674 | + |
2675 | +# This program is distributed in the hope that it will be useful, but |
2676 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
2677 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2678 | +# PURPOSE. See the GNU General Public License for more details. |
2679 | + |
2680 | +# You should have received a copy of the GNU General Public License along |
2681 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
2682 | + |
2683 | +import os |
2684 | +import mock |
2685 | +import unittest |
2686 | +import sys |
2687 | +import time |
2688 | + |
2689 | +path = os.path.join(os.path.dirname(__file__), '../scripts') |
2690 | +sys.path.append(path) |
2691 | + |
2692 | +import statsd |
2693 | + |
2694 | + |
2695 | +class TestStatsd(unittest.TestCase): |
2696 | + |
2697 | + def setUp(self): |
2698 | + self.origkey = os.environ.get('STATSD_KEY') |
2699 | + os.environ['STATSD_KEY'] = 'prefix' |
2700 | + reload(statsd) |
2701 | + |
2702 | + def tearDown(self): |
2703 | + if not self.origkey: |
2704 | + del os.environ['STATSD_KEY'] |
2705 | + else: |
2706 | + os.environ['STATSD_KEY'] = self.origkey |
2707 | + reload(statsd) |
2708 | + |
2709 | + """Simple set of tests to make sure the statsd calls work.""" |
2710 | + |
2711 | + @mock.patch('txstatsd.metrics.metric.Metric.write') |
2712 | + def testGaugeIt(self, _statsd): |
2713 | + statsd.gauge_it('foo', None) |
2714 | + _statsd.assert_called_with('prefix.foo:0|g') |
2715 | + _statsd.reset_mock() |
2716 | + |
2717 | + statsd.gauge_it('foo', []) |
2718 | + _statsd.assert_called_with('prefix.foo:0|g') |
2719 | + _statsd.reset_mock() |
2720 | + |
2721 | + statsd.gauge_it('foo', [1, 2, 3]) |
2722 | + _statsd.assert_called_with('prefix.foo:3|g') |
2723 | + _statsd.reset_mock() |
2724 | + |
2725 | + @mock.patch('txstatsd.metrics.metric.Metric.write') |
2726 | + def testTimeIt(self, _statsd): |
2727 | + with statsd.time_it('foo'): |
2728 | + time.sleep(0.1) |
2729 | + # should have a timing of about 100ms |
2730 | + self.assertRegexpMatches( |
2731 | + _statsd.call_args[0][0], 'prefix.foo:100.[\d+]|ms') |
2732 | |
2733 | === added directory 'tests' |
2734 | === added directory 'tests/address-book-app-autopilot' |
2735 | === added file 'tests/address-book-app-autopilot/master.run' |
2736 | --- tests/address-book-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2737 | +++ tests/address-book-app-autopilot/master.run 2014-01-15 20:49:07 +0000 |
2738 | @@ -0,0 +1,15 @@ |
2739 | +--- |
2740 | +testsuites: |
2741 | + - name: settle-before |
2742 | + fetch_method: dev |
2743 | + fetch_location: ../systemsettle |
2744 | + include_tests: |
2745 | + - systemsettle-before |
2746 | + - name: address-book-app-autopilot |
2747 | + fetch_method: dev |
2748 | + fetch_location: ./ |
2749 | + - name: settle-after |
2750 | + fetch_method: dev |
2751 | + fetch_location: ../systemsettle |
2752 | + include_tests: |
2753 | + - systemsettle-after |
2754 | |
2755 | === added file 'tests/address-book-app-autopilot/ts_control' |
2756 | --- tests/address-book-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2757 | +++ tests/address-book-app-autopilot/ts_control 2014-01-15 20:49:07 +0000 |
2758 | @@ -0,0 +1,1 @@ |
2759 | +ts_setup: PKGS=address-book-app-autopilot prepare-autopilot-test.sh |
2760 | |
2761 | === added file 'tests/address-book-app-autopilot/tslist.auto' |
2762 | --- tests/address-book-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2763 | +++ tests/address-book-app-autopilot/tslist.auto 2014-01-15 20:49:07 +0000 |
2764 | @@ -0,0 +1,4 @@ |
2765 | +- |
2766 | + discovery_cmd: autopilot-list address_book_app |
2767 | + test_cmd: autopilot-run address_book_app.tests.{} |
2768 | + |
2769 | |
2770 | === added directory 'tests/calendar-app-autopilot' |
2771 | === added file 'tests/calendar-app-autopilot/master.run' |
2772 | --- tests/calendar-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2773 | +++ tests/calendar-app-autopilot/master.run 2014-01-15 20:49:07 +0000 |
2774 | @@ -0,0 +1,15 @@ |
2775 | +--- |
2776 | +testsuites: |
2777 | + - name: settle-before |
2778 | + fetch_method: dev |
2779 | + fetch_location: ../systemsettle |
2780 | + include_tests: |
2781 | + - systemsettle-before |
2782 | + - name: calendar-app-autopilot |
2783 | + fetch_method: dev |
2784 | + fetch_location: ./ |
2785 | + - name: settle-after |
2786 | + fetch_method: dev |
2787 | + fetch_location: ../systemsettle |
2788 | + include_tests: |
2789 | + - systemsettle-after |
2790 | |
2791 | === added file 'tests/calendar-app-autopilot/ts_control' |
2792 | --- tests/calendar-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2793 | +++ tests/calendar-app-autopilot/ts_control 2014-01-15 20:49:07 +0000 |
2794 | @@ -0,0 +1,1 @@ |
2795 | +ts_setup: PKGS=python-dateutil prepare-autopilot-test.sh |
2796 | |
2797 | === added file 'tests/calendar-app-autopilot/tslist.auto' |
2798 | --- tests/calendar-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2799 | +++ tests/calendar-app-autopilot/tslist.auto 2014-01-15 20:49:07 +0000 |
2800 | @@ -0,0 +1,4 @@ |
2801 | +- |
2802 | + discovery_cmd: autopilot-list calendar_app |
2803 | + test_cmd: autopilot-run calendar_app.tests.{} |
2804 | + |
2805 | |
2806 | === added directory 'tests/camera-app-autopilot' |
2807 | === added file 'tests/camera-app-autopilot/master.run' |
2808 | --- tests/camera-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2809 | +++ tests/camera-app-autopilot/master.run 2014-01-15 20:49:07 +0000 |
2810 | @@ -0,0 +1,15 @@ |
2811 | +--- |
2812 | +testsuites: |
2813 | + - name: settle-before |
2814 | + fetch_method: dev |
2815 | + fetch_location: ../systemsettle |
2816 | + include_tests: |
2817 | + - systemsettle-before |
2818 | + - name: camera-app-autopilot |
2819 | + fetch_method: dev |
2820 | + fetch_location: ./ |
2821 | + - name: settle-after |
2822 | + fetch_method: dev |
2823 | + fetch_location: ../systemsettle |
2824 | + include_tests: |
2825 | + - systemsettle-after |
2826 | |
2827 | === added file 'tests/camera-app-autopilot/ts_control' |
2828 | --- tests/camera-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2829 | +++ tests/camera-app-autopilot/ts_control 2014-01-15 20:49:07 +0000 |
2830 | @@ -0,0 +1,1 @@ |
2831 | +ts_setup: PKGS=camera-app-autopilot prepare-autopilot-test.sh |
2832 | |
2833 | === added file 'tests/camera-app-autopilot/tslist.auto' |
2834 | --- tests/camera-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2835 | +++ tests/camera-app-autopilot/tslist.auto 2014-01-15 20:49:07 +0000 |
2836 | @@ -0,0 +1,4 @@ |
2837 | +- |
2838 | + discovery_cmd: autopilot-list camera_app |
2839 | + test_cmd: autopilot-run camera_app.tests.{} |
2840 | + |
2841 | |
2842 | === added directory 'tests/click_image_tests' |
2843 | === added directory 'tests/click_image_tests/check_preinstalled_list' |
2844 | === added file 'tests/click_image_tests/check_preinstalled_list/check_preinstalled_list.py' |
2845 | --- tests/click_image_tests/check_preinstalled_list/check_preinstalled_list.py 1970-01-01 00:00:00 +0000 |
2846 | +++ tests/click_image_tests/check_preinstalled_list/check_preinstalled_list.py 2014-01-15 20:49:07 +0000 |
2847 | @@ -0,0 +1,61 @@ |
2848 | +#!/usr/bin/python3 |
2849 | +# Copyright (C) 2013 Canonical Ltd. |
2850 | +# Author: Sergio Schvezov <sergio.schvezov@canonical.com> |
2851 | + |
2852 | +# This program is free software: you can redistribute it and/or modify |
2853 | +# it under the terms of the GNU General Public License as published by |
2854 | +# the Free Software Foundation; version 3 of the License. |
2855 | +# |
2856 | +# This program is distributed in the hope that it will be useful, |
2857 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2858 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2859 | +# GNU General Public License for more details. |
2860 | +# |
2861 | +# You should have received a copy of the GNU General Public License |
2862 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2863 | + |
2864 | +import subprocess |
2865 | +import unittest |
2866 | +import urllib.request |
2867 | + |
2868 | + |
2869 | +click_list_url = \ |
2870 | + 'http://people.canonical.com/~ubuntu-archive/click_packages/click_list' |
2871 | + |
2872 | + |
2873 | +def get_install_list(): |
2874 | + request = urllib.request.urlopen(click_list_url).read().decode('utf-8') |
2875 | + click_files = [x for x in request.split('\n') if x] |
2876 | + click_apps = {} |
2877 | + for entry in click_files: |
2878 | + entry_parts = entry.split('_') |
2879 | + click_apps[entry_parts[0]] = entry_parts[1] |
2880 | + return click_apps |
2881 | + |
2882 | + |
2883 | +def get_image_list(): |
2884 | + click_list = subprocess.check_output( |
2885 | + ['adb', 'shell', 'sudo', '-u', 'phablet', |
2886 | + 'bash', '-ic', 'click list']).decode('utf-8').split('\n') |
2887 | + click_entries = [x for x in click_list if x] |
2888 | + click_apps = {} |
2889 | + for entry in click_entries: |
2890 | + entry_parts = entry.split('\t') |
2891 | + click_apps[entry_parts[0]] = entry_parts[1].strip() |
2892 | + return click_apps |
2893 | + |
2894 | + |
2895 | +class ClickPreinstalled(unittest.TestCase): |
2896 | + |
2897 | + def setUp(self): |
2898 | + self.image_list = get_image_list() |
2899 | + self.install_list = get_install_list() |
2900 | + print('Search for %s on image' % self.install_list.keys()) |
2901 | + |
2902 | + def testPreinstalled(self): |
2903 | + for entry in self.install_list: |
2904 | + self.assertIn(entry, self.image_list.keys()) |
2905 | + |
2906 | + |
2907 | +if __name__ == '__main__': |
2908 | + unittest.main() |
2909 | |
2910 | === added file 'tests/click_image_tests/check_preinstalled_list/tc_control' |
2911 | --- tests/click_image_tests/check_preinstalled_list/tc_control 1970-01-01 00:00:00 +0000 |
2912 | +++ tests/click_image_tests/check_preinstalled_list/tc_control 2014-01-15 20:49:07 +0000 |
2913 | @@ -0,0 +1,10 @@ |
2914 | +description: check that all the expected click packages are installed |
2915 | +dependencies: a touch read-only image |
2916 | +action: | |
2917 | + 1. download the list of click packages |
2918 | + 2. list the current click packages installed on the device |
2919 | +expected_results: | |
2920 | + 1. the current list of click packages from the archive should match |
2921 | +type: userland |
2922 | +timeout: 120 |
2923 | +command: ./check_preinstalled_list.py |
2924 | |
2925 | === added file 'tests/click_image_tests/master.run' |
2926 | --- tests/click_image_tests/master.run 1970-01-01 00:00:00 +0000 |
2927 | +++ tests/click_image_tests/master.run 2014-01-15 20:49:07 +0000 |
2928 | @@ -0,0 +1,5 @@ |
2929 | +--- |
2930 | +testsuites: |
2931 | + - name: click_image_tests |
2932 | + fetch_method: dev |
2933 | + fetch_location: ./ |
2934 | |
2935 | === added file 'tests/click_image_tests/tslist.run' |
2936 | --- tests/click_image_tests/tslist.run 1970-01-01 00:00:00 +0000 |
2937 | +++ tests/click_image_tests/tslist.run 2014-01-15 20:49:07 +0000 |
2938 | @@ -0,0 +1,1 @@ |
2939 | +- test: check_preinstalled_list |
2940 | |
2941 | === added directory 'tests/customizations' |
2942 | === added file 'tests/customizations/master.run' |
2943 | --- tests/customizations/master.run 1970-01-01 00:00:00 +0000 |
2944 | +++ tests/customizations/master.run 2014-01-15 20:49:07 +0000 |
2945 | @@ -0,0 +1,5 @@ |
2946 | +--- |
2947 | +testsuites: |
2948 | + - name: customizations |
2949 | + fetch_method: dev |
2950 | + fetch_location: ./ |
2951 | |
2952 | === added file 'tests/customizations/setup.sh' |
2953 | --- tests/customizations/setup.sh 1970-01-01 00:00:00 +0000 |
2954 | +++ tests/customizations/setup.sh 2014-01-15 20:49:07 +0000 |
2955 | @@ -0,0 +1,10 @@ |
2956 | +#!/bin/sh |
2957 | + |
2958 | +set -ex |
2959 | + |
2960 | +BZR_HOME=/dev/null bzr branch lp:~savilerow-team/savilerow/tests customization_tests |
2961 | + |
2962 | +# copy the autopilot scripts over if needed (ie we are testing from HOST) |
2963 | +[ -z $ANDROID_SERIAL ] || adb push ./customization_tests /home/phablet/autopilot/customization_tests |
2964 | + |
2965 | +prepare-autopilot-test.sh |
2966 | |
2967 | === added file 'tests/customizations/ts_control' |
2968 | --- tests/customizations/ts_control 1970-01-01 00:00:00 +0000 |
2969 | +++ tests/customizations/ts_control 2014-01-15 20:49:07 +0000 |
2970 | @@ -0,0 +1,1 @@ |
2971 | +ts_setup: ./setup.sh |
2972 | |
2973 | === added file 'tests/customizations/tslist.auto' |
2974 | --- tests/customizations/tslist.auto 1970-01-01 00:00:00 +0000 |
2975 | +++ tests/customizations/tslist.auto 2014-01-15 20:49:07 +0000 |
2976 | @@ -0,0 +1,4 @@ |
2977 | +- |
2978 | + discovery_cmd: autopilot-list customization_tests |
2979 | + test_cmd: autopilot-run customization_tests.tests.{} |
2980 | + |
2981 | |
2982 | === added directory 'tests/default' |
2983 | === added directory 'tests/default/ifconfig' |
2984 | === added file 'tests/default/ifconfig/tc_control' |
2985 | --- tests/default/ifconfig/tc_control 1970-01-01 00:00:00 +0000 |
2986 | +++ tests/default/ifconfig/tc_control 2014-01-15 20:49:07 +0000 |
2987 | @@ -0,0 +1,13 @@ |
2988 | +description: make sure wlan0 exists |
2989 | +dependencies: none |
2990 | +action: | |
2991 | + 1. ifconfig |
2992 | + 2. Make sure there is a wlan0 |
2993 | +expected_results: | |
2994 | + 1. there is a wlan0 on the system |
2995 | +type: userland |
2996 | +timeout: 60 |
2997 | +command: $TARGET_PREFIX ifconfig | grep wlan0 |
2998 | +#build_cmd: |
2999 | +#tc_setup: |
3000 | +#tc_cleanup: |
3001 | |
3002 | === added directory 'tests/default/install' |
3003 | === added file 'tests/default/install/tc_control' |
3004 | --- tests/default/install/tc_control 1970-01-01 00:00:00 +0000 |
3005 | +++ tests/default/install/tc_control 2014-01-15 20:49:07 +0000 |
3006 | @@ -0,0 +1,12 @@ |
3007 | +description: apt-get install works |
3008 | +dependencies: openssh-server |
3009 | +action: | |
3010 | + 1. apt-get install -y curl |
3011 | +expected_results: | |
3012 | + 1. apt-get install can install a package and ends with exit code 0 |
3013 | +type: userland |
3014 | +timeout: 120 |
3015 | +command: $TARGET_PREFIX apt-get install -y curl |
3016 | +#build_cmd: |
3017 | +#tc_setup: |
3018 | +tc_cleanup: $TARGET_PREFIX apt-get remove -y curl |
3019 | |
3020 | === added file 'tests/default/master.run' |
3021 | --- tests/default/master.run 1970-01-01 00:00:00 +0000 |
3022 | +++ tests/default/master.run 2014-01-15 20:49:07 +0000 |
3023 | @@ -0,0 +1,5 @@ |
3024 | +--- |
3025 | +testsuites: |
3026 | + - name: smoke_touch |
3027 | + fetch_method: dev |
3028 | + fetch_location: ./ |
3029 | |
3030 | === added directory 'tests/default/netstat' |
3031 | === added file 'tests/default/netstat/tc_control' |
3032 | --- tests/default/netstat/tc_control 1970-01-01 00:00:00 +0000 |
3033 | +++ tests/default/netstat/tc_control 2014-01-15 20:49:07 +0000 |
3034 | @@ -0,0 +1,12 @@ |
3035 | +description: netstat -l lists all the services |
3036 | +dependencies: none |
3037 | +action: | |
3038 | + 1. netstat -l |
3039 | +expected_results: | |
3040 | + 1. netstat shows output and exists cleanly |
3041 | +type: userland |
3042 | +timeout: 60 |
3043 | +command: $TARGET_PREFIX netstat -l |
3044 | +#build_cmd: |
3045 | +#tc_setup: |
3046 | +#tc_cleanup: |
3047 | |
3048 | === added directory 'tests/default/ping' |
3049 | === added file 'tests/default/ping/pingtest.sh' |
3050 | --- tests/default/ping/pingtest.sh 1970-01-01 00:00:00 +0000 |
3051 | +++ tests/default/ping/pingtest.sh 2014-01-15 20:49:07 +0000 |
3052 | @@ -0,0 +1,12 @@ |
3053 | +#!/bin/sh |
3054 | + |
3055 | +set -e |
3056 | + |
3057 | +if [ -z $TARGET_PREFIX ] ; then |
3058 | + echo "RUNNING ON TARGET" |
3059 | + ping -c 5 $(ip route show | head -n1 |cut -d" " -f3) |
3060 | +else |
3061 | + echo "RUNNING FROM HOST" |
3062 | + ${TARGET_PREFIX} ping -c 5 '$(ip route show | head -n1 |cut -d" " -f3)' |
3063 | +fi |
3064 | + |
3065 | |
3066 | === added file 'tests/default/ping/tc_control' |
3067 | --- tests/default/ping/tc_control 1970-01-01 00:00:00 +0000 |
3068 | +++ tests/default/ping/tc_control 2014-01-15 20:49:07 +0000 |
3069 | @@ -0,0 +1,12 @@ |
3070 | +description: ping -c 5 $gateway |
3071 | +dependencies: None |
3072 | +action: | |
3073 | + 1. ping -c 5 $gateway |
3074 | +expected_results: | |
3075 | + 1. ping ends without an error |
3076 | +type: userland |
3077 | +timeout: 60 |
3078 | +command: ./pingtest.sh |
3079 | +#build_cmd: |
3080 | +#tc_setup: |
3081 | +#tc_cleanup: |
3082 | |
3083 | === added directory 'tests/default/pwd' |
3084 | === added file 'tests/default/pwd/tc_control' |
3085 | --- tests/default/pwd/tc_control 1970-01-01 00:00:00 +0000 |
3086 | +++ tests/default/pwd/tc_control 2014-01-15 20:49:07 +0000 |
3087 | @@ -0,0 +1,9 @@ |
3088 | +description: pwd works |
3089 | +dependencies: none |
3090 | +action: | |
3091 | + 1. cd to /tmp and verify which is the current directory |
3092 | +expected_results: | |
3093 | + 1. Current directory is /tmp |
3094 | +type: userland |
3095 | +timeout: 60 |
3096 | +command: ./test.sh |
3097 | |
3098 | === added file 'tests/default/pwd/test.sh' |
3099 | --- tests/default/pwd/test.sh 1970-01-01 00:00:00 +0000 |
3100 | +++ tests/default/pwd/test.sh 2014-01-15 20:49:07 +0000 |
3101 | @@ -0,0 +1,18 @@ |
3102 | +#!/bin/sh |
3103 | + |
3104 | +set -e |
3105 | + |
3106 | +if [ -n "$TARGET_PREFIX" ] ; then |
3107 | + echo "RUNNING FROM HOST" |
3108 | +else |
3109 | + echo "RUNNING ON TARGET" |
3110 | + TARGET_PREFIX="/bin/sh -c" |
3111 | +fi |
3112 | + |
3113 | +#when it comes from adb we get a \r\n that should be removed |
3114 | +dir=$($TARGET_PREFIX "cd /tmp; pwd" | head -n1 | tr -d '\r\n') |
3115 | +if [ $dir != "/tmp" ] ; then |
3116 | + echo "failed to change directory" |
3117 | + exit 1 |
3118 | +fi |
3119 | +exit 0 |
3120 | |
3121 | === added directory 'tests/default/route' |
3122 | === added file 'tests/default/route/tc_control' |
3123 | --- tests/default/route/tc_control 1970-01-01 00:00:00 +0000 |
3124 | +++ tests/default/route/tc_control 2014-01-15 20:49:07 +0000 |
3125 | @@ -0,0 +1,12 @@ |
3126 | +description: route shows wlan0 routes |
3127 | +dependencies: none |
3128 | +action: | |
3129 | + 1. route -n | grep wlan0 |
3130 | +expected_results: | |
3131 | + 1. route shows wlan0 routes |
3132 | +type: userland |
3133 | +timeout: 60 |
3134 | +command: $TARGET_PREFIX route -n | grep wlan0 |
3135 | +#build_cmd: |
3136 | +#tc_setup: |
3137 | +#tc_cleanup: |
3138 | |
3139 | === added directory 'tests/default/systemsettle' |
3140 | === added file 'tests/default/systemsettle/systemsettle.sh' |
3141 | --- tests/default/systemsettle/systemsettle.sh 1970-01-01 00:00:00 +0000 |
3142 | +++ tests/default/systemsettle/systemsettle.sh 2014-01-15 20:49:07 +0000 |
3143 | @@ -0,0 +1,120 @@ |
3144 | +#!/bin/bash |
3145 | + |
3146 | +# Configuration variables: |
3147 | +# TARGET_PREFIX - Allows this to be run from the host, by providings something |
3148 | +# like TARGET_PREFIX="adb shell" |
3149 | +# UTAH_PROBE_DIR - optionally where to save log files so utah will grab them |
3150 | + |
3151 | +set -e |
3152 | + |
3153 | +[ -z $UTAH_PROBE_DIR ] && UTAH_PROBE_DIR="/tmp" |
3154 | + |
3155 | +# default exit code storage |
3156 | +dump_error=1 |
3157 | + |
3158 | +calc () { awk "BEGIN{ print $* }" ;} |
3159 | + |
3160 | +function show_usage() { |
3161 | + echo "Usage:" |
3162 | + echo " $0 [options]" |
3163 | + echo "Options:" |
3164 | + echo " -r run forever without exiting" |
3165 | + echo " -p minimum idle percent to wait for (Default: 99)" |
3166 | + echo " -c number of times to run top at each iteration (Default: 10)" |
3167 | + echo " -d seconds to delay between each top iteration (Default: 6)" |
3168 | + echo " -i top measurements to ignore from each loop (Default: 1)" |
3169 | + echo " -m maximum loops of top before giving up if minimum idle" |
3170 | + echo " percent is not reached (Default: 10)" |
3171 | + echo " -l label to include for the top_log file" |
3172 | + exit 129 |
3173 | +} |
3174 | + |
3175 | +while getopts "h?rp:c:d:i:m:l:" opt; do |
3176 | + case "$opt" in |
3177 | + h|\?) show_usage |
3178 | + ;; |
3179 | + r) settle_prefix='-' |
3180 | + ;; |
3181 | + p) idle_avg_min=$OPTARG |
3182 | + ;; |
3183 | + c) top_repeat=$OPTARG |
3184 | + ;; |
3185 | + d) top_wait=$OPTARG |
3186 | + ;; |
3187 | + i) top_ignore=$OPTARG |
3188 | + ;; |
3189 | + m) settle_max=$OPTARG |
3190 | + ;; |
3191 | + l) top_log_label=$OPTARG |
3192 | + ;; |
3193 | + esac |
3194 | +done |
3195 | + |
3196 | +# minimum average idle level required to succeed |
3197 | +idle_avg_min=${idle_avg_min:-99} |
3198 | +# measurement details: top $top_wait $top_repeat |
3199 | +top_repeat=${top_repeat:-10} |
3200 | +top_wait=${top_wait:-6} |
3201 | +# how many samples to ignore |
3202 | +top_ignore=${top_ignore:-1} |
3203 | +# how many total attempts to settle the system |
3204 | +settle_max=${settle_max:-10} |
3205 | + |
3206 | +top_log="$UTAH_PROBE_DIR/top$top_log_label.log" |
3207 | + |
3208 | +# set and calc more runtime values |
3209 | +top_tail=`calc $top_repeat - $top_ignore` |
3210 | +settle_count=0 |
3211 | +idle_avg=0 |
3212 | + |
3213 | +echo "System Settle run - quiesce the system" |
3214 | +echo "--------------------------------------" |
3215 | +echo |
3216 | +echo " idle_avg_min = '$idle_avg_min'" |
3217 | +echo " top_repeat = '$top_repeat'" |
3218 | +echo " top_wait = '$top_wait'" |
3219 | +echo " top_ignore = '$top_ignore'" |
3220 | +echo " settle_max = '$settle_max'" |
3221 | +echo " run_forever = '$settle_prefix' (- = yes)" |
3222 | +echo " log files = $top_log $top_log.reduced" |
3223 | +echo " target prefix = $TARGET_PREFIX" |
3224 | +echo |
3225 | + |
3226 | +while test `calc $idle_avg '<' $idle_avg_min` = 1 -a "$settle_prefix$settle_count" -lt "$settle_max"; do |
3227 | + echo -n "Starting system idle measurement (run: $settle_count) ... " |
3228 | + |
3229 | + # get top |
3230 | + echo "TOP DUMP (after settle run: $settle_count)" >> $top_log |
3231 | + echo "========================" >> $top_log |
3232 | + ${TARGET_PREFIX} top -b -d $top_wait -n $top_repeat >> $top_log |
3233 | + cat $top_log | grep '.Cpu.*' | tail -n $top_tail > $top_log.reduced |
3234 | + echo >> $top_log |
3235 | + |
3236 | + # calc average of idle field for this measurement |
3237 | + sum=0 |
3238 | + count=0 |
3239 | + while read line; do |
3240 | + idle=`echo $line | sed -e 's/.* \([0-9\.]*\) id.*/\1/'` |
3241 | + sum=`calc $sum + $idle` |
3242 | + count=`calc $count + 1` |
3243 | + done < $top_log.reduced |
3244 | + |
3245 | + idle_avg=`calc $sum / $count` |
3246 | + settle_count=`calc $settle_count + 1` |
3247 | + |
3248 | + echo " DONE." |
3249 | + echo |
3250 | + echo "Measurement:" |
3251 | + echo " + idle level: $idle_avg" |
3252 | + echo " + idle sum: $sum / count: $count" |
3253 | + echo |
3254 | +done |
3255 | + |
3256 | +if test `calc $idle_avg '<' $idle_avg_min` = 1; then |
3257 | + echo "system not settled. FAIL" |
3258 | + exit 1 |
3259 | +else |
3260 | + echo "system settled. SUCCESS" |
3261 | + exit 0 |
3262 | +fi |
3263 | + |
3264 | |
3265 | === added file 'tests/default/systemsettle/tc_control' |
3266 | --- tests/default/systemsettle/tc_control 1970-01-01 00:00:00 +0000 |
3267 | +++ tests/default/systemsettle/tc_control 2014-01-15 20:49:07 +0000 |
3268 | @@ -0,0 +1,9 @@ |
3269 | +description: check if system settles to idle average > 99.25% |
3270 | +dependencies: none |
3271 | +action: | |
3272 | + 1. Take CPU load samples for 10 minutes and fail if average idle never goes above 99.25% percent |
3273 | +expected_results: | |
3274 | + 1. When doing nothing, system calms down to at least 99.25% idle level |
3275 | +type: userland |
3276 | +timeout: 720 |
3277 | +command: ./systemsettle.sh -c5 -d6 -p 97.5 |
3278 | |
3279 | === added file 'tests/default/ts_control' |
3280 | --- tests/default/ts_control 1970-01-01 00:00:00 +0000 |
3281 | +++ tests/default/ts_control 2014-01-15 20:49:07 +0000 |
3282 | @@ -0,0 +1,3 @@ |
3283 | +#build_cmd: echo building |
3284 | +#ts_setup: echo setting up |
3285 | +#ts_cleanup: echo cleaning up |
3286 | |
3287 | === added file 'tests/default/tslist.run' |
3288 | --- tests/default/tslist.run 1970-01-01 00:00:00 +0000 |
3289 | +++ tests/default/tslist.run 2014-01-15 20:49:07 +0000 |
3290 | @@ -0,0 +1,10 @@ |
3291 | +- test: pwd |
3292 | +- test: uname |
3293 | +- test: vmstat |
3294 | +- test: systemsettle |
3295 | +- test: netstat |
3296 | +- test: ifconfig |
3297 | +- test: route |
3298 | +- test: ping |
3299 | +- test: install |
3300 | +- test: unity8 |
3301 | |
3302 | === added directory 'tests/default/uname' |
3303 | === added file 'tests/default/uname/tc_control' |
3304 | --- tests/default/uname/tc_control 1970-01-01 00:00:00 +0000 |
3305 | +++ tests/default/uname/tc_control 2014-01-15 20:49:07 +0000 |
3306 | @@ -0,0 +1,12 @@ |
3307 | +description: uname shows an ubuntu-phablet image installed |
3308 | +dependencies: CHANGE_ME |
3309 | +action: | |
3310 | + 1. uname -a|grep ubuntu-phablet |
3311 | +expected_results: | |
3312 | + 1. ubuntu-phablet is installed as expected |
3313 | +type: userland |
3314 | +timeout: 60 |
3315 | +command: $TARGET_PREFIX uname -a | grep ubuntu-phablet |
3316 | +#build_cmd: |
3317 | +#tc_setup: |
3318 | +#tc_cleanup: |
3319 | |
3320 | === added directory 'tests/default/unity8' |
3321 | === added file 'tests/default/unity8/tc_control' |
3322 | --- tests/default/unity8/tc_control 1970-01-01 00:00:00 +0000 |
3323 | +++ tests/default/unity8/tc_control 2014-01-15 20:49:07 +0000 |
3324 | @@ -0,0 +1,9 @@ |
3325 | +description: check for unity8 process |
3326 | +dependencies: None |
3327 | +action: | |
3328 | + 1. pgrep unity8 |
3329 | +expected_results: | |
3330 | + 1. pgrep exits with 0, indicating it found a matching process |
3331 | +type: userland |
3332 | +timeout: 60 |
3333 | +command: $TARGET_PREFIX /usr/bin/pgrep unity8 |
3334 | |
3335 | === added directory 'tests/default/vmstat' |
3336 | === added file 'tests/default/vmstat/tc_control' |
3337 | --- tests/default/vmstat/tc_control 1970-01-01 00:00:00 +0000 |
3338 | +++ tests/default/vmstat/tc_control 2014-01-15 20:49:07 +0000 |
3339 | @@ -0,0 +1,12 @@ |
3340 | +description: Execute vmstat and capture output |
3341 | +dependencies: none |
3342 | +action: | |
3343 | + 1. vmstat |
3344 | +expected_results: | |
3345 | + 1. vmstat finishes without an error |
3346 | +type: userland |
3347 | +timeout: 60 |
3348 | +command: $TARGET_PREFIX vmstat |
3349 | +#build_cmd: |
3350 | +#tc_setup: |
3351 | +#tc_cleanup: |
3352 | |
3353 | === added directory 'tests/dialer-app-autopilot' |
3354 | === added file 'tests/dialer-app-autopilot/master.run' |
3355 | --- tests/dialer-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
3356 | +++ tests/dialer-app-autopilot/master.run 2014-01-15 20:49:07 +0000 |
3357 | @@ -0,0 +1,15 @@ |
3358 | +--- |
3359 | +testsuites: |
3360 | + - name: settle-before |
3361 | + fetch_method: dev |
3362 | + fetch_location: ../systemsettle |
3363 | + include_tests: |
3364 | + - systemsettle-before |
3365 | + - name: dialer-app-autopilot |
3366 | + fetch_method: dev |
3367 | + fetch_location: ./ |
3368 | + - name: settle-after |
3369 | + fetch_method: dev |
3370 | + fetch_location: ../systemsettle |
3371 | + include_tests: |
3372 | + - systemsettle-after |
3373 | |
3374 | === added file 'tests/dialer-app-autopilot/ts_control' |
3375 | --- tests/dialer-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
3376 | +++ tests/dialer-app-autopilot/ts_control 2014-01-15 20:49:07 +0000 |
3377 | @@ -0,0 +1,1 @@ |
3378 | +ts_setup: PKGS="dialer-app-autopilot ubuntu-ui-toolkit-autopilot" prepare-autopilot-test.sh |
3379 | |
3380 | === added file 'tests/dialer-app-autopilot/tslist.auto' |
3381 | --- tests/dialer-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
3382 | +++ tests/dialer-app-autopilot/tslist.auto 2014-01-15 20:49:07 +0000 |
3383 | @@ -0,0 +1,4 @@ |
3384 | +- |
3385 | + discovery_cmd: autopilot-list dialer_app |
3386 | + test_cmd: autopilot-run dialer_app.tests.{} |
3387 | + |
3388 | |
3389 | === added directory 'tests/dropping-letters-app-autopilot' |
3390 | === added file 'tests/dropping-letters-app-autopilot/master.run' |
3391 | --- tests/dropping-letters-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
3392 | +++ tests/dropping-letters-app-autopilot/master.run 2014-01-15 20:49:07 +0000 |
3393 | @@ -0,0 +1,15 @@ |
3394 | +--- |
3395 | +testsuites: |
3396 | + - name: settle-before |
3397 | + fetch_method: dev |
3398 | + fetch_location: ../systemsettle |
3399 | + include_tests: |
3400 | + - systemsettle-before |
3401 | + - name: dropping-letters-app-autopilot |
3402 | + fetch_method: dev |
3403 | + fetch_location: ./ |
3404 | + - name: settle-after |
3405 | + fetch_method: dev |
3406 | + fetch_location: ../systemsettle |
3407 | + include_tests: |
3408 | + - systemsettle-after |
3409 | |
3410 | === added file 'tests/dropping-letters-app-autopilot/ts_control' |
3411 | --- tests/dropping-letters-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
3412 | +++ tests/dropping-letters-app-autopilot/ts_control 2014-01-15 20:49:07 +0000 |
3413 | @@ -0,0 +1,1 @@ |
3414 | +ts_setup: prepare-autopilot-test.sh |
3415 | |
3416 | === added file 'tests/dropping-letters-app-autopilot/tslist.auto' |
3417 | --- tests/dropping-letters-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
3418 | +++ tests/dropping-letters-app-autopilot/tslist.auto 2014-01-15 20:49:07 +0000 |
3419 | @@ -0,0 +1,4 @@ |
3420 | +- |
3421 | + discovery_cmd: autopilot-list dropping_letters_app |
3422 | + test_cmd: autopilot-run dropping_letters_app.tests.{} |
3423 | + |
3424 | |
3425 | === added directory 'tests/eventstat' |
3426 | === added directory 'tests/eventstat/eventstat' |
3427 | === added file 'tests/eventstat/eventstat/eventstat.sh' |
3428 | --- tests/eventstat/eventstat/eventstat.sh 1970-01-01 00:00:00 +0000 |
3429 | +++ tests/eventstat/eventstat/eventstat.sh 2014-01-15 20:49:07 +0000 |
3430 | @@ -0,0 +1,5 @@ |
3431 | +#!/bin/bash |
3432 | +: ${DURATION:=60} |
3433 | +: ${COUNT:=10} |
3434 | +${TARGET_PREFIX} "echo \"{\\\"duration\\\": $DURATION, \\\"count\\\": $COUNT}\" > /tmp/results/options.json" |
3435 | +${TARGET_PREFIX} "eventstat -CSl -r /tmp/results/eventstat.csv $DURATION $COUNT > /tmp/results/eventstat.log" |
3436 | |
3437 | === added file 'tests/eventstat/eventstat/setup.sh' |
3438 | --- tests/eventstat/eventstat/setup.sh 1970-01-01 00:00:00 +0000 |
3439 | +++ tests/eventstat/eventstat/setup.sh 2014-01-15 20:49:07 +0000 |
3440 | @@ -0,0 +1,7 @@ |
3441 | +#!/bin/bash |
3442 | + |
3443 | +${TARGET_PREFIX} mkdir -p /tmp/results |
3444 | +NO_UNLOCK=1 PKGS="eventstat" prepare-autopilot-test.sh |
3445 | +#Let the system quiet down for a little while |
3446 | +sleep 300 |
3447 | + |
3448 | |
3449 | === added file 'tests/eventstat/eventstat/tc_control' |
3450 | --- tests/eventstat/eventstat/tc_control 1970-01-01 00:00:00 +0000 |
3451 | +++ tests/eventstat/eventstat/tc_control 2014-01-15 20:49:07 +0000 |
3452 | @@ -0,0 +1,12 @@ |
3453 | +description: Gather memory usage information |
3454 | +dependencies: none |
3455 | +action: | |
3456 | + 1. gather eventstat data |
3457 | +expected_results: | |
3458 | + 1. eventstat.log should be saved to /tmp/results |
3459 | +type: userland |
3460 | +timeout: 800 |
3461 | +command: ./eventstat.sh |
3462 | +#build_cmd: |
3463 | +tc_setup: ./setup.sh |
3464 | +#tc_cleanup: |
3465 | |
3466 | === added file 'tests/eventstat/master.run' |
3467 | --- tests/eventstat/master.run 1970-01-01 00:00:00 +0000 |
3468 | +++ tests/eventstat/master.run 2014-01-15 20:49:07 +0000 |
3469 | @@ -0,0 +1,5 @@ |
3470 | +--- |
3471 | +testsuites: |
3472 | + - name: eventstat |
3473 | + fetch_method: dev |
3474 | + fetch_location: ./ |
3475 | |
3476 | === added file 'tests/eventstat/tslist.run' |
3477 | --- tests/eventstat/tslist.run 1970-01-01 00:00:00 +0000 |
3478 | +++ tests/eventstat/tslist.run 2014-01-15 20:49:07 +0000 |
3479 | @@ -0,0 +1,1 @@ |
3480 | +- test: eventstat |
3481 | |
3482 | === added directory 'tests/friends-app-autopilot' |
3483 | === added file 'tests/friends-app-autopilot/master.run' |
3484 | --- tests/friends-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
3485 | +++ tests/friends-app-autopilot/master.run 2014-01-15 20:49:07 +0000 |
3486 | @@ -0,0 +1,15 @@ |
3487 | +--- |
3488 | +testsuites: |
3489 | + - name: settle-before |
3490 | + fetch_method: dev |
3491 | + fetch_location: ../systemsettle |
3492 | + include_tests: |
3493 | + - systemsettle-before |
3494 | + - name: friends-app-autopilot |
3495 | + fetch_method: dev |
3496 | + fetch_location: ./ |
3497 | + - name: settle-after |
3498 | + fetch_method: dev |
3499 | + fetch_location: ../systemsettle |
3500 | + include_tests: |
3501 | + - systemsettle-after |
3502 | |
3503 | === added file 'tests/friends-app-autopilot/ts_control' |
3504 | --- tests/friends-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
3505 | +++ tests/friends-app-autopilot/ts_control 2014-01-15 20:49:07 +0000 |
3506 | @@ -0,0 +1,1 @@ |
3507 | +ts_setup: PKGS=friends-app-autopilot prepare-autopilot-test.sh |
3508 | |
3509 | === added file 'tests/friends-app-autopilot/tslist.auto' |
3510 | --- tests/friends-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
3511 | +++ tests/friends-app-autopilot/tslist.auto 2014-01-15 20:49:07 +0000 |
3512 | @@ -0,0 +1,4 @@ |
3513 | +- |
3514 | + discovery_cmd: autopilot-list friends_app |
3515 | + test_cmd: autopilot-run friends_app.tests.{} |
3516 | + |
3517 | |
3518 | === added directory 'tests/gallery-app-autopilot' |
3519 | === added file 'tests/gallery-app-autopilot/master.run' |
3520 | --- tests/gallery-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
3521 | +++ tests/gallery-app-autopilot/master.run 2014-01-15 20:49:07 +0000 |
3522 | @@ -0,0 +1,15 @@ |
3523 | +--- |
3524 | +testsuites: |
3525 | + - name: settle-before |
3526 | + fetch_method: dev |
3527 | + fetch_location: ../systemsettle |
3528 | + include_tests: |
3529 | + - systemsettle-before |
3530 | + - name: gallery-app-autopilot |
3531 | + fetch_method: dev |
3532 | + fetch_location: ./ |
3533 | + - name: settle-after |
3534 | + fetch_method: dev |
3535 | + fetch_location: ../systemsettle |
3536 | + include_tests: |
3537 | + - systemsettle-after |
3538 | |
3539 | === added file 'tests/gallery-app-autopilot/ts_control' |
3540 | --- tests/gallery-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
3541 | +++ tests/gallery-app-autopilot/ts_control 2014-01-15 20:49:07 +0000 |
3542 | @@ -0,0 +1,1 @@ |
3543 | +ts_setup: PKGS=gallery-app-autopilot prepare-autopilot-test.sh |
3544 | |
3545 | === added file 'tests/gallery-app-autopilot/tslist.auto' |
3546 | --- tests/gallery-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
3547 | +++ tests/gallery-app-autopilot/tslist.auto 2014-01-15 20:49:07 +0000 |
3548 | @@ -0,0 +1,4 @@ |
3549 | +- |
3550 | + discovery_cmd: autopilot-list gallery_app |
3551 | + test_cmd: autopilot-run gallery_app.tests.{} |
3552 | + |
3553 | |
3554 | === added directory 'tests/install-and-boot' |
3555 | === added directory 'tests/install-and-boot/boot' |
3556 | === added file 'tests/install-and-boot/boot/tc_control' |
3557 | --- tests/install-and-boot/boot/tc_control 1970-01-01 00:00:00 +0000 |
3558 | +++ tests/install-and-boot/boot/tc_control 2014-01-15 20:49:07 +0000 |
3559 | @@ -0,0 +1,9 @@ |
3560 | +description: Ensures the target system has booted |
3561 | +dependencies: provision.sh was run |
3562 | +action: | |
3563 | + 1. checks adb-shell works |
3564 | +expected_results: | |
3565 | + 1. adb-shell is active to the target |
3566 | +type: userland |
3567 | +timeout: 60 |
3568 | +command: adb-shell /bin/true |
3569 | |
3570 | === added file 'tests/install-and-boot/master.run' |
3571 | --- tests/install-and-boot/master.run 1970-01-01 00:00:00 +0000 |
3572 | +++ tests/install-and-boot/master.run 2014-01-15 20:49:07 +0000 |
3573 | @@ -0,0 +1,5 @@ |
3574 | +--- |
3575 | +testsuites: |
3576 | + - name: install-and-boot |
3577 | + fetch_method: dev |
3578 | + fetch_location: ./ |
3579 | |
3580 | === added file 'tests/install-and-boot/tslist.run' |
3581 | --- tests/install-and-boot/tslist.run 1970-01-01 00:00:00 +0000 |
3582 | +++ tests/install-and-boot/tslist.run 2014-01-15 20:49:07 +0000 |
3583 | @@ -0,0 +1,1 @@ |
3584 | +- test: boot |
3585 | |
3586 | === added directory 'tests/mediaplayer-app-autopilot' |
3587 | === added file 'tests/mediaplayer-app-autopilot/master.run' |
3588 | --- tests/mediaplayer-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
3589 | +++ tests/mediaplayer-app-autopilot/master.run 2014-01-15 20:49:07 +0000 |
3590 | @@ -0,0 +1,15 @@ |
3591 | +--- |
3592 | +testsuites: |
3593 | + - name: settle-before |
3594 | + fetch_method: dev |
3595 | + fetch_location: ../systemsettle |
3596 | + include_tests: |
3597 | + - systemsettle-before |
3598 | + - name: mediaplayer-app-autopilot |
3599 | + fetch_method: dev |
3600 | + fetch_location: ./ |
3601 | + - name: settle-after |
3602 | + fetch_method: dev |
3603 | + fetch_location: ../systemsettle |
3604 | + include_tests: |
3605 | + - systemsettle-after |
3606 | |
3607 | === added file 'tests/mediaplayer-app-autopilot/ts_control' |
3608 | --- tests/mediaplayer-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
3609 | +++ tests/mediaplayer-app-autopilot/ts_control 2014-01-15 20:49:07 +0000 |
3610 | @@ -0,0 +1,1 @@ |
3611 | +ts_setup: PKGS=mediaplayer-app-autopilot prepare-autopilot-test.sh |
3612 | |
3613 | === added file 'tests/mediaplayer-app-autopilot/tslist.auto' |
3614 | --- tests/mediaplayer-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
3615 | +++ tests/mediaplayer-app-autopilot/tslist.auto 2014-01-15 20:49:07 +0000 |
3616 | @@ -0,0 +1,4 @@ |
3617 | +- |
3618 | + discovery_cmd: autopilot-list mediaplayer_app |
3619 | + test_cmd: autopilot-run mediaplayer_app.tests.{} |
3620 | + |
3621 | |
3622 | === added directory 'tests/memevent' |
3623 | === added file 'tests/memevent/master.run' |
3624 | --- tests/memevent/master.run 1970-01-01 00:00:00 +0000 |
3625 | +++ tests/memevent/master.run 2014-01-15 20:49:07 +0000 |
3626 | @@ -0,0 +1,5 @@ |
3627 | +--- |
3628 | +testsuites: |
3629 | + - name: memevent |
3630 | + fetch_method: dev |
3631 | + fetch_location: ./ |
3632 | |
3633 | === added file 'tests/memevent/setup.sh' |
3634 | --- tests/memevent/setup.sh 1970-01-01 00:00:00 +0000 |
3635 | +++ tests/memevent/setup.sh 2014-01-15 20:49:07 +0000 |
3636 | @@ -0,0 +1,8 @@ |
3637 | +#!/bin/sh |
3638 | + |
3639 | +set -e |
3640 | + |
3641 | +# copy the autopilot scripts over if needed |
3642 | +[ -z $ANDROID_SERIAL ] || adb push ./ubuntu_test_cases /home/phablet/autopilot/ubuntu_test_cases |
3643 | + |
3644 | +PKGS="camera-app-autopilot gallery-app-autopilot mediaplayer-app-autopilot webbrowser-app-autopilot" prepare-autopilot-test.sh |
3645 | |
3646 | === added file 'tests/memevent/ts_control' |
3647 | --- tests/memevent/ts_control 1970-01-01 00:00:00 +0000 |
3648 | +++ tests/memevent/ts_control 2014-01-15 20:49:07 +0000 |
3649 | @@ -0,0 +1,1 @@ |
3650 | +ts_setup: ./setup.sh |
3651 | |
3652 | === added file 'tests/memevent/tslist.auto' |
3653 | --- tests/memevent/tslist.auto 1970-01-01 00:00:00 +0000 |
3654 | +++ tests/memevent/tslist.auto 2014-01-15 20:49:07 +0000 |
3655 | @@ -0,0 +1,7 @@ |
3656 | +--- |
3657 | +# The discovery command is run from a directory containing the whole suite |
3658 | +# The test command is run from a sub directory in that |
3659 | +# We need to run each command in the directory that contains ubuntu_test_cases |
3660 | +# so that autopilot can find our python modules |
3661 | +- discovery_cmd: cd memevent; autopilot-list ubuntu_test_cases.memory_usage_measurement |
3662 | + test_cmd: cd ..; autopilot-run ubuntu_test_cases.memory_usage_measurement.tests.{} |
3663 | |
3664 | === added directory 'tests/memevent/ubuntu_test_cases' |
3665 | === added file 'tests/memevent/ubuntu_test_cases/__init__.py' |
3666 | --- tests/memevent/ubuntu_test_cases/__init__.py 1970-01-01 00:00:00 +0000 |
3667 | +++ tests/memevent/ubuntu_test_cases/__init__.py 2014-01-15 20:49:07 +0000 |
3668 | @@ -0,0 +1,6 @@ |
3669 | +"""ubuntu_test_cases package |
3670 | + |
3671 | +Warning: This python package is installed by a different debian package in a |
3672 | +different branch. It's been been created here only because it's convenient to |
3673 | +run autopilot directly from the branch. |
3674 | +""" |
3675 | |
3676 | === added directory 'tests/memevent/ubuntu_test_cases/memory_usage_measurement' |
3677 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/__init__.py' |
3678 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/__init__.py 1970-01-01 00:00:00 +0000 |
3679 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/__init__.py 2014-01-15 20:49:07 +0000 |
3680 | @@ -0,0 +1,1 @@ |
3681 | +"""Event based memory usage measurements test cases.""" |
3682 | |
3683 | === added directory 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps' |
3684 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/__init__.py' |
3685 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/__init__.py 1970-01-01 00:00:00 +0000 |
3686 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/__init__.py 2014-01-15 20:49:07 +0000 |
3687 | @@ -0,0 +1,21 @@ |
3688 | +"""Application classes used to drive them easily with autopilot.""" |
3689 | + |
3690 | +from autopilot.input import Keyboard, Mouse, Pointer, Touch |
3691 | +from autopilot.platform import model |
3692 | + |
3693 | + |
3694 | +class App(object): |
3695 | + |
3696 | + """Application class with common code.""" |
3697 | + |
3698 | + def __init__(self, tc): |
3699 | + self.tc = tc |
3700 | + self.app = None |
3701 | + self.window = None |
3702 | + |
3703 | + self.keyboard = Keyboard.create() |
3704 | + if model() == 'Desktop': |
3705 | + input_device = Mouse.create() |
3706 | + else: |
3707 | + input_device = Touch.create() |
3708 | + self.pointer = Pointer(input_device) |
3709 | |
3710 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/browser.py' |
3711 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/browser.py 1970-01-01 00:00:00 +0000 |
3712 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/browser.py 2014-01-15 20:49:07 +0000 |
3713 | @@ -0,0 +1,103 @@ |
3714 | +"""Browser application to write autopilot test cases easily.""" |
3715 | + |
3716 | +from testtools.matchers import Contains, Equals |
3717 | + |
3718 | +from ubuntuuitoolkit.emulators import UbuntuUIToolkitEmulatorBase |
3719 | +from webbrowser_app.emulators.browser import Browser |
3720 | + |
3721 | +from ubuntu_test_cases.memory_usage_measurement.apps import App |
3722 | +from ubuntu_test_cases.memory_usage_measurement.matchers import ( |
3723 | + DoesNotChange, |
3724 | + Eventually, |
3725 | +) |
3726 | + |
3727 | + |
3728 | +class BrowserApp(App): |
3729 | + |
3730 | + """Browser application.""" |
3731 | + |
3732 | + TYPING_DELAY = 0.01 |
3733 | + |
3734 | + def assert_chrome_eventually_hidden(self): |
3735 | + """Make sure chrome is eventually hidden.""" |
3736 | + |
3737 | + toolbar = self.window.get_toolbar() |
3738 | + self.tc.assertThat(toolbar.opened, Eventually(Equals(False))) |
3739 | + self.tc.assertThat(toolbar.animating, Eventually(Equals(False))) |
3740 | + |
3741 | + def assert_page_eventually_loaded(self, url): |
3742 | + """Make sure page is eventually loaded.""" |
3743 | + webview = self.window.get_current_webview() |
3744 | + self.tc.assertThat(webview.url, Eventually(Equals(url))) |
3745 | + # loadProgress == 100 ensures that a page has actually loaded |
3746 | + self.tc.assertThat(webview.loadProgress, Eventually(Equals(100))) |
3747 | + self.tc.assertThat(webview.loading, Eventually(Equals(False))) |
3748 | + |
3749 | + def clear_address_bar(self): |
3750 | + """Clear address bar.""" |
3751 | + self.focus_address_bar() |
3752 | + clear_button = self.window.get_address_bar_clear_button() |
3753 | + self.tc.assertThat(lambda: (clear_button.x, |
3754 | + clear_button.y, |
3755 | + clear_button.y), |
3756 | + Eventually(DoesNotChange())) |
3757 | + self.pointer.move_to_object(clear_button) |
3758 | + self.pointer.click() |
3759 | + text_field = self.window.get_address_bar_text_field() |
3760 | + self.tc.assertThat(text_field.text, Eventually(Equals(""))) |
3761 | + |
3762 | + def ensure_chrome_is_hidden(self): |
3763 | + """Make sure chrome is hidden.""" |
3764 | + webview = self.window.get_current_webview() |
3765 | + self.pointer.move_to_object(webview) |
3766 | + self.pointer.click() |
3767 | + self.assert_chrome_eventually_hidden() |
3768 | + |
3769 | + def focus_address_bar(self): |
3770 | + """Make sure address bar is focused.""" |
3771 | + address_bar = self.window.get_address_bar() |
3772 | + self.pointer.move_to_object(address_bar) |
3773 | + self.pointer.click() |
3774 | + self.tc.assertThat(address_bar.activeFocus, Eventually(Equals(True))) |
3775 | + |
3776 | + def go_to_url(self, url): |
3777 | + """Go to given url. |
3778 | + |
3779 | + :param url: URL that should be loaded in the browser |
3780 | + :type url: str |
3781 | + |
3782 | + """ |
3783 | + self.ensure_chrome_is_hidden() |
3784 | + self.window.open_toolbar() |
3785 | + self.clear_address_bar() |
3786 | + self.type_in_address_bar(url) |
3787 | + self.keyboard.press_and_release("Enter") |
3788 | + |
3789 | + def launch(self): |
3790 | + """Launch application.""" |
3791 | + args = [ |
3792 | + 'webbrowser-app', |
3793 | + '--fullscreen', |
3794 | + ('--desktop_file_hint=' |
3795 | + '/usr/share/applications/webbrowser-app.desktop'), |
3796 | + ] |
3797 | + self.app = self.tc.launch_test_application( |
3798 | + *args, |
3799 | + app_type='qt', |
3800 | + emulator_base=UbuntuUIToolkitEmulatorBase |
3801 | + ) |
3802 | + self.window = self.app.select_single(Browser) |
3803 | + self.window.visible.wait_for(True) |
3804 | + |
3805 | + def type_in_address_bar(self, text): |
3806 | + """Type text in address bar. |
3807 | + |
3808 | + :param text: Text to be typed in the address bar. |
3809 | + :type text: str |
3810 | + |
3811 | + """ |
3812 | + address_bar = self.window.get_address_bar() |
3813 | + self.tc.assertThat(address_bar.activeFocus, Eventually(Equals(True))) |
3814 | + self.keyboard.type(text, delay=self.TYPING_DELAY) |
3815 | + text_field = self.window.get_address_bar_text_field() |
3816 | + self.tc.assertThat(text_field.text, Eventually(Contains(text))) |
3817 | |
3818 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/camera.py' |
3819 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/camera.py 1970-01-01 00:00:00 +0000 |
3820 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/camera.py 2014-01-15 20:49:07 +0000 |
3821 | @@ -0,0 +1,58 @@ |
3822 | +"""Camera application to write autopilot test cases easily.""" |
3823 | + |
3824 | +import logging |
3825 | +import os |
3826 | + |
3827 | +from glob import glob |
3828 | + |
3829 | +from camera_app.emulators.main_window import MainWindow as CameraWindow |
3830 | +from testtools.matchers import Equals, HasLength |
3831 | + |
3832 | +from ubuntu_test_cases.memory_usage_measurement.apps import App |
3833 | +from ubuntu_test_cases.memory_usage_measurement.matchers import Eventually |
3834 | + |
3835 | +LOGGER = logging.getLogger(__file__) |
3836 | + |
3837 | + |
3838 | +class CameraApp(App): |
3839 | + |
3840 | + """Camera application.""" |
3841 | + |
3842 | + IMAGE_FILENAME_PATTERN = os.path.expanduser('~/Pictures/image*') |
3843 | + |
3844 | + def _remove_image_files(self): |
3845 | + """Remove all image files. |
3846 | + |
3847 | + This is useful not only to cleanup, but also to check that just one |
3848 | + image file has been written to disk. |
3849 | + |
3850 | + """ |
3851 | + for filename in glob(self.IMAGE_FILENAME_PATTERN): |
3852 | + LOGGER.debug('Removing image file: {}'.format(filename)) |
3853 | + os.remove(filename) |
3854 | + |
3855 | + def launch(self): |
3856 | + """Launch application.""" |
3857 | + args = [ |
3858 | + 'camera-app', |
3859 | + '--fullscreen', |
3860 | + ('--desktop_file_hint=' |
3861 | + '/usr/share/applications/camera-app.desktop'), |
3862 | + ] |
3863 | + self.app = self.tc.launch_test_application(*args, app_type='qt') |
3864 | + self.window = CameraWindow(self.app) |
3865 | + |
3866 | + def take_picture(self): |
3867 | + """Click on the exposure button to take picture.""" |
3868 | + self._remove_image_files() |
3869 | + |
3870 | + exposure_button = self.window.get_exposure_button() |
3871 | + self.tc.assertThat(exposure_button.enabled, Eventually(Equals(True))) |
3872 | + |
3873 | + LOGGER.debug('Taking picture...') |
3874 | + self.pointer.move_to_object(exposure_button) |
3875 | + self.pointer.click() |
3876 | + |
3877 | + # Wait for image file to be produced before memory usage measurement |
3878 | + self.tc.assertThat(lambda: glob(self.IMAGE_FILENAME_PATTERN), |
3879 | + Eventually(HasLength(1))) |
3880 | |
3881 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/gallery.py' |
3882 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/gallery.py 1970-01-01 00:00:00 +0000 |
3883 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/gallery.py 2014-01-15 20:49:07 +0000 |
3884 | @@ -0,0 +1,41 @@ |
3885 | +"""Gallery application to write autopilot test cases easily.""" |
3886 | + |
3887 | +import os |
3888 | +import shutil |
3889 | +import tempfile |
3890 | + |
3891 | +from ubuntu_test_cases.memory_usage_measurement.apps import App |
3892 | + |
3893 | + |
3894 | +class GalleryApp(App): |
3895 | + |
3896 | + """Gallery application.""" |
3897 | + |
3898 | + SAMPLE_DIR = '/usr/lib/python2.7/dist-packages/gallery_app/data/default' |
3899 | + |
3900 | + def __init__(self, tc): |
3901 | + super(GalleryApp, self).__init__(tc) |
3902 | + self.temp_sample_dir = None |
3903 | + self._copy_sample_dir() |
3904 | + |
3905 | + def _copy_sample_dir(self): |
3906 | + """Copy sample directory to a temporary location. |
3907 | + |
3908 | + This is useful to provide some default content. |
3909 | + |
3910 | + """ |
3911 | + self.temp_sample_dir = tempfile.mkdtemp(prefix='gallery-app-test-') |
3912 | + self.tc.addCleanup(shutil.rmtree, self.temp_sample_dir) |
3913 | + self.temp_sample_dir = os.path.join(self.temp_sample_dir, 'data') |
3914 | + shutil.copytree(self.SAMPLE_DIR, self.temp_sample_dir) |
3915 | + |
3916 | + def launch(self): |
3917 | + """Launch the application.""" |
3918 | + args = [ |
3919 | + 'gallery-app', |
3920 | + ('--desktop_file_hint=' |
3921 | + '/usr/share/applications/gallery-app.desktop'), |
3922 | + self.temp_sample_dir, |
3923 | + ] |
3924 | + self.app = self.tc.launch_test_application(*args, |
3925 | + app_type='qt') |
3926 | |
3927 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/media_player.py' |
3928 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/media_player.py 1970-01-01 00:00:00 +0000 |
3929 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/media_player.py 2014-01-15 20:49:07 +0000 |
3930 | @@ -0,0 +1,53 @@ |
3931 | +"""Media player application to write autopilot test cases easily.""" |
3932 | + |
3933 | +import os |
3934 | + |
3935 | +from testtools.matchers import Equals, GreaterThan |
3936 | + |
3937 | +from mediaplayer_app.emulators.main_window import ( |
3938 | + MainWindow as MediaPlayerWindow) |
3939 | + |
3940 | +from ubuntu_test_cases.memory_usage_measurement.apps import App |
3941 | +from ubuntu_test_cases.memory_usage_measurement.matchers import Eventually |
3942 | + |
3943 | + |
3944 | +class MediaPlayerApp(App): |
3945 | + |
3946 | + """Media player application.""" |
3947 | + |
3948 | + # Default content |
3949 | + VIDEOS_DIR = 'file:///usr/share/mediaplayer-app/videos/' |
3950 | + |
3951 | + def assert_playback_finished(self): |
3952 | + """Media player memory usage after playing a file.""" |
3953 | + time_line = self.window.get_object("Slider", "TimeLine.Slider") |
3954 | + |
3955 | + # Time line value isn't set to maximum value after playback is finished |
3956 | + # (LP: #1190555) |
3957 | + maximum_value = time_line.maximumValue - 2.0 |
3958 | + self.tc.assertThat(time_line.value, |
3959 | + Eventually(GreaterThan(maximum_value))) |
3960 | + |
3961 | + def launch(self, movie_file=None): |
3962 | + """Launch application. |
3963 | + |
3964 | + :param movie_file: |
3965 | + Relative path to movie file (uses default content directory as |
3966 | + root). |
3967 | + :type movie_file: str |
3968 | + |
3969 | + """ |
3970 | + binary = 'mediaplayer-app' |
3971 | + args = [ |
3972 | + binary, |
3973 | + '--fullscreen', |
3974 | + ('--desktop_file_hint=' |
3975 | + '/usr/share/applications/mediaplayer-app.desktop'), |
3976 | + ] |
3977 | + if movie_file: |
3978 | + args.insert(1, os.path.join(self.VIDEOS_DIR, movie_file)) |
3979 | + |
3980 | + self.app = self.tc.launch_test_application(*args, app_type='qt') |
3981 | + self.window = MediaPlayerWindow(self.app) |
3982 | + self.tc.assertThat(self.window.get_qml_view().visible, |
3983 | + Eventually(Equals(True))) |
3984 | |
3985 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/matchers.py' |
3986 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/matchers.py 1970-01-01 00:00:00 +0000 |
3987 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/matchers.py 2014-01-15 20:49:07 +0000 |
3988 | @@ -0,0 +1,37 @@ |
3989 | +"""Custom matchers used by the tests.""" |
3990 | + |
3991 | +from autopilot.matchers import Eventually as EventuallyMatcher |
3992 | +from testtools.matchers import Mismatch |
3993 | + |
3994 | + |
3995 | +def Eventually(matcher): |
3996 | + """Wrapper around autopilot.matchers.Eventually. |
3997 | + |
3998 | + The aim of the wrapper is just use a different timeout default |
3999 | + |
4000 | + :param matcher: A testools-like matcher that tests the desired condition |
4001 | + :type matcher: object |
4002 | + :returns: A value depending on the matcher protocol |
4003 | + :rtype: None | a mismatch object with information about the mismatch |
4004 | + |
4005 | + """ |
4006 | + return EventuallyMatcher(matcher, timeout=40) |
4007 | + |
4008 | + |
4009 | +class DoesNotChange(object): |
4010 | + """Match if two consecutive values are equal.""" |
4011 | + def __init__(self): |
4012 | + self.old_value = None |
4013 | + self.value = None |
4014 | + |
4015 | + def __str__(self): |
4016 | + return 'DoesNotChange()' |
4017 | + |
4018 | + def match(self, value): |
4019 | + self.old_value = self.value |
4020 | + self.value = value |
4021 | + if self.value != self.old_value: |
4022 | + return Mismatch('Current value ({}) does not match old value ({})' |
4023 | + .format(self.value, self.old_value)) |
4024 | + |
4025 | + return None |
4026 | |
4027 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/probes.py' |
4028 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/probes.py 1970-01-01 00:00:00 +0000 |
4029 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/probes.py 2014-01-15 20:49:07 +0000 |
4030 | @@ -0,0 +1,170 @@ |
4031 | +"""Probes used to take measurements4 while the tests are executed.""" |
4032 | + |
4033 | +import itertools |
4034 | +import logging |
4035 | +import os |
4036 | +import re |
4037 | +import subprocess |
4038 | + |
4039 | +from contextlib import contextmanager |
4040 | +from time import time |
4041 | + |
4042 | +LOGGER = logging.getLogger(__file__) |
4043 | + |
4044 | + |
4045 | +class SmemProbe(object): |
4046 | + |
4047 | + """Memory usage probe.""" |
4048 | + |
4049 | + BINARY = os.path.join(os.path.dirname(__file__), 'smem-tabs') |
4050 | + THRESHOLDS = { |
4051 | + 'foreground': 262144, # 256MB |
4052 | + 'background': 131072, # 128MB |
4053 | + } |
4054 | + |
4055 | + def __init__(self): |
4056 | + self.pids = [] # List of pids that should be monitored |
4057 | + self.readings = [] # List of readings |
4058 | + self.current_reading = None |
4059 | + self.threshold_exceeded_summary = [] |
4060 | + |
4061 | + @contextmanager |
4062 | + def probe(self, event): |
4063 | + """Run start and stop methods in a contex manager.""" |
4064 | + self.start(event) |
4065 | + yield |
4066 | + self.stop(event) |
4067 | + |
4068 | + def start(self, event): |
4069 | + """Start measurement. |
4070 | + |
4071 | + This method is not actually used, but defined to be consistent with the |
4072 | + probes API. |
4073 | + |
4074 | + :param event: Event name |
4075 | + :type event: str |
4076 | + :returns: None |
4077 | + |
4078 | + """ |
4079 | + LOGGER.debug('smem start: {}'.format(event)) |
4080 | + self.current_reading = { |
4081 | + 'event': event, |
4082 | + 'start_time': time(), |
4083 | + } |
4084 | + |
4085 | + def stop(self, event): |
4086 | + """Stop measurement. |
4087 | + |
4088 | + Run smem and get memory usage for a given set PIDs. |
4089 | + |
4090 | + :param event: Event name |
4091 | + :type event: str |
4092 | + :returns: None |
4093 | + |
4094 | + """ |
4095 | + LOGGER.debug('smem stop: {}'.format(event)) |
4096 | + LOGGER.debug('Running {!r}...'.format(self.BINARY)) |
4097 | + output = subprocess.check_output(self.BINARY) |
4098 | + parser = SmemParser() |
4099 | + pids_info = parser.parse(output) |
4100 | + threshold_exceeded_pids = self._calculate_threshold_exceeded(pids_info) |
4101 | + print '{:-^72}'.format(event) |
4102 | + for pid in self.pids: |
4103 | + print('PID: {pid}, command: {command}, PSS: {pss}, USS: {uss}' |
4104 | + .format(**pids_info[pid])) |
4105 | + |
4106 | + self.current_reading['stop_time'] = time() |
4107 | + self.current_reading['data'] = pids_info |
4108 | + self.readings.append(self.current_reading) |
4109 | + if threshold_exceeded_pids: |
4110 | + self.threshold_exceeded_summary.append( |
4111 | + (event, threshold_exceeded_pids)) |
4112 | + self.current_reading = None |
4113 | + |
4114 | + def _calculate_threshold_exceeded(self, pids_info): |
4115 | + """Calculate thresholds for the given set of pids. |
4116 | + |
4117 | + :param pids_info: |
4118 | + Memory usage data for a give set of pids. |
4119 | + |
4120 | + ..note:: |
4121 | + This parameter is modified in place to add a delta of the PSS |
4122 | + and the threshold. |
4123 | + :type pids_info: list(dict) |
4124 | + |
4125 | + """ |
4126 | + # It's assumed that the pid for the foreground application is the one |
4127 | + # that was last added to the probe |
4128 | + foreground_pid = self.pids[-1] |
4129 | + foreground_threshold = self.THRESHOLDS['foreground'] |
4130 | + background_pids = self.pids[:-1] |
4131 | + background_threshold = self.THRESHOLDS['background'] |
4132 | + |
4133 | + pids_and_thresholds = itertools.chain( |
4134 | + [(foreground_pid, foreground_threshold)], |
4135 | + itertools.product(background_pids, [background_threshold])) |
4136 | + |
4137 | + threshold_exceeded_pids = [] |
4138 | + for pid, threshold in pids_and_thresholds: |
4139 | + if pid in pids_info: |
4140 | + pid_info = pids_info[pid] |
4141 | + delta = pid_info['pss'] - threshold |
4142 | + pid_info['threshold_exceeded'] = delta |
4143 | + if delta > 0: |
4144 | + threshold_exceeded_pids.append(pid) |
4145 | + return threshold_exceeded_pids |
4146 | + |
4147 | + @property |
4148 | + def report(self): |
4149 | + """Return report with all the readings that have been made.""" |
4150 | + return {'pids': self.pids, |
4151 | + 'thresholds': self.THRESHOLDS, |
4152 | + 'readings': self.readings} |
4153 | + |
4154 | + |
4155 | +class SmemParser(object): |
4156 | + |
4157 | + """Parser object to map smem output to data structure.""" |
4158 | + |
4159 | + SMEM_LINE = re.compile( |
4160 | + r'\s*(?P<pid>\d+)' |
4161 | + r'\s+(?P<user>\w+)' |
4162 | + r'\s+(?P<command>.+?)' |
4163 | + r'\s+(?P<swap>\d+)' |
4164 | + r'\s+(?P<uss>\d+)' |
4165 | + r'\s+(?P<pss>\d+)' |
4166 | + r'\s+(?P<rss>\d+)') |
4167 | + |
4168 | + def parse(self, output): |
4169 | + """Parse smem output. |
4170 | + |
4171 | + :param output: The report printed to stdout by smem |
4172 | + :type output: str |
4173 | + :returns: Data structure that can be serialized |
4174 | + :rtype: dict(dict) |
4175 | + |
4176 | + """ |
4177 | + pids_info = filter(None, |
4178 | + [self._parse_line(line) |
4179 | + for line in output.splitlines()[1:]]) |
4180 | + return {pid_info['pid']: pid_info for pid_info in pids_info} |
4181 | + |
4182 | + def _parse_line(self, line): |
4183 | + """Parse a single smem output line. |
4184 | + |
4185 | + :param line: |
4186 | + A single line containing all the fields to parse for a process. |
4187 | + :type line: str |
4188 | + :returns: Data structure with the parsed fields |
4189 | + :rtype: dict |
4190 | + |
4191 | + """ |
4192 | + match = self.SMEM_LINE.match(line) |
4193 | + if not match: |
4194 | + LOGGER.warning('Unable to parse smem output: {}'.format(line)) |
4195 | + return None |
4196 | + |
4197 | + pid_info = match.groupdict() |
4198 | + for key in ('pid', 'swap', 'uss', 'pss', 'rss'): |
4199 | + pid_info[key] = int(pid_info[key]) |
4200 | + return pid_info |
4201 | |
4202 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/smem-tabs' |
4203 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/smem-tabs 1970-01-01 00:00:00 +0000 |
4204 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/smem-tabs 2014-01-15 20:49:07 +0000 |
4205 | @@ -0,0 +1,687 @@ |
4206 | +#!/usr/bin/env python |
4207 | +# |
4208 | +# smem - a tool for meaningful memory reporting |
4209 | +# |
4210 | +# Copyright 2008-2009 Matt Mackall <mpm@selenic.com> |
4211 | +# |
4212 | +# This software may be used and distributed according to the terms of |
4213 | +# the GNU General Public License version 2 or later, incorporated |
4214 | +# herein by reference. |
4215 | + |
4216 | +import re, os, sys, pwd, optparse, errno, tarfile |
4217 | + |
4218 | +warned = False |
4219 | + |
4220 | +class procdata(object): |
4221 | + def __init__(self, source): |
4222 | + self._ucache = {} |
4223 | + self._gcache = {} |
4224 | + self.source = source and source or "" |
4225 | + self._memdata = None |
4226 | + def _list(self): |
4227 | + return os.listdir(self.source + "/proc") |
4228 | + def _read(self, f): |
4229 | + return file(self.source + '/proc/' + f).read() |
4230 | + def _readlines(self, f): |
4231 | + return self._read(f).splitlines(True) |
4232 | + def _stat(self, f): |
4233 | + return os.stat(self.source + "/proc/" + f) |
4234 | + |
4235 | + def pids(self): |
4236 | + '''get a list of processes''' |
4237 | + return [int(e) for e in self._list() |
4238 | + if e.isdigit() and not iskernel(e)] |
4239 | + def mapdata(self, pid): |
4240 | + return self._readlines('%s/smaps' % pid) |
4241 | + def memdata(self): |
4242 | + if self._memdata is None: |
4243 | + self._memdata = self._readlines('meminfo') |
4244 | + return self._memdata |
4245 | + def version(self): |
4246 | + return self._readlines('version')[0] |
4247 | + def pidname(self, pid): |
4248 | + try: |
4249 | + l = self.pidcmd(pid).split(' ')[0] |
4250 | + return os.path.basename(l) |
4251 | + except: |
4252 | + return '?' |
4253 | + def pidcmd(self, pid): |
4254 | + try: |
4255 | + c = self._read('%s/cmdline' % pid)[:-1] |
4256 | + return c.replace('\0', ' ') |
4257 | + except: |
4258 | + return '?' |
4259 | + def piduser(self, pid): |
4260 | + try: |
4261 | + return self._stat('%d' % pid).st_uid |
4262 | + except: |
4263 | + return -1 |
4264 | + def pidgroup(self, pid): |
4265 | + try: |
4266 | + return self._stat('%d' % pid).st_gid |
4267 | + except: |
4268 | + return -1 |
4269 | + def username(self, uid): |
4270 | + if uid == -1: |
4271 | + return '?' |
4272 | + if uid not in self._ucache: |
4273 | + try: |
4274 | + self._ucache[uid] = pwd.getpwuid(uid)[0] |
4275 | + except KeyError: |
4276 | + self._ucache[uid] = str(uid) |
4277 | + return self._ucache[uid] |
4278 | + def groupname(self, gid): |
4279 | + if gid == -1: |
4280 | + return '?' |
4281 | + if gid not in self._gcache: |
4282 | + try: |
4283 | + self._gcache[gid] = pwd.getgrgid(gid)[0] |
4284 | + except KeyError: |
4285 | + self._gcache[gid] = str(gid) |
4286 | + return self._gcache[gid] |
4287 | + |
4288 | +class tardata(procdata): |
4289 | + def __init__(self, source): |
4290 | + procdata.__init__(self, source) |
4291 | + self.tar = tarfile.open(source) |
4292 | + def _list(self): |
4293 | + for ti in self.tar: |
4294 | + if ti.name.endswith('/smaps'): |
4295 | + d,f = ti.name.split('/') |
4296 | + yield d |
4297 | + def _read(self, f): |
4298 | + return self.tar.extractfile(f).read() |
4299 | + def _readlines(self, f): |
4300 | + return self.tar.extractfile(f).readlines() |
4301 | + def piduser(self, p): |
4302 | + t = self.tar.getmember("%d" % p) |
4303 | + if t.uname: |
4304 | + self._ucache[t.uid] = t.uname |
4305 | + return t.uid |
4306 | + def pidgroup(self, p): |
4307 | + t = self.tar.getmember("%d" % p) |
4308 | + if t.gname: |
4309 | + self._gcache[t.gid] = t.gname |
4310 | + return t.gid |
4311 | + def username(self, u): |
4312 | + return self._ucache.get(u, str(u)) |
4313 | + def groupname(self, g): |
4314 | + return self._gcache.get(g, str(g)) |
4315 | + |
4316 | +_totalmem = 0 |
4317 | +def totalmem(): |
4318 | + global _totalmem |
4319 | + if not _totalmem: |
4320 | + if options.realmem: |
4321 | + _totalmem = fromunits(options.realmem) / 1024 |
4322 | + else: |
4323 | + _totalmem = memory()['memtotal'] |
4324 | + return _totalmem |
4325 | + |
4326 | +_kernelsize = 0 |
4327 | +def kernelsize(): |
4328 | + global _kernelsize |
4329 | + if not _kernelsize and options.kernel: |
4330 | + try: |
4331 | + d = os.popen("size %s" % options.kernel).readlines()[1] |
4332 | + _kernelsize = int(d.split()[3]) / 1024 |
4333 | + except: |
4334 | + try: |
4335 | + # try some heuristic to find gzipped part in kernel image |
4336 | + packedkernel = open(options.kernel).read() |
4337 | + pos = packedkernel.find('\x1F\x8B') |
4338 | + if pos >= 0 and pos < 25000: |
4339 | + sys.stderr.write("Maybe uncompressed kernel can be extracted by the command:\n" |
4340 | + " dd if=%s bs=1 skip=%d | gzip -d >%s.unpacked\n\n" % (options.kernel, pos, options.kernel)) |
4341 | + except: |
4342 | + pass |
4343 | + sys.stderr.write("Parameter '%s' should be an original uncompressed compiled kernel file.\n\n" % options.kernel) |
4344 | + return _kernelsize |
4345 | + |
4346 | +def pidmaps(pid): |
4347 | + global warned |
4348 | + maps = {} |
4349 | + start = None |
4350 | + seen = False |
4351 | + for l in src.mapdata(pid): |
4352 | + f = l.split() |
4353 | + if f[-1] == 'kB': |
4354 | + if f[0].startswith('Pss'): |
4355 | + seen = True |
4356 | + maps[start][f[0][:-1].lower()] = int(f[1]) |
4357 | + elif f[0] == 'VmFlags:': |
4358 | + continue |
4359 | + else: |
4360 | + start, end = f[0].split('-') |
4361 | + start = int(start, 16) |
4362 | + name = "<anonymous>" |
4363 | + if len(f) > 5: |
4364 | + name = f[5] |
4365 | + maps[start] = dict(end=int(end, 16), mode=f[1], |
4366 | + offset=int(f[2], 16), |
4367 | + device=f[3], inode=f[4], name=name) |
4368 | + |
4369 | + if not seen and not warned: |
4370 | + sys.stderr.write('warning: kernel does not appear to support PSS measurement\n') |
4371 | + warned = True |
4372 | + if not options.sort: |
4373 | + options.sort = 'rss' |
4374 | + |
4375 | + if options.mapfilter: |
4376 | + f = {} |
4377 | + for m in maps: |
4378 | + if not filter(options.mapfilter, m, lambda x: maps[x]['name']): |
4379 | + f[m] = maps[m] |
4380 | + return f |
4381 | + |
4382 | + return maps |
4383 | + |
4384 | +def sortmaps(totals, key): |
4385 | + l = [] |
4386 | + for pid in totals: |
4387 | + l.append((totals[pid][key], pid)) |
4388 | + l.sort() |
4389 | + return [pid for pid,key in l] |
4390 | + |
4391 | +def iskernel(pid): |
4392 | + return src.pidcmd(pid) == "" |
4393 | + |
4394 | +def memory(): |
4395 | + t = {} |
4396 | + f = re.compile('(\\S+):\\s+(\\d+) kB') |
4397 | + for l in src.memdata(): |
4398 | + m = f.match(l) |
4399 | + if m: |
4400 | + t[m.group(1).lower()] = int(m.group(2)) |
4401 | + return t |
4402 | + |
4403 | +def units(x): |
4404 | + s = '' |
4405 | + if x == 0: |
4406 | + return '0' |
4407 | + for s in ('', 'K', 'M', 'G', 'T'): |
4408 | + if x < 1024: |
4409 | + break |
4410 | + x /= 1024.0 |
4411 | + return "%.1f%s" % (x, s) |
4412 | + |
4413 | +def fromunits(x): |
4414 | + s = dict(k=2**10, K=2**10, kB=2**10, KB=2**10, |
4415 | + M=2**20, MB=2**20, G=2**30, GB=2**30, |
4416 | + T=2**40, TB=2**40) |
4417 | + for k,v in s.items(): |
4418 | + if x.endswith(k): |
4419 | + return int(float(x[:-len(k)])*v) |
4420 | + sys.stderr.write("Memory size should be written with units, for example 1024M\n") |
4421 | + sys.exit(-1) |
4422 | + |
4423 | +def pidusername(pid): |
4424 | + return src.username(src.piduser(pid)) |
4425 | + |
4426 | +def showamount(a, total): |
4427 | + if options.abbreviate: |
4428 | + return units(a * 1024) |
4429 | + elif options.percent: |
4430 | + return "%.2f%%" % (100.0 * a / total) |
4431 | + return a |
4432 | + |
4433 | +def filter(opt, arg, *sources): |
4434 | + if not opt: |
4435 | + return False |
4436 | + |
4437 | + for f in sources: |
4438 | + if re.search(opt, f(arg)): |
4439 | + return False |
4440 | + return True |
4441 | + |
4442 | +def pidtotals(pid): |
4443 | + maps = pidmaps(pid) |
4444 | + t = dict(size=0, rss=0, pss=0, shared_clean=0, shared_dirty=0, |
4445 | + private_clean=0, private_dirty=0, referenced=0, swap=0) |
4446 | + for m in maps.iterkeys(): |
4447 | + for k in t: |
4448 | + t[k] += maps[m].get(k, 0) |
4449 | + |
4450 | + t['uss'] = t['private_clean'] + t['private_dirty'] |
4451 | + t['maps'] = len(maps) |
4452 | + |
4453 | + return t |
4454 | + |
4455 | +def processtotals(pids): |
4456 | + totals = {} |
4457 | + for pid in pids: |
4458 | + if (filter(options.processfilter, pid, src.pidname, src.pidcmd) or |
4459 | + filter(options.userfilter, pid, pidusername)): |
4460 | + continue |
4461 | + try: |
4462 | + p = pidtotals(pid) |
4463 | + if p['maps'] != 0: |
4464 | + totals[pid] = p |
4465 | + except: |
4466 | + continue |
4467 | + return totals |
4468 | + |
4469 | +def showpids(): |
4470 | + p = src.pids() |
4471 | + pt = processtotals(p) |
4472 | + |
4473 | + def showuser(p): |
4474 | + if options.numeric: |
4475 | + return src.piduser(p) |
4476 | + return pidusername(p) |
4477 | + |
4478 | + fields = dict( |
4479 | + pid=('PID', lambda n: n, '% 5s', lambda x: len(pt), |
4480 | + 'process ID'), |
4481 | + user=('User', showuser, '%-8s', lambda x: len(dict.fromkeys(x)), |
4482 | + 'owner of process'), |
4483 | + name=('Name', src.pidname, '%s', None, |
4484 | + 'name of process'), |
4485 | + command=('Command', src.pidcmd, '%s', None, |
4486 | + 'process command line'), |
4487 | + maps=('Maps',lambda n: pt[n]['maps'], '% 5s', sum, |
4488 | + 'total number of mappings'), |
4489 | + swap=('Swap',lambda n: pt[n]['swap'], '% 8a', sum, |
4490 | + 'amount of swap space consumed (ignoring sharing)'), |
4491 | + uss=('USS', lambda n: pt[n]['uss'], '%a', sum, |
4492 | + 'unique set size'), |
4493 | + rss=('RSS', lambda n: pt[n]['rss'], '%a', sum, |
4494 | + 'resident set size (ignoring sharing)'), |
4495 | + pss=('PSS', lambda n: pt[n]['pss'], '%a', sum, |
4496 | + 'proportional set size (including sharing)'), |
4497 | + vss=('VSS', lambda n: pt[n]['size'], '%a', sum, |
4498 | + 'virtual set size (total virtual memory mapped)'), |
4499 | + ) |
4500 | + columns = options.columns or 'pid user command swap uss pss rss' |
4501 | + |
4502 | + showtable(pt.keys(), fields, columns.split(), options.sort or 'pss') |
4503 | + |
4504 | +def maptotals(pids): |
4505 | + totals = {} |
4506 | + for pid in pids: |
4507 | + if (filter(options.processfilter, pid, src.pidname, src.pidcmd) or |
4508 | + filter(options.userfilter, pid, pidusername)): |
4509 | + continue |
4510 | + try: |
4511 | + maps = pidmaps(pid) |
4512 | + seen = {} |
4513 | + for m in maps.iterkeys(): |
4514 | + name = maps[m]['name'] |
4515 | + if name not in totals: |
4516 | + t = dict(size=0, rss=0, pss=0, shared_clean=0, |
4517 | + shared_dirty=0, private_clean=0, count=0, |
4518 | + private_dirty=0, referenced=0, swap=0, pids=0) |
4519 | + else: |
4520 | + t = totals[name] |
4521 | + |
4522 | + for k in t: |
4523 | + t[k] += maps[m].get(k, 0) |
4524 | + t['count'] += 1 |
4525 | + if name not in seen: |
4526 | + t['pids'] += 1 |
4527 | + seen[name] = 1 |
4528 | + totals[name] = t |
4529 | + except EnvironmentError: |
4530 | + continue |
4531 | + return totals |
4532 | + |
4533 | +def showmaps(): |
4534 | + p = src.pids() |
4535 | + pt = maptotals(p) |
4536 | + |
4537 | + fields = dict( |
4538 | + map=('Map', lambda n: n, '%-40.40s', len, |
4539 | + 'mapping name'), |
4540 | + count=('Count', lambda n: pt[n]['count'], '% 5s', sum, |
4541 | + 'number of mappings found'), |
4542 | + pids=('PIDs', lambda n: pt[n]['pids'], '% 5s', sum, |
4543 | + 'number of PIDs using mapping'), |
4544 | + swap=('Swap',lambda n: pt[n]['swap'], '% 8a', sum, |
4545 | + 'amount of swap space consumed (ignoring sharing)'), |
4546 | + uss=('USS', lambda n: pt[n]['private_clean'] |
4547 | + + pt[n]['private_dirty'], '% 8a', sum, |
4548 | + 'unique set size'), |
4549 | + rss=('RSS', lambda n: pt[n]['rss'], '% 8a', sum, |
4550 | + 'resident set size (ignoring sharing)'), |
4551 | + pss=('PSS', lambda n: pt[n]['pss'], '% 8a', sum, |
4552 | + 'proportional set size (including sharing)'), |
4553 | + vss=('VSS', lambda n: pt[n]['size'], '% 8a', sum, |
4554 | + 'virtual set size (total virtual address space mapped)'), |
4555 | + avgpss=('AVGPSS', lambda n: int(1.0 * pt[n]['pss']/pt[n]['pids']), |
4556 | + '% 8a', sum, |
4557 | + 'average PSS per PID'), |
4558 | + avguss=('AVGUSS', lambda n: int(1.0 * pt[n]['uss']/pt[n]['pids']), |
4559 | + '% 8a', sum, |
4560 | + 'average USS per PID'), |
4561 | + avgrss=('AVGRSS', lambda n: int(1.0 * pt[n]['rss']/pt[n]['pids']), |
4562 | + '% 8a', sum, |
4563 | + 'average RSS per PID'), |
4564 | + ) |
4565 | + columns = options.columns or 'map pids avgpss pss' |
4566 | + |
4567 | + showtable(pt.keys(), fields, columns.split(), options.sort or 'pss') |
4568 | + |
4569 | +def usertotals(pids): |
4570 | + totals = {} |
4571 | + for pid in pids: |
4572 | + if (filter(options.processfilter, pid, src.pidname, src.pidcmd) or |
4573 | + filter(options.userfilter, pid, pidusername)): |
4574 | + continue |
4575 | + try: |
4576 | + maps = pidmaps(pid) |
4577 | + if len(maps) == 0: |
4578 | + continue |
4579 | + except EnvironmentError: |
4580 | + continue |
4581 | + user = src.piduser(pid) |
4582 | + if user not in totals: |
4583 | + t = dict(size=0, rss=0, pss=0, shared_clean=0, |
4584 | + shared_dirty=0, private_clean=0, count=0, |
4585 | + private_dirty=0, referenced=0, swap=0) |
4586 | + else: |
4587 | + t = totals[user] |
4588 | + |
4589 | + for m in maps.iterkeys(): |
4590 | + for k in t: |
4591 | + t[k] += maps[m].get(k, 0) |
4592 | + |
4593 | + t['count'] += 1 |
4594 | + totals[user] = t |
4595 | + return totals |
4596 | + |
4597 | +def showusers(): |
4598 | + p = src.pids() |
4599 | + pt = usertotals(p) |
4600 | + |
4601 | + def showuser(u): |
4602 | + if options.numeric: |
4603 | + return u |
4604 | + return src.username(u) |
4605 | + |
4606 | + fields = dict( |
4607 | + user=('User', showuser, '%-8s', None, |
4608 | + 'user name or ID'), |
4609 | + count=('Count', lambda n: pt[n]['count'], '% 5s', sum, |
4610 | + 'number of processes'), |
4611 | + swap=('Swap',lambda n: pt[n]['swap'], '% 8a', sum, |
4612 | + 'amount of swapspace consumed (ignoring sharing)'), |
4613 | + uss=('USS', lambda n: pt[n]['private_clean'] |
4614 | + + pt[n]['private_dirty'], '% 8a', sum, |
4615 | + 'unique set size'), |
4616 | + rss=('RSS', lambda n: pt[n]['rss'], '% 8a', sum, |
4617 | + 'resident set size (ignoring sharing)'), |
4618 | + pss=('PSS', lambda n: pt[n]['pss'], '% 8a', sum, |
4619 | + 'proportional set size (including sharing)'), |
4620 | + vss=('VSS', lambda n: pt[n]['pss'], '% 8a', sum, |
4621 | + 'virtual set size (total virtual memory mapped)'), |
4622 | + ) |
4623 | + columns = options.columns or 'user count swap uss pss rss' |
4624 | + |
4625 | + showtable(pt.keys(), fields, columns.split(), options.sort or 'pss') |
4626 | + |
4627 | +def showsystem(): |
4628 | + t = totalmem() |
4629 | + ki = kernelsize() |
4630 | + m = memory() |
4631 | + |
4632 | + mt = m['memtotal'] |
4633 | + f = m['memfree'] |
4634 | + |
4635 | + # total amount used by hardware |
4636 | + fh = max(t - mt - ki, 0) |
4637 | + |
4638 | + # total amount mapped into userspace (ie mapped an unmapped pages) |
4639 | + u = m['anonpages'] + m['mapped'] |
4640 | + |
4641 | + # total amount allocated by kernel not for userspace |
4642 | + kd = mt - f - u |
4643 | + |
4644 | + # total amount in kernel caches |
4645 | + kdc = m['buffers'] + m['sreclaimable'] + (m['cached'] - m['mapped']) |
4646 | + |
4647 | + l = [("firmware/hardware", fh, 0), |
4648 | + ("kernel image", ki, 0), |
4649 | + ("kernel dynamic memory", kd, kdc), |
4650 | + ("userspace memory", u, m['mapped']), |
4651 | + ("free memory", f, f)] |
4652 | + |
4653 | + fields = dict( |
4654 | + order=('Order', lambda n: n, '% 1s', lambda x: '', |
4655 | + 'hierarchical order'), |
4656 | + area=('Area', lambda n: l[n][0], '%-24s', lambda x: '', |
4657 | + 'memory area'), |
4658 | + used=('Used', lambda n: l[n][1], '%10a', sum, |
4659 | + 'area in use'), |
4660 | + cache=('Cache', lambda n: l[n][2], '%10a', sum, |
4661 | + 'area used as reclaimable cache'), |
4662 | + noncache=('Noncache', lambda n: l[n][1] - l[n][2], '%10a', sum, |
4663 | + 'area not reclaimable')) |
4664 | + |
4665 | + columns = options.columns or 'area used cache noncache' |
4666 | + showtable(range(len(l)), fields, columns.split(), options.sort or 'order') |
4667 | + |
4668 | +def showfields(fields, f): |
4669 | + if f != list: |
4670 | + print "unknown field", f |
4671 | + print "known fields:" |
4672 | + for l in sorted(fields.keys()): |
4673 | + print "%-8s %s" % (l, fields[l][-1]) |
4674 | + |
4675 | +def showtable(rows, fields, columns, sort): |
4676 | + header = "" |
4677 | + format = "" |
4678 | + formatter = [] |
4679 | + |
4680 | + if sort not in fields: |
4681 | + showfields(fields, sort) |
4682 | + sys.exit(-1) |
4683 | + |
4684 | + if options.pie: |
4685 | + columns.append(options.pie) |
4686 | + if options.bar: |
4687 | + columns.append(options.bar) |
4688 | + |
4689 | + mt = totalmem() |
4690 | + st = memory()['swaptotal'] |
4691 | + |
4692 | + for n in columns: |
4693 | + if n not in fields: |
4694 | + showfields(fields, n) |
4695 | + sys.exit(-1) |
4696 | + |
4697 | + f = fields[n][2] |
4698 | + if 'a' in f: |
4699 | + if n == 'swap': |
4700 | + formatter.append(lambda x: showamount(x, st)) |
4701 | + else: |
4702 | + formatter.append(lambda x: showamount(x, mt)) |
4703 | + f = f.replace('a', 's') |
4704 | + else: |
4705 | + formatter.append(lambda x: x) |
4706 | + format += f + "\t" |
4707 | + header += f % fields[n][0] + "\t" |
4708 | + |
4709 | + l = [] |
4710 | + for n in rows: |
4711 | + r = [fields[c][1](n) for c in columns] |
4712 | + l.append((fields[sort][1](n), r)) |
4713 | + |
4714 | + l.sort(reverse=bool(options.reverse)) |
4715 | + |
4716 | + if options.pie: |
4717 | + showpie(l, sort) |
4718 | + return |
4719 | + elif options.bar: |
4720 | + showbar(l, columns, sort) |
4721 | + return |
4722 | + |
4723 | + if not options.no_header: |
4724 | + print header |
4725 | + |
4726 | + for k,r in l: |
4727 | + print format % tuple([f(v) for f,v in zip(formatter, r)]) |
4728 | + |
4729 | + if options.totals: |
4730 | + # totals |
4731 | + t = [] |
4732 | + for c in columns: |
4733 | + f = fields[c][3] |
4734 | + if f: |
4735 | + t.append(f([fields[c][1](n) for n in rows])) |
4736 | + else: |
4737 | + t.append("") |
4738 | + |
4739 | + print "-" * len(header) |
4740 | + print format % tuple([f(v) for f,v in zip(formatter, t)]) |
4741 | + |
4742 | +def showpie(l, sort): |
4743 | + try: |
4744 | + import pylab |
4745 | + except ImportError: |
4746 | + sys.stderr.write("pie chart requires matplotlib\n") |
4747 | + sys.exit(-1) |
4748 | + |
4749 | + if (l[0][0] < l[-1][0]): |
4750 | + l.reverse() |
4751 | + |
4752 | + labels = [r[1][-1] for r in l] |
4753 | + values = [r[0] for r in l] # sort field |
4754 | + |
4755 | + tm = totalmem() |
4756 | + s = sum(values) |
4757 | + unused = tm - s |
4758 | + t = 0 |
4759 | + while values and (t + values[-1] < (tm * .02) or |
4760 | + values[-1] < (tm * .005)): |
4761 | + t += values.pop() |
4762 | + labels.pop() |
4763 | + |
4764 | + if t: |
4765 | + values.append(t) |
4766 | + labels.append('other') |
4767 | + |
4768 | + explode = [0] * len(values) |
4769 | + if unused > 0: |
4770 | + values.insert(0, unused) |
4771 | + labels.insert(0, 'unused') |
4772 | + explode.insert(0, .05) |
4773 | + |
4774 | + pylab.figure(1, figsize=(6,6)) |
4775 | + ax = pylab.axes([0.1, 0.1, 0.8, 0.8]) |
4776 | + pylab.pie(values, explode = explode, labels=labels, |
4777 | + autopct="%.2f%%", shadow=True) |
4778 | + pylab.title('%s by %s' % (options.pie, sort)) |
4779 | + pylab.show() |
4780 | + |
4781 | +def showbar(l, columns, sort): |
4782 | + try: |
4783 | + import pylab, numpy |
4784 | + except ImportError: |
4785 | + sys.stderr.write("bar chart requires matplotlib\n") |
4786 | + sys.exit(-1) |
4787 | + |
4788 | + if (l[0][0] < l[-1][0]): |
4789 | + l.reverse() |
4790 | + |
4791 | + rc = [] |
4792 | + key = [] |
4793 | + for n in range(len(columns) - 1): |
4794 | + try: |
4795 | + if columns[n] in 'pid user group'.split(): |
4796 | + continue |
4797 | + float(l[0][1][n]) |
4798 | + rc.append(n) |
4799 | + key.append(columns[n]) |
4800 | + except: |
4801 | + pass |
4802 | + |
4803 | + width = 1.0 / (len(rc) + 1) |
4804 | + offset = width / 2 |
4805 | + |
4806 | + def gc(n): |
4807 | + return 'bgrcmyw'[n % 7] |
4808 | + |
4809 | + pl = [] |
4810 | + ind = numpy.arange(len(l)) |
4811 | + for n in xrange(len(rc)): |
4812 | + pl.append(pylab.bar(ind + offset + width * n, |
4813 | + [x[1][rc[n]] for x in l], width, color=gc(n))) |
4814 | + |
4815 | + #plt.xticks(ind + .5, ) |
4816 | + pylab.gca().set_xticks(ind + .5) |
4817 | + pylab.gca().set_xticklabels([x[1][-1] for x in l], rotation=45) |
4818 | + pylab.legend([p[0] for p in pl], key) |
4819 | + pylab.show() |
4820 | + |
4821 | + |
4822 | +parser = optparse.OptionParser("%prog [options]") |
4823 | +parser.add_option("-H", "--no-header", action="store_true", |
4824 | + help="disable header line") |
4825 | +parser.add_option("-c", "--columns", type="str", |
4826 | + help="columns to show") |
4827 | +parser.add_option("-t", "--totals", action="store_true", |
4828 | + help="show totals") |
4829 | + |
4830 | +parser.add_option("-R", "--realmem", type="str", |
4831 | + help="amount of physical RAM") |
4832 | +parser.add_option("-K", "--kernel", type="str", |
4833 | + help="path to kernel image") |
4834 | + |
4835 | +parser.add_option("-m", "--mappings", action="store_true", |
4836 | + help="show mappings") |
4837 | +parser.add_option("-u", "--users", action="store_true", |
4838 | + help="show users") |
4839 | +parser.add_option("-w", "--system", action="store_true", |
4840 | + help="show whole system") |
4841 | + |
4842 | +parser.add_option("-P", "--processfilter", type="str", |
4843 | + help="process filter regex") |
4844 | +parser.add_option("-M", "--mapfilter", type="str", |
4845 | + help="map filter regex") |
4846 | +parser.add_option("-U", "--userfilter", type="str", |
4847 | + help="user filter regex") |
4848 | + |
4849 | +parser.add_option("-n", "--numeric", action="store_true", |
4850 | + help="numeric output") |
4851 | +parser.add_option("-s", "--sort", type="str", |
4852 | + help="field to sort on") |
4853 | +parser.add_option("-r", "--reverse", action="store_true", |
4854 | + help="reverse sort") |
4855 | + |
4856 | +parser.add_option("-p", "--percent", action="store_true", |
4857 | + help="show percentage") |
4858 | +parser.add_option("-k", "--abbreviate", action="store_true", |
4859 | + help="show unit suffixes") |
4860 | + |
4861 | +parser.add_option("", "--pie", type='str', |
4862 | + help="show pie graph") |
4863 | +parser.add_option("", "--bar", type='str', |
4864 | + help="show bar graph") |
4865 | + |
4866 | +parser.add_option("-S", "--source", type="str", |
4867 | + help="/proc data source") |
4868 | + |
4869 | + |
4870 | +defaults = {} |
4871 | +parser.set_defaults(**defaults) |
4872 | +(options, args) = parser.parse_args() |
4873 | + |
4874 | +try: |
4875 | + src = tardata(options.source) |
4876 | +except: |
4877 | + src = procdata(options.source) |
4878 | + |
4879 | +try: |
4880 | + if options.mappings: |
4881 | + showmaps() |
4882 | + elif options.users: |
4883 | + showusers() |
4884 | + elif options.system: |
4885 | + showsystem() |
4886 | + else: |
4887 | + showpids() |
4888 | +except IOError, e: |
4889 | + if e.errno == errno.EPIPE: |
4890 | + pass |
4891 | +except KeyboardInterrupt: |
4892 | + pass |
4893 | |
4894 | === added directory 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests' |
4895 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/__init__.py' |
4896 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/__init__.py 1970-01-01 00:00:00 +0000 |
4897 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/__init__.py 2014-01-15 20:49:07 +0000 |
4898 | @@ -0,0 +1,1 @@ |
4899 | +"""Event based memory usage measurements test cases.""" |
4900 | |
4901 | === added file 'tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_memory_usage.py' |
4902 | --- tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_memory_usage.py 1970-01-01 00:00:00 +0000 |
4903 | +++ tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_memory_usage.py 2014-01-15 20:49:07 +0000 |
4904 | @@ -0,0 +1,80 @@ |
4905 | +"""Measure touch applications memory usage.""" |
4906 | + |
4907 | +import json |
4908 | +import logging |
4909 | +import os |
4910 | + |
4911 | +from autopilot.testcase import AutopilotTestCase |
4912 | + |
4913 | +from ubuntu_test_cases.memory_usage_measurement.apps.browser import BrowserApp |
4914 | +from ubuntu_test_cases.memory_usage_measurement.apps.camera import CameraApp |
4915 | +from ubuntu_test_cases.memory_usage_measurement.apps.gallery import GalleryApp |
4916 | +from ubuntu_test_cases.memory_usage_measurement.apps.media_player import ( |
4917 | + MediaPlayerApp, |
4918 | +) |
4919 | +from ubuntu_test_cases.memory_usage_measurement.probes import SmemProbe |
4920 | + |
4921 | +LOGGER = logging.getLogger(__file__) |
4922 | + |
4923 | + |
4924 | +class MemoryUsageTests(AutopilotTestCase): |
4925 | + |
4926 | + """Event based memory usage measurement scenario.""" |
4927 | + |
4928 | + def test_scenario(self): |
4929 | + """Scenario that takes measurements on some events.""" |
4930 | + self.smem = SmemProbe() |
4931 | + |
4932 | + # Make sure report is written with the data collected |
4933 | + # even if the test failed to complete |
4934 | + self.addCleanup(self._write_report) |
4935 | + |
4936 | + browser = BrowserApp(self) |
4937 | + with self.smem.probe('Browser started'): |
4938 | + browser.launch() |
4939 | + self.smem.pids.append(browser.app.pid) |
4940 | + |
4941 | + with self.smem.probe('Browser finished loading'): |
4942 | + url = 'http://acid3.acidtests.org/' |
4943 | + browser.go_to_url(url) |
4944 | + browser.assert_page_eventually_loaded(url) |
4945 | + |
4946 | + camera = CameraApp(self) |
4947 | + with self.smem.probe('Camera app started'): |
4948 | + camera.launch() |
4949 | + self.smem.pids.append(camera.app.pid) |
4950 | + |
4951 | + with self.smem.probe('Camera app picture taken'): |
4952 | + camera.take_picture() |
4953 | + |
4954 | + with self.smem.probe('Gallery app started'): |
4955 | + gallery = GalleryApp(self) |
4956 | + gallery.launch() |
4957 | + self.smem.pids.append(gallery.app.pid) |
4958 | + |
4959 | + with self.smem.probe('Media player app started'): |
4960 | + media_player = MediaPlayerApp(self) |
4961 | + media_player.launch() |
4962 | + self.smem.pids.append(media_player.app.pid) |
4963 | + |
4964 | + with self.smem.probe('Media player app finished playback'): |
4965 | + media_player = MediaPlayerApp(self) |
4966 | + media_player.launch('small.mp4') |
4967 | + self.smem.pids.append(media_player.app.pid) |
4968 | + media_player.assert_playback_finished() |
4969 | + |
4970 | + summary_msg = '\n'.join( |
4971 | + ['- {}: {}'.format(event, pids) |
4972 | + for event, pids in self.smem.threshold_exceeded_summary]) |
4973 | + self.assertListEqual( |
4974 | + self.smem.threshold_exceeded_summary, |
4975 | + [], |
4976 | + 'Threshold(s) exceded:\n{}'.format(summary_msg)) |
4977 | + |
4978 | + def _write_report(self): |
4979 | + """Write report to to results directory.""" |
4980 | + report_filename = '/tmp/memory_usage.json' |
4981 | + with open(report_filename, 'w') as report_file: |
4982 | + json.dump(self.smem.report, report_file, |
4983 | + indent=4, sort_keys=True) |
4984 | + LOGGER.debug('Report written to {}'.format(report_file.name)) |
4985 | |
4986 | === added directory 'tests/messaging-app-autopilot' |
4987 | === added file 'tests/messaging-app-autopilot/master.run' |
4988 | --- tests/messaging-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
4989 | +++ tests/messaging-app-autopilot/master.run 2014-01-15 20:49:07 +0000 |
4990 | @@ -0,0 +1,15 @@ |
4991 | +--- |
4992 | +testsuites: |
4993 | + - name: settle-before |
4994 | + fetch_method: dev |
4995 | + fetch_location: ../systemsettle |
4996 | + include_tests: |
4997 | + - systemsettle-before |
4998 | + - name: messaging-app-autopilot |
4999 | + fetch_method: dev |
5000 | + fetch_location: ./ |
The diff has been truncated for viewing.