Merge lp:~thomir-deactivatedaccount/ubuntu-test-cases/touch-convert-boottest-to-spaces into lp:ubuntu-test-cases

Proposed by Thomi Richards
Status: Superseded
Proposed branch: lp:~thomir-deactivatedaccount/ubuntu-test-cases/touch-convert-boottest-to-spaces
Merge into: lp:ubuntu-test-cases
Diff against target: 22838 lines (+21174/-0) (has conflicts)
321 files modified
README.rst (+259/-0)
config/boottest.rc.example (+10/-0)
jenkins/custom-demo.py (+32/-0)
jenkins/production-arale.py (+56/-0)
jenkins/production-krillin.py (+50/-0)
jenkins/production.py (+96/-0)
jenkins/setup_jenkins.py (+228/-0)
jenkins/staging.py (+42/-0)
jenkins/templates/touch-base.xml.jinja2 (+130/-0)
jenkins/templates/touch-master.xml.jinja2 (+80/-0)
jenkins/templates/touch-smoke.xml.jinja2 (+199/-0)
jenkins/testconfig.py (+242/-0)
scripts/assert-image (+31/-0)
scripts/boottest.sh (+204/-0)
scripts/combine_results (+124/-0)
scripts/dashboard.py (+305/-0)
scripts/device_info.py (+381/-0)
scripts/get-adb-id (+14/-0)
scripts/get-device-info (+38/-0)
scripts/jenkins.sh (+216/-0)
scripts/junit2utah.py (+70/-0)
scripts/masher_control.py (+64/-0)
scripts/ncd_usb.py (+48/-0)
scripts/provision.sh (+267/-0)
scripts/reboot-and-wait (+54/-0)
scripts/recover.py (+128/-0)
scripts/run-adt.py (+38/-0)
scripts/run-autopilot-tests.sh (+267/-0)
scripts/run-emulator (+97/-0)
scripts/run-mp.sh (+44/-0)
scripts/run-smoke (+408/-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 (+148/-0)
selftests/test_statsd.py (+64/-0)
tests/bootfail/README (+15/-0)
tests/bootfail/debian/changelog (+5/-0)
tests/bootfail/debian/compat (+1/-0)
tests/bootfail/debian/control (+10/-0)
tests/bootfail/debian/rules (+4/-0)
tests/bootfail/debian/tests/bootfail (+15/-0)
tests/bootfail/debian/tests/control (+3/-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/boottest/README (+10/-0)
tests/boottest/debian/changelog (+5/-0)
tests/boottest/debian/compat (+1/-0)
tests/boottest/debian/control (+10/-0)
tests/boottest/debian/rules (+4/-0)
tests/boottest/debian/tests/boottest (+13/-0)
tests/boottest/debian/tests/control (+6/-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/nfss_upload_results.py (+185/-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/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 (+183/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/smem-tabs (+687/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/__init__.py (+70/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_browser.py (+30/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_camera.py (+20/-0)
tests/memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_gallery.py (+16/-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 (+26/-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)
tests/ubuntu-sample-adt-test/COPYING (+674/-0)
tests/ubuntu-sample-adt-test/README.md (+41/-0)
tests/ubuntu-sample-adt-test/debian/changelog (+5/-0)
tests/ubuntu-sample-adt-test/debian/tests/control (+1/-0)
tests/ubuntu-sample-adt-test/debian/tests/sample (+19/-0)
utils/host/adb-shell (+23/-0)
utils/host/autopilot-list (+23/-0)
utils/host/autopilot-run (+12/-0)
utils/host/get-device-type (+9/-0)
utils/host/prepare-autopilot-test.sh (+7/-0)
utils/host/reboot-and-unlock.sh (+20/-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:~thomir-deactivatedaccount/ubuntu-test-cases/touch-convert-boottest-to-spaces
Reviewer Review Type Date Requested Status
Ubuntu Test Case Developers Pending
Review via email: mp+261030@code.launchpad.net

This proposal has been superseded by a proposal from 2015-06-03.

Commit message

Convert tabs to spaces in scripts/*

Description of the change

Convert tabs to spaces in scripts/*

To post a comment you must log in.
407. By Thomi Richards

realign comments.

Unmerged revisions

407. By Thomi Richards

realign comments.

406. By Thomi Richards

Convert tabs to spaces in scripts/*

405. By Francis Ginther

Extract the package version from the first installed binary package and supply that of the version of the source package under test in the result file sent to britney. [r=Paul Larson]

404. By Thomi Richards

Add a simple utility to retry adt-run several times in case of failure. [r=Francis Ginther]

403. By Paul Larson

Eliminate the need for getinstalledpkgs test in boottest [r=Francis Ginther]

402. By Francis Ginther

Install boottest binary packages during getinstalledpkgs, removing that responsibility from the boottest dep8 test.

401. By Francis Ginther

Remove boottest dependencies on the actual source package contents for the package under test.

400. By Paul Larson

Improve recovery image download logic [r=Parameswaran Sivatharman]

399. By Paul Larson

typo with quotes

398. By Paul Larson

include offline as a state we want to recover from

Preview Diff

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

Subscribers

People subscribed via source and target branches

to all changes: