Merge lp:~achiang/ubuntu-test-cases/savilerow into lp:ubuntu-test-cases

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
Reviewer Review Type Date Requested Status
Ubuntu Test Case Developers Pending
Review via email: mp+201849@code.launchpad.net

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+&lt;pre&gt;
460+#NOTE: Automatically created from a script as part of daily smoke testing&#xd;
461+ {{branch}}&#xd;
462+&lt;/pre&gt;
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=&quot;click_image_tests&quot;
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=&quot;customizations&quot;
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=&quot;default&quot;
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=&quot;memevent&quot;
758+export EXTRA_PULLS=&quot;-p /tmp/memory_usage.json&quot;
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=&quot;sdk&quot;
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=&quot;security&quot;
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=&quot;{{branch}}&quot;
794+BZRDIR=`echo &quot;$BRANCH&quot; | awk -F/ &apos;{ print $(NF) }&apos;`
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=&quot;{{branch}}&quot;
932+BZRDIR=`echo &quot;$BRANCH&quot; | awk -F/ &apos;{ print $(NF) }&apos;`
933+BZRDIR=$(readlink -f $BZRDIR)
934+[ -d $BZRDIR ] &amp;&amp; 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.

Subscribers

People subscribed via source and target branches