Merge lp:~pwlars/ubuntu-test-cases/dashboard-no-fail into lp:ubuntu-test-cases

Proposed by Paul Larson
Status: Superseded
Proposed branch: lp:~pwlars/ubuntu-test-cases/dashboard-no-fail
Merge into: lp:ubuntu-test-cases
Diff against target: 20676 lines (+19162/-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 (+208/-0)
scripts/assert-image (+30/-0)
scripts/combine_results (+124/-0)
scripts/dashboard.py (+305/-0)
scripts/device_info.py (+122/-0)
scripts/get-adb-id (+13/-0)
scripts/get-device-info (+37/-0)
scripts/jenkins.sh (+214/-0)
scripts/junit2utah.py (+70/-0)
scripts/ncd_usb.py (+48/-0)
scripts/provision.sh (+201/-0)
scripts/reboot-and-wait (+54/-0)
scripts/recover.py (+146/-0)
scripts/run-autopilot-tests.sh (+255/-0)
scripts/run-emulator (+97/-0)
scripts/run-smoke (+419/-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 (+10/-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:~pwlars/ubuntu-test-cases/dashboard-no-fail
Reviewer Review Type Date Requested Status
Ubuntu Test Case Developers Pending
Review via email: mp+237482@code.launchpad.net

Description of the change

We really don't want to fail out catastrophically if the dashboard client API fails. The worst this situation can cause is that if for a moment, we can't reach the dashboard, it's possible that people might have to wait a little longer to see the full results rather than seeing them update as it runs.

To post a comment you must log in.
315. By Paul Larson

merge fixups

Unmerged revisions

315. By Paul Larson

merge fixups

314. By Paul Larson

Don't fail if the dashboard client api has problems

313. By Paul Larson

Make the touch smoke tests that use utah work both with and without sudo

312. By Paul Larson

Detect when we haven't fully recovered a device to a working adb shell
state

311. By Paul Larson

revert nosudo utah for now to investigate a strange failure

310. By Paul Larson

Add the 7 new devices we just got back from modifications

309. By Paul Larson

Don't run utah with sudo unless the running user is not a member of the utah group

308. By Paul Larson

make systemsettle look at /proc/stat on the device

307. By Paul Larson

make whoopsie tests actually run on the device, and with necessary permissions

306. By Paul Larson

turn unity8 tests back on for utopic images

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

Subscribers

People subscribed via source and target branches