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

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

Description of the change

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

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

merge fixups

Unmerged revisions

315. By Paul Larson

merge fixups

314. By Paul Larson

Don't fail if the dashboard client api has problems

313. By Paul Larson

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

312. By Paul Larson

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

311. By Paul Larson

revert nosudo utah for now to investigate a strange failure

310. By Paul Larson

Add the 7 new devices we just got back from modifications

309. By Paul Larson

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

308. By Paul Larson

make systemsettle look at /proc/stat on the device

307. By Paul Larson

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

306. By Paul Larson

turn unity8 tests back on for utopic images

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'README-cli.rst'
--- README-cli.rst 1970-01-01 00:00:00 +0000
+++ README-cli.rst 2014-10-07 19:58:41 +0000
@@ -0,0 +1,80 @@
1Touch Testing From the CLI
2==========================
3
4The touch testing execution framework was written so that its very easy to
5run tests from home in the exact same way test are run in the lab. The only
6thigs you need are:
7
8 * This bzr branch
9 * The phablet-tools_ package
10 * An Ubuntu Touch supported_ device
11
12.. _phablet-tools: http://launchpad.net/phablet-tools
13.. _supported: http://wiki.ubuntu.com/Touch/Devices
14
15There are two pieces to touch testing, provisioning and test execution. These
16functions are independent of one another. eg, If your device already
17has the proper image/configuration, you can simply use the test-runner.
18
19Provisioning
20------------
21
22The provisioning script is a simple wrapper to commands from phablet-tools
23to get a device ready for testing. Provisioning is performed with the
24scripts/provision.sh command. Running::
25
26 ./scripts/provision.sh -h
27
28will list supported options.
29
30NOTE: provision.sh requires a path to a network-manager wifi connection that
31can be copied to the target device. By default this is set to
32/home/ubuntu/magners-wifi. This can be overriden with the -n parameter.
33
34Executing Tests
35---------------
36
37The touch testing repository supports both autopilot and UTAH test definitions.
38
39Executing Autopilot Tests
40~~~~~~~~~~~~~~~~~~~~~~~~~
41
42One or more autopilot tests can be run on the target device using the command::
43
44 ./scripts/run-autopilot-tests.sh
45
46This is a small wrapper that uses phablet-tools to drive the tests. The
47script can run one or more autopilot tests. By default it will reboot the
48device between each test and ensure the device is settled using the
49*system-settle* script. Both of those options can be disabled via command
50line options. By default the script will create a directory named
51*clientlogs* and then a subdirectory for each testsuite with result files.
52These sub-directories include a xUnit XML formatted file, *test_results.xml*,
53as well as several log files from the device to help with debugging failures.
54
55An example testing two applications::
56
57 ./scripts/run-autopilot-tests.sh -a dropping_letters_app -a music_app
58
59Executing UTAH Tests
60~~~~~~~~~~~~~~~~~~~~
61
62Executing UTAH tests locally will require you to install the UTAH client
63package from a PPA::
64
65 sudo add-apt-repository ppa:utah/stable
66 sudo apt-get update
67 sudo apt-get install utah-client
68
69With that package installed UTAH tests can be run with::
70
71 ./scripts/jenkins.sh
72
73This script runs one test at a time and will put its test artifacts under the
74*clientlogs* directory similar to the autopilot runner. The UTAH result file
75will be named clientlogs/utah.yaml.
76
77An example of running the sdk test suite::
78
79 ./scripts/jenkins.sh -a sdk
80
081
=== added directory 'jenkins'
=== added file 'jenkins/custom-demo.py'
--- jenkins/custom-demo.py 1970-01-01 00:00:00 +0000
+++ jenkins/custom-demo.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,32 @@
1# The configuration matrix of our production device testing
2
3JENKINS = 'http://q-jenkins.ubuntu-ci:8080'
4
5
6def _url(channel, device):
7 return 'http://system-image.ubuntu.com/ubuntu-touch/%s/%s/index.json' \
8 % (channel, device)
9
10
11TRUSTY_MATRIX = [
12 {
13 'image-type': 'touch_custom_demo',
14 'include-qa': True,
15 'dashboard-host': 'ci.ubuntu.com',
16 'dashboard-port': '80',
17 'dashboard-user': 'doanac',
18 'devices': [
19 {
20 'name': 'mako',
21 'slave-label': 'daily-mako',
22 'trigger_url': _url('trusty-proposed-customized-demo', 'mako'),
23 },
24 ],
25 'IMAGE_OPT': 'export IMAGE_OPT="ubuntu-system -b '
26 '--channel ubuntu-touch/trusty-proposed-customized-demo"'
27 },
28]
29
30MATRIX = {
31 'trusty': TRUSTY_MATRIX,
32}
033
=== added file 'jenkins/production.py'
--- jenkins/production.py 1970-01-01 00:00:00 +0000
+++ jenkins/production.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,92 @@
1# The configuration matrix of our production device testing
2
3JENKINS = 'http://q-jenkins.ubuntu-ci:8080'
4
5
6def _url(channel, device):
7 return 'http://system-image.ubuntu.com/ubuntu-touch/%s/%s/index.json' \
8 % (channel, device)
9
10
11UTOPIC_MATRIX = [
12 {
13 'image-type': 'touch',
14 'statsd-key': 'ubuntu-ci.daily-image.production',
15 'include-qa': True,
16 'dashboard-host': 'ci.ubuntu.com',
17 'dashboard-port': '80',
18 'dashboard-user': 'uci-bot',
19 'devices': [
20 {
21 'name': 'mako',
22 'slave-label': 'daily-mako',
23 'trigger_url': _url('devel-proposed', 'mako'),
24 'num-workers': 3,
25 },
26 {
27 'name': 'flo',
28 'slave-label': 'daily-flo',
29 'trigger_url': _url('devel-proposed', 'flo'),
30 'num-workers': 2,
31 },
32 {
33 'name': 'manta',
34 'slave-label': 'daily-manta',
35 'trigger_url': _url('devel-proposed', 'manta'),
36 'num-workers': 2,
37 },
38 ],
39 },
40 {
41 'image-type': 'touch_stable',
42 'statsd-key': 'ubuntu-ci.daily-image.production',
43 'include-qa': True,
44 'dashboard-host': 'ci.ubuntu.com',
45 'dashboard-port': '80',
46 'dashboard-user': 'uci-bot',
47 'devices': [
48 {
49 'name': 'mako',
50 'slave-label': 'daily-mako',
51 'trigger_url': _url('ubuntu-rtm/14.09-proposed', 'mako'),
52 'num-workers': 3,
53 },
54 {
55 'name': 'flo',
56 'slave-label': 'daily-flo',
57 'trigger_url': _url('ubuntu-rtm/14.09-proposed', 'flo'),
58 'num-workers': 2,
59 },
60 {
61 'name': 'manta',
62 'slave-label': 'daily-manta',
63 'trigger_url': _url('ubuntu-rtm/14.09-proposed', 'manta'),
64 'num-workers': 2,
65 },
66 ],
67 'IMAGE_OPT': 'export IMAGE_OPT="--bootstrap --developer-mode '
68 '--channel ubuntu-touch/ubuntu-rtm/14.09-proposed"'
69 },
70 {
71 'image-type': 'touch_custom',
72 'statsd-key': 'ubuntu-ci.daily-image.production',
73 'include-qa': False,
74 'dashboard-host': 'ci.ubuntu.com',
75 'dashboard-port': '80',
76 'dashboard-user': 'uci-bot',
77 'devices': [
78 {
79 'name': 'mako',
80 'slave-label': 'daily-mako',
81 'trigger_url': _url('utopic-proposed-customized', 'mako'),
82 },
83 ],
84 'IMAGE_OPT': 'export IMAGE_OPT="--bootstrap --developer-mode '
85 '--channel ubuntu-touch/utopic-proposed-customized"'
86 },
87]
88
89
90MATRIX = {
91 'utopic': UTOPIC_MATRIX,
92}
093
=== added file 'jenkins/setup_jenkins.py'
--- jenkins/setup_jenkins.py 1970-01-01 00:00:00 +0000
+++ jenkins/setup_jenkins.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,222 @@
1#!/usr/bin/env python
2
3# Ubuntu Testing Automation Harness
4# Copyright 2013 Canonical Ltd.
5
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17
18import argparse
19import imp
20import jenkins
21import jinja2
22import logging
23import os
24
25import testconfig
26
27from distro_info import UbuntuDistroInfo
28DEV_SERIES = UbuntuDistroInfo().devel()
29
30
31def _get_parser():
32 """Create and return command line parser.
33
34 :returns: command line parser
35 :rtype: argparse.ArgumentParser
36
37 """
38 parser = argparse.ArgumentParser(
39 description='Create/Update upgrade testing jenkins jobs.')
40 parser.add_argument("-d", "--dryrun", action="store_true",
41 help="Dry run mode. Don't execute jenkins commands.")
42 parser.add_argument("-u", "--username",
43 help="username to use when logging into Jenkins.")
44 parser.add_argument("-p", "--password",
45 help="username to use when logging into Jenkins")
46 parser.add_argument("--dashboard-key", default="",
47 help="The api-key for dashboard updates")
48 parser.add_argument("-b", "--branch", default="lp:ubuntu-test-cases/touch",
49 help="The branch this is located. default=%(default)s")
50 parser.add_argument("-c", "--config", required=True,
51 type=argparse.FileType('r'),
52 help="The job config to use.")
53 parser.add_argument("-P", "--publish", action="store_true",
54 help="Publish at the end of the job")
55 parser.add_argument("--prefix",
56 help="Prefix to add to the beginning of the job name")
57 parser.add_argument("-s", "--series", default=DEV_SERIES,
58 help=("series of Ubuntu to download "
59 "(default=%(default)s)"))
60 parser.add_argument("-w", "--wait", type=int, default=300,
61 help=("How long to wait after jenkins triggers the"
62 "install-and-boot job (default=%(default)d)"))
63 return parser
64
65
66def _get_jenkins(url, username, password):
67 logging.info('Attempting to login to jenkins at %s', url)
68 if username is not None:
69 logging.info('...with authentication as user: %s', username)
70 instance = jenkins.Jenkins(url, username=username, password=password)
71 else:
72 logging.info('...without authentication')
73 instance = jenkins.Jenkins(url)
74
75 return instance
76
77
78def _get_environment():
79 base = os.path.join(os.path.dirname(__file__), 'templates')
80 return jinja2.Environment(
81 loader=jinja2.FileSystemLoader(base),
82 undefined=jinja2.StrictUndefined,
83 trim_blocks=True)
84
85
86def _publish(instance, env, args, template, jobname, **params):
87 tmpl = env.get_template(template)
88 cfg = tmpl.render(**params)
89 if args.dryrun:
90 _dryrun_func(jobname, cfg)
91 return
92 if instance.job_exists(jobname):
93 logging.info('reconfiguring job %s', jobname)
94 instance.reconfig_job(jobname, cfg)
95 else:
96 logging.info('creating job %s', jobname)
97 instance.create_job(jobname, cfg)
98
99
100def _configure_smoke(instance, env, args, config_item, device):
101 defserial = '$(${BZRDIR}/scripts/get-adb-id ${NODE_NAME})'
102
103 params = {
104 'name': device['slave-label'],
105 'device_type': device['name'],
106 'serial': device.get('serial', defserial),
107 'publish': args.publish,
108 'branch': args.branch,
109 'imagetype': config_item['image-type'],
110 'series': args.series,
111 'image_opt': config_item.get('IMAGE_OPT', ''),
112 'statsd_key': config_item.get('statsd-key', ''),
113 'dashboard_host': config_item.get('dashboard-host', ''),
114 'dashboard_port': config_item.get('dashboard-port', ''),
115 'dashboard_prefix': config_item.get('dashboard-prefix', ''),
116 'dashboard_user': config_item.get('dashboard-user', ''),
117 'dashboard_key': args.dashboard_key,
118 }
119
120 prefix = ""
121 if(args.prefix):
122 prefix = args.prefix + "-"
123
124 job = '{}{}-{}-{}-smoke-daily'.format(
125 prefix, args.series, config_item['image-type'], device['name'])
126 _publish(instance, env, args, 'touch-smoke.xml.jinja2', job, **params)
127 return job
128
129
130def _configure_qa_job(instance, env, args, config_item, device, test):
131 defserial = '$(${BZRDIR}/scripts/get-adb-id ${NODE_NAME})'
132 #If the slave is specified for this test, set it
133 slave = getattr(test, 'device', device['slave-label'])
134 params = {
135 'name': slave,
136 'device_type': device['name'],
137 'serial': device.get('serial', defserial),
138 'publish': args.publish,
139 'branch': args.branch,
140 'imagetype': config_item['image-type'],
141 'series': args.series,
142 'image_opt': config_item.get('IMAGE_OPT', ''),
143 'timeout': test.timeout,
144 'test': test.name,
145 }
146 prefix = ""
147 if(args.prefix):
148 prefix = args.prefix + "-"
149 job = test.fmt.format(prefix=prefix,
150 series=args.series,
151 testname=test.name,
152 imagetype=config_item['image-type'],
153 type=device['name'])
154 _publish(instance, env, args, 'touch-base.xml.jinja2', job, **params)
155 return job
156
157
158def _configure_qa_jobs(instance, env, args, config_item, device):
159 tests = list(testconfig.TESTSUITES)
160 tests = testconfig.filter_tests(tests, config_item['image-type'],
161 device['name'])
162 tests = [t for t in tests if not t.smoke]
163 jobs = []
164 for t in tests:
165 j = _configure_qa_job(instance, env, args, config_item, device, t)
166 jobs.append(j)
167 return jobs
168
169
170def _configure_master(instance, env, args, config_item, device, smoke, jobs):
171 params = {
172 'branch': args.branch,
173 'trigger_url': device.get('trigger_url', ''),
174 'wait': args.wait,
175 'projects': jobs,
176 'smoke_job': smoke,
177 'num_workers': device.get('num-workers', 1),
178 }
179 prefix = ""
180 if(args.prefix):
181 prefix = args.prefix + "-"
182 job = testconfig.DEF_FMT.format(prefix=prefix,
183 series=args.series,
184 testname='master',
185 imagetype=config_item['image-type'],
186 type=device['name'])
187 _publish(instance, env, args, 'touch-master.xml.jinja2', job, **params)
188 return job
189
190
191def _dryrun_func(jobname, config):
192 logging.debug(jobname)
193 logging.debug(config)
194
195
196def main():
197 logging.basicConfig(level=logging.DEBUG)
198 args = _get_parser().parse_args()
199
200 config = imp.load_source('', 'config.py', args.config)
201 if args.series not in config.MATRIX:
202 print('"%s" series is not supported by this config.' % args.series)
203 exit(1)
204
205 jenkins_inst = _get_jenkins(config.JENKINS, args.username, args.password)
206 if args.dryrun:
207 jenkins_inst.create_job = _dryrun_func
208 jenkins_inst.reconfig_job = _dryrun_func
209
210 env = _get_environment()
211
212 for item in config.MATRIX[args.series]:
213 for device in item['devices']:
214 job = _configure_smoke(jenkins_inst, env, args, item, device)
215 jobs = []
216 if item.get('include-qa'):
217 jobs = _configure_qa_jobs(
218 jenkins_inst, env, args, item, device)
219 _configure_master(jenkins_inst, env, args, item, device, job, jobs)
220
221if __name__ == '__main__':
222 main()
0223
=== added file 'jenkins/staging.py'
--- jenkins/staging.py 1970-01-01 00:00:00 +0000
+++ jenkins/staging.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,42 @@
1# The configuration matrix of our staging device testing
2
3JENKINS = 'http://dev-jenkins.ubuntu-ci:8080/'
4
5UTOPIC_MATRIX = [
6 {
7 'image-type': 'touch',
8 'statsd-key': 'ubuntu-ci.daily-image.staging',
9 'include-qa': True,
10 'dashboard-host': 'dashboard.ubuntu-ci',
11 'dashboard-port': '8080',
12 'dashboard-user': 'ci-bot',
13 'devices': [
14 {
15 'name': 'mako',
16 'slave-label': 'mako',
17 #'trigger_url': 'http://system-image.ubuntu.com/utopic-proposed/mako/index.json',
18 }
19 ],
20 },
21 {
22 'image-type': 'touch_stable',
23 'statsd-key': 'ubuntu-ci.daily-image.staging',
24 'include-qa': True,
25 'dashboard-host': 'dashboard.ubuntu-ci',
26 'dashboard-port': '8080',
27 'dashboard-user': 'ci-bot',
28 'devices': [
29 {
30 'name': 'mako',
31 'slave-label': 'mako',
32 #'trigger_url': 'http://system-image.ubuntu.com/utopic-proposed/mako/index.json',
33 }
34 ],
35 'IMAGE_OPT': 'export IMAGE_OPT="--bootstrap --developer-mode '
36 '--channel ubuntu-touch/staging-stable-proposed"'
37 },
38]
39
40MATRIX = {
41 'utopic': UTOPIC_MATRIX,
42}
043
=== added directory 'jenkins/templates'
=== added file 'jenkins/templates/touch-base.xml.jinja2'
--- jenkins/templates/touch-base.xml.jinja2 1970-01-01 00:00:00 +0000
+++ jenkins/templates/touch-base.xml.jinja2 2014-10-07 19:58:41 +0000
@@ -0,0 +1,97 @@
1<?xml version='1.0' encoding='UTF-8'?>
2<project>
3 <actions/>
4 <description>
5&lt;pre&gt;
6#NOTE: Automatically created from a script as part of daily smoke testing&#xd;
7 {{branch}}&#xd;
8&lt;/pre&gt;
9 </description>
10 <keepDependencies>false</keepDependencies>
11 <properties>
12 <hudson.model.ParametersDefinitionProperty>
13 <parameterDefinitions>
14 <hudson.model.StringParameterDefinition>
15 <name>INSTALL_URL</name>
16 <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.
17 </description>
18 <defaultValue></defaultValue>
19 </hudson.model.StringParameterDefinition>
20 </parameterDefinitions>
21 </hudson.model.ParametersDefinitionProperty>
22 <com.sonyericsson.rebuild.RebuildSettings>
23 <autoRebuild>false</autoRebuild>
24 </com.sonyericsson.rebuild.RebuildSettings>
25 </properties>
26 <scm class="hudson.scm.NullSCM"/>
27 <assignedNode>{{ name }}</assignedNode>
28 <canRoam>false</canRoam>
29 <disabled>false</disabled>
30 <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
31 <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
32 <concurrentBuild>true</concurrentBuild>
33 <builders>
34 <hudson.tasks.Shell>
35 <command><![CDATA[
36set -e
37sudo rm -rf *
38
39BRANCH="{{branch}}"
40BZRDIR=`echo "$BRANCH" | awk -F/ '{ print $(NF) }'`
41BZRDIR=$(readlink -f $BZRDIR)
42bzr branch ${BRANCH} ${BZRDIR}
43
44export ANDROID_SERIAL={{serial}}
45export IMAGE_TYPE={{imagetype}}
46export IMAGE_SERIES={{series}}
47export DEVICE_TYPE={{device_type}}
48
49${BZRDIR}/scripts/recover.py ${NODE_NAME}
50
51{{image_opt}}
52${BZRDIR}/scripts/run-smoke -t {{test}}
53
54# move results to base directory as expected by dashboard:
55mv clientlogs/{{test}}/* ./clientlogs/
56rm -rf clientlogs/{{test}}
57
58{% if test == 'memevent' %}
59adb pull /tmp/memory_usage.json ./clientlogs/
60{% endif %}
61 ]]></command>
62 </hudson.tasks.Shell>
63 </builders>
64 <publishers>
65 <hudson.tasks.ArtifactArchiver>
66 <artifacts>clientlogs/*, clientlogs/**/*</artifacts>
67 <latestOnly>false</latestOnly>
68 </hudson.tasks.ArtifactArchiver>
69 <hudson.plugins.descriptionsetter.DescriptionSetterPublisher>
70 <regexp>^= TOUCH IMAGE VERSION:([0-9]+.*)</regexp>
71 <regexpForFailed>^= TOUCH IMAGE VERSION:([0-9]+.*)</regexpForFailed>
72 <setForMatrix>false</setForMatrix>
73 </hudson.plugins.descriptionsetter.DescriptionSetterPublisher>
74 <hudson.tasks.Mailer>
75 <recipients>paul.larson@canonical.com para.siva@canonical.com</recipients>
76 <dontNotifyEveryUnstableBuild>false</dontNotifyEveryUnstableBuild>
77 <sendToIndividuals>false</sendToIndividuals>
78 </hudson.tasks.Mailer>
79{% if publish %}
80 <hudson.plugins.build__publisher.BuildPublisher>
81 <publishUnstableBuilds>true</publishUnstableBuilds>
82 <publishFailedBuilds>true</publishFailedBuilds>
83 <postActions class="vector"/>
84 </hudson.plugins.build__publisher.BuildPublisher>
85{% endif %}
86 </publishers>
87 <buildWrappers>
88 <hudson.plugins.build__timeout.BuildTimeoutWrapper>
89 <timeoutMinutes>{{timeout}}</timeoutMinutes>
90 <failBuild>true</failBuild>
91 <writingDescription>false</writingDescription>
92 <timeoutPercentage>0</timeoutPercentage>
93 <timeoutType>absolute</timeoutType>
94 <timeoutMinutesElasticDefault>3</timeoutMinutesElasticDefault>
95 </hudson.plugins.build__timeout.BuildTimeoutWrapper>
96 </buildWrappers>
97</project>
098
=== added file 'jenkins/templates/touch-master.xml.jinja2'
--- jenkins/templates/touch-master.xml.jinja2 1970-01-01 00:00:00 +0000
+++ jenkins/templates/touch-master.xml.jinja2 2014-10-07 19:58:41 +0000
@@ -0,0 +1,80 @@
1<?xml version='1.0' encoding='UTF-8'?>
2<com.cloudbees.plugins.flow.BuildFlow>
3 <actions/>
4 <description>
5&lt;pre&gt;
6#NOTE: Automatically created from a script as part of daily smoke testing&#xd;
7 {{branch}}&#xd;
8&lt;/pre&gt;
9 </description>
10 <keepDependencies>false</keepDependencies>
11 <properties>
12 <hudson.model.ParametersDefinitionProperty>
13 <parameterDefinitions>
14 <hudson.model.StringParameterDefinition>
15 <name>sleep</name>
16 <description>Seconds to sleep before starting the job
17 </description>
18 <defaultValue>{{ wait }}</defaultValue>
19 </hudson.model.StringParameterDefinition>
20 </parameterDefinitions>
21 </hudson.model.ParametersDefinitionProperty>
22 <hudson.plugins.throttleconcurrents.ThrottleJobProperty>
23 <maxConcurrentPerNode>0</maxConcurrentPerNode>
24 <maxConcurrentTotal>0</maxConcurrentTotal>
25 <throttleEnabled>false</throttleEnabled>
26 <throttleOption>project</throttleOption>
27 </hudson.plugins.throttleconcurrents.ThrottleJobProperty>
28 <hudson.plugins.build__publisher.ExternalProjectProperty/>
29 </properties>
30 <scm class="hudson.scm.NullSCM"/>
31 <assignedNode>master</assignedNode>
32 <canRoam>false</canRoam>
33 <disabled>false</disabled>
34 <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
35 <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
36{%if trigger_url %}
37 <triggers class="vector">
38 <com.redfin.hudson.UrlChangeTrigger>
39 <spec></spec>
40 <url>{{trigger_url}}</url>
41 </com.redfin.hudson.UrlChangeTrigger>
42 </triggers>
43{% endif %}
44 <concurrentBuild>false</concurrentBuild>
45 <builders/>
46 <publishers/>
47 <buildWrappers>
48 <hudson.plugins.build__timeout.BuildTimeoutWrapper>
49 <timeoutMinutes>300</timeoutMinutes>
50 <failBuild>true</failBuild>
51 <writingDescription>false</writingDescription>
52 <timeoutPercentage>0</timeoutPercentage>
53 <timeoutType>absolute</timeoutType>
54 <timeoutMinutesElasticDefault>3</timeoutMinutesElasticDefault>
55 </hudson.plugins.build__timeout.BuildTimeoutWrapper>
56 </buildWrappers>
57 <dsl><![CDATA[
58// give the image time to show up before running tests
59out.println("sleeping for a bit")
60def sleep = build.environment.get("sleep").toLong()
61build.sleep(sleep * 1000)
62
63ignore(UNSTABLE) {
64 join = parallel ([
65{% for x in range(num_workers) %}
66 worker_{{x}}: { build("{{smoke_job}}", worker_idx: {{x}}, workers: {{num_workers}}) },
67{% endfor %}
68 ])
69}
70{% if projects %}
71out.println("kicking off downstream projects in parellel")
72install_url = build.environment.get("HUDSON_URL") + join.worker_0.lastBuild.build.url
73parallel (
74{% for project in projects %}
75 {build("{{project}}", INSTALL_URL: install_url)},
76{% endfor %}
77)
78{% endif %}
79 ]]></dsl>
80</com.cloudbees.plugins.flow.BuildFlow>
081
=== added file 'jenkins/templates/touch-smoke.xml.jinja2'
--- jenkins/templates/touch-smoke.xml.jinja2 1970-01-01 00:00:00 +0000
+++ jenkins/templates/touch-smoke.xml.jinja2 2014-10-07 19:58:41 +0000
@@ -0,0 +1,178 @@
1<?xml version='1.0' encoding='UTF-8'?>
2<project>
3 <actions/>
4 <description>
5<![CDATA[
6This job provides a flexible way to execute all the tests in our daily image
7testing process that contribute to the
8<a href="http://reports.qa.ubuntu.com/smokeng/">QA Dashboard</a>.
9The job is parameterized to give flexibility in what gets tested. A couple of
10common ways to run this job are:
11<dl>
12 <dt>Full Test Run</dt>
13 <dd>TESTS=ALL</dd>
14 <dd>APPS=ALL</dd>
15 <dt>Re-run a Failed Autopilot Test</dt>
16 <dd>INSTALL_URL=http://dev-jenkins:8080/job/utopic-touch_ro-mako/9</dd>
17 <dd>APPS=dropping_letters_app</dd>
18 <dt>Re-run a Failed UTAH Test</dt>
19 <dd>INSTALL_URL=http://dev-jenkins:8080/job/utopic-touch_ro-mako/9</dd>
20 <dd>TESTS=security</dd>
21</dl>
22<pre>
23#NOTE: Automatically created from a script as part of daily smoke testing
24 {{branch}}
25</pre>
26{% if statsd_key %}
27<h3>Graphite Reports</h3>
28<ul>
29 <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>
30 <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>
31</ul>
32{% endif %}
33]]>
34 </description>
35 <keepDependencies>false</keepDependencies>
36 <properties>
37 <hudson.model.ParametersDefinitionProperty>
38 <parameterDefinitions>
39 <hudson.model.StringParameterDefinition>
40 <name>INSTALL_URL</name>
41 <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.
42 </description>
43 <defaultValue></defaultValue>
44 </hudson.model.StringParameterDefinition>
45 <hudson.model.StringParameterDefinition>
46 <name>TESTS</name>
47 <description>A space separated list of utah tests to run. "ALL" can be used to run all known utah tests.
48 </description>
49 <defaultValue>ALL</defaultValue>
50 </hudson.model.StringParameterDefinition>
51 <hudson.model.StringParameterDefinition>
52 <name>APPS</name>
53 <description>A space separated list of autopilot tests to run. "ALL" can be used to run all known tests.
54 </description>
55 <defaultValue>ALL</defaultValue>
56 </hudson.model.StringParameterDefinition>
57 <hudson.model.StringParameterDefinition>
58 <name>REVISION</name>
59 <description>The image revision to test with.
60 </description>
61 <defaultValue></defaultValue>
62 </hudson.model.StringParameterDefinition>
63 <hudson.model.StringParameterDefinition>
64 <name>workers</name>
65 <description>The number of workers
66 </description>
67 <defaultValue></defaultValue>
68 </hudson.model.StringParameterDefinition>
69 <hudson.model.StringParameterDefinition>
70 <name>worker_idx</name>
71 <description>The index of this worker
72 </description>
73 <defaultValue></defaultValue>
74 </hudson.model.StringParameterDefinition>
75 </parameterDefinitions>
76 </hudson.model.ParametersDefinitionProperty>
77 <com.sonyericsson.rebuild.RebuildSettings>
78 <autoRebuild>false</autoRebuild>
79 </com.sonyericsson.rebuild.RebuildSettings>
80 </properties>
81 <scm class="hudson.scm.NullSCM"/>
82 <assignedNode>{{ name }}</assignedNode>
83 <canRoam>false</canRoam>
84 <disabled>false</disabled>
85 <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
86 <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
87 <triggers class="vector"/>
88 <concurrentBuild>true</concurrentBuild>
89 <builders>
90 <hudson.tasks.Shell>
91 <command>set -e
92BRANCH=&quot;{{branch}}&quot;
93BZRDIR=`echo &quot;$BRANCH&quot; | awk -F/ &apos;{ print $(NF) }&apos;`
94BZRDIR=$(readlink -f $BZRDIR)
95[ -d $BZRDIR ] &amp;&amp; rm -rf $BZRDIR
96bzr branch ${BRANCH} ${BZRDIR}
97
98export ANDROID_SERIAL={{serial}}
99export IMAGE_TYPE={{imagetype}}
100export IMAGE_SERIES={{series}}
101export DEVICE_TYPE={{device_type}}
102
103${BZRDIR}/scripts/recover.py ${NODE_NAME}
104
105{% if statsd_key %}
106# the txstatsd package is too old, use the one from LP:
107[ -d txstatsd ] &amp;&amp; rm -rf txstatsd
108bzr branch -r 109 lp:txstatsd
109export PYTHONPATH=`pwd`/txstatsd
110
111export STATSD_KEY={{statsd_key}}.{{imagetype}}
112{% endif %}
113
114{% if dashboard_host %}
115export DASHBOARD_HOST="{{dashboard_host}}"
116{% endif %}
117{% if dashboard_user %}
118export DASHBOARD_USER="{{dashboard_user}}"
119{% endif %}
120{% if dashboard_key %}
121set +x # don't let this leak into the public
122export DASHBOARD_KEY="{{dashboard_key}}"
123set -x
124{% endif %}
125{% if dashboard_prefix %}
126export DASHBOARD_PREFIX="{{dashboard_prefix}}"
127{% endif %}
128{% if dashboard_port %}
129export DASHBOARD_PORT="{{dashboard_port}}"
130{% endif %}
131
132{{image_opt}}
133${BZRDIR}/scripts/run-smoke
134 </command>
135 </hudson.tasks.Shell>
136 </builders>
137 <publishers>
138 <hudson.tasks.ArtifactArchiver>
139 <artifacts>clientlogs/**</artifacts>
140 <latestOnly>false</latestOnly>
141 </hudson.tasks.ArtifactArchiver>
142 <hudson.tasks.junit.JUnitResultArchiver>
143 <testResults>clientlogs/**/*.xml</testResults>
144 <keepLongStdio>true</keepLongStdio>
145 <testDataPublishers>
146 <hudson.plugins.junitattachments.AttachmentPublisher/>
147 </testDataPublishers>
148 </hudson.tasks.junit.JUnitResultArchiver>
149 <hudson.plugins.descriptionsetter.DescriptionSetterPublisher>
150 <regexp>^= TOUCH IMAGE VERSION:([0-9]+.*)</regexp>
151 <regexpForFailed>^= TOUCH IMAGE VERSION:([0-9]+.*)</regexpForFailed>
152 <setForMatrix>false</setForMatrix>
153 </hudson.plugins.descriptionsetter.DescriptionSetterPublisher>
154{% if publish %}
155 <hudson.tasks.Mailer>
156 <recipients>paul.larson@canonical.com</recipients>
157 <dontNotifyEveryUnstableBuild>false</dontNotifyEveryUnstableBuild>
158 <sendToIndividuals>false</sendToIndividuals>
159 </hudson.tasks.Mailer>
160 <hudson.plugins.build__publisher.BuildPublisher>
161 <publishUnstableBuilds>true</publishUnstableBuilds>
162 <publishFailedBuilds>true</publishFailedBuilds>
163 <postActions class="vector"/>
164 </hudson.plugins.build__publisher.BuildPublisher>
165{% endif %}
166 </publishers>
167 <buildWrappers>
168 <hudson.plugins.build__timeout.BuildTimeoutWrapper>
169 <timeoutMinutes>300</timeoutMinutes>
170 <failBuild>true</failBuild>
171 <writingDescription>false</writingDescription>
172 <timeoutPercentage>0</timeoutPercentage>
173 <timeoutType>absolute</timeoutType>
174 <timeoutMinutesElasticDefault>3</timeoutMinutesElasticDefault>
175 </hudson.plugins.build__timeout.BuildTimeoutWrapper>
176 </buildWrappers>
177</project>
178
0179
=== added file 'jenkins/testconfig.py'
--- jenkins/testconfig.py 1970-01-01 00:00:00 +0000
+++ jenkins/testconfig.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,208 @@
1#!/usr/bin/env python
2
3# Ubuntu Testing Automation Harness
4# Copyright 2013 Canonical Ltd.
5
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17
18import argparse
19
20DEF_FMT = '{prefix}{series}-{imagetype}-{type}-smoke-{testname}'
21IDLE_FMT = '{prefix}{testname}-{series}-{imagetype}-armhf-install-idle-{type}'
22
23
24class Test(object):
25 def __init__(self, name, timeout=60, fmt=DEF_FMT, smoke=True):
26 self.name = name
27 self.timeout = timeout
28 self.fmt = fmt
29 self.smoke = smoke
30
31
32class DevTest(Test):
33 def __init__(self, name, device):
34 Test.__init__(self, name, fmt=IDLE_FMT, smoke=False)
35 self.device = device
36
37
38class APTest(Test):
39 def __init__(self, name, app=None, pkgs=None):
40 Test.__init__(self, name)
41 self.pkgs = pkgs
42 if not app:
43 # convert share-app-autopilot to share_app
44 app = name.replace('-', '_').replace('_autopilot', '')
45 self.app = app
46
47
48TESTSUITES = [
49 Test('default'),
50]
51TESTSUITES += [
52 APTest('mediaplayer-app-autopilot', pkgs=['mediaplayer-app-autopilot']),
53 APTest('gallery-app-autopilot'),
54 APTest('webbrowser-app-autopilot', pkgs=['webbrowser-app-autopilot']),
55 APTest('unity8-autopilot', 'unity8'),
56 APTest('camera-app-autopilot'),
57 APTest('dialer-app-autopilot', pkgs=['dialer-app-autopilot']),
58 APTest('messaging-app-autopilot', pkgs=['messaging-app-autopilot']),
59 APTest('address-book-app-autopilot', pkgs=['address-book-app-autopilot']),
60 APTest('reminders-autopilot',
61 pkgs=['python3-dbusmock', 'python3-requests-oauthlib',
62 'account-plugin-evernote-sandbox']),
63 APTest('music-app-autopilot'),
64 APTest('dropping-letters-app-autopilot'),
65 APTest('sudoku-app-autopilot'),
66 APTest('ubuntu-calculator-app-autopilot'),
67 APTest('ubuntu-clock-app-autopilot'),
68 APTest('filemanager', pkgs=['python3-lxml']),
69 APTest('shorts-app-autopilot'),
70 APTest('ubuntu-terminal-app-autopilot'),
71 APTest('ubuntu-weather-app-autopilot'),
72 APTest('ubuntu-ui-toolkit-autopilot', 'ubuntuuitoolkit',
73 ['ubuntu-ui-toolkit-autopilot']),
74 APTest('ubuntu-system-settings-autopilot',
75 pkgs=['ubuntu-system-settings-autopilot']),
76 APTest('ubuntu-system-settings-online-accounts-autopilot',
77 'online_accounts_ui',
78 ['ubuntu-system-settings-online-accounts-autopilot']),
79]
80TESTSUITES += [
81 Test('click_image_tests'),
82 Test('sdk'),
83 Test('security'),
84 Test('eventstat', fmt=IDLE_FMT, smoke=False),
85 Test('smem', fmt=IDLE_FMT, smoke=False),
86 Test('health-check', timeout=300, smoke=False),
87 Test('memevent',
88 fmt='{prefix}{testname}-{series}-{imagetype}-armhf-default-{type}',
89 smoke=False),
90 Test('bootspeed',
91 fmt='{prefix}{testname}-{series}-{imagetype}-{type}-{type}',
92 smoke=False),
93]
94
95
96def filter_tests(tests, image_type, device_type=None):
97 if image_type:
98 func = globals().get('get_tests_%s' % image_type)
99 if func:
100 tests = func(tests)
101 elif image_type not in ['touch_stable', 'touch',
102 'touch_custom_demo']:
103 print('Unsupported image type: %s' % image_type)
104 exit(1)
105 if device_type:
106 func = globals().get('get_tests_%s' % device_type)
107 if func:
108 tests = func(tests)
109 return tests
110
111
112def _get_tests(test_type, image_type):
113 # take all our known tests, then call filter tests which should give
114 # us a list of tests customized for things like touch_custom.
115 # then eliminate tests that aren't of the proper test_type
116 tests = [t for t in filter_tests(TESTSUITES, image_type)
117 if type(t) == test_type and t.fmt == DEF_FMT]
118 return tests
119
120
121def _split_work(tests, total_workers, worker_idx):
122 assigned = []
123 for x in range(len(tests)):
124 if x % total_workers == worker_idx:
125 assigned.append(tests[x])
126 return assigned
127
128
129def _handle_utah(args):
130 tests = _get_tests(Test, args.image_type)
131 if args.with_autopilot:
132 tests = [t for t in TESTSUITES if t.fmt == DEF_FMT]
133 tests = _split_work(tests, args.total_workers, args.worker)
134 print(' '.join([t.name for t in tests if t.smoke is True]))
135
136
137def _handle_ap_apps(args):
138 tests = _get_tests(APTest, args.image_type)
139 tests = _split_work(tests, args.total_workers, args.worker)
140 print(' '.join([t.app for t in tests]))
141
142
143def _handle_ap_packages(args):
144 pkgs = []
145 tests = _get_tests(APTest, args.image_type)
146 for test in tests:
147 if not args.app or test.app in args.app:
148 if test.pkgs:
149 pkgs.extend(test.pkgs)
150 print(' '.join(pkgs))
151
152
153def get_tests_mako(common_tests):
154 tests = common_tests
155 tests.extend([DevTest('suspend-blocker', 'mako-01')])
156 return tests
157
158
159def get_tests_touch_custom(common_tests):
160 tests = common_tests
161 tests.insert(1, Test('customizations'))
162 return tests
163
164
165def _get_parser():
166 parser = argparse.ArgumentParser(
167 description='List information on configured tests for touch')
168 sub = parser.add_subparsers(title='Commands', metavar='')
169
170 p = sub.add_parser('utah', help='List UTAH tests')
171 p.set_defaults(func=_handle_utah)
172 p.add_argument('-i', '--image-type',
173 help='Return list of test configured for an image type.')
174 p.add_argument('-a', '--with-autopilot', action='store_true',
175 help='Include autopilot tests that can be run under UTAH.')
176 p.add_argument('-t', '--total-workers', type=int, default=1,
177 help='''The total number of workers available for running
178 tests.''')
179 p.add_argument('-w', '--worker', type=int, default=0,
180 help='The worker to allocate applications for testing to.')
181
182 p = sub.add_parser('apps', help='List autopilot application names')
183 p.set_defaults(func=_handle_ap_apps)
184 p.add_argument('-i', '--image-type',
185 help='Return list of test configured for an image type.')
186 p.add_argument('-t', '--total-workers', type=int, default=1,
187 help='''The total number of workers available for running
188 tests.''')
189 p.add_argument('-w', '--worker', type=int, default=0,
190 help='The worker to allocate applications for testing to.')
191
192 p = sub.add_parser('packages', help='List packages required for autopilot')
193 p.set_defaults(func=_handle_ap_packages)
194 g = p.add_mutually_exclusive_group()
195 g.add_argument('-i', '--image-type',
196 help='''If no apps are listed, limit to tests for an
197 image type.''')
198 g.add_argument('-a', '--app', action='append',
199 help='Autopilot test application. eg share_app')
200 return parser
201
202
203def main():
204 args = _get_parser().parse_args()
205 return args.func(args)
206
207if __name__ == '__main__':
208 exit(main())
0209
=== added directory 'scripts'
=== renamed directory 'scripts' => 'scripts.moved'
=== added file 'scripts/assert-image'
--- scripts/assert-image 1970-01-01 00:00:00 +0000
+++ scripts/assert-image 2014-10-07 19:58:41 +0000
@@ -0,0 +1,30 @@
1#!/bin/sh
2
3set -e
4
5BASEDIR=$(readlink -f $(dirname $0)/..)
6
7# a simple script to ensure the proper image is installed on the target
8
9[ -z $INSTALL_URL ] && echo "= INSTALL_URL not set. Using target as-is." && exit 0
10
11echo "Ensuring target has proper image..."
12REQUIRED_UUID=$(curl ${INSTALL_URL}/artifact/clientlogs/.ci-uuid)
13ACTUAL_UUID=$(adb shell "cat /home/phablet/.ci-uuid | tr -d '\r\n'")
14if [ "$REQUIRED_UUID" != "$ACTUAL_UUID" ] ; then
15 echo "= UUIDs $REQUIRED_UUID != $ACTUAL_UUID"
16 ARGS=$(curl ${INSTALL_URL}/artifact/clientlogs/.ci-flash-args | tr -d '\r\n')
17 CUST=$(curl ${INSTALL_URL}/artifact/clientlogs/.ci-customizations | tr -d '\r\n')
18 echo "reprovisioning device with: $ARGS"
19 echo "customizing device with: $CUST"
20 #Make the image writable if we reprovision by adding a space
21 #after to CUSTOMIZE so it is never empty
22 UUID=$REQUIRED_UUID IMAGE_OPT=$ARGS CUSTOMIZE="$CUST " \
23 ${BASEDIR}/scripts/provision.sh
24else
25 echo "= UUIDS match, reusing image on target"
26 echo $REQUIRED_UUID > clientlogs/.ci-uuid
27 curl ${INSTALL_URL}/artifact/clientlogs/.ci-flash-args > clientlogs/.ci-flash-args
28 curl ${INSTALL_URL}/artifact/clientlogs/.ci-customizations > clientlogs/.ci-customizations
29fi
30
031
=== added file 'scripts/combine_results'
--- scripts/combine_results 1970-01-01 00:00:00 +0000
+++ scripts/combine_results 2014-10-07 19:58:41 +0000
@@ -0,0 +1,124 @@
1#!/usr/bin/env python3
2
3"""
4We always run the system-settle test before and after an autopilot test. This
5script takes the results of the before/after results and combines them in with
6the junit xml results from the autopilot test so we have one unified report.
7"""
8
9
10import os
11import sys
12
13from xml.etree import ElementTree
14
15
16PRE_COMBINE = [
17 ('settle_before', 'settle_before'),
18 ('setup_setup', 'setup'),
19]
20
21POST_COMBINE = [
22 ('settle_after', 'settle_after'),
23 ('setup_teardown', 'teardown'),
24]
25
26
27def _build_node(classname, name, rcfile, stdout):
28 e = ElementTree.Element('testcase')
29 e.attrib['classname'] = classname
30 e.attrib['name'] = name
31
32 if not os.path.exists(rcfile):
33 return None, False
34
35 rc = int(open(rcfile).read())
36 if rc != 0:
37 f = ElementTree.Element('failure')
38 e.append(f)
39 f.attrib['type'] = 'testtools.testresult.real._StringException'
40 f.text = open(stdout).read()
41 return e, rc != 0
42
43
44def _get_results(apfile):
45 try:
46 tree = ElementTree.parse(apfile)
47 except Exception as ex:
48 e = ElementTree.Element('testsuite')
49 tree = ElementTree.ElementTree(e)
50 e.attrib['errors'] = '1'
51 e.attrib['failures'] = '0'
52 e.attrib['tests'] = '1'
53
54 # make a guess at the classname:
55 classname = os.path.basename(os.path.dirname(apfile))
56
57 t = ElementTree.Element('testcase')
58 e.append(t)
59 t.attrib['classname'] = classname
60 t.attrib['name'] = 'phablet-test-run'
61
62 f = ElementTree.Element('failure')
63 t.append(f)
64 f.attrib['type'] = 'testtools.testresult.real._StringException'
65 f.text = str(ex)
66
67 return tree
68
69
70def _get_classname(results):
71 if len(results) < 1:
72 return '???'
73
74 cname = results[0].attrib.get('classname')
75 if cname:
76 cname = cname.split('.')[0]
77 else:
78 cname = '???'
79 return cname
80
81
82def combine(resdir):
83 ap_file = os.path.join(resdir, 'test_results.xml')
84 tree = _get_results(ap_file)
85 ap_results = tree.getroot()
86 added_results = 0
87
88 errors = int(ap_results.attrib['errors'])
89
90 classname = _get_classname(ap_results)
91
92 for basename, label in PRE_COMBINE:
93 rc = os.path.join(resdir, basename + '.rc')
94 log = os.path.join(resdir, basename + '.log')
95 node, failed = _build_node(classname, label, rc, log)
96 if node is not None:
97 ap_results.insert(0, node)
98 if failed:
99 errors += 1
100 added_results += 1
101
102 for basename, label in POST_COMBINE:
103 rc = os.path.join(resdir, basename + '.rc')
104 log = os.path.join(resdir, basename + '.log')
105 node, failed = _build_node(classname, label, rc, log)
106 if node is not None:
107 ap_results.append(node)
108 if failed:
109 errors += 1
110 added_results += 1
111
112 num = int(ap_results.attrib['tests']) + added_results
113 ap_results.attrib['tests'] = str(num)
114 ap_results.attrib['errors'] = str(errors)
115
116 tree.write(ap_file)
117
118
119if __name__ == '__main__':
120 if len(sys.argv) != 2:
121 print('usage: {} <results directory>'.format(sys.argv[0]))
122 sys.exit(1)
123
124 combine(sys.argv[1])
0125
=== added file 'scripts/dashboard.py'
--- scripts/dashboard.py 1970-01-01 00:00:00 +0000
+++ scripts/dashboard.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,305 @@
1#!/usr/bin/python
2
3import argparse
4import datetime
5import json
6import logging
7import os
8
9import yaml
10
11from httplib import ACCEPTED, HTTPConnection, HTTPException, OK, CREATED
12from urllib import urlencode
13from urlparse import urlparse
14
15log = logging.getLogger()
16
17
18class API(object):
19 def __init__(self, host=None, port=None, user=None, key=None, prefix=None):
20 if not host:
21 host = os.environ.get('DASHBOARD_HOST', None)
22 if not port:
23 port = int(os.environ.get('DASHBOARD_PORT', '80'))
24 if not user:
25 user = os.environ.get('DASHBOARD_USER', None)
26 if not key:
27 key = os.environ.get('DASHBOARD_KEY', None)
28 if not prefix:
29 prefix = os.environ.get('DASHBOARD_PREFIX', None)
30
31 self.host = host
32 self.port = port
33 self.resource_base = prefix
34
35 self._headers = None
36 if user and key:
37 self._headers = {
38 'Content-Type': 'application/json',
39 'Authorization': 'ApiKey %s:%s' % (user, key)
40 }
41 # mod_wsgi will strip the Authorization header, but tastypie
42 # allows it as GET param also. More details for fixing apache:
43 # http://django-tastypie.rtfd.org/en/latest/authentication.html
44 self._auth_param = '?username=%s&api_key=%s' % (user, key)
45
46 def _connect(self):
47 if self.host:
48 return HTTPConnection(self.host, self.port)
49 return None
50
51 def _http_get(self, resource):
52 con = self._connect()
53 if not con:
54 # we just mock this for the case where the caller wants to
55 # use our API transparently enabled/disabled
56 return {}
57
58 if self.resource_base:
59 resource = self.resource_base + resource
60
61 logging.debug('doing get on: %s', resource)
62 headers = {'Content-Type': 'application/json'}
63 con.request('GET', resource, headers=headers)
64 resp = con.getresponse()
65 if resp.status != OK:
66 msg = ''
67 try:
68 msg = resp.read().decode()
69 except:
70 pass
71 fmt = '%d error getting resource(%s): %s'
72 raise HTTPException(fmt % (resp.status, resource, msg))
73 data = json.loads(resp.read().decode())
74 if len(data['objects']) == 0:
75 raise HTTPException('resource not found: %s' % resource)
76 assert len(data['objects']) == 1
77 return data['objects'][0]['resource_uri']
78
79 def _http_post(self, resource, params):
80 con = self._connect()
81 if not con or not self._headers:
82 return None
83
84 if self.resource_base:
85 resource = self.resource_base + resource
86 resource += self._auth_param
87
88 params = json.dumps(params)
89 log.debug('posting (%s): %s', resource, params)
90 con.request('POST', resource, params, self._headers)
91 resp = con.getresponse()
92 if resp.status != CREATED:
93 msg = ''
94 try:
95 msg = str(resp.getheaders())
96 msg += resp.read().decode()
97 except:
98 pass
99 raise HTTPException(
100 '%d creating resource(%s): %s' % (resp.status, resource, msg))
101 uri = resp.getheader('Location')
102 return urlparse(uri).path
103
104 def _http_patch(self, resource, params):
105 con = self._connect()
106 if not con or not self._headers:
107 return None
108
109 resource += self._auth_param
110
111 con.request('PATCH', resource, json.dumps(params), self._headers)
112 resp = con.getresponse()
113 if resp.status != ACCEPTED:
114 msg = ''
115 try:
116 msg = resp.getheaders()
117 except:
118 pass
119 raise HTTPException(
120 '%d patching resource(%s): %s' % (resp.status, resource, msg))
121 return resource
122
123 @staticmethod
124 def _uri_to_pk(resource_uri):
125 if resource_uri:
126 return resource_uri.split('/')[-2]
127 return None # we are mocked
128
129 def job_get(self, name):
130 resource = '/smokeng/api/v1/job/?' + urlencode({'name': name})
131 return self._http_get(resource)
132
133 def job_add(self, name):
134 resource = '/smokeng/api/v1/job/'
135 params = {
136 'name': name,
137 'url': 'http://jenkins.qa.ubuntu.com/job/' + name + '/'
138 }
139 return self._http_post(resource, params)
140
141 def build_add(self, job_name, job_number):
142 try:
143 logging.debug('trying to find job: %s', job_name)
144 job = self.job_get(job_name)
145 except HTTPException:
146 job = self.job_add(job_name)
147 logging.info('job is: %s', job)
148
149 resource = '/smokeng/api/v1/build/'
150 params = {
151 'build_number': job_number,
152 'job': job,
153 'ran_at': datetime.datetime.now().isoformat(),
154 'build_description': 'inprogress',
155 }
156 return self._http_post(resource, params)
157
158 def _image_get(self, build_number, release, variant, arch, flavor):
159 resource = '/smokeng/api/v1/image/?'
160 resource += urlencode({
161 'build_number': build_number,
162 'release': release,
163 'flavor': flavor,
164 'variant': variant,
165 'arch': arch,
166 })
167 return self._http_get(resource)
168
169 def image_add(self, build_number, release, variant, arch, flavor):
170 try:
171 img = self._image_get(build_number, release, variant, arch, flavor)
172 return img
173 except HTTPException:
174 # image doesn't exist so go continue and create
175 pass
176
177 resource = '/smokeng/api/v1/image/'
178 params = {
179 'build_number': build_number,
180 'release': release,
181 'flavor': flavor,
182 'variant': variant,
183 'arch': arch,
184 }
185 try:
186 return self._http_post(resource, params)
187 except HTTPException:
188 # race situation. Both callers saw _image_get fail and tried to
189 # create. Only one of them can succeed, so the failed call should
190 # now safely be able to get the image created by the other
191 img = self._image_get(build_number, release, variant, arch, flavor)
192 return img
193
194 def result_get(self, image, test):
195 # deal with getting resource uri's as parameters instead of id's
196 image = API._uri_to_pk(image)
197
198 resource = '/smokeng/api/v1/result/?'
199 resource += urlencode({
200 'image': image,
201 'name': test,
202 })
203 return self._http_get(resource)
204
205 def _result_status(self, image, build, test, status, results=None):
206 create = False
207 params = {
208 'ran_at': datetime.datetime.now().isoformat(),
209 'status': status,
210 'jenkins_build': build,
211 }
212 if results:
213 params['results'] = results
214
215 try:
216 resource = self.result_get(image, test)
217 except HTTPException:
218 create = True
219 resource = '/smokeng/api/v1/result/'
220 params['image'] = image
221 params['name'] = test
222
223 if create:
224 return self._http_post(resource, params)
225 else:
226 return self._http_patch(resource, params)
227
228 def result_queue(self, image, build, test):
229 return self._result_status(image, build, test, 0)
230
231 def result_running(self, image, build, test):
232 return self._result_status(image, build, test, 1)
233
234 def result_syncing(self, image, build, test, results):
235 return self._result_status(image, build, test, 2, results)
236
237
238def _result_running(api, args):
239 return api.result_running(args.image, args.build, args.test)
240
241
242def _result_syncing(api, args):
243 results = {}
244 with open(args.results) as f:
245 results = yaml.safe_load(f.read())
246 return api.result_syncing(args.image, args.build, args.test, results)
247
248
249def _set_args(parser, names, func):
250 for n in names:
251 parser.add_argument(n, required=True)
252 parser.set_defaults(func=func)
253
254
255def _get_parser():
256 parser = argparse.ArgumentParser(
257 description='Interact with the CI dashboard API')
258
259 sub = parser.add_subparsers(title='Commands', metavar='')
260
261 args = ['--image', '--build', '--test']
262 p = sub.add_parser('result-running', help='Set a SmokeResult "Running".')
263 _set_args(p, args, _result_running)
264
265 p = sub.add_parser('result-syncing', help='Set a SmokeResult "Syncing".')
266 _set_args(p, args, _result_syncing)
267 p.add_argument('--results', required=True, help='UTAH yaml file')
268
269 return parser
270
271
272def _assert_env():
273 required = [
274 'DASHBOARD_HOST', 'DASHBOARD_PORT', 'DASHBOARD_USER', 'DASHBOARD_KEY']
275 missing = []
276 for r in required:
277 if r not in os.environ:
278 missing.append(r)
279 if len(missing):
280 print('Missing the following environment variables:')
281 for x in missing:
282 print(' %s' % x)
283 exit(1)
284
285
286def _main(args):
287 _assert_env()
288
289 api = API()
290 try:
291 val = args.func(api, args)
292 if val:
293 if '/?' in val:
294 log.debug('stripping api-key from response')
295 val = val.split('/?')[0] + '/'
296 print(val)
297 except HTTPException as e:
298 print('ERROR: %s' % e)
299 exit(1)
300
301 exit(0)
302
303if __name__ == '__main__':
304 args = _get_parser().parse_args()
305 exit(_main(args))
0306
=== added file 'scripts/device_info.py'
--- scripts/device_info.py 1970-01-01 00:00:00 +0000
+++ scripts/device_info.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,122 @@
1#!/usr/bin/env python
2
3import re
4import subprocess
5
6
7class TouchDevice(object):
8 def __init__(self, devtype, serial, relay_url=None, bank=None,
9 power_pin=None, volume_pin=None):
10 self.devtype = devtype
11 self.serial = serial
12 self.relay_url = relay_url
13 self.bank = bank
14 self.power_pin = power_pin
15 self.volume_pin = volume_pin
16
17# When looking at the relay webUI for the mapping, we consider all
18# ports and banks to start numbering from 0
19DEVICES = {
20 "krillin-01": TouchDevice("krillin", "JB011018"),
21 "krillin-02": TouchDevice("krillin", "JB010894"),
22 "krillin-03": TouchDevice("krillin", "JB015156"),
23 "krillin-04": TouchDevice("krillin", "JB006885"),
24 "krillin-05": TouchDevice("krillin", "JB015256"),
25 "krillin-06": TouchDevice("krillin", "JW010687"),
26 "krillin-07": TouchDevice("krillin", "JW011999"),
27 "krillin-08": TouchDevice("krillin", "JW013513"),
28 "krillin-09": TouchDevice("krillin", "JW010053"),
29 "krillin-10": TouchDevice("krillin", "JB012976"),
30 "ps-mako-01": TouchDevice("mako", "0090f741e3d141bc"),
31 "ps-mako-02": TouchDevice("mako", "04ccca120acd4dea"),
32 "ps-mako-03": TouchDevice("mako", "04cb53b598546534"),
33 "ps-mako-04": TouchDevice("mako", "04cbcc545f5328a5"),
34 "mako-01": TouchDevice("mako", "01aa3d7a5dcba4a2"),
35 "mako-02": TouchDevice("mako", "01ade38b552014d4"),
36 "mako-03": TouchDevice("mako", "04c6714ed7c863f2"),
37 "mako-04": TouchDevice("mako", "04df89cf0f9d0933",
38 relay_url="http://qa-relay-control.ubuntu-ci",
39 bank=1, power_pin=4, volume_pin=5),
40 "mako-05": TouchDevice("mako", "01b22f82dc5cec63",
41 relay_url="http://10.98.4.100",
42 bank=0, power_pin=0, volume_pin=1),
43 "mako-06": TouchDevice("mako", "04ed70928fdc13ba",
44 relay_url="http://10.98.4.100",
45 bank=0, power_pin=2, volume_pin=3),
46 "mako-07": TouchDevice("mako", "01e2f64788556934",
47 relay_url="http://10.98.4.100",
48 bank=0, power_pin=4, volume_pin=5),
49 "mako-08": TouchDevice("mako", "04ea16a163930769",
50 relay_url="http://10.98.4.100",
51 bank=0, power_pin=6, volume_pin=7),
52 "mako-09": TouchDevice("mako", "04fda12ea08fe3c7"),
53 "mako-10": TouchDevice("mako", "01ce848e48dfa6a2"),
54 "mako-11": TouchDevice("mako", "04ed727c929709ba"),
55 #If looking at the LAB wiki page, subtract 1 from the bank and pin numbers
56 #from what it says on the wiki (our numbers start at 0)
57 "mako-12": TouchDevice("mako", "00693fd555c9186a",
58 relay_url="http://qa-relay-control.ubuntu-ci",
59 bank=0, power_pin=1, volume_pin=2),
60 "mako-13": TouchDevice("mako", "0084e99c5315731b",
61 relay_url="http://qa-relay-control.ubuntu-ci",
62 bank=0, power_pin=3, volume_pin=4),
63 "mako-14": TouchDevice("mako", "007c6d84d348838e",
64 relay_url="http://qa-relay-control.ubuntu-ci",
65 bank=0, power_pin=5, volume_pin=6),
66 "mako-15": TouchDevice("mako", "00763b4a61ce0f87",
67 relay_url="http://qa-relay-control.ubuntu-ci",
68 bank=1, power_pin=0, volume_pin=1),
69 "mako-16": TouchDevice("mako", "017121eacf5282c4",
70 relay_url="http://qa-relay-control.ubuntu-ci",
71 bank=1, power_pin=2, volume_pin=3),
72 #mako-17 has a broken screen but should work, on ashes
73 "mako-17": TouchDevice("mako", "04e0d2f6d3cab77d"),
74 "mako-18": TouchDevice("mako", "027b981a4c1110dd",
75 relay_url="http://10.98.4.100",
76 bank=1, power_pin=0, volume_pin=1),
77 "mako-19": TouchDevice("mako", "021c8cdfd5d38602"),
78 "mako-20": TouchDevice("mako", "05083705e0d29402",
79 relay_url="http://10.98.4.100",
80 bank=1, power_pin=2, volume_pin=3),
81 "ps-manta-01": TouchDevice("manta", "R32D203DDZR"),
82 "manta-01": TouchDevice("manta", "R32D102RPZL"),
83 "manta-02": TouchDevice("manta", "R32D102RPPK"),
84 "manta-03": TouchDevice("manta", "R32D200N4YH"),
85 "manta-05": TouchDevice("manta", "R32D203DMBY"), # Out of lab for now
86 "flo-01": TouchDevice("flo", "09f306dc"),
87 "flo-02": TouchDevice("flo", "08dbee36"),
88 "flo-03": TouchDevice("flo", "09d55fa8"),
89 "flo-04": TouchDevice("flo", "09e68682"),
90 "flo-05": TouchDevice("flo", "0a22f7cf"),
91 "flo-06": TouchDevice("flo", "08f09bb0"),
92}
93
94
95def get_state(serial):
96 """
97 Check adb and fastboot to determine the state a device is in.
98 Possible return values are:
99 device, recovery, unknown, bootloader, disconnected
100 """
101 pattern = "{}\t(.+)\n".format(serial)
102 adb_devices = subprocess.check_output(['adb', 'devices'])
103 found = re.search(pattern, adb_devices)
104 if not found:
105 #Otherwise, check fastboot
106 fastboot_devices = subprocess.check_output(['fastboot', 'devices'])
107 found = re.search(pattern, fastboot_devices)
108 if found:
109 state = found.group(1)
110 return state
111 else:
112 return 'disconnected'
113
114
115def get_serial(name):
116 return DEVICES.get(name).serial
117
118
119def get_power(name):
120 device = DEVICES.get(name)
121 return (device.relay_url, device.bank, device.power_pin,
122 device.volume_pin)
0123
=== added file 'scripts/get-adb-id'
--- scripts/get-adb-id 1970-01-01 00:00:00 +0000
+++ scripts/get-adb-id 2014-10-07 19:58:41 +0000
@@ -0,0 +1,13 @@
1#!/usr/bin/python
2
3import sys
4from device_info import get_serial
5
6if __name__ == '__main__':
7 name = sys.argv[1]
8
9 try:
10 print(get_serial(name))
11 except:
12 print("Unknown device name: '%s'" % name)
13 sys.exit(-1)
014
=== added file 'scripts/get-device-info'
--- scripts/get-device-info 1970-01-01 00:00:00 +0000
+++ scripts/get-device-info 2014-10-07 19:58:41 +0000
@@ -0,0 +1,37 @@
1#!/usr/bin/env python
2
3import argparse
4import device_info
5
6
7def _get_state(args):
8 print(device_info.get_state(device_info.get_serial(args.name)))
9
10
11def _get_serial(args):
12 print(device_info.get_serial(args.name))
13
14
15def _get_power(args):
16 print(device_info.get_power(args.name))
17
18
19def _get_parser():
20 parser = argparse.ArgumentParser(
21 description='Get information about a device')
22 sub = parser.add_subparsers(title='Commands', metavar='')
23 serial = sub.add_parser('serial', help='Get serial for a device name')
24 serial.set_defaults(func=_get_serial)
25 serial.add_argument('name', help='Device name')
26 power = sub.add_parser('power', help='Get power control info for a device')
27 power.set_defaults(func=_get_power)
28 power.add_argument('name', help='Device name')
29 state = sub.add_parser('state', help='Get device state for a device')
30 state.set_defaults(func=_get_state)
31 state.add_argument('name', help='Device name')
32 return parser
33
34
35if __name__ == '__main__':
36 args = _get_parser().parse_args()
37 exit(args.func(args))
038
=== added file 'scripts/jenkins.sh'
--- scripts/jenkins.sh 1970-01-01 00:00:00 +0000
+++ scripts/jenkins.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,214 @@
1#!/bin/bash
2
3## This is the script jenkins should run to execute various touch applications
4
5set -e
6
7BASEDIR=$(dirname $(readlink -f $0))/..
8
9RESDIR="${RESDIR-`pwd`/clientlogs}"
10UTAHFILE=${RESDIR}/utah.yaml
11UTAH_PHABLET_CMD="${UTAH_PHABLET_CMD-/usr/share/utah/examples/run_utah_phablet.py}"
12
13
14usage() {
15 cat <<EOF
16usage: $0 -a APP [-s ANDROID_SERIAL] [-p FILE -p FILE ...] [-Q]
17
18Provisions the given device with the latest build
19
20OPTIONS:
21 -h Show this message
22 -s Specify the serial of the device to install
23 -a The application under the "tests" directory to test
24 -p Extra file to pull from target (absolute path or relative to /home/phablet)
25 -Q "Quick" don't do a reboot of the device before running the test
26
27EOF
28}
29
30PIDS=""
31
32cleanup() {
33 set +e
34 echo "killing child pids: $PIDS"
35 for p in $PIDS ; do
36 kill $p
37 done
38}
39
40test_from_host() {
41 export PATH=${BASEDIR}/utils/host:${PATH}
42
43 # allow for certain commands to run from host/target
44 # see unity8-autopilot/ts_control for example
45 export TARGET_PREFIX=adb-shell
46
47 [ -z $ANDROID_SERIAL ] || ADBOPTS="-s $ANDROID_SERIAL"
48
49 # If we are not in the utah group, then we don't have permissions
50 # for /var/lib/utah, so run under sudo
51 if ! groups |grep -q utah ; then
52 SUDO="sudo"
53 sudo TARGET_PREFIX="${TARGET_PREFIX}" PATH="${PATH}" \
54 ${UTAH_PHABLET_CMD} \
55 ${ADBOPTS} \
56 --from-host \
57 --whoopsie \
58 --results-dir "${RESDIR}" \
59 --skip-install --skip-network --skip-utah \
60 --pull /var/crash \
61 --pull /home/phablet/.cache/upstart \
62 --pull /tmp/xmlresults \
63 --pull /var/log/syslog \
64 --pull /var/log/kern.log \
65 --pull /var/log/upstart/whoopsie.log \
66 $EXTRA_PULL \
67 -l "${TESTSUITE_HOST}/master.run"
68 else
69 TARGET_PREFIX="${TARGET_PREFIX}" PATH="${PATH}" \
70 ${UTAH_PHABLET_CMD} \
71 ${ADBOPTS} \
72 --from-host \
73 --whoopsie \
74 --results-dir "${RESDIR}" \
75 --skip-install --skip-network --skip-utah \
76 --pull /var/crash \
77 --pull /home/phablet/.cache/upstart \
78 --pull /tmp/xmlresults \
79 --pull /var/log/syslog \
80 --pull /var/log/kern.log \
81 --pull /var/log/upstart/whoopsie.log \
82 $EXTRA_PULL \
83 -l "${TESTSUITE_HOST}/master.run"
84 fi
85
86 # make sure the user running this script can remove its artifacts.
87 # only run this if we had to run under sudo
88 if [ "${SUDO}" = "sudo" ] ; then
89 sudo chown -R "${USER}" ${RESDIR}
90 fi
91}
92
93assert_image() {
94 [ -z $INSTALL_URL ] && return
95 echo "Ensuring target has proper image..."
96 REQUIRED_UUID=$(curl ${INSTALL_URL}/artifact/clientlogs/.ci-uuid)
97 ACTUAL_UUID=$(adb shell "cat /home/phablet/.ci-uuid | tr -d '\r\n'")
98 if [ "$REQUIRED_UUID" != "$ACTUAL_UUID" ] ; then
99 echo "UUIDs $REQUIRED_UUID != $ACTUAL_UUID, reprovisioning device..."
100 ARGS=$(curl ${INSTALL_URL}/artifact/clientlogs/.ci-utah-args | tr -d '\r\n')
101 UUID=$REQUIRED_UUID IMAGE_OPT=$ARGS ${BASEDIR}/scripts/provision.sh
102 else
103 echo "UUIDS match"
104 fi
105}
106
107main() {
108 rm -rf $RESDIR
109 mkdir $RESDIR
110
111 assert_image
112
113 # print the build date so the jenkins job can use it as the
114 # build description
115 adb pull /var/log/installer/media-info ${RESDIR}
116 BUILDID=$(adb shell cat /home/phablet/.ci-version)
117 echo "= TOUCH IMAGE VERSION:$BUILDID"
118
119 adb shell "top -n1 -b" > ${RESDIR}/top.log
120
121 set -x
122 adb shell 'sudo rm -f /var/crash/*'
123 if [ -z $QUICK ] ; then
124 # get the phone in sane place
125 adb reboot
126 # sometimes reboot doesn't happen fast enough, so add a little
127 # delay to help ensure its actually rebooted and we didn't just
128 # connect back to the device before it rebooted
129 adb wait-for-device
130 sleep 5
131 adb wait-for-device
132 phablet-network --skip-setup -t 90s
133 adb shell sudo powerd-cli active &
134 PIDS="$PIDS $!"
135 adb shell sudo powerd-cli display on &
136 PIDS="$PIDS $!"
137 else
138 echo "SKIPPING phone reboot..."
139 fi
140
141 ${BASEDIR}/utils/host/adb-shell "sudo aa-clickhook -f --include=/usr/share/autopilot-touch/apparmor/click.rules"
142
143 echo "launching test from the host...."
144 test_from_host
145 adb shell 'sudo rm -f /var/crash/*'
146
147 if ! `grep "^errors: [!0]" < $UTAHFILE >/dev/null` ; then
148 echo "errors found"
149 EXITCODE=1
150 fi
151 if ! `grep "^failures: [!0]" < $UTAHFILE >/dev/null` ; then
152 echo "failures found"
153 EXITCODE=2
154 fi
155 echo "Results Summary"
156 echo "---------------"
157 egrep '^(errors|failures|passes|fetch_errors):' $UTAHFILE
158 exit $EXITCODE
159}
160
161while getopts p:s:a:Qh opt; do
162 case $opt in
163 h)
164 usage
165 exit 0
166 ;;
167 s)
168 export ANDROID_SERIAL=$OPTARG
169 ;;
170 a)
171 APP=$OPTARG
172 ;;
173 p)
174 EXTRA_PULL_FILE=$OPTARG
175
176 if [ ! -z $EXTRA_PULL_FILE ]; then
177 # relative paths are assumed to be relative to /home/phablet
178 E_P_START=`echo $EXTRA_PULL_FILE | cut -c1`
179
180 if [ $E_P_START = '/' ]; then
181 EXTRA_PULL="$EXTRA_PULL --pull $EXTRA_PULL_FILE"
182 else
183 EXTRA_PULL="$EXTRA_PULL --pull /home/phablet/$EXTRA_PULL_FILE"
184 fi
185 fi
186 ;;
187 Q)
188 QUICK=1
189 ;;
190 esac
191done
192
193if [ -z $ANDROID_SERIAL ] ; then
194 # ensure we only have one device attached
195 lines=$(adb devices | wc -l)
196 if [ $lines -gt 3 ] ; then
197 echo "ERROR: More than one device attached, please use -s option"
198 echo
199 usage
200 exit 1
201 fi
202fi
203if [ -z $APP ] ; then
204 echo "ERROR: No app specified"
205 usage
206 exit 1
207fi
208
209TESTSUITE_HOST=$(readlink -f ${BASEDIR}/tests/${APP})
210TESTSUITE_TARGET_BASE=/tmp/tests
211TESTSUITE_TARGET=${TESTSUITE_TARGET_BASE}/$(basename ${TESTSUITE_HOST})
212
213trap cleanup TERM INT EXIT
214main
0215
=== added file 'scripts/junit2utah.py'
--- scripts/junit2utah.py 1970-01-01 00:00:00 +0000
+++ scripts/junit2utah.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,70 @@
1#!/usr/bin/python
2
3import datetime
4import sys
5
6from xml.etree import ElementTree
7
8import yaml
9
10
11def _convert_testcase(tc):
12 x = {
13 'testcase': tc.attrib['name'],
14 'testsuite': tc.attrib['classname'],
15 'command': 'autopilot',
16 'cmd_type': 'testcase_test',
17 'stdout': '',
18 'stderr': '',
19 'returncode': 0
20 }
21 t = tc.attrib.get('time', False)
22 if t:
23 x['time_delta'] = t
24
25 for e in tc.getchildren():
26 if e.tag in ('failure', 'error'):
27 x['stderr'] = e.text
28 x['returncode'] = 1
29 elif e.tag == 'skip':
30 # NOTE: this isn't a real thing in UTAH. However, the
31 # qa-dashboard code doesn't care and will display it as skipped
32 x['cmd_type'] = 'testcase_skipped'
33 x['stdout'] = e.text
34 else:
35 raise RuntimeError('Unknown element type: %s' % e.tag)
36 return x
37
38
39def _get_results(stream):
40 tree = ElementTree.fromstring(stream.read())
41 results = {
42 'errors': int(tree.attrib.get('errors', '0')),
43 'failures': int(tree.attrib.get('failures', '0')),
44 'commands': [],
45 'fetch_errors': 0,
46 'uname': 'n/a',
47 'media-info': 'n/a',
48 'install_type': 'n/a',
49 'arch': 'n/a',
50 'release': 'n/a',
51 'build_number': 'n/a',
52 'name': 'unamed',
53 'runlist': 'n/a',
54 'ran_at': datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'),
55 }
56 results['passes'] = \
57 int(tree.attrib['tests']) - results['errors'] - results['failures']
58
59 for tc in tree.getchildren():
60 results['commands'].append(_convert_testcase(tc))
61 return results
62
63
64def _main(stream):
65 results = _get_results(stream)
66 print(yaml.safe_dump(results, default_flow_style=False))
67
68
69if __name__ == '__main__':
70 exit(_main(sys.stdin))
071
=== added file 'scripts/ncd_usb.py'
--- scripts/ncd_usb.py 1970-01-01 00:00:00 +0000
+++ scripts/ncd_usb.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,48 @@
1#! /usr/bin/python
2
3"""A utility to control the USB relay's in the QA lab."""
4
5import argparse
6import sys
7import urllib2
8
9
10def set_relay(urlbase, bank, relay, on):
11 # the values 100/108 came from the JavaScript of our web-based management
12 # system for the relays. The meaning of the values isn't documented.
13 if on:
14 relay += 108
15 else:
16 relay += 100
17 cmd = '254,{},{}'.format(relay, bank + 1)
18 url = '{}/cgi-bin/runcommand.sh?1:cmd={}'.format(urlbase, cmd)
19 resp = urllib2.urlopen(url)
20 resp = resp.read()
21 if 'OK' not in resp:
22 print('ERROR: bad response: {}'.format(resp))
23 sys.exit(1)
24
25
26def _get_parser():
27 parser = argparse.ArgumentParser(
28 description='Toggles an NCD relay connected to a USB cable on/off')
29 parser.add_argument('-u', '--url',
30 default='http://qa-relay-control.ubuntu-ci',
31 help='NCD relay URL. default=%(default)s')
32 parser.add_argument('-b', '--bank', type=int, required=True,
33 help='NCD relay 0-based bank ID.')
34 parser.add_argument('-r', '--relay', type=int, required=True,
35 help='NCD relay 0-based relay ID.')
36 parser.add_argument('action', metavar='action',
37 choices=('on', 'off'),
38 help='action to perform on|off')
39 return parser
40
41
42if __name__ == '__main__':
43 args = _get_parser().parse_args()
44
45 # NOTE: when the relay is ON usb is actually OFF. ie the logic
46 # is backwards between them, thus action=off actually turns
47 # the relay on
48 set_relay(args.url, args.bank, args.relay, args.action == 'off')
049
=== added file 'scripts/provision.sh'
--- scripts/provision.sh 1970-01-01 00:00:00 +0000
+++ scripts/provision.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,201 @@
1#!/bin/bash
2
3## This is the script jenkins should run to provision a device in the lab
4
5set -e
6
7BASEDIR=$(dirname $(readlink -f $0))
8export PATH=${BASEDIR}/../utils/host:${PATH}
9
10RESDIR=`pwd`/clientlogs
11
12NETWORK_FILE="${NETWORK_FILE-/home/ubuntu/magners-wifi}"
13
14IMAGE_OPT="${IMAGE_OPT---bootstrap --developer-mode --channel ubuntu-touch/devel-proposed}"
15UUID="${UUID-$(uuidgen -r)}"
16
17usage() {
18cat <<EOF
19usage: $0 [-s ANDROID_SERIAL] [-n NETWORK_FILE] [-P ppa] [-p package] [-r revision] [-w]
20
21Provisions the given device with the latest build
22
23OPTIONS:
24 -h Show this message
25 -s Specify the serial of the device to install
26 -n Select network file
27 -P add the ppa to the target (can be repeated)
28 -p add the package to the target (can be repeated)
29 -r Specify the image revision to flash
30 -w make the system writeable (implied with -p and -P arguments)
31
32EOF
33}
34
35image_info() {
36 # mark the version we installed in /home/phablet/.ci-[uuid,flash-args]
37 # adb shell messes up \n's with \r\n's so do the whole of the regex on the target
38 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:")
39 CHAN=$(adb shell "sudo system-image-cli -i | sed -n -e 's/channel: \(.*\)/\1/p' | paste -s -d:")
40 REV=$(echo $IMAGEVER | cut -d: -f1)
41 echo "$IMAGE_OPT" | grep -q "\-\-revision" || IMAGE_OPT="${IMAGE_OPT} --revision $REV"
42 echo "$IMAGE_OPT" | grep -q "\-\-channel" || IMAGE_OPT="${IMAGE_OPT} --channel $CHAN"
43 adb shell "echo '${IMAGEVER}' > /home/phablet/.ci-version"
44 echo $UUID > $RESDIR/.ci-uuid
45 adb push $RESDIR/.ci-uuid /home/phablet/
46 cat > $RESDIR/.ci-flash-args <<EOF
47$IMAGE_OPT
48EOF
49 adb push $RESDIR/.ci-flash-args /home/phablet/.ci-flash-args
50 echo $CUSTOMIZE > $RESDIR/.ci-customizations
51 adb push $RESDIR/.ci-customizations /home/phablet/.ci-customizations
52}
53
54log() {
55 echo = $(date): $*
56}
57
58set_hwclock() {
59 log "SETTING HWCLOCK TO CURRENT TIME"
60 # Use ip for ntp.ubuntu.com in case resolving doesn't work yet
61 adb-shell sudo ntpdate 91.189.94.4 || log "WARNING: could not set ntpdate"
62 # hwclock sync has to happen after we set writable image
63 adb-shell sudo hwclock -w || log "WARNING: could not sync hwclock"
64 log "Current date on device is:"
65 adb shell date
66 log "Current hwclock on device is:"
67 adb shell sudo hwclock
68}
69
70retry() {
71 timeout=$1
72 shift
73 loops=$1
74 shift
75 cmd=$*
76 loopcnt=0
77 while true; do
78 $cmd && break || {
79 if [ $loopcnt -lt $loops ] ; then
80 loopcnt=$[$loopcnt+1]
81 echo "Retry [$loopcnt/$loops] after $timeout seconds..."
82 sleep $timeout
83 else
84 echo Failed on \'$cmd\' after $loops retries
85 exit 1
86 fi
87 }
88 done
89}
90
91while getopts i:s:n:P:p:r:wh opt; do
92 case $opt in
93 h)
94 usage
95 exit 0
96 ;;
97 n)
98 NETWORK_FILE=$OPTARG
99 ;;
100 s)
101 export ANDROID_SERIAL=$OPTARG
102 ;;
103 i)
104 IMAGE_TYPE=$OPTARG
105 ;;
106 w)
107 # making this a non-zero length string enables the logic
108 CUSTOMIZE=" "
109 ;;
110 P)
111 CUSTOMIZE="$CUSTOMIZE --ppa $OPTARG"
112 ;;
113 p)
114 CUSTOMIZE="$CUSTOMIZE -p $OPTARG"
115 ;;
116 r)
117 IMAGE_OPT="$IMAGE_OPT --revision $OPTARG"
118 ;;
119
120 esac
121done
122
123if [ -z $ANDROID_SERIAL ] ; then
124 # ensure we only have one device attached
125 lines=$(adb devices | wc -l)
126 if [ $lines -gt 3 ] ; then
127 echo "ERROR: More than one device attached, please use -s option"
128 echo
129 usage
130 exit 1
131 fi
132fi
133
134if [ ! -f $NETWORK_FILE ] && [ -z $USE_EMULATOR ] ; then
135 echo "ERROR: NETWORK_FILE, $NETWORK_FILE, not found"
136 exit 1
137fi
138
139set -x
140[ -d $RESDIR ] && rm -rf $RESDIR
141mkdir -p $RESDIR
142
143if [ -z $USE_EMULATOR ] ; then
144 log "FLASHING DEVICE"
145 if [ "${DEVICE_TYPE}" = "krillin" ]; then
146 # reboot to recovery for krillin
147 adb reboot recovery
148 # Wait for recovery to boot
149 sleep 30
150 else
151 adb reboot bootloader
152 fi
153 ubuntu-device-flash --password ubuntuci $IMAGE_OPT
154 adb wait-for-device
155 sleep 60 #give the system a little time
156else
157 log "CREATING EMULATOR"
158 ubuntu-emulator destroy --yes $ANDROID_SERIAL || true
159 sudo ubuntu-emulator create $ANDROID_SERIAL $IMAGE_OPT
160 ${BASEDIR}/reboot-and-wait
161fi
162
163if [ -z $USE_EMULATOR ] ; then
164 log "SETTING UP WIFI"
165 retry 60 5 adb-shell 'sudo -iu phablet env |grep UPSTART_SESSION=unix'
166 phablet-network -n $NETWORK_FILE
167fi
168
169phablet-config welcome-wizard --disable
170
171if [ -n "$CUSTOMIZE" ] ; then
172 log "CUSTOMIZING IMAGE"
173 phablet-config writable-image $CUSTOMIZE
174fi
175
176log "SETTING UP SUDO"
177adb shell "echo ubuntuci |sudo -S bash -c 'echo phablet ALL=\(ALL\) NOPASSWD: ALL > /etc/sudoers.d/phablet && chmod 600 /etc/sudoers.d/phablet'"
178
179# FIXME: Can't do this through phablet-config for now because it needs auth
180# phablet-config edges-intro --disable
181adb 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"
182
183log "SETTING UP CLICK PACKAGES"
184CLICK_TEST_OPTS=""
185channel_name=$(adb shell "sudo system-image-cli -i | sed -n -e 's/channel: \(.*\)/\1/p' | paste -s -d:")
186# Before running phablet-click-test setup, we need to make sure the
187# session is available
188retry 60 5 adb-shell 'sudo -iu phablet env |grep UPSTART_SESSION=unix'
189
190# FIXME: workaround for phablet-click-test-setup to pull the right sources
191if [[ $channel_name == *rtm* ]] ; then
192 CLICK_TEST_OPTS="--distribution ubuntu-rtm --series 14.09"
193fi
194phablet-click-test-setup $CLICK_TEST_OPTS
195
196# get our target-based utilities into our PATH
197adb push ${BASEDIR}/../utils/target /home/phablet/bin
198
199image_info
200
201set_hwclock
0202
=== added file 'scripts/reboot-and-wait'
--- scripts/reboot-and-wait 1970-01-01 00:00:00 +0000
+++ scripts/reboot-and-wait 2014-10-07 19:58:41 +0000
@@ -0,0 +1,54 @@
1#!/usr/bin/python
2
3import argparse
4import logging
5import os
6import subprocess
7import time
8
9from phabletutils.device import AndroidBridge
10
11EMULATOR = os.environ.get('USE_EMULATOR', '')
12
13
14def _get_arg_parser():
15 parser = argparse.ArgumentParser(
16 description='Reboot device and waits for networking to become active.')
17 parser.add_argument('-s', '--serial', help='Device serial')
18 parser.add_argument('-n', '--num-tries', type=int, default=3,
19 help='''How many times to retry on failure.
20 default=%(default)d''')
21 return parser
22
23
24def main(args):
25 device = AndroidBridge(args.serial)
26 device.wait_for_device()
27 for i in range(args.num_tries):
28 device.reboot()
29 device.wait_for_device()
30 time.sleep(5)
31 device.wait_for_device()
32 try:
33 device.wait_for_network()
34 return 0
35 except:
36 pass # try the loop again
37 logging.error('device failed to start and activate networking')
38 return 1
39
40
41def emulator_main(args):
42 emulator = os.path.join(os.path.dirname(__file__), 'run-emulator')
43 subprocess.check_call([emulator])
44
45
46if __name__ == '__main__':
47 logging.basicConfig(level=logging.INFO)
48 logging.getLogger().name = 'reboot-and-wait'
49 args = _get_arg_parser().parse_args()
50 if EMULATOR:
51 logging.info('using emulator logic for reboot')
52 exit(emulator_main(args))
53 else:
54 exit(main(args))
055
=== added file 'scripts/recover.py'
--- scripts/recover.py 1970-01-01 00:00:00 +0000
+++ scripts/recover.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,146 @@
1#!/usr/bin/env python
2
3import device_info
4import logging
5import subprocess
6import sys
7import time
8from ncd_usb import set_relay
9
10log = logging.getLogger()
11logging.basicConfig(level=logging.INFO)
12
13
14class DeviceError(Exception):
15 pass
16
17
18def _reimage_from_fastboot(serial):
19 #Starting from fastboot mode, put a known-good image on the device
20 log.info("Flashing the last stable image")
21 subprocess.check_output(['ubuntu-device-flash', '--serial', serial,
22 '--channel', 'ubuntu-touch/stable',
23 '--bootstrap', '--password', 'ubuntuci'])
24 return _wait_for_device(serial, 600)
25
26
27def _wait_for_device(serial, timeout=120):
28 # Wait for the device to come up to a good/booted state
29 log.info("Waiting for the device to become available")
30 try:
31 subprocess.check_call(['timeout', str(timeout), 'adb', '-s',
32 serial, 'wait-for-device'])
33 except:
34 log.error("Timed out waiting for reboot. Recover device manually")
35 raise
36 dev_state = device_info.get_state(serial)
37 if dev_state != 'device':
38 raise DeviceError("Device in state: {0}, still not available after "
39 "{1} seconds".format(dev_state, timeout))
40 else:
41 log.info("Device is now available")
42 return 0
43
44
45def _wait_for_fastboot(serial, timeout=120):
46 if timeout > 10:
47 wait = 10
48 else:
49 wait = timeout
50 waited = 0
51 while waited < timeout:
52 state = device_info.get_state(serial)
53 if state == 'fastboot':
54 return 0
55 time.sleep(wait)
56 waited += wait
57 else:
58 state = device_info.get_state(serial)
59 if state == 'fastboot':
60 return 0
61 log.error("Timed out waiting for fastboot. Recover device manually")
62 raise DeviceError("Device in state: {0}, still not available after "
63 "{1} seconds".format(state, timeout))
64
65
66def _mako_to_bootloader(urlbase, bank, power=1, volume=2):
67 """
68 This just works on mako for certain, but that's all we have connected
69 right now. After this runs, the device should be in the bootloader
70 """
71 log.info("Forcing the device to enter the bootloader")
72 #Power off the device from any state
73 set_relay(urlbase, bank, power, 1)
74 time.sleep(10)
75 set_relay(urlbase, bank, power, 0)
76 time.sleep(10)
77 #Enter the bootloader
78 set_relay(urlbase, bank, volume, 1)
79 set_relay(urlbase, bank, power, 1)
80 time.sleep(5)
81 set_relay(urlbase, bank, volume, 0)
82 set_relay(urlbase, bank, power, 0)
83
84
85def _full_recovery(device_name):
86 #we only support mako at the moment
87 (url, bank, power, volume) = device_info.get_power(device_name)
88 if None in (url, bank, power, volume):
89 #This device does not have information about relays
90 raise DeviceError("Full recovery not possible with this device")
91 _mako_to_bootloader(url, bank, power, volume)
92 serial = device_info.get_serial(device_name)
93 _wait_for_fastboot(serial)
94 _reimage_from_fastboot(serial)
95 try:
96 _check_adb_shell(serial)
97 except:
98 # The device looks like it's available, but not responding
99 raise DeviceError("Could not fully recover {}".format(device_name))
100 return 0
101
102
103def _check_adb_shell(serial):
104 # Run a quick command in adb to see if the device is responding
105 subprocess.check_call(['timeout', '10', 'adb', '-s',
106 serial, 'shell', 'pwd'])
107
108
109def recover(device):
110 try:
111 serial = device_info.get_serial(device)
112 except AttributeError:
113 log.error("No device found for '{}'".format(device))
114 raise
115 state = device_info.get_state(serial)
116 if state in ('device', 'recovery'):
117 try:
118 _check_adb_shell(serial)
119 except:
120 # The device looks like it's available, but not responding
121 return _full_recovery(device)
122 #The device can proceed with testing
123 return 0
124 if state == 'fastboot':
125 #The device is in fastboot right now, we need it booted first
126 _reimage_from_fastboot(serial)
127 try:
128 _check_adb_shell(serial)
129 except:
130 # The device looks like it's available, but not responding
131 return _full_recovery(device)
132 if state in ('unknown', 'disconnected'):
133 #The device is in an unknown state, we need full recovery
134 return _full_recovery(device)
135 #In theory, we should never get here, but....
136 raise DeviceError("Device '{}' is in an unknown state!".format(device))
137
138
139if __name__ == '__main__':
140 name = sys.argv[1]
141 try:
142 print(recover(name))
143 except AttributeError:
144 #This is what we'll get if it's an unknown device, raise for
145 #everything else so we get better debugging information
146 sys.exit(-1)
0147
=== added file 'scripts/run-autopilot-tests.sh'
--- scripts/run-autopilot-tests.sh 1970-01-01 00:00:00 +0000
+++ scripts/run-autopilot-tests.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,255 @@
1#!/bin/sh
2
3set -e
4
5BASEDIR=$(dirname $(readlink -f $0))/..
6RESDIR=`pwd`/clientlogs
7
8export PATH=${BASEDIR}/utils/host:${PATH}
9export TARGET_PREFIX=adb-shell
10
11
12usage() {
13 cat <<EOF
14usage: $0 -a APP [-s ANDROID_SERIAL] [-Q] [-o results_dir] [-S]
15
16Runs a set of autopilot tests on the target
17
18OPTIONS:
19 -h Show this message
20 -s Specify the serial of the device to test
21 -a The application to test (can be repeated)
22 -o Specify the directory to place results in.
23 Default: $RESDIR
24 -Q "Quick" don't do a reboot of the device before/between testsuites.
25 -S Skip the system-settle tests that run before/after each testsuite.
26
27EOF
28}
29
30log_error() {
31 echo ERROR: $* >> ${RESDIR}/runner-errors.txt
32}
33
34setup_test() {
35 app=$1
36 label=$2
37 odir=$3
38 {
39 pkgs=$(${BASEDIR}/jenkins/testconfig.py packages -a $app)
40 if [ "$label" = "setup" ] ; then
41 adb-shell sudo apt-get install -yq --force-yes $pkgs
42 else
43 #Always remove dbus-x11 because it causes
44 #problems when we leave it around
45 pkgs="$pkgs dbus-x11"
46 adb-shell sudo apt-get autoremove --purge -y $pkgs \
47 || /bin/true
48 fi
49 echo $? > ${odir}/setup_${label}.rc
50 } 2>&1 | tee ${odir}/setup_${label}.log
51}
52
53system_settle() {
54 [ -z $NOSETTLE ] || return 0
55
56 label=$1
57 odir=$2
58 rc=0
59 timeout=120s
60 if [ "$label" = "before" ] ; then
61 timeout=300s
62 fi
63
64 settle=${BASEDIR}/tests/systemsettle/systemsettle.sh
65 {
66 export UTAH_PROBE_DIR=${odir} # needed for log file location
67 timeout $timeout $settle -c5 -d6 -p 97.5 -l $label || rc=1
68 echo $rc > ${odir}/settle_${label}.rc
69 } 2>&1 | tee ${odir}/settle_${label}.log
70}
71
72test_app() {
73 app=$1
74
75 odir=${RESDIR}/${app}
76 [ -d $odir ] && rm -rf $odir
77 mkdir -p $odir || return 1
78
79 system_settle before $odir
80 phablet-config autopilot --dbus-probe enable || \
81 (log_error "'autopilot dbus-probe enable' failed"; return 1)
82 adb-shell /home/phablet/bin/check-clickhook-rules || \
83 (log_error "some click profiles missing autopilot rules")
84
85 setup_test $app setup $odir
86
87 NOSHELL=""
88 [ "$app" = "unity8" ] && NOSHELL="-n"
89 EXTRA=""
90 # Use --timeout-profile=long only if we are using the emulator
91 [ -z $USE_EMULATOR ] || EXTRA="-A '--timeout-profile=long'"
92
93 phablet-test-run \
94 $NOSHELL $EXTRA \
95 -o ${odir} -f subunit \
96 -a /var/crash -a /home/phablet/.cache/upstart \
97 -a /var/log/syslog -a /var/log/kern.log \
98 -a /var/log/upstart/whoopsie.log \
99 -A --timeout-profile=long \
100 -v $app || true
101
102 system_settle after $odir
103 setup_test $app teardown $odir
104 if [ -f ${odir}/test_results.subunit ] ; then
105 cat ${odir}/test_results.subunit | subunit2junitxml > ${odir}/test_results.xml
106 fi
107 ${BASEDIR}/scripts/combine_results ${odir}
108}
109
110reboot_wait() {
111 if [ -z $QUICK ] ; then
112 reboot-and-unlock.sh
113 FILES="/var/crash/* /home/phablet/.cache/upstart/*.log*"
114 if ! adb shell "sudo rm -rf $FILES" ; then
115 log_error "unable to remove crash and log files, retrying"
116 adb wait-for-device
117 adb shell "sudo rm -rf $FILES"
118 fi
119 else
120 echo "SKIPPING phone reboot..."
121 fi
122}
123
124if [ -z $USE_EMULATOR ] ; then
125grab_powerd() {
126 echo "grabbing powerd cli locks..."
127 adb shell sudo powerd-cli active &
128 PIDS="$!"
129 adb shell sudo powerd-cli display on &
130 PIDS="$PIDS $!"
131}
132
133release_powerd() {
134 if [ -n "$PIDS" ] ; then
135 echo "killing child pids: $PIDS"
136 for p in $PIDS ; do
137 kill $p || true
138 done
139 PIDS=""
140 fi
141 adb shell sudo pkill powerd-cli
142}
143
144else
145grab_powerd() {
146 #emulator does not use powerd, so this is noop
147 return 0
148}
149
150release_powerd() {
151 #emulator does not use powerd, so this is noop
152 return 0
153}
154fi
155
156dashboard_update() {
157 # only try and update the dashboard if we are configured to
158 [ -z $DASHBOARD_KEY ] && return 0
159 [ -z $DASHBOARD_BUILD ] && return 0
160 [ -z $DASHBOARD_IMAGE ] && return 0
161 ${BASEDIR}/scripts/dashboard.py $* \
162 --image $DASHBOARD_IMAGE \
163 --build $DASHBOARD_BUILD || true
164}
165
166dashboard_result_running() {
167 dashboard_update result-running --test $1
168}
169
170dashboard_result_syncing() {
171 xunit=${RESDIR}/${app}/test_results.xml
172 [ -f $xunit ] || return 0
173
174 # save a utah.yaml version of the results so the dashboard can process
175 cat $xunit | ${BASEDIR}/scripts/junit2utah.py > ${RESDIR}/${app}/utah.yaml
176 dashboard_update result-syncing --test $1 --results ${RESDIR}/${app}/utah.yaml
177}
178
179main() {
180 [ -d $RESDIR ] || mkdir -p $RESDIR
181
182 set -x
183
184 for app in $APPS ; do
185 set +x
186 echo "========================================================"
187 echo "= testing $app"
188 echo "========================================================"
189 set -x
190 dashboard_result_running $app
191 reboot_wait
192
193 grab_powerd
194
195 if ! test_app $app ; then
196 log_error "testing $app, retrying"
197 # we sometimes see sporatic adb failures that seem to
198 # related to MTP. This adds a retry for the test.
199 # test_app only fails on a device error (not a test
200 # case error)
201 adb wait-for-device
202 test_app $app
203 fi
204 dashboard_result_syncing $app
205
206 release_powerd
207 done
208}
209
210while getopts s:a:o:QSh opt; do
211 case $opt in
212 h)
213 usage
214 exit 0
215 ;;
216 s)
217 export ANDROID_SERIAL=$OPTARG
218 ;;
219 o)
220 RESDIR=$OPTARG
221 ;;
222 a)
223 APPS="$APPS $OPTARG"
224 ;;
225 Q)
226 QUICK=1
227 ;;
228 S)
229 NOSETTLE=1
230 ;;
231 esac
232done
233
234if [ -z $ANDROID_SERIAL ] ; then
235 # ensure we only have one device attached
236 lines=$(adb devices | wc -l)
237 if [ $lines -gt 3 ] ; then
238 echo "ERROR: More than one device attached, please use -s option"
239 echo
240 usage
241 exit 1
242 fi
243fi
244if [ -z "$APPS" ] ; then
245 echo "ERROR: No app specified"
246 usage
247 exit 1
248fi
249
250trap release_powerd TERM INT EXIT
251if [ -n "$USE_EMULATOR" ] ; then
252 echo "disabling system-settle testing for emulator"
253 NOSETTLE=1
254fi
255main
0256
=== added file 'scripts/run-emulator'
--- scripts/run-emulator 1970-01-01 00:00:00 +0000
+++ scripts/run-emulator 2014-10-07 19:58:41 +0000
@@ -0,0 +1,97 @@
1#!/usr/bin/python
2
3import logging
4import os
5import subprocess
6import sys
7import time
8
9FULL_RETRIES = 3
10# unity8 takes a long time because it needs apparmor to start. apparmor is
11# slow because its parsing all the profiles on first boot. qemu seems to
12# be inconsisent, sometimes this takes 8 tries, sometimes >40.
13UNITY_RETRIES = 50
14UNITY_WAIT = 20
15ADB_RETRIES = 3
16ADB_WAIT = 120
17
18EMULATOR_ARCH = os.environ.get('EMULATOR_ARCH', 'x86')
19
20
21class RetryException(Exception):
22 pass
23
24
25def _kill():
26 logging.info('killing all emulator pids')
27 with open('/dev/null', 'w') as f:
28 subprocess.call(['killall', 'ubuntu-emulator'], stderr=f)
29 time.sleep(1)
30 subprocess.call(['killall', 'emulator-' + EMULATOR_ARCH], stderr=f)
31 time.sleep(1)
32
33
34def _launch():
35 logging.info('launching emulator...')
36 subprocess.Popen(['ubuntu-emulator', 'run', os.environ['ANDROID_SERIAL']])
37
38
39def _adb_wait(retries, timeout):
40 timeout = '%ds' % timeout
41 for i in range(retries):
42 logging.info('waiting for emulator via adb (%d of %d)...', i, retries)
43 rc = subprocess.call(['timeout', timeout, 'adb', 'wait-for-device'])
44 if rc == 0:
45 return
46 # the emulator isn't always being detected by the adb-server
47 # running kill-server works around this. NOTE: this is only
48 # safe when run on a slave hooked up to a single emulator
49 logging.info('emulator not found, restarting adbd')
50 subprocess.check_call(['adb', 'kill-server'])
51 return RetryException('emulator not found via adb')
52
53
54def _unity_wait(retries, timeout):
55 for i in range(retries):
56 logging.info('waiting for unity8 (%d of %d)...', i, retries)
57 time.sleep(timeout)
58 try:
59 out = subprocess.check_output(
60 ['adb', 'shell', 'sudo -i -u phablet status unity8'])
61 if 'start/running' in out:
62 return
63 except subprocess.CalledProcessError:
64 logging.info('adb shell failed, retrying')
65 raise RetryException('unity8 not running on device')
66
67
68def main():
69 for i in range(FULL_RETRIES):
70 try:
71 _kill()
72 _launch()
73 _adb_wait(ADB_RETRIES, ADB_WAIT)
74 logging.info('emulator is running, waiting on unity8')
75 if EMULATOR_ARCH == 'arm':
76 logging.info('sleeping for 160s to wait for ARM emulator')
77 time.sleep(160)
78 _unity_wait(UNITY_RETRIES, UNITY_WAIT)
79 logging.info('emulator is booted and ready')
80 return 0
81 except RetryException as e:
82 logging.warn('emulator failed to boot: %s', e.message)
83 logging.warn('kill and retry %d more times', FULL_RETRIES - i)
84 next
85 logging.error('emulator failed to boot')
86 _kill()
87 return 1
88
89if __name__ == '__main__':
90 handler = logging.StreamHandler(stream=sys.stderr)
91 formatter = logging.Formatter(
92 '%(asctime)s %(levelname)s: %(message)s', datefmt='%H:%M:%S')
93 handler.setFormatter(formatter)
94 l = logging.getLogger('')
95 l.addHandler(handler)
96 l.setLevel(logging.INFO)
97 exit(main())
098
=== added file 'scripts/run-smoke'
--- scripts/run-smoke 1970-01-01 00:00:00 +0000
+++ scripts/run-smoke 2014-10-07 19:58:41 +0000
@@ -0,0 +1,419 @@
1#!/usr/bin/python
2
3import argparse
4import datetime
5import logging
6import os
7import shutil
8import subprocess
9
10import yaml
11
12from phabletutils.environment import detect_device
13
14import dashboard
15import statsd
16
17EMULATOR = os.environ.get('USE_EMULATOR')
18if EMULATOR:
19 def fake_detect(serial, device=None):
20 log.info('faking detect device for emulator')
21 return 'emulator'
22
23 # detect_device doesn't support the emulator
24 globals()['detect_device'] = fake_detect
25 if 'ANDROID_SERIAL' not in os.environ:
26 # we need something here or "serial required" logic fails
27 os.environ['ANDROID_SERIAL'] = 'emulator-5554'
28
29log = logging.getLogger()
30script_dir = os.path.dirname(__file__)
31res_dir = os.path.join(os.getcwd(), 'clientlogs')
32
33dashboard_api = dashboard.API()
34
35
36class SerialAction(argparse.Action):
37 def __call__(self, parser, namespace, values, option_string=None):
38 log.info('android serial: %s', values[0])
39 os.environ['ANDROID_SERIAL'] = values[0]
40
41
42class DebugAction(argparse.Action):
43 def __call__(self, parser, namespace, values, option_string=None):
44 log.setLevel(level=logging.DEBUG)
45 log.debug('debug logging enabled')
46
47
48def _serial_required():
49 required = 'ANDROID_SERIAL' not in os.environ
50 if required:
51 try:
52 out = subprocess.check_output(['adb', 'devices'])
53 required = (len(out.decode().split('\n')) != 4)
54 except subprocess.CalledProcessError as e:
55 logging.debug('error getting adb devices: %s', e)
56 return required
57
58
59def _get_parser():
60 parser = argparse.ArgumentParser(
61 description='Run the complete test-execution-service suite.')
62
63 parser.add_argument('-s', '--serial', action=SerialAction, nargs=1,
64 required=_serial_required(),
65 help='Android serial if more than one device present')
66 parser.add_argument('--debug', action=DebugAction, nargs=0,
67 help='''Enable debug logging.''')
68
69 parser.add_argument('--install-url',
70 help='''Flash with image from previous jenkins job.
71 This option will check if the device already has image
72 noted from this URL and will skip provisioning. The URL
73 should be the path the job like:
74 http://q-jenkins:8080/job/<your job>/<build number>''')
75 parser.add_argument('-p', '--package', action='append',
76 help='Additional packages to install on target.')
77 parser.add_argument('-P', '--ppa', action='append',
78 help='Additional PPA to configure on target.')
79 parser.add_argument('-a', '--app', action='append',
80 help='Autopilot tests tor run.')
81 parser.add_argument('-t', '--test', action='append',
82 help='UTAH tests tor run.')
83 parser.add_argument('-r', '--revision', help='Image revision to install.')
84 parser.add_argument('-n', '--no-provision', action='store_true',
85 help='Skip provisioning of the target device')
86 parser.add_argument('--hooks-dir',
87 help='''A directory containing scripts to be run after
88 the target has been provisioned and before testing.''')
89 parser.add_argument('--image-opt',
90 help='Options to pass to phablet-flash')
91 parser.add_argument('--image-type', default='touch',
92 help='''Image type being tested. This can be changed
93 to 'touch_sf4p' so that SurfaceFlinger will be used
94 instead of Mir. default=%(default)s''')
95 parser.add_argument('--num-workers', type=int, default=1,
96 help='''The total number of workers available for
97 running tests.''')
98 parser.add_argument('--worker-idx', type=int, default=0,
99 help='The worker to allocate testing work to.')
100 return parser
101
102
103def _arg_from_env(args, attr, envkey, array):
104 val = os.environ.get(envkey, False)
105 if val:
106 if array:
107 setattr(args, attr, val.split())
108 else:
109 setattr(args, attr, val)
110 del os.environ[envkey]
111
112
113def _merge_env(args):
114 '''When run in Jenkins everything comes as environment variables.
115
116 Its makes a much simpler job this way. While command line args are
117 much easier for a user.
118 '''
119 _arg_from_env(args, 'app', 'APPS', True)
120 _arg_from_env(args, 'test', 'TESTS', True)
121 _arg_from_env(args, 'package', 'PACKAGES', True)
122 _arg_from_env(args, 'ppa', 'PPAS', True)
123 _arg_from_env(args, 'image_opt', 'IMAGE_OPT', False)
124 _arg_from_env(args, 'image_type', 'IMAGE_TYPE', False)
125 _arg_from_env(args, 'install_url', 'INSTALL_URL', False)
126 _arg_from_env(args, 'revision', 'REVISION', False)
127 _arg_from_env(args, 'num_workers', 'workers', False)
128 _arg_from_env(args, 'worker_idx', 'worker_idx', False)
129
130
131def _assert_args(args):
132 if args.install_url:
133 # this means you shouldn't specify packages, ppas, or image options
134 if args.package or args.ppa or args.image_opt:
135 msg = 'ERROR: --install-url can\'t be used with ' \
136 '--package, -ppa, or --image_opt'
137 print(msg)
138 return False
139
140 # don't bother the install_url check, a user might be copy/pasting and
141 # doesn't hurt. Its just good to not encourage it.
142 _merge_env(args)
143
144 script = os.path.join(script_dir, '../jenkins/testconfig.py')
145 if args.package and args.package[0] == 'ALL':
146 logging.info('Discovering all required dependencies')
147 out = subprocess.check_output(
148 [script, 'packages', '-i', args.image_type])
149 args.package = [x for x in out.decode().split()]
150
151 if args.app and args.app[0] == 'ALL':
152 logging.info('Discovering all autopilot tests')
153 out = subprocess.check_output(
154 [script, 'apps', '-i', args.image_type,
155 '-t', str(args.num_workers), '-w', str(args.worker_idx)])
156 args.app = [x for x in out.decode().split()]
157 logging.info('Autopilot test list: {}'.format(' '.join(args.app)))
158
159 if args.test and args.test[0].startswith('ALL'):
160 logging.info('Discovering all UTAH tests')
161 argv = [script, 'utah', '-i', args.image_type,
162 '-t', str(args.num_workers), '-w', str(args.worker_idx)]
163 if args.test[0] == 'ALL_INCLUDING_AUTOPILOT':
164 argv.append('-a')
165 out = subprocess.check_output(argv)
166 args.test = [x for x in out.decode().split()]
167 logging.info('Utah test list: {}'.format(' '.join(args.test)))
168
169 logging.debug('ARGS: %r', args)
170
171 statsd.gauge_it('PACKAGES', args.package)
172 statsd.gauge_it('APPS', args.app)
173 statsd.gauge_it('TESTS', args.test)
174
175 return True
176
177
178def _run(args, ignore_error=False):
179 try:
180 logging.info('Running: %s', ' '.join(args))
181 subprocess.check_call(args)
182 except subprocess.CalledProcessError:
183 if ignore_error:
184 logging.error('failed to run %r, continuing', args)
185 else:
186 exit(1)
187
188
189def _image_info():
190 info = subprocess.check_output(['adb', 'shell', 'sudo',
191 'system-image-cli', '-i'])
192 v_ver = u_ver = d_ver = channel = None
193 for line in info.split('\n'):
194 if not line.strip():
195 continue
196 key, val = line.split(':', 1)
197 if key == 'version version':
198 v_ver = val.strip()
199 elif key == 'version ubuntu':
200 u_ver = val.strip()
201 elif key == 'version device':
202 d_ver = val.strip()
203 elif key == 'channel':
204 channel = val.strip()
205 ver = '%s:%s:%s' % (v_ver, u_ver, d_ver)
206 # required for the jenkins job's build description
207 print('= TOUCH IMAGE VERSION:' + ver)
208 return ver, channel
209
210
211def _assert_image(args):
212 log.info('checking if device has proper image ...')
213 os.environ['INSTALL_URL'] = args.install_url
214 _run([os.path.join(script_dir, 'assert-image')])
215
216
217def _write_utah(start, end, passed):
218 passes = failures = rc = 0
219 if passed:
220 passes = 1
221 else:
222 rc = failures = 1
223
224 delta = '%s' % (end - start)
225 start = start.strftime('%Y-%m-%d %H:%M:%S')
226 data = {
227 'name': 'install-and-boot',
228 'errors': 0,
229 'failures': failures,
230 'passes': passes,
231 'fetch_errors': 0,
232 'uname': 'n/a',
233 'media-info': 'n/a',
234 'install_type': 'n/a',
235 'arch': 'n/a',
236 'release': 'n/a',
237 'build_number': 'n/a',
238 'runlist': 'n/a',
239 'ran_at': start,
240 'commands': [{
241 'cmd_type': 'testcase_test',
242 'command': 'provision',
243 'returncode': rc,
244 'start_time': start,
245 'time_delta': delta,
246 'stderr': '',
247 'stdout': '',
248 'testcase': 'boot',
249 'testsuite': 'install-and-boot',
250 }]
251 }
252 path = os.path.join(res_dir, 'install-and-boot')
253 if not os.path.exists(path):
254 os.mkdir(path)
255 with open(os.path.join(path, 'utah.yaml'), 'w') as f:
256 f.write(yaml.safe_dump(data, default_flow_style=False))
257
258
259def _post_install_hooks(args):
260 if not args.hooks_dir:
261 return
262 log.info('running post install hooks ...')
263 if not os.path.isdir(args.hooks_dir):
264 log.warn('hooks directory (%s) does not exist ... skipping',
265 args.hooks_dir)
266 for hook in sorted(os.listdir(args.hooks_dir)):
267 s = os.stat(os.path.join(args.hooks_dir, hook))
268 if s.st_mode & os.path.stat.S_IXUSR == 0:
269 log.warn('skipping hook (%s) - not executable', hook)
270 continue
271 log.info('executing hook: %s', hook)
272 hook = os.path.join(args.hooks_dir, hook)
273 subprocess.check_call([hook])
274
275
276def _provision(args):
277 log.info('provisioning device ...')
278 if args.image_opt:
279 log.debug('overriding IMAGE_OPT with: %s', args.image_opt)
280 os.environ['IMAGE_OPT'] = args.image_opt
281
282 cargs = [os.path.join(script_dir, 'provision.sh'), '-i', args.image_type]
283
284 if args.package:
285 for p in args.package:
286 cargs.extend(['-p', p])
287 if args.ppa:
288 for p in args.ppa:
289 cargs.extend(['-P', p])
290 if not args.ppa and not args.package:
291 # All tests require a writeable system the -p and -P args
292 # implicitly create a writable system. so we have to ensure here:
293 cargs.append('-w')
294 if args.revision:
295 cargs.extend(['-r', args.revision])
296
297 with statsd.time_it('provision'):
298 start = datetime.datetime.utcnow()
299 passed = False
300 try:
301 _run(cargs)
302 _post_install_hooks(args)
303 passed = True
304 finally:
305 end = datetime.datetime.utcnow()
306 _write_utah(start, end, passed)
307
308
309def _test_autopilot(args, build, image):
310 if args.app:
311 if build:
312 os.environ['DASHBOARD_BUILD'] = build
313 if image:
314 os.environ['DASHBOARD_IMAGE'] = image
315 cargs = [os.path.join(script_dir, 'run-autopilot-tests.sh')]
316 for app in args.app:
317 cargs.extend(['-a', app])
318 with statsd.time_it('APPS'):
319 _run(cargs)
320
321
322def _sync_results(build, image, test, fname):
323 with open(fname) as f:
324 d = yaml.safe_load(f)
325 if image and build:
326 try:
327 dashboard_api.result_syncing(image, build, test, d)
328 except:
329 log.warn('Dashboard live update failed')
330
331
332def _test_utah(args, build, image):
333 if args.test:
334 cargs = [os.path.join(script_dir, 'jenkins.sh')]
335 with statsd.time_it('TESTS'):
336 for test in args.test:
337 os.environ['RESDIR'] = os.path.join(res_dir, test)
338 if image and build:
339 try:
340 dashboard_api.result_running(image, build, test)
341 except:
342 log.warn('Dashboard live update failed')
343 _run(cargs + ['-a', test, '-p', '/tmp/results'],
344 ignore_error=True)
345 fname = os.path.join(res_dir, test, 'utah.yaml')
346 _sync_results(build, image, test, fname)
347
348
349def _image_add(args):
350 build_number, channel = _image_info()
351 # get the release series (ex. trusty, utopic)
352 # this is set in the job environment variable IMAGE_SERIES
353 release = os.environ.get('IMAGE_SERIES')
354 if release:
355 try:
356 img = dashboard_api.image_add(build_number, release,
357 args.image_type,
358 detect_device(None), 'ubuntu')
359 except:
360 img = 0
361 log.warn('Dashboard live update failed')
362 return img
363
364
365def main(args):
366 with statsd.time_it('main'):
367 if os.path.exists(res_dir):
368 logging.info('deleting old result directory: %s', res_dir)
369 shutil.rmtree(res_dir)
370 os.mkdir(res_dir)
371
372 job_name = os.environ.get('JOB_NAME', '')
373 job_number = os.environ.get('BUILD_NUMBER', '')
374 try:
375 build = dashboard_api.build_add(job_name, job_number)
376 except:
377 build = 0
378 log.warn('Dashboard live update failed')
379
380 if args.no_provision:
381 logging.info('Skipping the provisioning step as requested')
382 elif args.install_url:
383 _assert_image(args)
384 else:
385 _provision(args)
386
387 # TODO - this should be incororated into provision and assert_image
388 # so that the status is updated *before* flashing rather than after
389 image = _image_add(args)
390
391 if args.test and image and build:
392 for x in args.test:
393 try:
394 dashboard_api.result_queue(image, build, x)
395 except:
396 log.warn('Dashboard live update failed')
397 if args.app and image and build:
398 for x in args.app:
399 try:
400 dashboard_api.result_queue(image, build, x)
401 except:
402 log.warn('Dashboard live update failed')
403
404 _test_utah(args, build, image)
405 _test_autopilot(args, build, image)
406
407 return 0
408
409
410if __name__ == '__main__':
411 logging.basicConfig(level=logging.INFO)
412 log.name = 'run-smoke'
413 dashboard.log = logging.getLogger('dashboard')
414
415 args = _get_parser().parse_args()
416 if not _assert_args(args):
417 exit(1)
418
419 exit(main(args))
0420
=== added file 'scripts/run-touch-upgrade.sh'
--- scripts/run-touch-upgrade.sh 1970-01-01 00:00:00 +0000
+++ scripts/run-touch-upgrade.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,46 @@
1#!/bin/bash
2
3## This is the script jenkins should run to test upgrading a system image
4## in the lab.
5## Intersting environment variables that must be set:
6## ANDROID_SERIAL - specify another android device
7## RUNLIST - the path the runlist
8## NETWORK_FILE - specify an alternative network file (passed to runlist)
9## UPGRADE_FROM - the revision to upgrade from, eg -1 (passed to runlist)
10
11set -eux
12
13BASEDIR=$(dirname $(readlink -f $0))
14
15RESDIR=`pwd`/clientlogs
16
17UTAH_PHABLET_CMD="${UTAH_PHABLET_CMD-/usr/share/utah/examples/run_utah_phablet.py}"
18RUNLIST=${RUNLIST-"`pwd`/smoke-touch-apps/upgrade/master.run"}
19ANDROID_SERIAL="${ANDROID_SERIAL-015d1884b20c1c0f}" #doanac's nexus7 at home
20NETWORK_FILE="${NETWORK_FILE-/home/ubuntu/magners-wifi}"
21
22rm -rf clientlogs
23mkdir clientlogs
24
25export ANDROID_SERIAL=$ANDROID_SERIAL
26
27set +e
28sudo NETWORK_FILE=$NETWORK_FILE \
29 $UTAH_PHABLET_CMD -s $ANDROID_SERIAL \
30 --from-host --skip-install --skip-utah --skip-network -l $RUNLIST \
31 --results-dir=$RESDIR
32EXITCODE=$?
33
34UTAHFILE=$RESDIR/utah.yaml
35if ! `grep "^errors: [!0]" < $UTAHFILE >/dev/null` ; then
36 echo "errors found"
37 EXITCODE=1
38fi
39if ! `grep "^failures: [!0]" < $UTAHFILE >/dev/null` ; then
40 echo "failures found"
41 EXITCODE=2
42fi
43echo "Results Summary"
44echo "---------------"
45egrep '^(errors|failures|passes|fetch_errors):' $UTAHFILE
46exit $EXITCODE
047
=== added file 'scripts/statsd.py'
--- scripts/statsd.py 1970-01-01 00:00:00 +0000
+++ scripts/statsd.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,35 @@
1#!/usr/bin/python
2
3import os
4import contextlib
5import time
6
7
8_namespace = os.environ.get('STATSD_KEY')
9if _namespace:
10 from txstatsd.client import UdpStatsDClient
11 from txstatsd.metrics.timermetric import TimerMetric
12 from txstatsd.metrics.gaugemetric import GaugeMetric
13 _host = os.environ.get('SERVER', 'snakefruit.canonical.com')
14 _port = int(os.environ.get('PORT', '10041'))
15 _client = UdpStatsDClient(_host, _port)
16 _client.connect()
17
18
19@contextlib.contextmanager
20def time_it(key):
21 start = time.time()
22 try:
23 yield
24 finally:
25 if _namespace:
26 m = TimerMetric(_client, _namespace + '.' + key)
27 m.mark(time.time() - start)
28
29
30def gauge_it(key, array):
31 val = 0
32 if array:
33 val = len(array)
34 if _namespace:
35 GaugeMetric(_client, _namespace + '.' + key).mark(val)
036
=== added directory 'selftests'
=== added file 'selftests/test_junit2utah.py'
--- selftests/test_junit2utah.py 1970-01-01 00:00:00 +0000
+++ selftests/test_junit2utah.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,49 @@
1import StringIO
2import os
3import sys
4import unittest
5
6here = os.path.dirname(__file__)
7sys.path.append(os.path.join(here, '../scripts'))
8
9import junit2utah
10
11RESULT = '''
12<testsuite errors="0" failures="1" name="" tests="4" time="0.001">
13<testcase classname="classname" name="testFails" time="0.000">
14<failure type="testtools.testresult.real._StringException">
15testtools.testresult.real._StringException: Traceback (most recent call last):
16 File "junit2utah.py", line 14, in testFails
17 self.assertFalse(True)
18 File "/usr/lib/python2.7/unittest/case.py", line 418, in assertFalse
19 raise self.failureException(msg)
20AssertionError: True is not false
21</failure>
22</testcase>
23<testcase classname="classname" name="testPasses" time="0.100"/>
24<testcase classname="classname" name="testPasses2" time="0.200"/>
25<testcase classname="classname" name="testSkip" time="0.000">
26<skip>ensure skip works</skip>
27</testcase>
28</testsuite>
29'''
30
31
32class TestJunit2Utah(unittest.TestCase):
33 def testFull(self):
34 stream = StringIO.StringIO(RESULT)
35 results = junit2utah._get_results(stream)
36 self.assertEquals(3, results['passes'])
37 self.assertEquals(1, results['failures'])
38 self.assertEquals(0, results['errors'])
39
40 tcs = results['commands']
41 self.assertEqual('classname', tcs[0]['testsuite'])
42 self.assertEqual('testFails', tcs[0]['testcase'])
43 self.assertIn('AssertionError', tcs[0]['stderr'])
44
45 self.assertEqual('0.200', tcs[2]['time_delta'])
46
47 self.assertEqual('classname', tcs[3]['testsuite'])
48 self.assertEqual('testSkip', tcs[3]['testcase'])
49 self.assertEqual('ensure skip works', tcs[3]['stdout'])
050
=== added file 'selftests/test_reboot_and_wait.py'
--- selftests/test_reboot_and_wait.py 1970-01-01 00:00:00 +0000
+++ selftests/test_reboot_and_wait.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,66 @@
1# Ubuntu Test Cases for Touch
2# Copyright 2013 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16from __future__ import print_function
17
18import imp
19import mock
20import os
21import unittest
22
23
24class TestRebootAndWait(unittest.TestCase):
25
26 """Simple set of tests to make sure the reboot-and-wait command works."""
27
28 def setUp(self):
29 # do some trickery to load this as module
30 module = 'reboot-and-wait'
31 fname = os.path.join(os.path.dirname(__file__), '../scripts', module)
32 m = imp.load_source(module, fname)
33 self._main = m.main
34 self._get_parser = m._get_arg_parser
35
36 @mock.patch('phabletutils.device.AndroidBridge.reboot')
37 def testRebootFail(self, reboot):
38 reboot.side_effect = RuntimeError('foo')
39 args = self._get_parser().parse_args([])
40 with self.assertRaisesRegexp(RuntimeError, 'foo'):
41 self._main(args)
42
43 @mock.patch('phabletutils.device.AndroidBridge.reboot')
44 @mock.patch('phabletutils.device.AndroidBridge.wait_for_device')
45 def testWaitForDeviceFail(self, wait_for, reboot):
46 wait_for.side_effect = RuntimeError('foo')
47 args = self._get_parser().parse_args([])
48 with self.assertRaisesRegexp(RuntimeError, 'foo'):
49 self._main(args)
50 reboot.assert_called_once_with()
51
52 @mock.patch('phabletutils.device.AndroidBridge.reboot')
53 @mock.patch('phabletutils.device.AndroidBridge.wait_for_device')
54 @mock.patch('phabletutils.device.AndroidBridge.wait_for_network')
55 def testRetries(self, wait_for_net, wait_for_dev, reboot):
56 args = self._get_parser().parse_args([])
57 wait_for_net.side_effect = RuntimeError('foo')
58 self.assertEquals(1, self._main(args))
59 self.assertEquals(args.num_tries, reboot.call_count)
60
61 # now make sure it can recover after a single network failure
62 reboot.reset_mock()
63 wait_for_net.reset_mock()
64 wait_for_net.side_effect = [RuntimeError('foo'), None]
65 self.assertEquals(0, self._main(args))
66 self.assertEquals(2, reboot.call_count)
067
=== added file 'selftests/test_run_smoke.py'
--- selftests/test_run_smoke.py 1970-01-01 00:00:00 +0000
+++ selftests/test_run_smoke.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,143 @@
1# Ubuntu Test Cases for Touch
2# Copyright 2013 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16import imp
17import mock
18import os
19import subprocess
20import sys
21import unittest
22
23
24class TestRunSmoke(unittest.TestCase):
25
26 """Simple set of tests to make sure the smoke-run command works."""
27
28 def setUp(self):
29 # load the module
30 module = 'run-smoke'
31 path = os.path.join(os.path.dirname(__file__), '../scripts')
32 sys.path.append(path)
33 fname = os.path.join(path, module)
34 self.run_smoke = imp.load_source(module, fname)
35 if 'ANDROID_SERIAL' in os.environ:
36 del os.environ['ANDROID_SERIAL']
37
38 @mock.patch.dict('os.environ')
39 @mock.patch('subprocess.check_output')
40 def testSerialRequired(self, check_output):
41 '''Ensure android serial is required when appropriate'''
42 check_output.return_value = '1'.encode()
43 self.assertTrue(self.run_smoke._serial_required())
44
45 check_output.return_value = '1\n2\n3\n4'.encode()
46 self.assertFalse(self.run_smoke._serial_required())
47
48 check_output.return_value = '1\n2\n3\n4\n5'.encode()
49 self.assertTrue(self.run_smoke._serial_required())
50
51 # make sure serial isn't required if specified in env
52 os.environ['ANDROID_SERIAL'] = 'foo'
53 check_output.return_value = '1\n2\n3\n4\n5'.encode()
54 self.assertFalse(self.run_smoke._serial_required())
55
56 @mock.patch('statsd.gauge_it')
57 def testAssertArgs(self, gauge):
58 '''Ensure install-url is used properly'''
59 patterns = [
60 (['--install-url', 'x', '-p', 'x'], False),
61 (['--install-url', 'x', '-P', 'x'], False),
62 (['--install-url', 'x', '--image-opt', 'x'], False),
63 (['-p', 'x', '-P', 'x', '--image-opt', 'x'], True),
64 ]
65 for pat, val in patterns:
66 args = self.run_smoke._get_parser().parse_args(['-s', 'foo'] + pat)
67 self.assertEqual(val, self.run_smoke._assert_args(args))
68
69 # ensure the -p ALL pulls in all packages
70 gauge.reset_mock()
71 args = self.run_smoke._get_parser().parse_args(['-p', 'ALL'])
72 self.assertTrue(self.run_smoke._assert_args(args))
73 self.assertTrue(len(args.package) > 1)
74 args = gauge.call_args_list[0][0]
75 self.assertEqual('PACKAGES', args[0])
76 self.assertLess(1, len(args[1]))
77
78 args = gauge.call_args_list[1][0]
79 self.assertEqual('APPS', args[0])
80 self.assertIsNone(args[1])
81 args = gauge.call_args_list[2][0]
82 self.assertEqual('TESTS', args[0])
83 self.assertIsNone(args[1])
84
85 # don't bother checking gauge calls for the remaining "ALL" tests
86
87 # ensure the -a ALL pulls in all APPS
88 args = self.run_smoke._get_parser().parse_args(['-a', 'ALL'])
89 self.assertTrue(self.run_smoke._assert_args(args))
90 self.assertTrue(len(args.app) > 1)
91
92 # ensure the -t ALL pulls in all TESTS
93 args = self.run_smoke._get_parser().parse_args(['-t', 'ALL'])
94 self.assertTrue(self.run_smoke._assert_args(args))
95 self.assertTrue(len(args.test) > 1)
96
97 def testAssertArgsEnv(self):
98 '''Ensure we pull in environment variables that jenkins uses.'''
99 with mock.patch.dict('os.environ'):
100 os.environ['APPS'] = 'apps'
101 os.environ['TESTS'] = 'tests'
102 os.environ['PACKAGES'] = 'packages'
103 os.environ['PPAS'] = 'ppas'
104 os.environ['IMAGE_TYPE'] = 'type'
105 os.environ['INSTALL_URL'] = 'url'
106 os.environ['IMAGE_OPT'] = 'opts opts'
107 os.environ['ANDROID_SERIAL'] = 'foo'
108
109 args = self.run_smoke._get_parser().parse_args([])
110 self.assertTrue(self.run_smoke._assert_args(args))
111
112 self.assertEqual(args.app, ['apps'])
113 self.assertEqual(args.test, ['tests'])
114 self.assertEqual(args.package, ['packages'])
115 self.assertEqual(args.ppa, ['ppas'])
116 self.assertEqual(args.image_type, 'type')
117 self.assertEqual(args.install_url, 'url')
118 self.assertEqual(args.image_opt, 'opts opts')
119
120 def testProvision(self):
121 orig = os.environ.get('IMAGE_OPT', '')
122 with mock.patch.object(self.run_smoke, '_run') as run:
123 args = self.run_smoke._get_parser().parse_args(
124 ['-s', 'foo', '--image-opt', 'FOOBAR', '-p', '1', '-p', '2'])
125 self.run_smoke._provision(args)
126 self.assertTrue(run.called)
127 val = os.environ.get('IMAGE_OPT')
128 os.environ['IMAGE_OPT'] = orig
129 self.assertEqual('FOOBAR', val)
130
131 def testUtahTests(self):
132 args = self.run_smoke._get_parser().parse_args(
133 ['-s', 'foo', '-t', 'a', '-t', 'b'])
134 with mock.patch.object(self.run_smoke, '_run') as run:
135 with mock.patch.dict('os.environ'):
136 run.side_effects = [subprocess.CalledProcessError, None]
137 with mock.patch.object(self.run_smoke, '_sync_results') as sr:
138 self.run_smoke._test_utah(args, None, None)
139 p = os.path.join(self.run_smoke.res_dir, 'b')
140 # ensuring b ran means, that we handled the failure of test
141 # 'a' and that the environment is setup correctly
142 self.assertEqual(os.environ['RESDIR'], p)
143 self.assertTrue(sr.called)
0144
=== added file 'selftests/test_statsd.py'
--- selftests/test_statsd.py 1970-01-01 00:00:00 +0000
+++ selftests/test_statsd.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,64 @@
1# Ubuntu Test Cases for Touch
2# Copyright 2013 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16import os
17import mock
18import unittest
19import sys
20import time
21
22path = os.path.join(os.path.dirname(__file__), '../scripts')
23sys.path.append(path)
24
25import statsd
26
27
28class TestStatsd(unittest.TestCase):
29
30 def setUp(self):
31 self.origkey = os.environ.get('STATSD_KEY')
32 os.environ['STATSD_KEY'] = 'prefix'
33 reload(statsd)
34
35 def tearDown(self):
36 if not self.origkey:
37 del os.environ['STATSD_KEY']
38 else:
39 os.environ['STATSD_KEY'] = self.origkey
40 reload(statsd)
41
42 """Simple set of tests to make sure the statsd calls work."""
43
44 @mock.patch('txstatsd.metrics.metric.Metric.write')
45 def testGaugeIt(self, _statsd):
46 statsd.gauge_it('foo', None)
47 _statsd.assert_called_with('prefix.foo:0|g')
48 _statsd.reset_mock()
49
50 statsd.gauge_it('foo', [])
51 _statsd.assert_called_with('prefix.foo:0|g')
52 _statsd.reset_mock()
53
54 statsd.gauge_it('foo', [1, 2, 3])
55 _statsd.assert_called_with('prefix.foo:3|g')
56 _statsd.reset_mock()
57
58 @mock.patch('txstatsd.metrics.metric.Metric.write')
59 def testTimeIt(self, _statsd):
60 with statsd.time_it('foo'):
61 time.sleep(0.1)
62 # should have a timing of about 100ms
63 self.assertRegexpMatches(
64 _statsd.call_args[0][0], 'prefix.foo:100.[\d+]|ms')
065
=== added directory 'tests'
=== added directory 'tests/bootspeed'
=== added directory 'tests/bootspeed/bootchart'
=== added file 'tests/bootspeed/bootchart/run.py'
--- tests/bootspeed/bootchart/run.py 1970-01-01 00:00:00 +0000
+++ tests/bootspeed/bootchart/run.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,73 @@
1#!/usr/bin/python
2
3import datetime
4import json
5import os
6import shutil
7import subprocess
8
9
10def _get_dashboard_data(timing_file):
11 info = subprocess.check_output(['adb', 'shell', 'system-image-cli', '-i'])
12 data = {
13 'image_md5': 'n/a',
14 'machine_mac': 'ff:ff:ff:ff:ff:ff',
15 'ran_at': datetime.datetime.now().isoformat(),
16 'kernel_init': 0.0,
17 }
18 for line in info.split('\r\n'):
19 if not line:
20 continue
21 key, val = line.split(':', 1)
22 val = val.strip()
23 if key == 'device name':
24 data['image_arch'] = val
25 elif key == 'channel':
26 # get 'touch' and 'trusty' from something like:
27 # ubuntu-touch/trusty-proposed
28 variant, release = val.split('/')
29 data['image_variant'] = variant.split('-')[1]
30 data['image_release'] = release.split('-')[0]
31 elif key == 'version version':
32 data['number'] = val
33 elif key == 'version ubuntu':
34 data['version_ubuntu'] = val
35 elif key == 'version device':
36 data['version_device'] = val
37 data['build_number'] = '%s:%s:%s' % (
38 data['number'], data['version_ubuntu'], data['version_device'])
39
40 with open(timing_file) as f:
41 # the timings file is sequence of readings (in hundredths of a second):
42 # line 0 - the total boot time
43 # line X - the time from boot until the given annotation *started*
44 timings = [float(x) / 100.0 for x in f.read().split('\n') if x]
45 data['boot'] = timings[0]
46 data['kernel'] = timings[1]
47 data['plumbing'] = timings[2] - timings[1]
48 data['xorg'] = timings[3] - timings[2]
49 data['desktop'] = timings[0] - timings[3]
50 return data
51
52
53def chart(results_dir):
54 timings = os.path.join(results_dir, 'timings')
55 os.environ['CHARTOPTS'] = ' '.join([
56 '--crop-after=unity8',
57 '--annotate=mountall',
58 '--annotate=lightdm',
59 '--annotate=unity8',
60 '--annotate-file=%s' % timings,
61 ])
62 subprocess.check_call(['phablet-bootchart', '-n', '-k',
63 '-w', '/home/ubuntu/magners-wifi',
64 '-o', results_dir])
65 data = _get_dashboard_data(timings)
66 with open(os.path.join(results_dir, 'boot.json'), 'w') as f:
67 json.dump(data, f, indent=4)
68
69if __name__ == '__main__':
70 # run_utah_phablet will pass us a "UTAH_PROBE_DIR":
71 resdir = os.environ.get('UTAH_PROBE_DIR', '/tmp/results')
72 for x in range(3):
73 chart(os.path.join(resdir, str(x)))
074
=== added file 'tests/bootspeed/bootchart/setup.sh'
--- tests/bootspeed/bootchart/setup.sh 1970-01-01 00:00:00 +0000
+++ tests/bootspeed/bootchart/setup.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,4 @@
1#!/bin/bash
2
3${TARGET_PREFIX} apt-get install bootchart
4
05
=== added file 'tests/bootspeed/bootchart/tc_control'
--- tests/bootspeed/bootchart/tc_control 1970-01-01 00:00:00 +0000
+++ tests/bootspeed/bootchart/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,12 @@
1description: run phablet-bootchart on a phone
2dependencies: none
3action: |
4 1. setup bootchart
5 2. reboot 3 times
6 3. collect
7expected_results: |
8 1. boot chart data
9type: userland
10timeout: 2000
11command: ./run.py
12tc_setup: ./setup.sh
013
=== added file 'tests/bootspeed/master.run'
--- tests/bootspeed/master.run 1970-01-01 00:00:00 +0000
+++ tests/bootspeed/master.run 2014-10-07 19:58:41 +0000
@@ -0,0 +1,5 @@
1---
2testsuites:
3 - name: bootspeed
4 fetch_method: dev
5 fetch_location: ./
06
=== added file 'tests/bootspeed/tslist.run'
--- tests/bootspeed/tslist.run 1970-01-01 00:00:00 +0000
+++ tests/bootspeed/tslist.run 2014-10-07 19:58:41 +0000
@@ -0,0 +1,1 @@
1- test: bootchart
02
=== added directory 'tests/click_image_tests'
=== added directory 'tests/click_image_tests/check_preinstalled_list'
=== added file 'tests/click_image_tests/check_preinstalled_list/check_preinstalled_list.py'
--- tests/click_image_tests/check_preinstalled_list/check_preinstalled_list.py 1970-01-01 00:00:00 +0000
+++ tests/click_image_tests/check_preinstalled_list/check_preinstalled_list.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,61 @@
1#!/usr/bin/python3
2# Copyright (C) 2013 Canonical Ltd.
3# Author: Sergio Schvezov <sergio.schvezov@canonical.com>
4
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; version 3 of the License.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import subprocess
18import unittest
19import urllib.request
20
21
22click_list_url = \
23 'http://people.canonical.com/~ubuntu-archive/click_packages/click_list'
24
25
26def get_install_list():
27 request = urllib.request.urlopen(click_list_url).read().decode('utf-8')
28 click_files = [x for x in request.split('\n') if x]
29 click_apps = {}
30 for entry in click_files:
31 entry_parts = entry.split('_')
32 click_apps[entry_parts[0]] = entry_parts[1]
33 return click_apps
34
35
36def get_image_list():
37 click_list = subprocess.check_output(
38 ['adb', 'shell', 'sudo', '-iu', 'phablet',
39 'click', 'list']).decode('utf-8').split('\n')
40 click_entries = [x for x in click_list if x]
41 click_apps = {}
42 for entry in click_entries:
43 entry_parts = entry.split('\t')
44 click_apps[entry_parts[0]] = entry_parts[1].strip()
45 return click_apps
46
47
48class ClickPreinstalled(unittest.TestCase):
49
50 def setUp(self):
51 self.image_list = get_image_list()
52 self.install_list = get_install_list()
53 print('Search for {} on image'.format(list(self.install_list.keys())))
54
55 def testPreinstalled(self):
56 for entry in self.install_list:
57 self.assertIn(entry, list(self.image_list.keys()))
58
59
60if __name__ == '__main__':
61 unittest.main()
062
=== added file 'tests/click_image_tests/check_preinstalled_list/tc_control'
--- tests/click_image_tests/check_preinstalled_list/tc_control 1970-01-01 00:00:00 +0000
+++ tests/click_image_tests/check_preinstalled_list/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,10 @@
1description: check that all the expected click packages are installed
2dependencies: a touch read-only image
3action: |
4 1. download the list of click packages
5 2. list the current click packages installed on the device
6expected_results: |
7 1. the current list of click packages from the archive should match
8type: userland
9timeout: 120
10command: ./check_preinstalled_list.py
011
=== added file 'tests/click_image_tests/master.run'
--- tests/click_image_tests/master.run 1970-01-01 00:00:00 +0000
+++ tests/click_image_tests/master.run 2014-10-07 19:58:41 +0000
@@ -0,0 +1,5 @@
1---
2testsuites:
3 - name: click_image_tests
4 fetch_method: dev
5 fetch_location: ./
06
=== added file 'tests/click_image_tests/tslist.run'
--- tests/click_image_tests/tslist.run 1970-01-01 00:00:00 +0000
+++ tests/click_image_tests/tslist.run 2014-10-07 19:58:41 +0000
@@ -0,0 +1,1 @@
1- test: check_preinstalled_list
02
=== added directory 'tests/customizations'
=== added file 'tests/customizations/master.run'
--- tests/customizations/master.run 1970-01-01 00:00:00 +0000
+++ tests/customizations/master.run 2014-10-07 19:58:41 +0000
@@ -0,0 +1,5 @@
1---
2testsuites:
3 - name: customizations
4 fetch_method: dev
5 fetch_location: ./
06
=== added file 'tests/customizations/setup.sh'
--- tests/customizations/setup.sh 1970-01-01 00:00:00 +0000
+++ tests/customizations/setup.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,10 @@
1#!/bin/sh
2
3set -ex
4
5BZR_HOME=/dev/null bzr export customization_tests lp:savilerow/tests
6
7# copy the autopilot scripts over if needed (ie we are testing from HOST)
8[ -z $ANDROID_SERIAL ] || adb push ./customization_tests /home/phablet/autopilot/customization_tests
9
10prepare-autopilot-test.sh
011
=== added file 'tests/customizations/ts_control'
--- tests/customizations/ts_control 1970-01-01 00:00:00 +0000
+++ tests/customizations/ts_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,1 @@
1ts_setup: ./setup.sh
02
=== added file 'tests/customizations/tslist.auto'
--- tests/customizations/tslist.auto 1970-01-01 00:00:00 +0000
+++ tests/customizations/tslist.auto 2014-10-07 19:58:41 +0000
@@ -0,0 +1,4 @@
1-
2 discovery_cmd: autopilot-list -3 customization_tests
3 test_cmd: autopilot-run -3 {}
4
05
=== added directory 'tests/default'
=== added directory 'tests/default/apport'
=== added file 'tests/default/apport/tc_control'
--- tests/default/apport/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/apport/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,9 @@
1description: check that apport is enabled
2dependencies: none
3action: |
4 1. status apport | grep running
5expected_results: |
6 1. status apport says that it is running
7type: userland
8timeout: 60
9command: $TARGET_PREFIX sudo status apport | grep running
010
=== added directory 'tests/default/ifconfig'
=== added file 'tests/default/ifconfig/tc_control'
--- tests/default/ifconfig/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/ifconfig/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,13 @@
1description: make sure wlan0 exists
2dependencies: none
3action: |
4 1. ifconfig
5 2. Make sure there is a wlan0
6expected_results: |
7 1. there is a wlan0 on the system
8type: userland
9timeout: 60
10command: $TARGET_PREFIX ifconfig | grep wlan0
11#build_cmd:
12#tc_setup:
13#tc_cleanup:
014
=== added directory 'tests/default/install'
=== added file 'tests/default/install/tc_control'
--- tests/default/install/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/install/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,12 @@
1description: apt-get install works
2dependencies: openssh-server
3action: |
4 1. apt-get install -y curl
5expected_results: |
6 1. apt-get install can install a package and ends with exit code 0
7type: userland
8timeout: 120
9command: $TARGET_PREFIX sudo apt-get install -y curl
10#build_cmd:
11#tc_setup:
12tc_cleanup: $TARGET_PREFIX sudo apt-get remove -y curl
013
=== added file 'tests/default/master.run'
--- tests/default/master.run 1970-01-01 00:00:00 +0000
+++ tests/default/master.run 2014-10-07 19:58:41 +0000
@@ -0,0 +1,5 @@
1---
2testsuites:
3 - name: smoke_touch
4 fetch_method: dev
5 fetch_location: ./
06
=== added directory 'tests/default/netstat'
=== added file 'tests/default/netstat/tc_control'
--- tests/default/netstat/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/netstat/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,12 @@
1description: netstat -l lists all the services
2dependencies: none
3action: |
4 1. netstat -l
5expected_results: |
6 1. netstat shows output and exists cleanly
7type: userland
8timeout: 60
9command: $TARGET_PREFIX netstat -l
10#build_cmd:
11#tc_setup:
12#tc_cleanup:
013
=== added directory 'tests/default/ping'
=== added file 'tests/default/ping/pingtest.sh'
--- tests/default/ping/pingtest.sh 1970-01-01 00:00:00 +0000
+++ tests/default/ping/pingtest.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,12 @@
1#!/bin/sh
2
3set -e
4
5if [ -z $TARGET_PREFIX ] ; then
6 echo "RUNNING ON TARGET"
7 ping -c 5 $(ip route show | head -n1 |cut -d" " -f3)
8else
9 echo "RUNNING FROM HOST"
10 ${TARGET_PREFIX} ping -c 5 '$(ip route show | head -n1 |cut -d" " -f3)'
11fi
12
013
=== added file 'tests/default/ping/tc_control'
--- tests/default/ping/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/ping/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,12 @@
1description: ping -c 5 $gateway
2dependencies: None
3action: |
4 1. ping -c 5 $gateway
5expected_results: |
6 1. ping ends without an error
7type: userland
8timeout: 60
9command: ./pingtest.sh
10#build_cmd:
11#tc_setup:
12#tc_cleanup:
013
=== added directory 'tests/default/pwd'
=== added file 'tests/default/pwd/tc_control'
--- tests/default/pwd/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/pwd/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,9 @@
1description: pwd works
2dependencies: none
3action: |
4 1. cd to /tmp and verify which is the current directory
5expected_results: |
6 1. Current directory is /tmp
7type: userland
8timeout: 60
9command: ./test.sh
010
=== added file 'tests/default/pwd/test.sh'
--- tests/default/pwd/test.sh 1970-01-01 00:00:00 +0000
+++ tests/default/pwd/test.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,18 @@
1#!/bin/sh
2
3set -e
4
5if [ -n "$TARGET_PREFIX" ] ; then
6 echo "RUNNING FROM HOST"
7else
8 echo "RUNNING ON TARGET"
9 TARGET_PREFIX="/bin/sh -c"
10fi
11
12#when it comes from adb we get a \r\n that should be removed
13dir=$($TARGET_PREFIX "cd /tmp; pwd" | head -n1 | tr -d '\r\n')
14if [ $dir != "/tmp" ] ; then
15 echo "failed to change directory"
16 exit 1
17fi
18exit 0
019
=== added directory 'tests/default/route'
=== added file 'tests/default/route/tc_control'
--- tests/default/route/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/route/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,12 @@
1description: route shows wlan0 routes
2dependencies: none
3action: |
4 1. route -n | grep wlan0
5expected_results: |
6 1. route shows wlan0 routes
7type: userland
8timeout: 60
9command: $TARGET_PREFIX route -n | grep wlan0
10#build_cmd:
11#tc_setup:
12#tc_cleanup:
013
=== added directory 'tests/default/systemsettle'
=== added file 'tests/default/systemsettle/systemsettle.sh'
--- tests/default/systemsettle/systemsettle.sh 1970-01-01 00:00:00 +0000
+++ tests/default/systemsettle/systemsettle.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,127 @@
1#!/bin/bash
2
3# Configuration variables:
4# TARGET_PREFIX - Allows this to be run from the host, by providings something
5# like TARGET_PREFIX="adb shell"
6# UTAH_PROBE_DIR - optionally where to save log files so utah will grab them
7
8set -e
9
10[ -z $UTAH_PROBE_DIR ] && UTAH_PROBE_DIR="/tmp"
11
12# default exit code storage
13dump_error=1
14
15calc () { awk "BEGIN{ print $* }" ;}
16
17function show_usage() {
18 echo "Usage:"
19 echo " $0 [options]"
20 echo "Options:"
21 echo " -r run forever without exiting"
22 echo " -p minimum idle percent to wait for (Default: 99)"
23 echo " -c number of times to run top at each iteration (Default: 10)"
24 echo " -d seconds to delay between each top iteration (Default: 6)"
25 echo " -i top measurements to ignore from each loop (Default: 1)"
26 echo " -m maximum loops of top before giving up if minimum idle"
27 echo " percent is not reached (Default: 10)"
28 echo " -l label to include for the top_log file"
29 echo " -s sleep timeout for %cpu calculation (Default: 10)"
30 exit 129
31}
32
33while getopts "h?rp:c:d:i:m:l:s:" opt; do
34 case "$opt" in
35 h|\?) show_usage
36 ;;
37 r) settle_prefix='-'
38 ;;
39 p) idle_avg_min=$OPTARG
40 ;;
41 c) top_repeat=$OPTARG
42 ;;
43 d) top_wait=$OPTARG
44 ;;
45 i) top_ignore=$OPTARG
46 ;;
47 m) settle_max=$OPTARG
48 ;;
49 l) top_log_label=$OPTARG
50 ;;
51 s) sleep_len=$OPTARG
52 ;;
53 esac
54done
55
56sleep_len=${sleep_len:-10}
57HZ=`getconf CLK_TCK`
58# minimum average idle level required to succeed
59idle_avg_min=${idle_avg_min:-99}
60# measurement details: top $top_wait $top_repeat
61top_repeat=${top_repeat:-10}
62top_wait=${top_wait:-6}
63# how many samples to ignore
64top_ignore=${top_ignore:-1}
65# how many total attempts to settle the system
66settle_max=${settle_max:-10}
67
68top_log="$UTAH_PROBE_DIR/top$top_log_label.log"
69
70# set and calc more runtime values
71top_tail=`calc $top_repeat - $top_ignore`
72settle_count=0
73idle_avg=0
74
75echo "System Settle run - quiesce the system"
76echo "--------------------------------------"
77echo
78echo " idle_avg_min = '$idle_avg_min'"
79echo " top_repeat = '$top_repeat'"
80echo " top_wait = '$top_wait'"
81echo " top_ignore = '$top_ignore'"
82echo " settle_max = '$settle_max'"
83echo " run_forever = '$settle_prefix' (- = yes)"
84echo " log files = $top_log $top_log.reduced"
85echo
86
87while test `calc $idle_avg '<' $idle_avg_min` = 1 -a "$settle_prefix$settle_count" -lt "$settle_max"; do
88 echo -n "Starting system idle measurement (run: $settle_count) ... "
89
90 # get top
91 echo "TOP DUMP (after settle run: $settle_count)" >> $top_log
92 echo "========================" >> $top_log
93 ${TARGET_PREFIX} COLUMNS=900 top -c -b -d $top_wait -n $top_repeat >> $top_log
94 cat $top_log | grep '.Cpu.*' | tail -n $top_tail > $top_log.reduced
95 echo >> $top_log
96
97 # Instead of using top, we need to use /proc/stat and compensate for
98 # the number of cpus and any frequency scaling that could be in effect
99 cpu_avg=$({
100 ${TARGET_PREFIX} cat /proc/stat
101 sleep "$sleep_len"
102 ${TARGET_PREFIX} cat /proc/stat
103 } | awk '
104 BEGIN { iter = 0 }
105 /^cpu / { iter = iter + 1; count = 0; next }
106 /^cpu/ { S[iter] = S[iter] + ($2+$3+$4+$6); count = count + 1;
107next }
108 END { print (S[2] - S[1]) * 100 / ('"$HZ"' * count * '"$sleep_len"') }
109 ')
110 idle_avg=`calc 100 - $cpu_avg`
111 settle_count=`calc $settle_count + 1`
112
113 echo " DONE."
114 echo
115 echo "Measurement:"
116 echo " + idle level: $idle_avg"
117 echo
118done
119
120if test `calc $idle_avg '<' $idle_avg_min` = 1; then
121 echo "system not settled. FAIL"
122 exit 1
123else
124 echo "system settled. SUCCESS"
125 exit 0
126fi
127
0128
=== added file 'tests/default/systemsettle/tc_control'
--- tests/default/systemsettle/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/systemsettle/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,9 @@
1description: check if system settles to idle average > 99.25%
2dependencies: none
3action: |
4 1. Take CPU load samples for 10 minutes and fail if average idle never goes above 99.25% percent
5expected_results: |
6 1. When doing nothing, system calms down to at least 99.25% idle level
7type: userland
8timeout: 720
9command: ./systemsettle.sh -c5 -d6 -p 97.5
010
=== added file 'tests/default/ts_control'
--- tests/default/ts_control 1970-01-01 00:00:00 +0000
+++ tests/default/ts_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,3 @@
1#build_cmd: echo building
2#ts_setup: echo setting up
3#ts_cleanup: echo cleaning up
04
=== added file 'tests/default/tslist.run'
--- tests/default/tslist.run 1970-01-01 00:00:00 +0000
+++ tests/default/tslist.run 2014-10-07 19:58:41 +0000
@@ -0,0 +1,12 @@
1- test: pwd
2- test: uname
3- test: vmstat
4- test: systemsettle
5- test: netstat
6- test: ifconfig
7- test: route
8- test: ping
9- test: install
10- test: unity8
11- test: apport
12- test: whoopsie
013
=== added directory 'tests/default/uname'
=== added file 'tests/default/uname/tc_control'
--- tests/default/uname/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/uname/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,12 @@
1description: uname shows an ubuntu-phablet image installed
2dependencies: CHANGE_ME
3action: |
4 1. uname -a|grep ubuntu-phablet
5expected_results: |
6 1. ubuntu-phablet is installed as expected
7type: userland
8timeout: 60
9command: $TARGET_PREFIX uname -a | grep ubuntu-phablet
10#build_cmd:
11#tc_setup:
12#tc_cleanup:
013
=== added directory 'tests/default/unity8'
=== added file 'tests/default/unity8/tc_control'
--- tests/default/unity8/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/unity8/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,9 @@
1description: check for unity8 process
2dependencies: None
3action: |
4 1. pgrep unity8
5expected_results: |
6 1. pgrep exits with 0, indicating it found a matching process
7type: userland
8timeout: 60
9command: $TARGET_PREFIX /usr/bin/pgrep unity8
010
=== added directory 'tests/default/vmstat'
=== added file 'tests/default/vmstat/tc_control'
--- tests/default/vmstat/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/vmstat/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,12 @@
1description: Execute vmstat and capture output
2dependencies: none
3action: |
4 1. vmstat
5expected_results: |
6 1. vmstat finishes without an error
7type: userland
8timeout: 60
9command: $TARGET_PREFIX vmstat
10#build_cmd:
11#tc_setup:
12#tc_cleanup:
013
=== added directory 'tests/default/whoopsie'
=== added file 'tests/default/whoopsie/tc_control'
--- tests/default/whoopsie/tc_control 1970-01-01 00:00:00 +0000
+++ tests/default/whoopsie/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,10 @@
1description: verify whoopsie functionality
2dependencies: None
3action: |
4 1. trigger a segfault and verify that whoopsie uploads it
5expected_results: |
6 1. /var/crash/_bin_sleep.0.uploaded is created, indicating a successful upload
7type: userland
8timeout: 720
9command: adb-shell sudo /tmp/whoopsie-test.sh
10tc_setup: adb push whoopsie-test.sh /tmp
011
=== added file 'tests/default/whoopsie/whoopsie-test.sh'
--- tests/default/whoopsie/whoopsie-test.sh 1970-01-01 00:00:00 +0000
+++ tests/default/whoopsie/whoopsie-test.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,86 @@
1#!/bin/sh
2
3set -e
4
5cleanup()
6{
7 stop whoopsie || true
8 rm -f /var/crash/_bin_sleep.0.*
9 start whoopsie
10}
11
12if [ ! -e /var/lib/apport/autoreport ]; then
13 echo "Automatic crash reporting not enabled."
14 exit 1
15fi
16
17if [ -e /var/crash/_bin_sleep.0.crash ] || [ -e /var/crash/_bin_sleep.0.upload ] \
18 || [ -e /var/crash/_bin_sleep.0.uploaded ]
19then
20 echo "Error: existing crash data found on disk. Did a previous run fail?"
21 exit 1
22fi
23
24trap cleanup 0 2 3 5 10 13 15
25
26echo "Configuring whoopsie for staging"
27stop whoopsie
28if ! start whoopsie CRASH_DB_URL=https://daisy.staging.ubuntu.com
29then
30 echo "Failed to start whoopsie"
31 exit 1
32fi
33
34sleep 10 &
35echo "Background process id $!"
36ps $!
37echo "Sending SIGSEGV"
38kill -SEGV $!
39
40echo "Polling for .crash file"
41crash_found=false
42for i in $(seq 0 99); do
43 if [ -e /var/crash/_bin_sleep.0.crash ]; then
44 echo "Crash file created after $(($i*2)) seconds."
45 crash_found=:
46 break
47 fi
48 sleep 2
49done
50if ! $crash_found; then
51 echo "whoopsie failed to create crash file within 200 seconds."
52 exit 1
53fi
54
55echo "Polling for .upload file"
56upload_found=false
57for i in $(seq 0 19); do
58 if [ -e /var/crash/_bin_sleep.0.upload ]; then
59 echo "Upload file created after $i seconds."
60 upload_found=:
61 break
62 fi
63 sleep 1
64done
65if ! $upload_found; then
66 echo "whoopsie_upload_all failed to run within 20 seconds."
67 exit 1
68fi
69
70echo "Polling for .uploaded file"
71uploaded_found=false
72for i in $(seq 0 79); do
73 if [ -e /var/crash/_bin_sleep.0.uploaded ]; then
74 echo ".uploaded file created after $(($i*5)) seconds."
75 uploaded_found=:
76 break
77 fi
78 sleep 5
79done
80if ! $uploaded_found; then
81 echo "whoopsie failed to upload crash file within 400 seconds."
82 exit 1
83fi
84
85echo "crash file successfully uploaded."
86exit 0
087
=== added directory 'tests/eventstat'
=== added directory 'tests/eventstat/eventstat'
=== added file 'tests/eventstat/eventstat/eventstat.sh'
--- tests/eventstat/eventstat/eventstat.sh 1970-01-01 00:00:00 +0000
+++ tests/eventstat/eventstat/eventstat.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,5 @@
1#!/bin/bash
2: ${DURATION:=60}
3: ${COUNT:=10}
4${TARGET_PREFIX} "echo \"{\\\"duration\\\": $DURATION, \\\"count\\\": $COUNT}\" > /tmp/results/options.json"
5${TARGET_PREFIX} "eventstat -CSl -r /tmp/results/eventstat.csv $DURATION $COUNT > /tmp/results/eventstat.log"
06
=== added file 'tests/eventstat/eventstat/setup.sh'
--- tests/eventstat/eventstat/setup.sh 1970-01-01 00:00:00 +0000
+++ tests/eventstat/eventstat/setup.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,7 @@
1#!/bin/bash
2
3${TARGET_PREFIX} mkdir -p /tmp/results
4NO_UNLOCK=1 PKGS="eventstat" prepare-autopilot-test.sh
5#Let the system quiet down for a little while
6sleep 300
7
08
=== added file 'tests/eventstat/eventstat/tc_control'
--- tests/eventstat/eventstat/tc_control 1970-01-01 00:00:00 +0000
+++ tests/eventstat/eventstat/tc_control 2014-10-07 19:58:41 +0000
@@ -0,0 +1,12 @@
1description: Gather memory usage information
2dependencies: none
3action: |
4 1. gather eventstat data
5expected_results: |
6 1. eventstat.log should be saved to /tmp/results
7type: userland
8timeout: 800
9command: ./eventstat.sh
10#build_cmd:
11tc_setup: ./setup.sh
12#tc_cleanup:
013
=== added file 'tests/eventstat/master.run'
--- tests/eventstat/master.run 1970-01-01 00:00:00 +0000
+++ tests/eventstat/master.run 2014-10-07 19:58:41 +0000
@@ -0,0 +1,5 @@
1---
2testsuites:
3 - name: eventstat
4 fetch_method: dev
5 fetch_location: ./
06
=== added file 'tests/eventstat/tslist.run'
--- tests/eventstat/tslist.run 1970-01-01 00:00:00 +0000
+++ tests/eventstat/tslist.run 2014-10-07 19:58:41 +0000
@@ -0,0 +1,1 @@
1- test: eventstat
02
=== added directory 'tests/health-check'
=== added file 'tests/health-check/health-check-test-get-pids.py'
--- tests/health-check/health-check-test-get-pids.py 1970-01-01 00:00:00 +0000
+++ tests/health-check/health-check-test-get-pids.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,38 @@
1#!/usr/bin/python3
2
3import os
4import psutil
5import platform
6
7basedir = os.path.dirname(__file__)
8default_threshold_path = os.path.join(
9 os.path.join(basedir, 'thresholds'), platform.machine())
10
11ignore_procs = [
12 'health-check', 'init', 'cat', 'vi', 'emacs', 'getty', 'csh', 'bash',
13 'sh', 'powerd', 'thermald', 'mpdecision', 'polkitd', 'whoopsie',
14 'mediascanner-service', 'window-stack-bridge', 'dconf-service',
15 'pulseaudio', 'hud-service', 'indicator-bluetooth-service',
16 'indicator-location-service', 'indicator-sound-service',
17 'indicator-secret-agent', 'mtp-server', 'address-book-service',
18 'dnsmasq', 'systemd-logind', 'systemd-udevd']
19
20with open(os.path.join(basedir, 'procmapping.txt'), 'w') as mapping:
21 procnames = {}
22 for p in psutil.process_iter():
23 try:
24 proc = p.as_dict(attrs=['pid', 'name'])
25 if os.getpgid(proc['pid']) != 0:
26 procname = os.path.basename(proc['name'])
27 fname = os.path.join(
28 default_threshold_path, procname + ".threshold")
29 count = procnames.get(procname, 0)
30 procnames[procname] = count + 1
31 if count > 0:
32 procname = '%s_%d' % (procname, count)
33 if not proc['name'] in ignore_procs:
34 if os.path.isfile(fname):
35 mapping.write('%s:%d\n' % (procname, proc['pid']))
36 print(procname)
37 except:
38 pass
039
=== added file 'tests/health-check/health-check-test-pid.py'
--- tests/health-check/health-check-test-pid.py 1970-01-01 00:00:00 +0000
+++ tests/health-check/health-check-test-pid.py 2014-10-07 19:58:41 +0000
@@ -0,0 +1,198 @@
1#!/usr/bin/python3
2#
3#
4# Copyright (C) 2013 Canonical
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License
8# as published by the Free Software Foundation; either version 2
9# of the License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19#
20#
21# Syntax:
22# health-check-test-pid.py pid [ path-to-threshold-files ]
23#
24# The process name is resolved and the tool will use a
25# `procname`.threshold file to compare against. If this file does not exist,
26# default.threshold is used.
27#
28
29import json
30import os
31import subprocess
32import sys
33import psutil
34import platform
35
36#
37# Default test run durations in seconds
38#
39default_duration = 60
40
41default_threshold_path = os.path.join(
42 os.path.join(os.path.dirname(__file__), 'thresholds'), platform.machine())
43
44default_pass_unknown_process = True
45
46
47def read_threshold(procname):
48 """Parse thresholds file.
49
50 lines starting with '#' are comments
51 format is: key value, e.g.
52 health-check.cpu-load.cpu-load-total.total-cpu-percent 0.5
53 health-check.cpu-load.cpu-load-total.user-cpu-percent 0.5
54 health-check.cpu-load.cpu-load-total.system-cpu-percent 0.5
55 """
56 fname = default_threshold_path + "/" + procname + ".threshold"
57 thresholds = {}
58 n = 0
59
60 with open(fname) as file:
61 for line in file:
62 n = n + 1
63 if len(line) > 1 and not line.startswith("#"):
64 tmp = line.split()
65 if len(tmp) == 2:
66 thresholds[tmp[0]] = tmp[1]
67 else:
68 sys.stderr.write(
69 "Threshold file %s line %d format error" % (fname, n))
70
71 return thresholds
72
73
74def check_threshold(data, key, fullkey, threshold):
75 """Locate a threshold in the JSON data, compare it to the threshold"""
76
77 try:
78 d = data[key[0]]
79 except KeyError:
80 sys.stderr.write(
81 "health-check JSON data does not have key " + fullkey + "\n")
82 return (True, "Attribute not found and ignored")
83
84 key = key[1:]
85 if len(key) > 0:
86 return check_threshold(d, key, fullkey, threshold)
87 else:
88 val = float(d)
89 if threshold >= val:
90 cmp = str(threshold) + " >= " + str(val)
91 return (True, cmp)
92 else:
93 cmp = str(threshold) + " < " + str(val)
94 return (False, cmp)
95
96
97def check_thresholds(procname, data, thresholds):
98 print("process: " + procname)
99 failed = False
100 for key in sorted(thresholds.keys()):
101 if key.startswith("health-check"):
102 threshold = float(thresholds[key])
103 (ret, str) = check_threshold(data, key.split('.'), key, threshold)
104 if ret:
105 msg = "PASSED"
106 else:
107 msg = "FAILED"
108 failed = True
109
110 sys.stderr.write(msg + ": " + str + ": " + key + "\n")
111
112 return failed
113
114
115def health_check(pid, procname):
116 """run health-check on a given process
117
118 :return: True if failed, False if passed
119 """
120 thresholds = read_threshold(procname)
121 #
122 # Can't test without thresholds
123 #
124 if len(thresholds) == 0:
125 if default_pass_unknown_process:
126 sys.stderr.write("No thresholds for process " + procname + "\n")
127 sys.stderr.write("Defaulting to pass this test\n")
128 return False
129 else:
130 thresholds = read_threshold("default")
131 if len(thresholds) == 0:
132 sys.stderr.write(
133 "No thresholds for process " + procname + "\n")
134 else:
135 sys.stderr.write(
136 "Using default thresholds for process " + procname + "\n")
137
138 duration = default_duration
139
140 if 'duration' in thresholds:
141 duration = int(thresholds['duration'])
142
143 filename = "health-check-" + str(pid) + ".json"
144 args = [
145 'health-check', '-c', '-f', '-d', str(duration),
146 '-w', '-W', '-r', '-p', str(pid), '-o', filename
147 ]
148
149 try:
150 subprocess.check_output(args)
151 with open(filename) as f:
152 data = json.load(f)
153 return check_thresholds(procname, data, thresholds)
154 except subprocess.CalledProcessError as e:
155 print(e)
156 exit(1)
157
158
159def get_proc(pid):
160 proc = None
161 try:
162 p = psutil.Process(pid)
163 pgid = os.getpgid(pid)
164 if pgid == 0:
165 sys.stderr.write(
166 "Cannot run health-check on kernel task with PID(%d)\n" % pid)
167 else:
168 proc = p
169 except psutil.NoSuchProcess as e:
170 sys.stderr.write('%s\n' % e)
171 except OSError as e:
172 if e.errno == 3:
173 sys.stderr.write("Cannot find pgid on process with PID %d\n" % pid)
174 return proc.as_dict(attrs=['pid', 'name'])
175
176
177def main(pid):
178 if os.getuid() != 0:
179 sys.stderr.write("Need to run as root\n")
180 exit(1)
181
182 p = get_proc(pid)
183 if not p:
184 exit(1)
185
186 procname = os.path.basename(p['name'])
187 if (health_check(pid, procname)):
188 exit(1)
189 else:
190 exit(0)
191
192if __name__ == '__main__':
193 if len(sys.argv) != 2:
194 sys.stderr.write("Usage: %s PID\n" % sys.argv[0])
195 exit(1)
196
197 pid = int(sys.argv[1])
198 main(pid)
0199
=== added file 'tests/health-check/master.run'
--- tests/health-check/master.run 1970-01-01 00:00:00 +0000
+++ tests/health-check/master.run 2014-10-07 19:58:41 +0000
@@ -0,0 +1,5 @@
1---
2testsuites:
3 - name: health-check
4 fetch_method: dev
5 fetch_location: ./
06
=== added file 'tests/health-check/setup.sh'
--- tests/health-check/setup.sh 1970-01-01 00:00:00 +0000
+++ tests/health-check/setup.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,10 @@
1#!/bin/sh -x
2echo "Setting up"
3
4${TARGET_PREFIX} apt-get install health-check
5
6${TARGET_PREFIX} mkdir -p /tmp/results
7
8adb push . /tmp/healthcheck
9
10exit 0
011
=== added file 'tests/health-check/test.sh'
--- tests/health-check/test.sh 1970-01-01 00:00:00 +0000
+++ tests/health-check/test.sh 2014-10-07 19:58:41 +0000
@@ -0,0 +1,15 @@
1#!/bin/sh
2
3procname=$1
4RC=0
5
6pidline=$(cat /tmp/healthcheck/procmapping.txt | grep $procname:)
7sed -i "/$pidline/d" /tmp/healthcheck/procmapping.txt
8pid=$(echo $pidline | awk -F: '{print $NF}')
9
10echo "Testing $procname - $pid"
11sudo /tmp/healthcheck/health-check-test-pid.py $pid
12RC=$?
13
14cp *.json /tmp/results
15exit $RC
016
=== added directory 'tests/health-check/thresholds'
=== added directory 'tests/health-check/thresholds/armv7l'
=== added file 'tests/health-check/thresholds/armv7l/NetworkManager.threshold'
--- tests/health-check/thresholds/armv7l/NetworkManager.threshold 1970-01-01 00:00:00 +0000
+++ tests/health-check/thresholds/armv7l/NetworkManager.threshold 2014-10-07 19:58:41 +0000
@@ -0,0 +1,73 @@
1#
2# Default "IDLE" process thresholds. Typically, an idle process
3# should be doing very little, so this profile checks some simple
4# process specific settings to see if we can find "busy" idle processes
5#
6# Length of test in seconds
7#
8duration 300
9#
10# CPU loading, should be really low for idle processes
11#
12health-check.cpu-load.cpu-load-total.total-cpu-percent 0.9
13health-check.cpu-load.cpu-load-total.user-cpu-percent 0.5
14health-check.cpu-load.cpu-load-total.system-cpu-percent 0.6
15#
16# Page faults, ignore these
17#
18#health-check.page-faults.page-faults-total.minor-page-faults-total-rate 10
19#health-check.page-faults.page-faults-total.major-page-faults-total-rate 10
20#health-check.page-faults.page-faults-total.total-page-faults-total-rate 10
21#
22# Wakeup Events, NetworkManager can be quite busy
23#
24health-check.wakeup-events.wakeup-events-total.wakeup-total-rate 1.0
25#
26# Context Switches, ignore these
27#
28#health-check.context-switches.context-switches-total.context-switch-total-rate 10
29#
30# Files, NetworkManager can do quite a lot of I/O at times
31#
32health-check.file-access.file-access-total.access-count-total-rate 0.5
33#health-check.file-io-operations.file-io-operations-total.open-call-total-rate 0.05
34#health-check.file-io-operations.file-io-operations-total.close-call-total-rate 0.05
35#health-check.file-io-operations.file-io-operations-total.read-call-total-rate 0.05
36#health-check.file-io-operations.file-io-operations-total.write-call-total-rate 0.05
37#
38# System calls poll rates
39#
40#health-check.system-calls.system-calls-total.system-call-count-total-rate 10
41#health-check.polling-system-calls.polling-system-calls-total.system-call-total-rate 10
42health-check.polling-system-calls.polling-system-calls-total.poll-count-infinite-total-rate 0
43health-check.polling-system-calls.polling-system-calls-total.poll-count-zero-total-rate 0
44#
45# File system syncs, an idle process should not do any
46#
47health-check.file-system-syncs.sync-system-calls-total.fdatasync-call-count-total-rate 0
48health-check.file-system-syncs.sync-system-calls-total.fsync-call-count-total-rate 0
49health-check.file-system-syncs.sync-system-calls-total.sync-call-count-total-rate 0
50health-check.file-system-syncs.sync-system-calls-total.syncfs-call-count-total-rate 0
51#
52# Memory usage, can't have a generic memory limit, so ignore
53#
54#health-check.memory-usage.memory-usage-total.stack-size-total-kbytes 1000000
55#health-check.memory-usage.memory-usage-total.stack-rss-total-kbytes 1000000
56#health-check.memory-usage.memory-usage-total.stack-pss-total-kbytes 1000000
57#health-check.memory-usage.memory-usage-total.heap-size-total-kbytes 9000
58#health-check.memory-usage.memory-usage-total.heap-rss-total-kbytes 1000000
59#health-check.memory-usage.memory-usage-total.heap-pss-total-kbytes 1000000
60#health-check.memory-usage.memory-usage-total.mapped-size-total-kbytes 1000000
61#health-check.memory-usage.memory-usage-total.mapped-rss-total-kbytes 1000000
62#health-check.memory-usage.memory-usage-total.mapped-pss-total-kbytes 1000000
63#
64# Memory change, should not grow more than say 10K an hour
65#
66# health-check.memory-change.memory-change-total.
67health-check.heap-usage-via-brk.heap-usage-via-brk-total.brk-size-total-Kbytes-rate 0.002777778
68health-check.memory-usage-via-mmap.memory-usage-via-mmap-total.mmap-total-Kbytes-rate 0.002777778
69#
70# Network, should be fairly idle
71#
72health-check.network-connections.network-connections-total.send-total-rate 1024
73health-check.network-connections.network-connections-total.receive-total-rate 1024
074
=== added file 'tests/health-check/thresholds/armv7l/accounts-daemon.threshold'
--- tests/health-check/thresholds/armv7l/accounts-daemon.threshold 1970-01-01 00:00:00 +0000
+++ tests/health-check/thresholds/armv7l/accounts-daemon.threshold 2014-10-07 19:58:41 +0000
@@ -0,0 +1,73 @@
1#
2# Default "IDLE" process thresholds. Typically, an idle process
3# should be doing very little, so this profile checks some simple
4# process specific settings to see if we can find "busy" idle processes
5#
6# Length of test in seconds
7#
8duration 300
9#
10# CPU loading, should be really low for idle processes
11#
12health-check.cpu-load.cpu-load-total.total-cpu-percent 0.05
13health-check.cpu-load.cpu-load-total.user-cpu-percent 0.02
14health-check.cpu-load.cpu-load-total.system-cpu-percent 0.03
15#
16# Page faults, ignore these
17#
18#health-check.page-faults.page-faults-total.minor-page-faults-total-rate 10
19#health-check.page-faults.page-faults-total.major-page-faults-total-rate 10
20#health-check.page-faults.page-faults-total.total-page-faults-total-rate 10
21#
22# Wakeup Events, anything more than 1 a second is busy
23#
24health-check.wakeup-events.wakeup-events-total.wakeup-total-rate 0.4
25#
26# Context Switches, ignore these
27#
28#health-check.context-switches.context-switches-total.context-switch-total-rate 10
29#
30# Files, really should not be doing much so allow for 1 a minute top
31#
32health-check.file-access.file-access-total.access-count-total-rate 0.016666667
33health-check.file-io-operations.file-io-operations-total.open-call-total-rate 0.016666667
34health-check.file-io-operations.file-io-operations-total.close-call-total-rate 0.016666667
35health-check.file-io-operations.file-io-operations-total.read-call-total-rate 0.016666667
36health-check.file-io-operations.file-io-operations-total.write-call-total-rate 0.016666667
37#
38# System calls, ignore these
39#
40#health-check.system-calls.system-calls-total.system-call-count-total-rate 10
41#health-check.polling-system-calls.polling-system-calls-total.system-call-total-rate 10
42#health-check.polling-system-calls.polling-system-calls-total.poll-count-infinite-total-rate 10
43#health-check.polling-system-calls.polling-system-calls-total.poll-count-zero-total-rate 0
44#
45# File system syncs, an idle process should not do any
46#
47health-check.file-system-syncs.sync-system-calls-total.fdatasync-call-count-total-rate 0
48health-check.file-system-syncs.sync-system-calls-total.fsync-call-count-total-rate 0
49health-check.file-system-syncs.sync-system-calls-total.sync-call-count-total-rate 0
50health-check.file-system-syncs.sync-system-calls-total.syncfs-call-count-total-rate 0
51#
52# Memory usage, can't have a generic memory limit, so ignore
53#
54#health-check.memory-usage.memory-usage-total.stack-size-total-kbytes 1000000
55#health-check.memory-usage.memory-usage-total.stack-rss-total-kbytes 1000000
56#health-check.memory-usage.memory-usage-total.stack-pss-total-kbytes 1000000
57#health-check.memory-usage.memory-usage-total.heap-size-total-kbytes 25000
58#health-check.memory-usage.memory-usage-total.heap-rss-total-kbytes 1000000
59#health-check.memory-usage.memory-usage-total.heap-pss-total-kbytes 1000000
60#health-check.memory-usage.memory-usage-total.mapped-size-total-kbytes 1000000
61#health-check.memory-usage.memory-usage-total.mapped-rss-total-kbytes 1000000
62#health-check.memory-usage.memory-usage-total.mapped-pss-total-kbytes 1000000
63#
64# Memory change, should not grow more than say 10K an hour
65#
66# health-check.memory-change.memory-change-total.
67health-check.heap-usage-via-brk.heap-usage-via-brk-total.brk-size-total-Kbytes-rate 0.002777778
68health-check.memory-usage-via-mmap.memory-usage-via-mmap-total.mmap-total-Kbytes-rate 0.002777778
69#
70# Network, should be fairly idle
71#
72health-check.network-connections.network-connections-total.send-total-rate 16
73health-check.network-connections.network-connections-total.receive-total-rate 16
074
=== added file 'tests/health-check/thresholds/armv7l/address-book-service.threshold'
--- tests/health-check/thresholds/armv7l/address-book-service.threshold 1970-01-01 00:00:00 +0000
+++ tests/health-check/thresholds/armv7l/address-book-service.threshold 2014-10-07 19:58:41 +0000
@@ -0,0 +1,73 @@
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches