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