Merge lp:~nskaggs/ubuntu-test-cases/fix-1367654 into lp:ubuntu-test-cases

Proposed by Nicholas Skaggs
Status: Superseded
Proposed branch: lp:~nskaggs/ubuntu-test-cases/fix-1367654
Merge into: lp:ubuntu-test-cases
Diff against target: 20554 lines (+19040/-0) (has conflicts)
293 files modified
README-cli.rst (+80/-0)
jenkins/custom-demo.py (+32/-0)
jenkins/production.py (+92/-0)
jenkins/setup_jenkins.py (+222/-0)
jenkins/staging.py (+42/-0)
jenkins/templates/touch-base.xml.jinja2 (+97/-0)
jenkins/templates/touch-master.xml.jinja2 (+80/-0)
jenkins/templates/touch-smoke.xml.jinja2 (+178/-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 (+100/-0)
scripts/get-adb-id (+13/-0)
scripts/get-device-info (+37/-0)
scripts/jenkins.sh (+189/-0)
scripts/junit2utah.py (+70/-0)
scripts/ncd_usb.py (+48/-0)
scripts/provision.sh (+175/-0)
scripts/reboot-and-wait (+54/-0)
scripts/recover.py (+124/-0)
scripts/run-autopilot-tests.sh (+254/-0)
scripts/run-emulator (+97/-0)
scripts/run-smoke (+395/-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/default/whoopsie/whoopsie-test.sh (+86/-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 (+26/-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 (+25/-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/check-clickhook-rules (+10/-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:~nskaggs/ubuntu-test-cases/fix-1367654
Reviewer Review Type Date Requested Status
Ubuntu Test Case Developers Pending
Review via email: mp+234111@code.launchpad.net

Commit message

Add address-book-service-testability depends for calendar

Description of the change

Add address-book-service-testability depends for calendar

To post a comment you must log in.

Unmerged revisions

290. By Nicholas Skaggs

add new calendar depends

289. By Paul Larson

also specify password when recovering, in case we soon have stable images with the new adb

288. By Paul Larson

run security tests that require root under sudo

287. By Paul Larson

Fix provisioning to work with the new rtm and adbd as phablet user

286. By Paul Larson

Check to make sure that autoreporting is enabled, if it isn't then the .upload file won't ever be created.

285. By Paul Larson

hard kill powerd-cli on the device after the test run

284. By Paul Larson

also capture whoopsie.log

283. By Paul Larson

add more support for phablet user running adbd

282. By Paul Larson

a few more tweaks on health check

281. By Paul Larson

update health check thresholds for minor tweaks

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

Subscribers

People subscribed via source and target branches