Merge lp:~nskaggs/ubuntu-test-cases/increase-ap-timeout into lp:ubuntu-test-cases

Proposed by Nicholas Skaggs
Status: Superseded
Proposed branch: lp:~nskaggs/ubuntu-test-cases/increase-ap-timeout
Merge into: lp:ubuntu-test-cases
Diff against target: 20582 lines (+19068/-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 (+100/-0)
scripts/get-adb-id (+13/-0)
scripts/get-device-info (+37/-0)
scripts/jenkins.sh (+189/-0)
scripts/junit2utah.py (+70/-0)
scripts/ncd_usb.py (+48/-0)
scripts/provision.sh (+201/-0)
scripts/reboot-and-wait (+54/-0)
scripts/recover.py (+124/-0)
scripts/run-autopilot-tests.sh (+255/-0)
scripts/run-emulator (+97/-0)
scripts/run-smoke (+395/-0)
scripts/run-touch-upgrade.sh (+46/-0)
scripts/statsd.py (+35/-0)
selftests/test_junit2utah.py (+49/-0)
selftests/test_reboot_and_wait.py (+66/-0)
selftests/test_run_smoke.py (+143/-0)
selftests/test_statsd.py (+64/-0)
tests/bootspeed/bootchart/run.py (+73/-0)
tests/bootspeed/bootchart/setup.sh (+4/-0)
tests/bootspeed/bootchart/tc_control (+12/-0)
tests/bootspeed/master.run (+5/-0)
tests/bootspeed/tslist.run (+1/-0)
tests/click_image_tests/check_preinstalled_list/check_preinstalled_list.py (+61/-0)
tests/click_image_tests/check_preinstalled_list/tc_control (+10/-0)
tests/click_image_tests/master.run (+5/-0)
tests/click_image_tests/tslist.run (+1/-0)
tests/customizations/master.run (+5/-0)
tests/customizations/setup.sh (+10/-0)
tests/customizations/ts_control (+1/-0)
tests/customizations/tslist.auto (+4/-0)
tests/default/apport/tc_control (+9/-0)
tests/default/ifconfig/tc_control (+13/-0)
tests/default/install/tc_control (+12/-0)
tests/default/master.run (+5/-0)
tests/default/netstat/tc_control (+12/-0)
tests/default/ping/pingtest.sh (+12/-0)
tests/default/ping/tc_control (+12/-0)
tests/default/pwd/tc_control (+9/-0)
tests/default/pwd/test.sh (+18/-0)
tests/default/route/tc_control (+12/-0)
tests/default/systemsettle/systemsettle.sh (+127/-0)
tests/default/systemsettle/tc_control (+9/-0)
tests/default/ts_control (+3/-0)
tests/default/tslist.run (+12/-0)
tests/default/uname/tc_control (+12/-0)
tests/default/unity8/tc_control (+9/-0)
tests/default/vmstat/tc_control (+12/-0)
tests/default/whoopsie/tc_control (+9/-0)
tests/default/whoopsie/whoopsie-test.sh (+86/-0)
tests/eventstat/eventstat/eventstat.sh (+5/-0)
tests/eventstat/eventstat/setup.sh (+7/-0)
tests/eventstat/eventstat/tc_control (+12/-0)
tests/eventstat/master.run (+5/-0)
tests/eventstat/tslist.run (+1/-0)
tests/health-check/health-check-test-get-pids.py (+38/-0)
tests/health-check/health-check-test-pid.py (+198/-0)
tests/health-check/master.run (+5/-0)
tests/health-check/setup.sh (+10/-0)
tests/health-check/test.sh (+15/-0)
tests/health-check/thresholds/armv7l/NetworkManager.threshold (+73/-0)
tests/health-check/thresholds/armv7l/accounts-daemon.threshold (+73/-0)
tests/health-check/thresholds/armv7l/address-book-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/bluetoothd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/bridgemhrd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/dconf-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/default.threshold (+73/-0)
tests/health-check/thresholds/armv7l/dhclient.threshold (+73/-0)
tests/health-check/thresholds/armv7l/dnsmasq.threshold (+73/-0)
tests/health-check/thresholds/armv7l/evolution-calendar-factory.threshold (+73/-0)
tests/health-check/thresholds/armv7l/evolution-source-registry.threshold (+73/-0)
tests/health-check/thresholds/armv7l/hud-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-bluetooth-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-datetime-service.threshold (+74/-0)
tests/health-check/thresholds/armv7l/indicator-location-service.threshold (+74/-0)
tests/health-check/thresholds/armv7l/indicator-messages-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-network-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-power-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-secret-agent.threshold (+73/-0)
tests/health-check/thresholds/armv7l/indicator-sound-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/maliit-server.threshold (+73/-0)
tests/health-check/thresholds/armv7l/mediascanner-service.threshold (+73/-0)
tests/health-check/thresholds/armv7l/mission-control-5.threshold (+73/-0)
tests/health-check/thresholds/armv7l/mpdecision.threshold (+73/-0)
tests/health-check/thresholds/armv7l/mtp-server.threshold (+73/-0)
tests/health-check/thresholds/armv7l/ofonod.threshold (+73/-0)
tests/health-check/thresholds/armv7l/polkitd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/powerd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/pulseaudio.threshold (+73/-0)
tests/health-check/thresholds/armv7l/qmuxd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/rsyslogd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/rtkit-daemon.threshold (+73/-0)
tests/health-check/thresholds/armv7l/systemd-logind.threshold (+73/-0)
tests/health-check/thresholds/armv7l/systemd-udevd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/telepathy-ofono.threshold (+73/-0)
tests/health-check/thresholds/armv7l/thermald.threshold (+73/-0)
tests/health-check/thresholds/armv7l/ubuntu-location-serviced.threshold (+74/-0)
tests/health-check/thresholds/armv7l/ueventd.theshold (+73/-0)
tests/health-check/thresholds/armv7l/unity-scope-home.threshold (+73/-0)
tests/health-check/thresholds/armv7l/unity-scope-loader.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upowerd.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-dbus-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-event-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-file-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-local-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-property-watcher.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-socket-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/upstart-udev-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/url-dispatcher.threshold (+73/-0)
tests/health-check/thresholds/armv7l/whoopsie.threshold (+73/-0)
tests/health-check/thresholds/armv7l/window-stack-bridge.threshold (+73/-0)
tests/health-check/thresholds/armv7l/wpa_supplicant.threshold (+73/-0)
tests/health-check/thresholds/i686/NetworkManager.threshold (+73/-0)
tests/health-check/thresholds/i686/accounts-daemon.threshold (+73/-0)
tests/health-check/thresholds/i686/acpid.threshold (+73/-0)
tests/health-check/thresholds/i686/avahi-daemon:.threshold (+74/-0)
tests/health-check/thresholds/i686/colord.threshold (+73/-0)
tests/health-check/thresholds/i686/cupsd.threshold (+73/-0)
tests/health-check/thresholds/i686/dbus-daemon.threshold.blacklist (+73/-0)
tests/health-check/thresholds/i686/dconf-service.threshold (+73/-0)
tests/health-check/thresholds/i686/default.threshold (+73/-0)
tests/health-check/thresholds/i686/deja-dup-monitor.threshold (+73/-0)
tests/health-check/thresholds/i686/dhclient.threshold (+73/-0)
tests/health-check/thresholds/i686/dnsmasq.threshold (+73/-0)
tests/health-check/thresholds/i686/evolution-calendar-factory.threshold (+73/-0)
tests/health-check/thresholds/i686/evolution-source-registry.threshold (+73/-0)
tests/health-check/thresholds/i686/gnome-fallback-mount-helper.threshold (+73/-0)
tests/health-check/thresholds/i686/gnome-keyring-daemon.threshold.blacklist (+73/-0)
tests/health-check/thresholds/i686/gnome-settings-daemon.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfs-afc-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfs-gphoto2-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfs-mtp-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfs-udisks2-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfsd-burn.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfsd-fuse.threshold (+73/-0)
tests/health-check/thresholds/i686/gvfsd.threshold (+73/-0)
tests/health-check/thresholds/i686/hud-service.threshold (+73/-0)
tests/health-check/thresholds/i686/ibus-dconf.threshold (+73/-0)
tests/health-check/thresholds/i686/ibus-engine-simple.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-application-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-bluetooth-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-datetime-service.threshold (+74/-0)
tests/health-check/thresholds/i686/indicator-keyboard-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-messages-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-power-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-printers-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-session-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-sound-service.threshold (+73/-0)
tests/health-check/thresholds/i686/indicator-sync-service.threshold (+73/-0)
tests/health-check/thresholds/i686/kerneloops.threshold (+73/-0)
tests/health-check/thresholds/i686/modem-manager.threshold (+73/-0)
tests/health-check/thresholds/i686/nm-applet.threshold (+73/-0)
tests/health-check/thresholds/i686/polkitd.threshold (+73/-0)
tests/health-check/thresholds/i686/rtkit-daemon.threshold (+73/-0)
tests/health-check/thresholds/i686/systemd-logind.threshold (+73/-0)
tests/health-check/thresholds/i686/systemd-udevd.threshold (+73/-0)
tests/health-check/thresholds/i686/telepathy-indicator.threshold (+73/-0)
tests/health-check/thresholds/i686/udisksd.threshold (+73/-0)
tests/health-check/thresholds/i686/unity-panel-service.threshold (+73/-0)
tests/health-check/thresholds/i686/update-notifier.threshold (+73/-0)
tests/health-check/thresholds/i686/upowerd.threshold (+73/-0)
tests/health-check/thresholds/i686/upstart-dbus-bridge.threshold (+73/-0)
tests/health-check/thresholds/i686/upstart-event-bridge.threshold (+73/-0)
tests/health-check/thresholds/i686/upstart-file-bridge.threshold (+73/-0)
tests/health-check/thresholds/i686/upstart-socket-bridge.threshold (+73/-0)
tests/health-check/thresholds/i686/upstart-udev-bridge.threshold (+73/-0)
tests/health-check/thresholds/i686/whoopsie.threshold (+73/-0)
tests/health-check/thresholds/i686/zeitgeist-daemon.threshold (+73/-0)
tests/health-check/thresholds/i686/zeitgeist-datahub.threshold (+73/-0)
tests/health-check/thresholds/i686/zeitgeist-fts.threshold (+73/-0)
tests/health-check/thresholds/x86_64/NetworkManager.threshold (+73/-0)
tests/health-check/thresholds/x86_64/accounts-daemon.threshold (+73/-0)
tests/health-check/thresholds/x86_64/acpid.threshold (+73/-0)
tests/health-check/thresholds/x86_64/avahi-daemon:.threshold (+74/-0)
tests/health-check/thresholds/x86_64/colord.threshold (+73/-0)
tests/health-check/thresholds/x86_64/cupsd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/dbus-daemon.threshold.blacklist (+73/-0)
tests/health-check/thresholds/x86_64/dconf-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/default.threshold (+73/-0)
tests/health-check/thresholds/x86_64/deja-dup-monitor.threshold (+73/-0)
tests/health-check/thresholds/x86_64/dhclient.threshold (+73/-0)
tests/health-check/thresholds/x86_64/dnsmasq.threshold (+73/-0)
tests/health-check/thresholds/x86_64/evolution-calendar-factory.threshold (+73/-0)
tests/health-check/thresholds/x86_64/evolution-source-registry.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gnome-fallback-mount-helper.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gnome-keyring-daemon.threshold.blacklist (+73/-0)
tests/health-check/thresholds/x86_64/gnome-settings-daemon.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfs-afc-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfs-gphoto2-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfs-mtp-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfs-udisks2-volume-monitor.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfsd-burn.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfsd-fuse.threshold (+73/-0)
tests/health-check/thresholds/x86_64/gvfsd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/hud-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/ibus-dconf.threshold (+73/-0)
tests/health-check/thresholds/x86_64/ibus-engine-simple.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-application-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-bluetooth-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-datetime-service.threshold (+74/-0)
tests/health-check/thresholds/x86_64/indicator-keyboard-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-messages-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-power-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-printers-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-session-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-sound-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/indicator-sync-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/kerneloops.threshold (+73/-0)
tests/health-check/thresholds/x86_64/modem-manager.threshold (+73/-0)
tests/health-check/thresholds/x86_64/nm-applet.threshold (+73/-0)
tests/health-check/thresholds/x86_64/polkitd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/rtkit-daemon.threshold (+73/-0)
tests/health-check/thresholds/x86_64/systemd-logind.threshold (+73/-0)
tests/health-check/thresholds/x86_64/systemd-udevd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/telepathy-indicator.threshold (+73/-0)
tests/health-check/thresholds/x86_64/udisksd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/unity-panel-service.threshold (+73/-0)
tests/health-check/thresholds/x86_64/update-notifier.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upowerd.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upstart-dbus-bridge.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upstart-event-bridge.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upstart-file-bridge.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upstart-socket-bridge.threshold (+73/-0)
tests/health-check/thresholds/x86_64/upstart-udev-bridge.threshold (+73/-0)
tests/health-check/thresholds/x86_64/whoopsie.threshold (+73/-0)
tests/health-check/thresholds/x86_64/zeitgeist-daemon.threshold (+73/-0)
tests/health-check/thresholds/x86_64/zeitgeist-datahub.threshold (+73/-0)
tests/health-check/thresholds/x86_64/zeitgeist-fts.threshold (+73/-0)
tests/health-check/ts_control (+2/-0)
tests/health-check/tslist.auto (+3/-0)
tests/memevent/master.run (+5/-0)
tests/memevent/setup.sh (+8/-0)
tests/memevent/ts_control (+1/-0)
tests/memevent/tslist.auto (+7/-0)
tests/memevent/ubuntu_test_cases/__init__.py (+6/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/__init__.py (+1/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/__init__.py (+21/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/browser.py (+103/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/camera.py (+58/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/gallery.py (+41/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/apps/media_player.py (+53/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/matchers.py (+37/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/probes.py (+169/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/smem-tabs (+687/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/__init__.py (+1/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_memory_usage.py (+79/-0)
tests/sdk/master.run (+5/-0)
tests/sdk/run_test.sh (+20/-0)
tests/sdk/setup.sh (+12/-0)
tests/sdk/ts_control (+1/-0)
tests/sdk/tslist.auto (+3/-0)
tests/security/master.run (+5/-0)
tests/security/run_test.sh (+26/-0)
tests/security/setup.sh (+12/-0)
tests/security/ts_control (+1/-0)
tests/security/tslist.auto (+6/-0)
tests/smem/master.run (+15/-0)
tests/smem/smem/smem-tabs (+687/-0)
tests/smem/smem/smem.sh (+12/-0)
tests/smem/smem/tc_control (+11/-0)
tests/smem/tslist.run (+1/-0)
tests/suspend-blocker/master.run (+5/-0)
tests/suspend-blocker/suspend-blocker/README (+7/-0)
tests/suspend-blocker/suspend-blocker/setup.sh (+10/-0)
tests/suspend-blocker/suspend-blocker/susblock.conf (+5/-0)
tests/suspend-blocker/suspend-blocker/suspend-blocker.sh (+25/-0)
tests/suspend-blocker/suspend-blocker/tc_control (+16/-0)
tests/suspend-blocker/tslist.run (+1/-0)
tests/systemsettle/systemsettle-after/tc_control (+9/-0)
tests/systemsettle/systemsettle-before/tc_control (+9/-0)
tests/systemsettle/systemsettle.sh (+127/-0)
tests/systemsettle/tslist.run (+2/-0)
utils/host/adb-shell (+23/-0)
utils/host/autopilot-list (+23/-0)
utils/host/autopilot-run (+12/-0)
utils/host/prepare-autopilot-test.sh (+7/-0)
utils/host/reboot-and-unlock.sh (+15/-0)
utils/target/autopilot-list (+13/-0)
utils/target/autopilot-run (+6/-0)
utils/target/check-clickhook-rules (+10/-0)
utils/target/prepare-autopilot-test.sh (+16/-0)
Conflict adding file scripts.  Moved existing file to scripts.moved.
To merge this branch: bzr merge lp:~nskaggs/ubuntu-test-cases/increase-ap-timeout
Reviewer Review Type Date Requested Status
Ubuntu Test Case Developers Pending
Review via email: mp+235705@code.launchpad.net

This proposal has been superseded by a proposal from 2014-09-23.

Commit message

This increases the default timeout for autopilot test runs to 'long', which is currently defined as 30 seconds.

Description of the change

This increases the default timeout for autopilot test runs to 'long', which is currently defined as 30 seconds. This is intended to prevent bug 369990, but it will affect all timeouts for autopilot, including wait_select's, which are currently timing out after the default timeout of 10 seconds. This could cause tests to take an additional 20 seconds to fail (when they do).

Test case authors that require or expect the default timeout would also be affected. In general waiting longer shouldn't impose any additional risk beyond taking longer to fail (any assertions made on a specific time should already be defined inside a test). This is somewhat a heavy handed approach towards fixing the bug, and if possible perhaps it could be applied on a individual testsuite basis.

The underlying causes for why applications don't launch within 10 seconds is concerning and worthy of study, but that is outside of the scope of running these tests. I would rather see more reflective results of the application than using it as a proxy to potential app startup performance concerns. As to tests not reflecting reality and hiding long startup issues, I would only point out the apps incur some additional overhead to load with autopilot (including memory), and thus take longer to launch than launching an application without introspection. Thus this is not reflective of a real world user experience from the start.

To post a comment you must log in.
301. By Nicholas Skaggs

fix unintended whitespace changes

Unmerged revisions

301. By Nicholas Skaggs

fix unintended whitespace changes

300. By Nicholas Skaggs

change default AP timeout to long (30 seconds), fix bug 1369990

299. By Paul Larson

remove calendar app

298. By Paul Larson

run health check with sudo

297. By Paul Larson

Add python3-dateutil for calendar tests

296. By Paul Larson

Apply the same workaround to phablet-network that we previously used for phablet-click-test-setup

295. By Paul Larson

match a bit more of the upstart session env variable

294. By Paul Larson

correct for some oddness that seems to only happen when running it from a script

293. By Paul Larson

Don't run phablet-click-test-setup until we're sure it should work

292. By Paul Larson

retry phablet-click-test-setup if the session is not yet available

Preview Diff

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

Subscribers

People subscribed via source and target branches