Merge lp:~joetalbott/ubuntu-test-cases/add_alias_support into lp:ubuntu-test-cases

Proposed by Joe Talbott
Status: Needs review
Proposed branch: lp:~joetalbott/ubuntu-test-cases/add_alias_support
Merge into: lp:ubuntu-test-cases
Diff against target: 20362 lines (+18858/-0) (has conflicts)
291 files modified
README-cli.rst (+80/-0)
jenkins/custom-demo.py (+32/-0)
jenkins/production.py (+92/-0)
jenkins/setup_jenkins.py (+218/-0)
jenkins/staging.py (+36/-0)
jenkins/templates/touch-base.xml.jinja2 (+95/-0)
jenkins/templates/touch-master.xml.jinja2 (+69/-0)
jenkins/templates/touch-smoke.xml.jinja2 (+164/-0)
jenkins/testconfig.py (+207/-0)
scripts/assert-image (+30/-0)
scripts/combine_results (+124/-0)
scripts/dashboard.py (+305/-0)
scripts/device_info.py (+89/-0)
scripts/get-adb-id (+13/-0)
scripts/get-device-info (+37/-0)
scripts/jenkins.sh (+188/-0)
scripts/junit2utah.py (+70/-0)
scripts/ncd_usb.py (+48/-0)
scripts/provision.sh (+143/-0)
scripts/reboot-and-wait (+54/-0)
scripts/recover.py (+124/-0)
scripts/run-autopilot-tests.sh (+250/-0)
scripts/run-emulator (+97/-0)
scripts/run-smoke (+398/-0)
scripts/run-touch-upgrade.sh (+46/-0)
scripts/statsd.py (+35/-0)
selftests/test_junit2utah.py (+49/-0)
selftests/test_reboot_and_wait.py (+66/-0)
selftests/test_run_smoke.py (+143/-0)
selftests/test_statsd.py (+64/-0)
tests/bootspeed/bootchart/run.py (+73/-0)
tests/bootspeed/bootchart/setup.sh (+4/-0)
tests/bootspeed/bootchart/tc_control (+12/-0)
tests/bootspeed/master.run (+5/-0)
tests/bootspeed/tslist.run (+1/-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/apport/tc_control (+9/-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 (+127/-0)
tests/default/systemsettle/tc_control (+9/-0)
tests/default/ts_control (+3/-0)
tests/default/tslist.run (+12/-0)
tests/default/uname/tc_control (+12/-0)
tests/default/unity8/tc_control (+9/-0)
tests/default/vmstat/tc_control (+12/-0)
tests/default/whoopsie/tc_control (+9/-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/health-check/health-check-test-get-pids.py (+38/-0)
tests/health-check/health-check-test-pid.py (+198/-0)
tests/health-check/master.run (+5/-0)
tests/health-check/setup.sh (+10/-0)
tests/health-check/test.sh (+15/-0)
tests/health-check/thresholds/armv7l/NetworkManager.threshold (+73/-0)
tests/health-check/thresholds/armv7l/accounts-daemon.threshold (+73/-0)
tests/health-check/thresholds/armv7l/address-book-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/bluetoothd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/bridgemhrd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/dconf-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/default.threshold (+73/-0)
tests/health-check/thresholds/armv7l/dhclient.threshold (+73/-0)
tests/health-check/thresholds/armv7l/dnsmasq.threshold (+73/-0)
tests/health-check/thresholds/armv7l/evolution-calendar-factory.threshold (+73/-0)
tests/health-check/thresholds/armv7l/evolution-source-registry.threshold (+73/-0)
tests/health-check/thresholds/armv7l/hud-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-bluetooth-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-datetime-service.threshold (+74/-0)
tests/health-check/thresholds/armv7l/indicator-location-service.threshold (+74/-0)
tests/health-check/thresholds/armv7l/indicator-messages-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-network-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-power-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-secret-agent.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-sound-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/maliit-server.threshold (+73/-0)
tests/health-check/thresholds/armv7l/mediascanner-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/mission-control-5.threshold (+73/-0)
tests/health-check/thresholds/armv7l/mpdecision.threshold (+73/-0)
tests/health-check/thresholds/armv7l/mtp-server.threshold (+73/-0)
tests/health-check/thresholds/armv7l/ofonod.threshold (+73/-0)
tests/health-check/thresholds/armv7l/polkitd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/powerd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/pulseaudio.threshold (+73/-0)
tests/health-check/thresholds/armv7l/qmuxd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/rsyslogd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/rtkit-daemon.threshold (+73/-0)
tests/health-check/thresholds/armv7l/systemd-logind.threshold (+73/-0)
tests/health-check/thresholds/armv7l/systemd-udevd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/telepathy-ofono.threshold (+73/-0)
tests/health-check/thresholds/armv7l/thermald.threshold (+73/-0)
tests/health-check/thresholds/armv7l/ubuntu-location-serviced.threshold (+74/-0)
tests/health-check/thresholds/armv7l/ueventd.theshold (+73/-0)
tests/health-check/thresholds/armv7l/unity-scope-home.threshold (+73/-0)
tests/health-check/thresholds/armv7l/unity-scope-loader.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upowerd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-dbus-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-event-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-file-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-local-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-property-watcher.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-socket-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-udev-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/url-dispatcher.threshold (+73/-0)
tests/health-check/thresholds/armv7l/whoopsie.threshold (+73/-0)
tests/health-check/thresholds/armv7l/window-stack-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/wpa_supplicant.threshold (+73/-0)
tests/health-check/thresholds/i686/NetworkManager.threshold (+73/-0)
tests/health-check/thresholds/i686/accounts-daemon.threshold (+73/-0)
tests/health-check/thresholds/i686/acpid.threshold (+73/-0)
tests/health-check/thresholds/i686/avahi-daemon:.threshold (+74/-0)
tests/health-check/thresholds/i686/colord.threshold (+73/-0)
tests/health-check/thresholds/i686/cupsd.threshold (+73/-0)
tests/health-check/thresholds/i686/dbus-daemon.threshold.blacklist (+73/-0)
tests/health-check/thresholds/i686/dconf-service.threshold (+73/-0)
tests/health-check/thresholds/i686/default.threshold (+73/-0)
tests/health-check/thresholds/i686/deja-dup-monitor.threshold (+73/-0)
tests/health-check/thresholds/i686/dhclient.threshold (+73/-0)
tests/health-check/thresholds/i686/dnsmasq.threshold (+73/-0)
tests/health-check/thresholds/i686/evolution-calendar-factory.threshold (+73/-0)
tests/health-check/thresholds/i686/evolution-source-registry.threshold (+73/-0)
tests/health-check/thresholds/i686/gnome-fallback-mount-helper.threshold (+73/-0)
tests/health-check/thresholds/i686/gnome-keyring-daemon.threshold.blacklist (+73/-0)
tests/health-check/thresholds/i686/gnome-settings-daemon.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfs-afc-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfs-gphoto2-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfs-mtp-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfs-udisks2-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfsd-burn.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfsd-fuse.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfsd.threshold (+73/-0)
tests/health-check/thresholds/i686/hud-service.threshold (+73/-0)
tests/health-check/thresholds/i686/ibus-dconf.threshold (+73/-0)
tests/health-check/thresholds/i686/ibus-engine-simple.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-application-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-bluetooth-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-datetime-service.threshold (+74/-0)
tests/health-check/thresholds/i686/indicator-keyboard-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-messages-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-power-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-printers-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-session-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-sound-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-sync-service.threshold (+73/-0)
tests/health-check/thresholds/i686/kerneloops.threshold (+73/-0)
tests/health-check/thresholds/i686/modem-manager.threshold (+73/-0)
tests/health-check/thresholds/i686/nm-applet.threshold (+73/-0)
tests/health-check/thresholds/i686/polkitd.threshold (+73/-0)
tests/health-check/thresholds/i686/rtkit-daemon.threshold (+73/-0)
tests/health-check/thresholds/i686/systemd-logind.threshold (+73/-0)
tests/health-check/thresholds/i686/systemd-udevd.threshold (+73/-0)
tests/health-check/thresholds/i686/telepathy-indicator.threshold (+73/-0)
tests/health-check/thresholds/i686/udisksd.threshold (+73/-0)
tests/health-check/thresholds/i686/unity-panel-service.threshold (+73/-0)
tests/health-check/thresholds/i686/update-notifier.threshold (+73/-0)
tests/health-check/thresholds/i686/upowerd.threshold (+73/-0)
tests/health-check/thresholds/i686/upstart-dbus-bridge.threshold (+73/-0)
tests/health-check/thresholds/i686/upstart-event-bridge.threshold (+73/-0)
tests/health-check/thresholds/i686/upstart-file-bridge.threshold (+73/-0)
tests/health-check/thresholds/i686/upstart-socket-bridge.threshold (+73/-0)
tests/health-check/thresholds/i686/upstart-udev-bridge.threshold (+73/-0)
tests/health-check/thresholds/i686/whoopsie.threshold (+73/-0)
tests/health-check/thresholds/i686/zeitgeist-daemon.threshold (+73/-0)
tests/health-check/thresholds/i686/zeitgeist-datahub.threshold (+73/-0)
tests/health-check/thresholds/i686/zeitgeist-fts.threshold (+73/-0)
tests/health-check/thresholds/x86_64/NetworkManager.threshold (+73/-0)
tests/health-check/thresholds/x86_64/accounts-daemon.threshold (+73/-0)
tests/health-check/thresholds/x86_64/acpid.threshold (+73/-0)
tests/health-check/thresholds/x86_64/avahi-daemon:.threshold (+74/-0)
tests/health-check/thresholds/x86_64/colord.threshold (+73/-0)
tests/health-check/thresholds/x86_64/cupsd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/dbus-daemon.threshold.blacklist (+73/-0)
tests/health-check/thresholds/x86_64/dconf-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/default.threshold (+73/-0)
tests/health-check/thresholds/x86_64/deja-dup-monitor.threshold (+73/-0)
tests/health-check/thresholds/x86_64/dhclient.threshold (+73/-0)
tests/health-check/thresholds/x86_64/dnsmasq.threshold (+73/-0)
tests/health-check/thresholds/x86_64/evolution-calendar-factory.threshold (+73/-0)
tests/health-check/thresholds/x86_64/evolution-source-registry.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gnome-fallback-mount-helper.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gnome-keyring-daemon.threshold.blacklist (+73/-0)
tests/health-check/thresholds/x86_64/gnome-settings-daemon.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfs-afc-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfs-gphoto2-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfs-mtp-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfs-udisks2-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfsd-burn.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfsd-fuse.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfsd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/hud-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/ibus-dconf.threshold (+73/-0)
tests/health-check/thresholds/x86_64/ibus-engine-simple.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-application-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-bluetooth-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-datetime-service.threshold (+74/-0)
tests/health-check/thresholds/x86_64/indicator-keyboard-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-messages-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-power-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-printers-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-session-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-sound-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-sync-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/kerneloops.threshold (+73/-0)
tests/health-check/thresholds/x86_64/modem-manager.threshold (+73/-0)
tests/health-check/thresholds/x86_64/nm-applet.threshold (+73/-0)
tests/health-check/thresholds/x86_64/polkitd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/rtkit-daemon.threshold (+73/-0)
tests/health-check/thresholds/x86_64/systemd-logind.threshold (+73/-0)
tests/health-check/thresholds/x86_64/systemd-udevd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/telepathy-indicator.threshold (+73/-0)
tests/health-check/thresholds/x86_64/udisksd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/unity-panel-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/update-notifier.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upowerd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upstart-dbus-bridge.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upstart-event-bridge.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upstart-file-bridge.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upstart-socket-bridge.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upstart-udev-bridge.threshold (+73/-0)
tests/health-check/thresholds/x86_64/whoopsie.threshold (+73/-0)
tests/health-check/thresholds/x86_64/zeitgeist-daemon.threshold (+73/-0)
tests/health-check/thresholds/x86_64/zeitgeist-datahub.threshold (+73/-0)
tests/health-check/thresholds/x86_64/zeitgeist-fts.threshold (+73/-0)
tests/health-check/ts_control (+2/-0)
tests/health-check/tslist.auto (+3/-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 (+169/-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 (+79/-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/suspend-blocker/master.run (+5/-0)
tests/suspend-blocker/suspend-blocker/README (+7/-0)
tests/suspend-blocker/suspend-blocker/setup.sh (+10/-0)
tests/suspend-blocker/suspend-blocker/susblock.conf (+5/-0)
tests/suspend-blocker/suspend-blocker/suspend-blocker.sh (+22/-0)
tests/suspend-blocker/suspend-blocker/tc_control (+16/-0)
tests/suspend-blocker/tslist.run (+1/-0)
tests/systemsettle/systemsettle-after/tc_control (+9/-0)
tests/systemsettle/systemsettle-before/tc_control (+9/-0)
tests/systemsettle/systemsettle.sh (+127/-0)
tests/systemsettle/tslist.run (+2/-0)
utils/host/adb-shell (+23/-0)
utils/host/autopilot-list (+23/-0)
utils/host/autopilot-run (+12/-0)
utils/host/prepare-autopilot-test.sh (+7/-0)
utils/host/reboot-and-unlock.sh (+15/-0)
utils/target/autopilot-list (+13/-0)
utils/target/autopilot-run (+6/-0)
utils/target/prepare-autopilot-test.sh (+16/-0)
Conflict adding file scripts.  Moved existing file to scripts.moved.
To merge this branch: bzr merge lp:~joetalbott/ubuntu-test-cases/add_alias_support
Reviewer Review Type Date Requested Status
Ubuntu Test Case Developers Pending
Review via email: mp+228516@code.launchpad.net

Commit message

smoke - Add support for parsing the release name from the channel alias.

* Check channel alias first and falls back to channel second.

Description of the change

smoke - Add support for parsing the release name from the channel alias.

* Check channel alias first and falls back to channel second.

To post a comment you must log in.
Revision history for this message
Paul Larson (pwlars) wrote :

Since you seemed to have some concern about relying on the alias, how about https://code.launchpad.net/~pwlars/ubuntu-test-cases/release-series-environment/+merge/228555 as an alternative solution?

Unmerged revisions

259. By Joe Talbott

smoke - Add support for parsing the alias for the release name.

* Check for release name (i.e. trusty, utopic, etc.) in the alias first
  and then in the channel.

258. By Paul Larson

This should give us the stable-staging-proposed channel as touch_stable, and also move to running devel-proposed instead of utopic-proposed

257. By Paul Larson

This enables apport autoreporting so that whoopsie can do its job

256. By Paul Larson

Remove the test for friends_app

255. By Paul Larson

revert workaround for NM bug #1340217 which is fixed in the next image

254. By Para Siva

Workaround for wifi setup issue, bug 1340217

253. By Para Siva

Pull syslog and kern.log as archives

252. By Paul Larson

Invert logic for using --timeout-profile=long

251. By Paul Larson

Add developer-mode option to ubuntu-device-flash

250. By Francis Ginther

Use new phablet-config welcome-wizard support to disable wizard when provisioning.

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

Subscribers

People subscribed via source and target branches