Merge lp:~pwlars/ubuntu-test-cases/dialer-messaging-address-book into lp:ubuntu-test-cases
- dialer-messaging-address-book
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~pwlars/ubuntu-test-cases/dialer-messaging-address-book |
Merge into: | lp:ubuntu-test-cases |
Diff against target: |
2937 lines (+2377/-0) 105 files modified
address-book-app-autopilot/master.run (+15/-0) address-book-app-autopilot/ts_control (+1/-0) address-book-app-autopilot/tslist.auto (+4/-0) calendar-app-autopilot/master.run (+15/-0) calendar-app-autopilot/ts_control (+1/-0) calendar-app-autopilot/tslist.auto (+4/-0) camera-app-autopilot/master.run (+15/-0) camera-app-autopilot/ts_control (+1/-0) camera-app-autopilot/tslist.auto (+4/-0) dialer-app-autopilot/master.run (+15/-0) dialer-app-autopilot/ts_control (+1/-0) dialer-app-autopilot/tslist.auto (+4/-0) friends-app-autopilot/master.run (+15/-0) friends-app-autopilot/ts_control (+1/-0) friends-app-autopilot/tslist.auto (+4/-0) gallery-app-autopilot/master.run (+15/-0) gallery-app-autopilot/ts_control (+1/-0) gallery-app-autopilot/tslist.auto (+4/-0) jenkins/jenkins.sh (+109/-0) jenkins/provision.sh (+26/-0) mediaplayer-app-autopilot/master.run (+15/-0) mediaplayer-app-autopilot/ts_control (+1/-0) mediaplayer-app-autopilot/tslist.auto (+4/-0) memevent/master.run (+5/-0) memevent/setup.sh (+8/-0) memevent/ts_control (+1/-0) memevent/tslist.auto (+7/-0) memevent/ubuntu_test_cases/__init__.py (+6/-0) memevent/ubuntu_test_cases/memory_usage_measurement/__init__.py (+1/-0) memevent/ubuntu_test_cases/memory_usage_measurement/apps/__init__.py (+21/-0) memevent/ubuntu_test_cases/memory_usage_measurement/apps/browser.py (+110/-0) memevent/ubuntu_test_cases/memory_usage_measurement/apps/camera.py (+58/-0) memevent/ubuntu_test_cases/memory_usage_measurement/apps/gallery.py (+41/-0) memevent/ubuntu_test_cases/memory_usage_measurement/apps/media_player.py (+53/-0) memevent/ubuntu_test_cases/memory_usage_measurement/matchers.py (+37/-0) memevent/ubuntu_test_cases/memory_usage_measurement/probes.py (+170/-0) memevent/ubuntu_test_cases/memory_usage_measurement/smem-tabs (+687/-0) memevent/ubuntu_test_cases/memory_usage_measurement/tests/__init__.py (+1/-0) memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_memory_usage.py (+79/-0) messaging-app-autopilot/master.run (+15/-0) messaging-app-autopilot/ts_control (+1/-0) messaging-app-autopilot/tslist.auto (+4/-0) music-app-autopilot/master.run (+15/-0) music-app-autopilot/ts_control (+1/-0) music-app-autopilot/tslist.auto (+4/-0) notes-app-autopilot/master.run (+15/-0) notes-app-autopilot/ts_control (+1/-0) notes-app-autopilot/tslist.auto (+4/-0) phone-app-connected-autopilot/master.run (+5/-0) phone-app-connected-autopilot/setup.sh (+36/-0) phone-app-connected-autopilot/sms_self.py (+34/-0) phone-app-connected-autopilot/testnumbers.cfg (+23/-0) phone-app-connected-autopilot/ts_control (+1/-0) phone-app-connected-autopilot/tslist.auto (+4/-0) share-app-autopilot/master.run (+15/-0) share-app-autopilot/ts_control (+1/-0) share-app-autopilot/tslist.auto (+4/-0) systemsettle/systemsettle-after/tc_control (+9/-0) systemsettle/systemsettle-before/tc_control (+9/-0) systemsettle/systemsettle.sh (+119/-0) systemsettle/tslist.run (+2/-0) ubuntu-calculator-app-autopilot/master.run (+15/-0) ubuntu-calculator-app-autopilot/ts_control (+1/-0) ubuntu-calculator-app-autopilot/tslist.auto (+4/-0) ubuntu-clock-app-autopilot/master.run (+15/-0) ubuntu-clock-app-autopilot/ts_control (+1/-0) ubuntu-clock-app-autopilot/tslist.auto (+4/-0) ubuntu-docviewer-app-autopilot/master.run (+15/-0) ubuntu-docviewer-app-autopilot/ts_control (+1/-0) ubuntu-docviewer-app-autopilot/tslist.auto (+4/-0) ubuntu-filemanager-app-autopilot/master.run (+15/-0) ubuntu-filemanager-app-autopilot/ts_control (+1/-0) ubuntu-filemanager-app-autopilot/tslist.auto (+4/-0) ubuntu-rssreader-app-autopilot/master.run (+15/-0) ubuntu-rssreader-app-autopilot/ts_control (+1/-0) ubuntu-rssreader-app-autopilot/tslist.auto (+4/-0) ubuntu-terminal-app-autopilot/master.run (+15/-0) ubuntu-terminal-app-autopilot/ts_control (+1/-0) ubuntu-terminal-app-autopilot/tslist.auto (+4/-0) ubuntu-weather-app-autopilot/master.run (+15/-0) ubuntu-weather-app-autopilot/ts_control (+1/-0) ubuntu-weather-app-autopilot/tslist.auto (+4/-0) unity8-autopilot/master.run (+15/-0) unity8-autopilot/setup.sh (+6/-0) unity8-autopilot/ts_control (+2/-0) unity8-autopilot/tslist.auto (+4/-0) upgrade/README (+3/-0) upgrade/install_old/run.sh (+27/-0) upgrade/install_old/tc_control (+9/-0) upgrade/master.run (+5/-0) upgrade/tslist.run (+2/-0) upgrade/upgrade/tc_control (+9/-0) upgrade/upgrade/upgrade.sh (+79/-0) utils/host/adb-shell (+20/-0) utils/host/autopilot-list (+18/-0) utils/host/autopilot-run (+3/-0) utils/host/prepare-autopilot-test.sh (+5/-0) utils/target/autopilot-list (+13/-0) utils/target/autopilot-run (+4/-0) utils/target/prepare-autopilot-test.sh (+17/-0) utils/target/unlock_screen.py (+87/-0) utils/target/unlock_screen.sh (+7/-0) webbrowser-app-autopilot/master.run (+15/-0) webbrowser-app-autopilot/ts_control (+1/-0) webbrowser-app-autopilot/tslist.auto (+4/-0) |
To merge this branch: | bzr merge lp:~pwlars/ubuntu-test-cases/dialer-messaging-address-book |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Test Case Developers | Pending | ||
Review via email: mp+182983@code.launchpad.net |
This proposal has been superseded by a proposal from 2013-08-29.
Commit message
Description of the change
- 85. By Paul Larson
-
rename phone-app tests to dialer-app and add messaging and address-book tests
Unmerged revisions
- 85. By Paul Larson
-
rename phone-app tests to dialer-app and add messaging and address-book tests
- 84. By Andy Doan
-
update to new phablet-network script
- 83. By Andy Doan
-
make systemsettle less verbose and host/target friendly
- 82. By Andy Doan
-
add ability to run apps from host rather than target
This allows the test be driven from either the target or the
host. To run from host simply add FROM_HOST=1 to the jenkins.sh
environment. - 81. By Andy Doan
-
use common scripts for all tests
this moves the tests over to using some common scripts to do all their heavy lifting. with this in place, the next step is to provide equivalent scripts that can run from the host.
- 80. By Andy Doan
-
simplify touch test setup logic
- 79. By Paul Larson
-
change systemsettle percent to 97.5
- 78. By Paul Larson
-
Use top instead of vmstat and always output toplot
- 77. By Andy Doan
-
add test for sending sms
- 76. By Javier Collado
-
Merged use cnn url instead of launhpad one
Source branch: lp:~javier.collado/ubuntu-test-cases/memevent-update-url
Preview Diff
1 | === added directory 'address-book-app-autopilot' |
2 | === added file 'address-book-app-autopilot/master.run' |
3 | --- address-book-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
4 | +++ address-book-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
5 | @@ -0,0 +1,15 @@ |
6 | +--- |
7 | +testsuites: |
8 | + - name: settle-before |
9 | + fetch_method: dev |
10 | + fetch_location: ../systemsettle |
11 | + include_tests: |
12 | + - systemsettle-before |
13 | + - name: address-book-app-autopilot |
14 | + fetch_method: dev |
15 | + fetch_location: ./ |
16 | + - name: settle-after |
17 | + fetch_method: dev |
18 | + fetch_location: ../systemsettle |
19 | + include_tests: |
20 | + - systemsettle-after |
21 | |
22 | === added file 'address-book-app-autopilot/ts_control' |
23 | --- address-book-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
24 | +++ address-book-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
25 | @@ -0,0 +1,1 @@ |
26 | +ts_setup: PKGS=address-book-app-autopilot prepare-autopilot-test.sh |
27 | |
28 | === added file 'address-book-app-autopilot/tslist.auto' |
29 | --- address-book-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
30 | +++ address-book-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
31 | @@ -0,0 +1,4 @@ |
32 | +- |
33 | + discovery_cmd: autopilot-list address_book_app |
34 | + test_cmd: autopilot-run address_book_app.tests.{} |
35 | + |
36 | |
37 | === added directory 'calendar-app-autopilot' |
38 | === added file 'calendar-app-autopilot/master.run' |
39 | --- calendar-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
40 | +++ calendar-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
41 | @@ -0,0 +1,15 @@ |
42 | +--- |
43 | +testsuites: |
44 | + - name: settle-before |
45 | + fetch_method: dev |
46 | + fetch_location: ../systemsettle |
47 | + include_tests: |
48 | + - systemsettle-before |
49 | + - name: calendar-app-autopilot |
50 | + fetch_method: dev |
51 | + fetch_location: ./ |
52 | + - name: settle-after |
53 | + fetch_method: dev |
54 | + fetch_location: ../systemsettle |
55 | + include_tests: |
56 | + - systemsettle-after |
57 | |
58 | === added file 'calendar-app-autopilot/ts_control' |
59 | --- calendar-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
60 | +++ calendar-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
61 | @@ -0,0 +1,1 @@ |
62 | +ts_setup: PKGS=calendar-app-autopilot prepare-autopilot-test.sh |
63 | |
64 | === added file 'calendar-app-autopilot/tslist.auto' |
65 | --- calendar-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
66 | +++ calendar-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
67 | @@ -0,0 +1,4 @@ |
68 | +- |
69 | + discovery_cmd: autopilot-list calendar_app |
70 | + test_cmd: autopilot-run calendar_app.tests.{} |
71 | + |
72 | |
73 | === added directory 'camera-app-autopilot' |
74 | === added file 'camera-app-autopilot/master.run' |
75 | --- camera-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
76 | +++ camera-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
77 | @@ -0,0 +1,15 @@ |
78 | +--- |
79 | +testsuites: |
80 | + - name: settle-before |
81 | + fetch_method: dev |
82 | + fetch_location: ../systemsettle |
83 | + include_tests: |
84 | + - systemsettle-before |
85 | + - name: camera-app-autopilot |
86 | + fetch_method: dev |
87 | + fetch_location: ./ |
88 | + - name: settle-after |
89 | + fetch_method: dev |
90 | + fetch_location: ../systemsettle |
91 | + include_tests: |
92 | + - systemsettle-after |
93 | |
94 | === added file 'camera-app-autopilot/ts_control' |
95 | --- camera-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
96 | +++ camera-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
97 | @@ -0,0 +1,1 @@ |
98 | +ts_setup: PKGS=camera-app-autopilot prepare-autopilot-test.sh |
99 | |
100 | === added file 'camera-app-autopilot/tslist.auto' |
101 | --- camera-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
102 | +++ camera-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
103 | @@ -0,0 +1,4 @@ |
104 | +- |
105 | + discovery_cmd: autopilot-list camera_app |
106 | + test_cmd: autopilot-run camera_app.tests.{} |
107 | + |
108 | |
109 | === added directory 'dialer-app-autopilot' |
110 | === added file 'dialer-app-autopilot/master.run' |
111 | --- dialer-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
112 | +++ dialer-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
113 | @@ -0,0 +1,15 @@ |
114 | +--- |
115 | +testsuites: |
116 | + - name: settle-before |
117 | + fetch_method: dev |
118 | + fetch_location: ../systemsettle |
119 | + include_tests: |
120 | + - systemsettle-before |
121 | + - name: phone-app-autopilot |
122 | + fetch_method: dev |
123 | + fetch_location: ./ |
124 | + - name: settle-after |
125 | + fetch_method: dev |
126 | + fetch_location: ../systemsettle |
127 | + include_tests: |
128 | + - systemsettle-after |
129 | |
130 | === added file 'dialer-app-autopilot/ts_control' |
131 | --- dialer-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
132 | +++ dialer-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
133 | @@ -0,0 +1,1 @@ |
134 | +ts_setup: PKGS=phone-app-autopilot prepare-autopilot-test.sh |
135 | |
136 | === added file 'dialer-app-autopilot/tslist.auto' |
137 | --- dialer-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
138 | +++ dialer-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
139 | @@ -0,0 +1,4 @@ |
140 | +- |
141 | + discovery_cmd: autopilot-list phone_app |
142 | + test_cmd: autopilot-run phone_app.tests.{} |
143 | + |
144 | |
145 | === added directory 'friends-app-autopilot' |
146 | === added file 'friends-app-autopilot/master.run' |
147 | --- friends-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
148 | +++ friends-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
149 | @@ -0,0 +1,15 @@ |
150 | +--- |
151 | +testsuites: |
152 | + - name: settle-before |
153 | + fetch_method: dev |
154 | + fetch_location: ../systemsettle |
155 | + include_tests: |
156 | + - systemsettle-before |
157 | + - name: friends-app-autopilot |
158 | + fetch_method: dev |
159 | + fetch_location: ./ |
160 | + - name: settle-after |
161 | + fetch_method: dev |
162 | + fetch_location: ../systemsettle |
163 | + include_tests: |
164 | + - systemsettle-after |
165 | |
166 | === added file 'friends-app-autopilot/ts_control' |
167 | --- friends-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
168 | +++ friends-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
169 | @@ -0,0 +1,1 @@ |
170 | +ts_setup: PKGS=friends-app-autopilot prepare-autopilot-test.sh |
171 | |
172 | === added file 'friends-app-autopilot/tslist.auto' |
173 | --- friends-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
174 | +++ friends-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
175 | @@ -0,0 +1,4 @@ |
176 | +- |
177 | + discovery_cmd: autopilot-list friends_app |
178 | + test_cmd: autopilot-run friends_app.tests.{} |
179 | + |
180 | |
181 | === added directory 'gallery-app-autopilot' |
182 | === added file 'gallery-app-autopilot/master.run' |
183 | --- gallery-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
184 | +++ gallery-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
185 | @@ -0,0 +1,15 @@ |
186 | +--- |
187 | +testsuites: |
188 | + - name: settle-before |
189 | + fetch_method: dev |
190 | + fetch_location: ../systemsettle |
191 | + include_tests: |
192 | + - systemsettle-before |
193 | + - name: gallery-app-autopilot |
194 | + fetch_method: dev |
195 | + fetch_location: ./ |
196 | + - name: settle-after |
197 | + fetch_method: dev |
198 | + fetch_location: ../systemsettle |
199 | + include_tests: |
200 | + - systemsettle-after |
201 | |
202 | === added file 'gallery-app-autopilot/ts_control' |
203 | --- gallery-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
204 | +++ gallery-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
205 | @@ -0,0 +1,1 @@ |
206 | +ts_setup: PKGS=gallery-app-autopilot prepare-autopilot-test.sh |
207 | |
208 | === added file 'gallery-app-autopilot/tslist.auto' |
209 | --- gallery-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
210 | +++ gallery-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
211 | @@ -0,0 +1,4 @@ |
212 | +- |
213 | + discovery_cmd: autopilot-list gallery_app |
214 | + test_cmd: autopilot-run gallery_app.tests.{} |
215 | + |
216 | |
217 | === added directory 'jenkins' |
218 | === added file 'jenkins/jenkins.sh' |
219 | --- jenkins/jenkins.sh 1970-01-01 00:00:00 +0000 |
220 | +++ jenkins/jenkins.sh 2013-08-29 18:33:39 +0000 |
221 | @@ -0,0 +1,109 @@ |
222 | +#!/bin/bash |
223 | + |
224 | +## This is the script jenkins should run to execute various touch applications |
225 | +## Intersting environment variables that must be set: |
226 | +## ANDROID_SERIAL - specify another android device |
227 | +## APP - the name of the app to test, ie share_app_autopilot |
228 | +## QUICK - if set, skips the reboot and wait-for-network logic |
229 | +## FROM_HOST - if set, runs the test from the host instead of the target |
230 | + |
231 | +set -e |
232 | + |
233 | +BASEDIR=$(dirname $(readlink -f $0))/.. |
234 | + |
235 | +RESDIR=`pwd`/clientlogs |
236 | +UTAHFILE=${RESDIR}/utah.yaml |
237 | +UTAH_PHABLET_CMD="${UTAH_PHABLET_CMD-/usr/share/utah/examples/run_utah_phablet.py}" |
238 | + |
239 | +ANDROID_SERIAL="${ANDROID_SERIAL-015d1884b20c1c0f}" #doanac's nexus7 at home |
240 | + |
241 | +TESTSUITE_HOST=$(readlink -f ${BASEDIR}/${APP}) |
242 | +TESTSUITE_TARGET_BASE=/tmp/tests |
243 | +TESTSUITE_TARGET=${TESTSUITE_TARGET_BASE}/$(basename ${TESTSUITE_HOST}) |
244 | + |
245 | +cleanup() { |
246 | + set +e |
247 | +} |
248 | + |
249 | +test_from_target() { |
250 | + # push the runlist over to the test |
251 | + adb push ${BASEDIR} ${TESTSUITE_TARGET_BASE} &> /dev/null |
252 | + ${UTAH_PHABLET_CMD} \ |
253 | + -s ${ANDROID_SERIAL} \ |
254 | + --results-dir ${RESDIR} \ |
255 | + --skip-install --skip-network --skip-utah \ |
256 | + --pull /var/crash \ |
257 | + -l ${TESTSUITE_TARGET}/master.run |
258 | +} |
259 | + |
260 | +test_from_host() { |
261 | + export ANDROID_SERIAL # need for utils/hosts scripts |
262 | + |
263 | + export PATH=${BASEDIR}/utils/host:${PATH} |
264 | + |
265 | + # allow for certain commands to run from host/target |
266 | + # see unity8-autopilot/ts_control for example |
267 | + export TARGET_PREFIX=adb-shell |
268 | + |
269 | + sudo TARGET_PREFIX=$TARGET_PREFIX PATH=$PATH ${UTAH_PHABLET_CMD} \ |
270 | + -s ${ANDROID_SERIAL} \ |
271 | + --from-host \ |
272 | + --results-dir ${RESDIR} \ |
273 | + --skip-install --skip-network --skip-utah \ |
274 | + --pull /var/crash \ |
275 | + -l ${TESTSUITE_HOST}/master.run |
276 | +} |
277 | + |
278 | +main() { |
279 | + rm -rf clientlogs |
280 | + mkdir clientlogs |
281 | + |
282 | + # print the build date so the jenkins job can use it as the |
283 | + # build description |
284 | + adb -s ${ANDROID_SERIAL} pull /var/log/installer/media-info ${RESDIR} |
285 | + BUILDID=`cat ${RESDIR}/media-info | awk '{ print $(NF)}' | sed -e 's/(//' -e 's/)//'` |
286 | + echo "= TOUCH BUILD DATE:$BUILDID" |
287 | + |
288 | + adb shell "top -n1 -b" > ${RESDIR}/top.log |
289 | + |
290 | + set -x |
291 | + adb shell 'rm -f /var/crash/*' |
292 | + if [ -z $QUICK ] ; then |
293 | + # get the phone in sane place |
294 | + adb -s ${ANDROID_SERIAL} reboot |
295 | + # sometimes reboot doesn't happen fast enough, so add a little |
296 | + # delay to help ensure its actually rebooted and we didn't just |
297 | + # connect back to the device before it rebooted |
298 | + adb -s ${ANDROID_SERIAL} wait-for-device |
299 | + sleep 5 |
300 | + adb -s ${ANDROID_SERIAL} wait-for-device |
301 | + timeout 120s adb -s ${ANDROID_SERIAL} shell /usr/local/bin/utah-wait-for-network |
302 | + else |
303 | + echo "SKIPPING phone reboot..." |
304 | + fi |
305 | + |
306 | + if [ -z $FROM_HOST ] ; then |
307 | + echo "launching test on the target...." |
308 | + test_from_target |
309 | + else |
310 | + echo "launching test from the host...." |
311 | + test_from_host |
312 | + fi |
313 | + adb shell 'rm -f /var/crash/*' |
314 | + |
315 | + if ! `grep "^errors: [!0]" < $UTAHFILE >/dev/null` ; then |
316 | + echo "errors found" |
317 | + EXITCODE=1 |
318 | + fi |
319 | + if ! `grep "^failures: [!0]" < $UTAHFILE >/dev/null` ; then |
320 | + echo "failures found" |
321 | + EXITCODE=2 |
322 | + fi |
323 | + echo "Results Summary" |
324 | + echo "---------------" |
325 | + egrep '^(errors|failures|passes|fetch_errors):' $UTAHFILE |
326 | + exit $EXITCODE |
327 | +} |
328 | + |
329 | +trap cleanup TERM INT EXIT |
330 | +main |
331 | |
332 | === added file 'jenkins/provision.sh' |
333 | --- jenkins/provision.sh 1970-01-01 00:00:00 +0000 |
334 | +++ jenkins/provision.sh 2013-08-29 18:33:39 +0000 |
335 | @@ -0,0 +1,26 @@ |
336 | +#!/bin/bash |
337 | + |
338 | +## This is the script jenkins should run to provision a device in the lab |
339 | +## Intersting environment variables that must be set: |
340 | +## ANDROID_SERIAL - specify another android device |
341 | +## NETWORK_FILE - an alternative network file if you aren't in the lab |
342 | +## TOUCH_IMAGE=--ubuntu-bootstrap (provision with read-only system image) |
343 | + |
344 | +set -e |
345 | +set -x |
346 | + |
347 | +BASEDIR=$(dirname $(readlink -f $0)) |
348 | + |
349 | +RESDIR=`pwd`/clientlogs |
350 | +UTAH_PHABLET_CMD="${UTAH_PHABLET_CMD-/usr/share/utah/examples/run_utah_phablet.py}" |
351 | + |
352 | +ANDROID_SERIAL="${ANDROID_SERIAL-015d1884b20c1c0f}" #doanac's nexus7 at home |
353 | +NETWORK_FILE="${NETWORK_FILE-/home/ubuntu/magners-wifi}" |
354 | + |
355 | +rm -rf clientlogs |
356 | +mkdir clientlogs |
357 | + |
358 | +${UTAH_PHABLET_CMD} -s ${ANDROID_SERIAL} --results-dir ${RESDIR} --network-file=${NETWORK_FILE} ${TOUCH_IMAGE} |
359 | + |
360 | +# get our target-based utilities into our PATH |
361 | +adb -s ${ANDROID_SERIAL} push ${BASEDIR}/../utils/target /usr/local/bin/ |
362 | |
363 | === added directory 'mediaplayer-app-autopilot' |
364 | === added file 'mediaplayer-app-autopilot/master.run' |
365 | --- mediaplayer-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
366 | +++ mediaplayer-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
367 | @@ -0,0 +1,15 @@ |
368 | +--- |
369 | +testsuites: |
370 | + - name: settle-before |
371 | + fetch_method: dev |
372 | + fetch_location: ../systemsettle |
373 | + include_tests: |
374 | + - systemsettle-before |
375 | + - name: mediaplayer-app-autopilot |
376 | + fetch_method: dev |
377 | + fetch_location: ./ |
378 | + - name: settle-after |
379 | + fetch_method: dev |
380 | + fetch_location: ../systemsettle |
381 | + include_tests: |
382 | + - systemsettle-after |
383 | |
384 | === added file 'mediaplayer-app-autopilot/ts_control' |
385 | --- mediaplayer-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
386 | +++ mediaplayer-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
387 | @@ -0,0 +1,1 @@ |
388 | +ts_setup: PKGS=mediaplayer-app-autopilot prepare-autopilot-test.sh |
389 | |
390 | === added file 'mediaplayer-app-autopilot/tslist.auto' |
391 | --- mediaplayer-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
392 | +++ mediaplayer-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
393 | @@ -0,0 +1,4 @@ |
394 | +- |
395 | + discovery_cmd: autopilot-list mediaplayer_app |
396 | + test_cmd: autopilot-run mediaplayer_app.tests.{} |
397 | + |
398 | |
399 | === added directory 'memevent' |
400 | === added file 'memevent/master.run' |
401 | --- memevent/master.run 1970-01-01 00:00:00 +0000 |
402 | +++ memevent/master.run 2013-08-29 18:33:39 +0000 |
403 | @@ -0,0 +1,5 @@ |
404 | +--- |
405 | +testsuites: |
406 | + - name: memevent |
407 | + fetch_method: dev |
408 | + fetch_location: ./ |
409 | |
410 | === added file 'memevent/setup.sh' |
411 | --- memevent/setup.sh 1970-01-01 00:00:00 +0000 |
412 | +++ memevent/setup.sh 2013-08-29 18:33:39 +0000 |
413 | @@ -0,0 +1,8 @@ |
414 | +#!/bin/sh |
415 | + |
416 | +set -e |
417 | + |
418 | +# copy the autopilot scripts over if needed |
419 | +[ -z $ANDROID_SERIAL ] || adb push ./ubuntu_test_cases /home/phablet/autopilot/ubuntu_test_cases |
420 | + |
421 | +PKGS="camera-app-autopilot gallery-app-autopilot mediaplayer-app-autopilot webbrowser-app-autopilot" prepare-autopilot-test.sh |
422 | |
423 | === added file 'memevent/ts_control' |
424 | --- memevent/ts_control 1970-01-01 00:00:00 +0000 |
425 | +++ memevent/ts_control 2013-08-29 18:33:39 +0000 |
426 | @@ -0,0 +1,1 @@ |
427 | +ts_setup: ./setup.sh |
428 | |
429 | === added file 'memevent/tslist.auto' |
430 | --- memevent/tslist.auto 1970-01-01 00:00:00 +0000 |
431 | +++ memevent/tslist.auto 2013-08-29 18:33:39 +0000 |
432 | @@ -0,0 +1,7 @@ |
433 | +--- |
434 | +# The discovery command is run from a directory containing the whole suite |
435 | +# The test command is run from a sub directory in that |
436 | +# We need to run each command in the directory that contains ubuntu_test_cases |
437 | +# so that autopilot can find our python modules |
438 | +- discovery_cmd: cd memevent; autopilot-list ubuntu_test_cases.memory_usage_measurement |
439 | + test_cmd: cd ..; autopilot-run ubuntu_test_cases.memory_usage_measurement.tests.{} |
440 | |
441 | === added directory 'memevent/ubuntu_test_cases' |
442 | === added file 'memevent/ubuntu_test_cases/__init__.py' |
443 | --- memevent/ubuntu_test_cases/__init__.py 1970-01-01 00:00:00 +0000 |
444 | +++ memevent/ubuntu_test_cases/__init__.py 2013-08-29 18:33:39 +0000 |
445 | @@ -0,0 +1,6 @@ |
446 | +"""ubuntu_test_cases package |
447 | + |
448 | +Warning: This python package is installed by a different debian package in a |
449 | +different branch. It's been been created here only because it's convenient to |
450 | +run autopilot directly from the branch. |
451 | +""" |
452 | |
453 | === added directory 'memevent/ubuntu_test_cases/memory_usage_measurement' |
454 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/__init__.py' |
455 | --- memevent/ubuntu_test_cases/memory_usage_measurement/__init__.py 1970-01-01 00:00:00 +0000 |
456 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/__init__.py 2013-08-29 18:33:39 +0000 |
457 | @@ -0,0 +1,1 @@ |
458 | +"""Event based memory usage measurements test cases.""" |
459 | |
460 | === added directory 'memevent/ubuntu_test_cases/memory_usage_measurement/apps' |
461 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/apps/__init__.py' |
462 | --- memevent/ubuntu_test_cases/memory_usage_measurement/apps/__init__.py 1970-01-01 00:00:00 +0000 |
463 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/apps/__init__.py 2013-08-29 18:33:39 +0000 |
464 | @@ -0,0 +1,21 @@ |
465 | +"""Application classes used to drive them easily with autopilot.""" |
466 | + |
467 | +from autopilot.input import Keyboard, Mouse, Pointer, Touch |
468 | +from autopilot.platform import model |
469 | + |
470 | + |
471 | +class App(object): |
472 | + |
473 | + """Application class with common code.""" |
474 | + |
475 | + def __init__(self, tc): |
476 | + self.tc = tc |
477 | + self.app = None |
478 | + self.window = None |
479 | + |
480 | + self.keyboard = Keyboard.create() |
481 | + if model() == 'Desktop': |
482 | + input_device = Mouse.create() |
483 | + else: |
484 | + input_device = Touch.create() |
485 | + self.pointer = Pointer(input_device) |
486 | |
487 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/apps/browser.py' |
488 | --- memevent/ubuntu_test_cases/memory_usage_measurement/apps/browser.py 1970-01-01 00:00:00 +0000 |
489 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/apps/browser.py 2013-08-29 18:33:39 +0000 |
490 | @@ -0,0 +1,110 @@ |
491 | +"""Browser application to write autopilot test cases easily.""" |
492 | + |
493 | +from testtools.matchers import Contains, Equals |
494 | + |
495 | +from webbrowser_app.emulators.main_window import MainWindow as BrowserWindow |
496 | + |
497 | +from ubuntu_test_cases.memory_usage_measurement.apps import App |
498 | +from ubuntu_test_cases.memory_usage_measurement.matchers import ( |
499 | + DoesNotChange, |
500 | + Eventually, |
501 | +) |
502 | + |
503 | + |
504 | +class BrowserApp(App): |
505 | + |
506 | + """Browser application.""" |
507 | + |
508 | + TYPING_DELAY = 0.01 |
509 | + |
510 | + def assert_chrome_eventually_hidden(self): |
511 | + """Make sure chrome is eventually hidden.""" |
512 | + view = self.window.get_qml_view() |
513 | + chrome = self.window.get_chrome() |
514 | + self.tc.assertThat(lambda: chrome.globalRect[1], |
515 | + Eventually(Equals(view.y + view.height))) |
516 | + |
517 | + def assert_page_eventually_loaded(self, url): |
518 | + """Make sure page is eventually loaded.""" |
519 | + webview = self.window.get_current_webview() |
520 | + self.tc.assertThat(webview.url, Eventually(Equals(url))) |
521 | + # loadProgress == 100 ensures that a page has actually loaded |
522 | + self.tc.assertThat(webview.loadProgress, Eventually(Equals(100))) |
523 | + self.tc.assertThat(webview.loading, Eventually(Equals(False))) |
524 | + |
525 | + def clear_address_bar(self): |
526 | + """Clear address bar.""" |
527 | + self.focus_address_bar() |
528 | + clear_button = self.window.get_address_bar_clear_button() |
529 | + self.tc.assertThat(lambda: (clear_button.x, |
530 | + clear_button.y, |
531 | + clear_button.y), |
532 | + Eventually(DoesNotChange())) |
533 | + self.pointer.move_to_object(clear_button) |
534 | + self.pointer.click() |
535 | + text_field = self.window.get_address_bar_text_field() |
536 | + self.tc.assertThat(text_field.text, Eventually(Equals(""))) |
537 | + |
538 | + def ensure_chrome_is_hidden(self): |
539 | + """Make sure chrome is hidden.""" |
540 | + webview = self.window.get_current_webview() |
541 | + self.pointer.move_to_object(webview) |
542 | + self.pointer.click() |
543 | + self.assert_chrome_eventually_hidden() |
544 | + |
545 | + def focus_address_bar(self): |
546 | + """Make sure address bar is focused.""" |
547 | + address_bar = self.window.get_address_bar() |
548 | + self.pointer.move_to_object(address_bar) |
549 | + self.pointer.click() |
550 | + self.tc.assertThat(address_bar.activeFocus, Eventually(Equals(True))) |
551 | + |
552 | + def go_to_url(self, url): |
553 | + """Go to given url. |
554 | + |
555 | + :param url: URL that should be loaded in the browser |
556 | + :type url: str |
557 | + |
558 | + """ |
559 | + self.ensure_chrome_is_hidden() |
560 | + self.reveal_chrome() |
561 | + self.clear_address_bar() |
562 | + self.type_in_address_bar(url) |
563 | + self.keyboard.press_and_release("Enter") |
564 | + |
565 | + def launch(self): |
566 | + """Launch application.""" |
567 | + args = [ |
568 | + 'webbrowser-app', |
569 | + '--fullscreen', |
570 | + ('--desktop_file_hint=' |
571 | + '/usr/share/applications/webbrowser-app.desktop'), |
572 | + ] |
573 | + self.app = self.tc.launch_test_application(*args, app_type='qt') |
574 | + self.window = BrowserWindow(self.app) |
575 | + self.tc.assertThat(self.window.get_qml_view().visible, |
576 | + Eventually(Equals(True))) |
577 | + |
578 | + def reveal_chrome(self): |
579 | + """Reveal chrome.""" |
580 | + panel = self.window.get_panel() |
581 | + distance = self.window.get_chrome().height |
582 | + view = self.window.get_qml_view() |
583 | + x_line = int(view.x + view.width * 0.5) |
584 | + start_y = int(view.y + view.height - 1) |
585 | + stop_y = int(start_y - distance) |
586 | + self.pointer.drag(x_line, start_y, x_line, stop_y) |
587 | + self.tc.assertThat(panel.state, Eventually(Equals('spread'))) |
588 | + |
589 | + def type_in_address_bar(self, text): |
590 | + """Type text in address bar. |
591 | + |
592 | + :param text: Text to be typed in the address bar. |
593 | + :type text: str |
594 | + |
595 | + """ |
596 | + address_bar = self.window.get_address_bar() |
597 | + self.tc.assertThat(address_bar.activeFocus, Eventually(Equals(True))) |
598 | + self.keyboard.type(text, delay=self.TYPING_DELAY) |
599 | + text_field = self.window.get_address_bar_text_field() |
600 | + self.tc.assertThat(text_field.text, Eventually(Contains(text))) |
601 | |
602 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/apps/camera.py' |
603 | --- memevent/ubuntu_test_cases/memory_usage_measurement/apps/camera.py 1970-01-01 00:00:00 +0000 |
604 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/apps/camera.py 2013-08-29 18:33:39 +0000 |
605 | @@ -0,0 +1,58 @@ |
606 | +"""Camera application to write autopilot test cases easily.""" |
607 | + |
608 | +import logging |
609 | +import os |
610 | + |
611 | +from glob import glob |
612 | + |
613 | +from camera_app.emulators.main_window import MainWindow as CameraWindow |
614 | +from testtools.matchers import Equals, HasLength |
615 | + |
616 | +from ubuntu_test_cases.memory_usage_measurement.apps import App |
617 | +from ubuntu_test_cases.memory_usage_measurement.matchers import Eventually |
618 | + |
619 | +LOGGER = logging.getLogger(__file__) |
620 | + |
621 | + |
622 | +class CameraApp(App): |
623 | + |
624 | + """Camera application.""" |
625 | + |
626 | + IMAGE_FILENAME_PATTERN = os.path.expanduser('~/Pictures/image*') |
627 | + |
628 | + def _remove_image_files(self): |
629 | + """Remove all image files. |
630 | + |
631 | + This is useful not only to cleanup, but also to check that just one |
632 | + image file has been written to disk. |
633 | + |
634 | + """ |
635 | + for filename in glob(self.IMAGE_FILENAME_PATTERN): |
636 | + LOGGER.debug('Removing image file: {}'.format(filename)) |
637 | + os.remove(filename) |
638 | + |
639 | + def launch(self): |
640 | + """Launch application.""" |
641 | + args = [ |
642 | + 'camera-app', |
643 | + '--fullscreen', |
644 | + ('--desktop_file_hint=' |
645 | + '/usr/share/applications/camera-app.desktop'), |
646 | + ] |
647 | + self.app = self.tc.launch_test_application(*args, app_type='qt') |
648 | + self.window = CameraWindow(self.app) |
649 | + |
650 | + def take_picture(self): |
651 | + """Click on the exposure button to take picture.""" |
652 | + self._remove_image_files() |
653 | + |
654 | + exposure_button = self.window.get_exposure_button() |
655 | + self.tc.assertThat(exposure_button.enabled, Eventually(Equals(True))) |
656 | + |
657 | + LOGGER.debug('Taking picture...') |
658 | + self.pointer.move_to_object(exposure_button) |
659 | + self.pointer.click() |
660 | + |
661 | + # Wait for image file to be produced before memory usage measurement |
662 | + self.tc.assertThat(lambda: glob(self.IMAGE_FILENAME_PATTERN), |
663 | + Eventually(HasLength(1))) |
664 | |
665 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/apps/gallery.py' |
666 | --- memevent/ubuntu_test_cases/memory_usage_measurement/apps/gallery.py 1970-01-01 00:00:00 +0000 |
667 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/apps/gallery.py 2013-08-29 18:33:39 +0000 |
668 | @@ -0,0 +1,41 @@ |
669 | +"""Gallery application to write autopilot test cases easily.""" |
670 | + |
671 | +import os |
672 | +import shutil |
673 | +import tempfile |
674 | + |
675 | +from ubuntu_test_cases.memory_usage_measurement.apps import App |
676 | + |
677 | + |
678 | +class GalleryApp(App): |
679 | + |
680 | + """Gallery application.""" |
681 | + |
682 | + SAMPLE_DIR = '/usr/lib/python2.7/dist-packages/gallery_app/data/default' |
683 | + |
684 | + def __init__(self, tc): |
685 | + super(GalleryApp, self).__init__(tc) |
686 | + self.temp_sample_dir = None |
687 | + self._copy_sample_dir() |
688 | + |
689 | + def _copy_sample_dir(self): |
690 | + """Copy sample directory to a temporary location. |
691 | + |
692 | + This is useful to provide some default content. |
693 | + |
694 | + """ |
695 | + self.temp_sample_dir = tempfile.mkdtemp(prefix='gallery-app-test-') |
696 | + self.tc.addCleanup(shutil.rmtree, self.temp_sample_dir) |
697 | + self.temp_sample_dir = os.path.join(self.temp_sample_dir, 'data') |
698 | + shutil.copytree(self.SAMPLE_DIR, self.temp_sample_dir) |
699 | + |
700 | + def launch(self): |
701 | + """Launch the application.""" |
702 | + args = [ |
703 | + 'gallery-app', |
704 | + ('--desktop_file_hint=' |
705 | + '/usr/share/applications/gallery-app.desktop'), |
706 | + self.temp_sample_dir, |
707 | + ] |
708 | + self.app = self.tc.launch_test_application(*args, |
709 | + app_type='qt') |
710 | |
711 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/apps/media_player.py' |
712 | --- memevent/ubuntu_test_cases/memory_usage_measurement/apps/media_player.py 1970-01-01 00:00:00 +0000 |
713 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/apps/media_player.py 2013-08-29 18:33:39 +0000 |
714 | @@ -0,0 +1,53 @@ |
715 | +"""Media player application to write autopilot test cases easily.""" |
716 | + |
717 | +import os |
718 | + |
719 | +from testtools.matchers import Equals, GreaterThan |
720 | + |
721 | +from mediaplayer_app.emulators.main_window import ( |
722 | + MainWindow as MediaPlayerWindow) |
723 | + |
724 | +from ubuntu_test_cases.memory_usage_measurement.apps import App |
725 | +from ubuntu_test_cases.memory_usage_measurement.matchers import Eventually |
726 | + |
727 | + |
728 | +class MediaPlayerApp(App): |
729 | + |
730 | + """Media player application.""" |
731 | + |
732 | + # Default content |
733 | + VIDEOS_DIR = 'file:///usr/share/mediaplayer-app/videos/' |
734 | + |
735 | + def assert_playback_finished(self): |
736 | + """Media player memory usage after playing a file.""" |
737 | + time_line = self.window.get_object("Slider", "TimeLine.Slider") |
738 | + |
739 | + # Time line value isn't set to maximum value after playback is finished |
740 | + # (LP: #1190555) |
741 | + maximum_value = time_line.maximumValue - 2.0 |
742 | + self.tc.assertThat(time_line.value, |
743 | + Eventually(GreaterThan(maximum_value))) |
744 | + |
745 | + def launch(self, movie_file=None): |
746 | + """Launch application. |
747 | + |
748 | + :param movie_file: |
749 | + Relative path to movie file (uses default content directory as |
750 | + root). |
751 | + :type movie_file: str |
752 | + |
753 | + """ |
754 | + binary = 'mediaplayer-app' |
755 | + args = [ |
756 | + binary, |
757 | + '--fullscreen', |
758 | + ('--desktop_file_hint=' |
759 | + '/usr/share/applications/mediaplayer-app.desktop'), |
760 | + ] |
761 | + if movie_file: |
762 | + args.insert(1, os.path.join(self.VIDEOS_DIR, movie_file)) |
763 | + |
764 | + self.app = self.tc.launch_test_application(*args, app_type='qt') |
765 | + self.window = MediaPlayerWindow(self.app) |
766 | + self.tc.assertThat(self.window.get_qml_view().visible, |
767 | + Eventually(Equals(True))) |
768 | |
769 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/matchers.py' |
770 | --- memevent/ubuntu_test_cases/memory_usage_measurement/matchers.py 1970-01-01 00:00:00 +0000 |
771 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/matchers.py 2013-08-29 18:33:39 +0000 |
772 | @@ -0,0 +1,37 @@ |
773 | +"""Custom matchers used by the tests.""" |
774 | + |
775 | +from autopilot.matchers import Eventually as EventuallyMatcher |
776 | +from testtools.matchers import Mismatch |
777 | + |
778 | + |
779 | +def Eventually(matcher): |
780 | + """Wrapper around autopilot.matchers.Eventually. |
781 | + |
782 | + The aim of the wrapper is just use a different timeout default |
783 | + |
784 | + :param matcher: A testools-like matcher that tests the desired condition |
785 | + :type matcher: object |
786 | + :returns: A value depending on the matcher protocol |
787 | + :rtype: None | a mismatch object with information about the mismatch |
788 | + |
789 | + """ |
790 | + return EventuallyMatcher(matcher, timeout=40) |
791 | + |
792 | + |
793 | +class DoesNotChange(object): |
794 | + """Match if two consecutive values are equal.""" |
795 | + def __init__(self): |
796 | + self.old_value = None |
797 | + self.value = None |
798 | + |
799 | + def __str__(self): |
800 | + return 'DoesNotChange()' |
801 | + |
802 | + def match(self, value): |
803 | + self.old_value = self.value |
804 | + self.value = value |
805 | + if self.value != self.old_value: |
806 | + return Mismatch('Current value ({}) does not match old value ({})' |
807 | + .format(self.value, self.old_value)) |
808 | + |
809 | + return None |
810 | |
811 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/probes.py' |
812 | --- memevent/ubuntu_test_cases/memory_usage_measurement/probes.py 1970-01-01 00:00:00 +0000 |
813 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/probes.py 2013-08-29 18:33:39 +0000 |
814 | @@ -0,0 +1,170 @@ |
815 | +"""Probes used to take measurements4 while the tests are executed.""" |
816 | + |
817 | +import itertools |
818 | +import logging |
819 | +import os |
820 | +import re |
821 | +import subprocess |
822 | + |
823 | +from contextlib import contextmanager |
824 | +from time import time |
825 | + |
826 | +LOGGER = logging.getLogger(__file__) |
827 | + |
828 | + |
829 | +class SmemProbe(object): |
830 | + |
831 | + """Memory usage probe.""" |
832 | + |
833 | + BINARY = os.path.join(os.path.dirname(__file__), 'smem-tabs') |
834 | + THRESHOLDS = { |
835 | + 'foreground': 262144, # 256MB |
836 | + 'background': 131072, # 128MB |
837 | + } |
838 | + |
839 | + def __init__(self): |
840 | + self.pids = [] # List of pids that should be monitored |
841 | + self.readings = [] # List of readings |
842 | + self.current_reading = None |
843 | + self.threshold_exceeded_summary = [] |
844 | + |
845 | + @contextmanager |
846 | + def probe(self, event): |
847 | + """Run start and stop methods in a contex manager.""" |
848 | + self.start(event) |
849 | + yield |
850 | + self.stop(event) |
851 | + |
852 | + def start(self, event): |
853 | + """Start measurement. |
854 | + |
855 | + This method is not actually used, but defined to be consistent with the |
856 | + probes API. |
857 | + |
858 | + :param event: Event name |
859 | + :type event: str |
860 | + :returns: None |
861 | + |
862 | + """ |
863 | + LOGGER.debug('smem start: {}'.format(event)) |
864 | + self.current_reading = { |
865 | + 'event': event, |
866 | + 'start_time': time(), |
867 | + } |
868 | + |
869 | + def stop(self, event): |
870 | + """Stop measurement. |
871 | + |
872 | + Run smem and get memory usage for a given set PIDs. |
873 | + |
874 | + :param event: Event name |
875 | + :type event: str |
876 | + :returns: None |
877 | + |
878 | + """ |
879 | + LOGGER.debug('smem stop: {}'.format(event)) |
880 | + LOGGER.debug('Running {!r}...'.format(self.BINARY)) |
881 | + output = subprocess.check_output(self.BINARY) |
882 | + parser = SmemParser() |
883 | + pids_info = parser.parse(output) |
884 | + threshold_exceeded_pids = self._calculate_threshold_exceeded(pids_info) |
885 | + print '{:-^72}'.format(event) |
886 | + for pid in self.pids: |
887 | + print('PID: {pid}, command: {command}, PSS: {pss}, USS: {uss}' |
888 | + .format(**pids_info[pid])) |
889 | + |
890 | + self.current_reading['stop_time'] = time() |
891 | + self.current_reading['data'] = pids_info |
892 | + self.readings.append(self.current_reading) |
893 | + if threshold_exceeded_pids: |
894 | + self.threshold_exceeded_summary.append( |
895 | + (event, threshold_exceeded_pids)) |
896 | + self.current_reading = None |
897 | + |
898 | + def _calculate_threshold_exceeded(self, pids_info): |
899 | + """Calculate thresholds for the given set of pids. |
900 | + |
901 | + :param pids_info: |
902 | + Memory usage data for a give set of pids. |
903 | + |
904 | + ..note:: |
905 | + This parameter is modified in place to add a delta of the PSS |
906 | + and the threshold. |
907 | + :type pids_info: list(dict) |
908 | + |
909 | + """ |
910 | + # It's assumed that the pid for the foreground application is the one |
911 | + # that was last added to the probe |
912 | + foreground_pid = self.pids[-1] |
913 | + foreground_threshold = self.THRESHOLDS['foreground'] |
914 | + background_pids = self.pids[:-1] |
915 | + background_threshold = self.THRESHOLDS['background'] |
916 | + |
917 | + pids_and_thresholds = itertools.chain( |
918 | + [(foreground_pid, foreground_threshold)], |
919 | + itertools.product(background_pids, [background_threshold])) |
920 | + |
921 | + threshold_exceeded_pids = [] |
922 | + for pid, threshold in pids_and_thresholds: |
923 | + if pid in pids_info: |
924 | + pid_info = pids_info[pid] |
925 | + delta = pid_info['pss'] - threshold |
926 | + pid_info['threshold_exceeded'] = delta |
927 | + if delta > 0: |
928 | + threshold_exceeded_pids.append(pid) |
929 | + return threshold_exceeded_pids |
930 | + |
931 | + @property |
932 | + def report(self): |
933 | + """Return report with all the readings that have been made.""" |
934 | + return {'pids': self.pids, |
935 | + 'thresholds': self.THRESHOLDS, |
936 | + 'readings': self.readings} |
937 | + |
938 | + |
939 | +class SmemParser(object): |
940 | + |
941 | + """Parser object to map smem output to data structure.""" |
942 | + |
943 | + SMEM_LINE = re.compile( |
944 | + r'\s*(?P<pid>\d+)' |
945 | + r'\s+(?P<user>\w+)' |
946 | + r'\s+(?P<command>.+?)' |
947 | + r'\s+(?P<swap>\d+)' |
948 | + r'\s+(?P<uss>\d+)' |
949 | + r'\s+(?P<pss>\d+)' |
950 | + r'\s+(?P<rss>\d+)') |
951 | + |
952 | + def parse(self, output): |
953 | + """Parse smem output. |
954 | + |
955 | + :param output: The report printed to stdout by smem |
956 | + :type output: str |
957 | + :returns: Data structure that can be serialized |
958 | + :rtype: dict(dict) |
959 | + |
960 | + """ |
961 | + pids_info = filter(None, |
962 | + [self._parse_line(line) |
963 | + for line in output.splitlines()[1:]]) |
964 | + return {pid_info['pid']: pid_info for pid_info in pids_info} |
965 | + |
966 | + def _parse_line(self, line): |
967 | + """Parse a single smem output line. |
968 | + |
969 | + :param line: |
970 | + A single line containing all the fields to parse for a process. |
971 | + :type line: str |
972 | + :returns: Data structure with the parsed fields |
973 | + :rtype: dict |
974 | + |
975 | + """ |
976 | + match = self.SMEM_LINE.match(line) |
977 | + if not match: |
978 | + LOGGER.warning('Unable to parse smem output: {}'.format(line)) |
979 | + return None |
980 | + |
981 | + pid_info = match.groupdict() |
982 | + for key in ('pid', 'swap', 'uss', 'pss', 'rss'): |
983 | + pid_info[key] = int(pid_info[key]) |
984 | + return pid_info |
985 | |
986 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/smem-tabs' |
987 | --- memevent/ubuntu_test_cases/memory_usage_measurement/smem-tabs 1970-01-01 00:00:00 +0000 |
988 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/smem-tabs 2013-08-29 18:33:39 +0000 |
989 | @@ -0,0 +1,687 @@ |
990 | +#!/usr/bin/env python |
991 | +# |
992 | +# smem - a tool for meaningful memory reporting |
993 | +# |
994 | +# Copyright 2008-2009 Matt Mackall <mpm@selenic.com> |
995 | +# |
996 | +# This software may be used and distributed according to the terms of |
997 | +# the GNU General Public License version 2 or later, incorporated |
998 | +# herein by reference. |
999 | + |
1000 | +import re, os, sys, pwd, optparse, errno, tarfile |
1001 | + |
1002 | +warned = False |
1003 | + |
1004 | +class procdata(object): |
1005 | + def __init__(self, source): |
1006 | + self._ucache = {} |
1007 | + self._gcache = {} |
1008 | + self.source = source and source or "" |
1009 | + self._memdata = None |
1010 | + def _list(self): |
1011 | + return os.listdir(self.source + "/proc") |
1012 | + def _read(self, f): |
1013 | + return file(self.source + '/proc/' + f).read() |
1014 | + def _readlines(self, f): |
1015 | + return self._read(f).splitlines(True) |
1016 | + def _stat(self, f): |
1017 | + return os.stat(self.source + "/proc/" + f) |
1018 | + |
1019 | + def pids(self): |
1020 | + '''get a list of processes''' |
1021 | + return [int(e) for e in self._list() |
1022 | + if e.isdigit() and not iskernel(e)] |
1023 | + def mapdata(self, pid): |
1024 | + return self._readlines('%s/smaps' % pid) |
1025 | + def memdata(self): |
1026 | + if self._memdata is None: |
1027 | + self._memdata = self._readlines('meminfo') |
1028 | + return self._memdata |
1029 | + def version(self): |
1030 | + return self._readlines('version')[0] |
1031 | + def pidname(self, pid): |
1032 | + try: |
1033 | + l = self.pidcmd(pid).split(' ')[0] |
1034 | + return os.path.basename(l) |
1035 | + except: |
1036 | + return '?' |
1037 | + def pidcmd(self, pid): |
1038 | + try: |
1039 | + c = self._read('%s/cmdline' % pid)[:-1] |
1040 | + return c.replace('\0', ' ') |
1041 | + except: |
1042 | + return '?' |
1043 | + def piduser(self, pid): |
1044 | + try: |
1045 | + return self._stat('%d' % pid).st_uid |
1046 | + except: |
1047 | + return -1 |
1048 | + def pidgroup(self, pid): |
1049 | + try: |
1050 | + return self._stat('%d' % pid).st_gid |
1051 | + except: |
1052 | + return -1 |
1053 | + def username(self, uid): |
1054 | + if uid == -1: |
1055 | + return '?' |
1056 | + if uid not in self._ucache: |
1057 | + try: |
1058 | + self._ucache[uid] = pwd.getpwuid(uid)[0] |
1059 | + except KeyError: |
1060 | + self._ucache[uid] = str(uid) |
1061 | + return self._ucache[uid] |
1062 | + def groupname(self, gid): |
1063 | + if gid == -1: |
1064 | + return '?' |
1065 | + if gid not in self._gcache: |
1066 | + try: |
1067 | + self._gcache[gid] = pwd.getgrgid(gid)[0] |
1068 | + except KeyError: |
1069 | + self._gcache[gid] = str(gid) |
1070 | + return self._gcache[gid] |
1071 | + |
1072 | +class tardata(procdata): |
1073 | + def __init__(self, source): |
1074 | + procdata.__init__(self, source) |
1075 | + self.tar = tarfile.open(source) |
1076 | + def _list(self): |
1077 | + for ti in self.tar: |
1078 | + if ti.name.endswith('/smaps'): |
1079 | + d,f = ti.name.split('/') |
1080 | + yield d |
1081 | + def _read(self, f): |
1082 | + return self.tar.extractfile(f).read() |
1083 | + def _readlines(self, f): |
1084 | + return self.tar.extractfile(f).readlines() |
1085 | + def piduser(self, p): |
1086 | + t = self.tar.getmember("%d" % p) |
1087 | + if t.uname: |
1088 | + self._ucache[t.uid] = t.uname |
1089 | + return t.uid |
1090 | + def pidgroup(self, p): |
1091 | + t = self.tar.getmember("%d" % p) |
1092 | + if t.gname: |
1093 | + self._gcache[t.gid] = t.gname |
1094 | + return t.gid |
1095 | + def username(self, u): |
1096 | + return self._ucache.get(u, str(u)) |
1097 | + def groupname(self, g): |
1098 | + return self._gcache.get(g, str(g)) |
1099 | + |
1100 | +_totalmem = 0 |
1101 | +def totalmem(): |
1102 | + global _totalmem |
1103 | + if not _totalmem: |
1104 | + if options.realmem: |
1105 | + _totalmem = fromunits(options.realmem) / 1024 |
1106 | + else: |
1107 | + _totalmem = memory()['memtotal'] |
1108 | + return _totalmem |
1109 | + |
1110 | +_kernelsize = 0 |
1111 | +def kernelsize(): |
1112 | + global _kernelsize |
1113 | + if not _kernelsize and options.kernel: |
1114 | + try: |
1115 | + d = os.popen("size %s" % options.kernel).readlines()[1] |
1116 | + _kernelsize = int(d.split()[3]) / 1024 |
1117 | + except: |
1118 | + try: |
1119 | + # try some heuristic to find gzipped part in kernel image |
1120 | + packedkernel = open(options.kernel).read() |
1121 | + pos = packedkernel.find('\x1F\x8B') |
1122 | + if pos >= 0 and pos < 25000: |
1123 | + sys.stderr.write("Maybe uncompressed kernel can be extracted by the command:\n" |
1124 | + " dd if=%s bs=1 skip=%d | gzip -d >%s.unpacked\n\n" % (options.kernel, pos, options.kernel)) |
1125 | + except: |
1126 | + pass |
1127 | + sys.stderr.write("Parameter '%s' should be an original uncompressed compiled kernel file.\n\n" % options.kernel) |
1128 | + return _kernelsize |
1129 | + |
1130 | +def pidmaps(pid): |
1131 | + global warned |
1132 | + maps = {} |
1133 | + start = None |
1134 | + seen = False |
1135 | + for l in src.mapdata(pid): |
1136 | + f = l.split() |
1137 | + if f[-1] == 'kB': |
1138 | + if f[0].startswith('Pss'): |
1139 | + seen = True |
1140 | + maps[start][f[0][:-1].lower()] = int(f[1]) |
1141 | + elif f[0] == 'VmFlags:': |
1142 | + continue |
1143 | + else: |
1144 | + start, end = f[0].split('-') |
1145 | + start = int(start, 16) |
1146 | + name = "<anonymous>" |
1147 | + if len(f) > 5: |
1148 | + name = f[5] |
1149 | + maps[start] = dict(end=int(end, 16), mode=f[1], |
1150 | + offset=int(f[2], 16), |
1151 | + device=f[3], inode=f[4], name=name) |
1152 | + |
1153 | + if not seen and not warned: |
1154 | + sys.stderr.write('warning: kernel does not appear to support PSS measurement\n') |
1155 | + warned = True |
1156 | + if not options.sort: |
1157 | + options.sort = 'rss' |
1158 | + |
1159 | + if options.mapfilter: |
1160 | + f = {} |
1161 | + for m in maps: |
1162 | + if not filter(options.mapfilter, m, lambda x: maps[x]['name']): |
1163 | + f[m] = maps[m] |
1164 | + return f |
1165 | + |
1166 | + return maps |
1167 | + |
1168 | +def sortmaps(totals, key): |
1169 | + l = [] |
1170 | + for pid in totals: |
1171 | + l.append((totals[pid][key], pid)) |
1172 | + l.sort() |
1173 | + return [pid for pid,key in l] |
1174 | + |
1175 | +def iskernel(pid): |
1176 | + return src.pidcmd(pid) == "" |
1177 | + |
1178 | +def memory(): |
1179 | + t = {} |
1180 | + f = re.compile('(\\S+):\\s+(\\d+) kB') |
1181 | + for l in src.memdata(): |
1182 | + m = f.match(l) |
1183 | + if m: |
1184 | + t[m.group(1).lower()] = int(m.group(2)) |
1185 | + return t |
1186 | + |
1187 | +def units(x): |
1188 | + s = '' |
1189 | + if x == 0: |
1190 | + return '0' |
1191 | + for s in ('', 'K', 'M', 'G', 'T'): |
1192 | + if x < 1024: |
1193 | + break |
1194 | + x /= 1024.0 |
1195 | + return "%.1f%s" % (x, s) |
1196 | + |
1197 | +def fromunits(x): |
1198 | + s = dict(k=2**10, K=2**10, kB=2**10, KB=2**10, |
1199 | + M=2**20, MB=2**20, G=2**30, GB=2**30, |
1200 | + T=2**40, TB=2**40) |
1201 | + for k,v in s.items(): |
1202 | + if x.endswith(k): |
1203 | + return int(float(x[:-len(k)])*v) |
1204 | + sys.stderr.write("Memory size should be written with units, for example 1024M\n") |
1205 | + sys.exit(-1) |
1206 | + |
1207 | +def pidusername(pid): |
1208 | + return src.username(src.piduser(pid)) |
1209 | + |
1210 | +def showamount(a, total): |
1211 | + if options.abbreviate: |
1212 | + return units(a * 1024) |
1213 | + elif options.percent: |
1214 | + return "%.2f%%" % (100.0 * a / total) |
1215 | + return a |
1216 | + |
1217 | +def filter(opt, arg, *sources): |
1218 | + if not opt: |
1219 | + return False |
1220 | + |
1221 | + for f in sources: |
1222 | + if re.search(opt, f(arg)): |
1223 | + return False |
1224 | + return True |
1225 | + |
1226 | +def pidtotals(pid): |
1227 | + maps = pidmaps(pid) |
1228 | + t = dict(size=0, rss=0, pss=0, shared_clean=0, shared_dirty=0, |
1229 | + private_clean=0, private_dirty=0, referenced=0, swap=0) |
1230 | + for m in maps.iterkeys(): |
1231 | + for k in t: |
1232 | + t[k] += maps[m].get(k, 0) |
1233 | + |
1234 | + t['uss'] = t['private_clean'] + t['private_dirty'] |
1235 | + t['maps'] = len(maps) |
1236 | + |
1237 | + return t |
1238 | + |
1239 | +def processtotals(pids): |
1240 | + totals = {} |
1241 | + for pid in pids: |
1242 | + if (filter(options.processfilter, pid, src.pidname, src.pidcmd) or |
1243 | + filter(options.userfilter, pid, pidusername)): |
1244 | + continue |
1245 | + try: |
1246 | + p = pidtotals(pid) |
1247 | + if p['maps'] != 0: |
1248 | + totals[pid] = p |
1249 | + except: |
1250 | + continue |
1251 | + return totals |
1252 | + |
1253 | +def showpids(): |
1254 | + p = src.pids() |
1255 | + pt = processtotals(p) |
1256 | + |
1257 | + def showuser(p): |
1258 | + if options.numeric: |
1259 | + return src.piduser(p) |
1260 | + return pidusername(p) |
1261 | + |
1262 | + fields = dict( |
1263 | + pid=('PID', lambda n: n, '% 5s', lambda x: len(pt), |
1264 | + 'process ID'), |
1265 | + user=('User', showuser, '%-8s', lambda x: len(dict.fromkeys(x)), |
1266 | + 'owner of process'), |
1267 | + name=('Name', src.pidname, '%s', None, |
1268 | + 'name of process'), |
1269 | + command=('Command', src.pidcmd, '%s', None, |
1270 | + 'process command line'), |
1271 | + maps=('Maps',lambda n: pt[n]['maps'], '% 5s', sum, |
1272 | + 'total number of mappings'), |
1273 | + swap=('Swap',lambda n: pt[n]['swap'], '% 8a', sum, |
1274 | + 'amount of swap space consumed (ignoring sharing)'), |
1275 | + uss=('USS', lambda n: pt[n]['uss'], '%a', sum, |
1276 | + 'unique set size'), |
1277 | + rss=('RSS', lambda n: pt[n]['rss'], '%a', sum, |
1278 | + 'resident set size (ignoring sharing)'), |
1279 | + pss=('PSS', lambda n: pt[n]['pss'], '%a', sum, |
1280 | + 'proportional set size (including sharing)'), |
1281 | + vss=('VSS', lambda n: pt[n]['size'], '%a', sum, |
1282 | + 'virtual set size (total virtual memory mapped)'), |
1283 | + ) |
1284 | + columns = options.columns or 'pid user command swap uss pss rss' |
1285 | + |
1286 | + showtable(pt.keys(), fields, columns.split(), options.sort or 'pss') |
1287 | + |
1288 | +def maptotals(pids): |
1289 | + totals = {} |
1290 | + for pid in pids: |
1291 | + if (filter(options.processfilter, pid, src.pidname, src.pidcmd) or |
1292 | + filter(options.userfilter, pid, pidusername)): |
1293 | + continue |
1294 | + try: |
1295 | + maps = pidmaps(pid) |
1296 | + seen = {} |
1297 | + for m in maps.iterkeys(): |
1298 | + name = maps[m]['name'] |
1299 | + if name not in totals: |
1300 | + t = dict(size=0, rss=0, pss=0, shared_clean=0, |
1301 | + shared_dirty=0, private_clean=0, count=0, |
1302 | + private_dirty=0, referenced=0, swap=0, pids=0) |
1303 | + else: |
1304 | + t = totals[name] |
1305 | + |
1306 | + for k in t: |
1307 | + t[k] += maps[m].get(k, 0) |
1308 | + t['count'] += 1 |
1309 | + if name not in seen: |
1310 | + t['pids'] += 1 |
1311 | + seen[name] = 1 |
1312 | + totals[name] = t |
1313 | + except EnvironmentError: |
1314 | + continue |
1315 | + return totals |
1316 | + |
1317 | +def showmaps(): |
1318 | + p = src.pids() |
1319 | + pt = maptotals(p) |
1320 | + |
1321 | + fields = dict( |
1322 | + map=('Map', lambda n: n, '%-40.40s', len, |
1323 | + 'mapping name'), |
1324 | + count=('Count', lambda n: pt[n]['count'], '% 5s', sum, |
1325 | + 'number of mappings found'), |
1326 | + pids=('PIDs', lambda n: pt[n]['pids'], '% 5s', sum, |
1327 | + 'number of PIDs using mapping'), |
1328 | + swap=('Swap',lambda n: pt[n]['swap'], '% 8a', sum, |
1329 | + 'amount of swap space consumed (ignoring sharing)'), |
1330 | + uss=('USS', lambda n: pt[n]['private_clean'] |
1331 | + + pt[n]['private_dirty'], '% 8a', sum, |
1332 | + 'unique set size'), |
1333 | + rss=('RSS', lambda n: pt[n]['rss'], '% 8a', sum, |
1334 | + 'resident set size (ignoring sharing)'), |
1335 | + pss=('PSS', lambda n: pt[n]['pss'], '% 8a', sum, |
1336 | + 'proportional set size (including sharing)'), |
1337 | + vss=('VSS', lambda n: pt[n]['size'], '% 8a', sum, |
1338 | + 'virtual set size (total virtual address space mapped)'), |
1339 | + avgpss=('AVGPSS', lambda n: int(1.0 * pt[n]['pss']/pt[n]['pids']), |
1340 | + '% 8a', sum, |
1341 | + 'average PSS per PID'), |
1342 | + avguss=('AVGUSS', lambda n: int(1.0 * pt[n]['uss']/pt[n]['pids']), |
1343 | + '% 8a', sum, |
1344 | + 'average USS per PID'), |
1345 | + avgrss=('AVGRSS', lambda n: int(1.0 * pt[n]['rss']/pt[n]['pids']), |
1346 | + '% 8a', sum, |
1347 | + 'average RSS per PID'), |
1348 | + ) |
1349 | + columns = options.columns or 'map pids avgpss pss' |
1350 | + |
1351 | + showtable(pt.keys(), fields, columns.split(), options.sort or 'pss') |
1352 | + |
1353 | +def usertotals(pids): |
1354 | + totals = {} |
1355 | + for pid in pids: |
1356 | + if (filter(options.processfilter, pid, src.pidname, src.pidcmd) or |
1357 | + filter(options.userfilter, pid, pidusername)): |
1358 | + continue |
1359 | + try: |
1360 | + maps = pidmaps(pid) |
1361 | + if len(maps) == 0: |
1362 | + continue |
1363 | + except EnvironmentError: |
1364 | + continue |
1365 | + user = src.piduser(pid) |
1366 | + if user not in totals: |
1367 | + t = dict(size=0, rss=0, pss=0, shared_clean=0, |
1368 | + shared_dirty=0, private_clean=0, count=0, |
1369 | + private_dirty=0, referenced=0, swap=0) |
1370 | + else: |
1371 | + t = totals[user] |
1372 | + |
1373 | + for m in maps.iterkeys(): |
1374 | + for k in t: |
1375 | + t[k] += maps[m].get(k, 0) |
1376 | + |
1377 | + t['count'] += 1 |
1378 | + totals[user] = t |
1379 | + return totals |
1380 | + |
1381 | +def showusers(): |
1382 | + p = src.pids() |
1383 | + pt = usertotals(p) |
1384 | + |
1385 | + def showuser(u): |
1386 | + if options.numeric: |
1387 | + return u |
1388 | + return src.username(u) |
1389 | + |
1390 | + fields = dict( |
1391 | + user=('User', showuser, '%-8s', None, |
1392 | + 'user name or ID'), |
1393 | + count=('Count', lambda n: pt[n]['count'], '% 5s', sum, |
1394 | + 'number of processes'), |
1395 | + swap=('Swap',lambda n: pt[n]['swap'], '% 8a', sum, |
1396 | + 'amount of swapspace consumed (ignoring sharing)'), |
1397 | + uss=('USS', lambda n: pt[n]['private_clean'] |
1398 | + + pt[n]['private_dirty'], '% 8a', sum, |
1399 | + 'unique set size'), |
1400 | + rss=('RSS', lambda n: pt[n]['rss'], '% 8a', sum, |
1401 | + 'resident set size (ignoring sharing)'), |
1402 | + pss=('PSS', lambda n: pt[n]['pss'], '% 8a', sum, |
1403 | + 'proportional set size (including sharing)'), |
1404 | + vss=('VSS', lambda n: pt[n]['pss'], '% 8a', sum, |
1405 | + 'virtual set size (total virtual memory mapped)'), |
1406 | + ) |
1407 | + columns = options.columns or 'user count swap uss pss rss' |
1408 | + |
1409 | + showtable(pt.keys(), fields, columns.split(), options.sort or 'pss') |
1410 | + |
1411 | +def showsystem(): |
1412 | + t = totalmem() |
1413 | + ki = kernelsize() |
1414 | + m = memory() |
1415 | + |
1416 | + mt = m['memtotal'] |
1417 | + f = m['memfree'] |
1418 | + |
1419 | + # total amount used by hardware |
1420 | + fh = max(t - mt - ki, 0) |
1421 | + |
1422 | + # total amount mapped into userspace (ie mapped an unmapped pages) |
1423 | + u = m['anonpages'] + m['mapped'] |
1424 | + |
1425 | + # total amount allocated by kernel not for userspace |
1426 | + kd = mt - f - u |
1427 | + |
1428 | + # total amount in kernel caches |
1429 | + kdc = m['buffers'] + m['sreclaimable'] + (m['cached'] - m['mapped']) |
1430 | + |
1431 | + l = [("firmware/hardware", fh, 0), |
1432 | + ("kernel image", ki, 0), |
1433 | + ("kernel dynamic memory", kd, kdc), |
1434 | + ("userspace memory", u, m['mapped']), |
1435 | + ("free memory", f, f)] |
1436 | + |
1437 | + fields = dict( |
1438 | + order=('Order', lambda n: n, '% 1s', lambda x: '', |
1439 | + 'hierarchical order'), |
1440 | + area=('Area', lambda n: l[n][0], '%-24s', lambda x: '', |
1441 | + 'memory area'), |
1442 | + used=('Used', lambda n: l[n][1], '%10a', sum, |
1443 | + 'area in use'), |
1444 | + cache=('Cache', lambda n: l[n][2], '%10a', sum, |
1445 | + 'area used as reclaimable cache'), |
1446 | + noncache=('Noncache', lambda n: l[n][1] - l[n][2], '%10a', sum, |
1447 | + 'area not reclaimable')) |
1448 | + |
1449 | + columns = options.columns or 'area used cache noncache' |
1450 | + showtable(range(len(l)), fields, columns.split(), options.sort or 'order') |
1451 | + |
1452 | +def showfields(fields, f): |
1453 | + if f != list: |
1454 | + print "unknown field", f |
1455 | + print "known fields:" |
1456 | + for l in sorted(fields.keys()): |
1457 | + print "%-8s %s" % (l, fields[l][-1]) |
1458 | + |
1459 | +def showtable(rows, fields, columns, sort): |
1460 | + header = "" |
1461 | + format = "" |
1462 | + formatter = [] |
1463 | + |
1464 | + if sort not in fields: |
1465 | + showfields(fields, sort) |
1466 | + sys.exit(-1) |
1467 | + |
1468 | + if options.pie: |
1469 | + columns.append(options.pie) |
1470 | + if options.bar: |
1471 | + columns.append(options.bar) |
1472 | + |
1473 | + mt = totalmem() |
1474 | + st = memory()['swaptotal'] |
1475 | + |
1476 | + for n in columns: |
1477 | + if n not in fields: |
1478 | + showfields(fields, n) |
1479 | + sys.exit(-1) |
1480 | + |
1481 | + f = fields[n][2] |
1482 | + if 'a' in f: |
1483 | + if n == 'swap': |
1484 | + formatter.append(lambda x: showamount(x, st)) |
1485 | + else: |
1486 | + formatter.append(lambda x: showamount(x, mt)) |
1487 | + f = f.replace('a', 's') |
1488 | + else: |
1489 | + formatter.append(lambda x: x) |
1490 | + format += f + "\t" |
1491 | + header += f % fields[n][0] + "\t" |
1492 | + |
1493 | + l = [] |
1494 | + for n in rows: |
1495 | + r = [fields[c][1](n) for c in columns] |
1496 | + l.append((fields[sort][1](n), r)) |
1497 | + |
1498 | + l.sort(reverse=bool(options.reverse)) |
1499 | + |
1500 | + if options.pie: |
1501 | + showpie(l, sort) |
1502 | + return |
1503 | + elif options.bar: |
1504 | + showbar(l, columns, sort) |
1505 | + return |
1506 | + |
1507 | + if not options.no_header: |
1508 | + print header |
1509 | + |
1510 | + for k,r in l: |
1511 | + print format % tuple([f(v) for f,v in zip(formatter, r)]) |
1512 | + |
1513 | + if options.totals: |
1514 | + # totals |
1515 | + t = [] |
1516 | + for c in columns: |
1517 | + f = fields[c][3] |
1518 | + if f: |
1519 | + t.append(f([fields[c][1](n) for n in rows])) |
1520 | + else: |
1521 | + t.append("") |
1522 | + |
1523 | + print "-" * len(header) |
1524 | + print format % tuple([f(v) for f,v in zip(formatter, t)]) |
1525 | + |
1526 | +def showpie(l, sort): |
1527 | + try: |
1528 | + import pylab |
1529 | + except ImportError: |
1530 | + sys.stderr.write("pie chart requires matplotlib\n") |
1531 | + sys.exit(-1) |
1532 | + |
1533 | + if (l[0][0] < l[-1][0]): |
1534 | + l.reverse() |
1535 | + |
1536 | + labels = [r[1][-1] for r in l] |
1537 | + values = [r[0] for r in l] # sort field |
1538 | + |
1539 | + tm = totalmem() |
1540 | + s = sum(values) |
1541 | + unused = tm - s |
1542 | + t = 0 |
1543 | + while values and (t + values[-1] < (tm * .02) or |
1544 | + values[-1] < (tm * .005)): |
1545 | + t += values.pop() |
1546 | + labels.pop() |
1547 | + |
1548 | + if t: |
1549 | + values.append(t) |
1550 | + labels.append('other') |
1551 | + |
1552 | + explode = [0] * len(values) |
1553 | + if unused > 0: |
1554 | + values.insert(0, unused) |
1555 | + labels.insert(0, 'unused') |
1556 | + explode.insert(0, .05) |
1557 | + |
1558 | + pylab.figure(1, figsize=(6,6)) |
1559 | + ax = pylab.axes([0.1, 0.1, 0.8, 0.8]) |
1560 | + pylab.pie(values, explode = explode, labels=labels, |
1561 | + autopct="%.2f%%", shadow=True) |
1562 | + pylab.title('%s by %s' % (options.pie, sort)) |
1563 | + pylab.show() |
1564 | + |
1565 | +def showbar(l, columns, sort): |
1566 | + try: |
1567 | + import pylab, numpy |
1568 | + except ImportError: |
1569 | + sys.stderr.write("bar chart requires matplotlib\n") |
1570 | + sys.exit(-1) |
1571 | + |
1572 | + if (l[0][0] < l[-1][0]): |
1573 | + l.reverse() |
1574 | + |
1575 | + rc = [] |
1576 | + key = [] |
1577 | + for n in range(len(columns) - 1): |
1578 | + try: |
1579 | + if columns[n] in 'pid user group'.split(): |
1580 | + continue |
1581 | + float(l[0][1][n]) |
1582 | + rc.append(n) |
1583 | + key.append(columns[n]) |
1584 | + except: |
1585 | + pass |
1586 | + |
1587 | + width = 1.0 / (len(rc) + 1) |
1588 | + offset = width / 2 |
1589 | + |
1590 | + def gc(n): |
1591 | + return 'bgrcmyw'[n % 7] |
1592 | + |
1593 | + pl = [] |
1594 | + ind = numpy.arange(len(l)) |
1595 | + for n in xrange(len(rc)): |
1596 | + pl.append(pylab.bar(ind + offset + width * n, |
1597 | + [x[1][rc[n]] for x in l], width, color=gc(n))) |
1598 | + |
1599 | + #plt.xticks(ind + .5, ) |
1600 | + pylab.gca().set_xticks(ind + .5) |
1601 | + pylab.gca().set_xticklabels([x[1][-1] for x in l], rotation=45) |
1602 | + pylab.legend([p[0] for p in pl], key) |
1603 | + pylab.show() |
1604 | + |
1605 | + |
1606 | +parser = optparse.OptionParser("%prog [options]") |
1607 | +parser.add_option("-H", "--no-header", action="store_true", |
1608 | + help="disable header line") |
1609 | +parser.add_option("-c", "--columns", type="str", |
1610 | + help="columns to show") |
1611 | +parser.add_option("-t", "--totals", action="store_true", |
1612 | + help="show totals") |
1613 | + |
1614 | +parser.add_option("-R", "--realmem", type="str", |
1615 | + help="amount of physical RAM") |
1616 | +parser.add_option("-K", "--kernel", type="str", |
1617 | + help="path to kernel image") |
1618 | + |
1619 | +parser.add_option("-m", "--mappings", action="store_true", |
1620 | + help="show mappings") |
1621 | +parser.add_option("-u", "--users", action="store_true", |
1622 | + help="show users") |
1623 | +parser.add_option("-w", "--system", action="store_true", |
1624 | + help="show whole system") |
1625 | + |
1626 | +parser.add_option("-P", "--processfilter", type="str", |
1627 | + help="process filter regex") |
1628 | +parser.add_option("-M", "--mapfilter", type="str", |
1629 | + help="map filter regex") |
1630 | +parser.add_option("-U", "--userfilter", type="str", |
1631 | + help="user filter regex") |
1632 | + |
1633 | +parser.add_option("-n", "--numeric", action="store_true", |
1634 | + help="numeric output") |
1635 | +parser.add_option("-s", "--sort", type="str", |
1636 | + help="field to sort on") |
1637 | +parser.add_option("-r", "--reverse", action="store_true", |
1638 | + help="reverse sort") |
1639 | + |
1640 | +parser.add_option("-p", "--percent", action="store_true", |
1641 | + help="show percentage") |
1642 | +parser.add_option("-k", "--abbreviate", action="store_true", |
1643 | + help="show unit suffixes") |
1644 | + |
1645 | +parser.add_option("", "--pie", type='str', |
1646 | + help="show pie graph") |
1647 | +parser.add_option("", "--bar", type='str', |
1648 | + help="show bar graph") |
1649 | + |
1650 | +parser.add_option("-S", "--source", type="str", |
1651 | + help="/proc data source") |
1652 | + |
1653 | + |
1654 | +defaults = {} |
1655 | +parser.set_defaults(**defaults) |
1656 | +(options, args) = parser.parse_args() |
1657 | + |
1658 | +try: |
1659 | + src = tardata(options.source) |
1660 | +except: |
1661 | + src = procdata(options.source) |
1662 | + |
1663 | +try: |
1664 | + if options.mappings: |
1665 | + showmaps() |
1666 | + elif options.users: |
1667 | + showusers() |
1668 | + elif options.system: |
1669 | + showsystem() |
1670 | + else: |
1671 | + showpids() |
1672 | +except IOError, e: |
1673 | + if e.errno == errno.EPIPE: |
1674 | + pass |
1675 | +except KeyboardInterrupt: |
1676 | + pass |
1677 | |
1678 | === added directory 'memevent/ubuntu_test_cases/memory_usage_measurement/tests' |
1679 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/tests/__init__.py' |
1680 | --- memevent/ubuntu_test_cases/memory_usage_measurement/tests/__init__.py 1970-01-01 00:00:00 +0000 |
1681 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/tests/__init__.py 2013-08-29 18:33:39 +0000 |
1682 | @@ -0,0 +1,1 @@ |
1683 | +"""Event based memory usage measurements test cases.""" |
1684 | |
1685 | === added file 'memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_memory_usage.py' |
1686 | --- memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_memory_usage.py 1970-01-01 00:00:00 +0000 |
1687 | +++ memevent/ubuntu_test_cases/memory_usage_measurement/tests/test_memory_usage.py 2013-08-29 18:33:39 +0000 |
1688 | @@ -0,0 +1,79 @@ |
1689 | +"""Measure touch applications memory usage.""" |
1690 | + |
1691 | +import json |
1692 | +import logging |
1693 | + |
1694 | +from autopilot.testcase import AutopilotTestCase |
1695 | + |
1696 | +from ubuntu_test_cases.memory_usage_measurement.apps.browser import BrowserApp |
1697 | +from ubuntu_test_cases.memory_usage_measurement.apps.camera import CameraApp |
1698 | +from ubuntu_test_cases.memory_usage_measurement.apps.gallery import GalleryApp |
1699 | +from ubuntu_test_cases.memory_usage_measurement.apps.media_player import ( |
1700 | + MediaPlayerApp, |
1701 | +) |
1702 | +from ubuntu_test_cases.memory_usage_measurement.probes import SmemProbe |
1703 | + |
1704 | +LOGGER = logging.getLogger(__file__) |
1705 | + |
1706 | + |
1707 | +class MemoryUsageTests(AutopilotTestCase): |
1708 | + |
1709 | + """Event based memory usage measurement scenario.""" |
1710 | + |
1711 | + def test_scenario(self): |
1712 | + """Scenario that takes measurements on some events.""" |
1713 | + self.smem = SmemProbe() |
1714 | + |
1715 | + # Make sure report is written with the data collected |
1716 | + # even if the test failed to complete |
1717 | + self.addCleanup(self._write_report) |
1718 | + |
1719 | + browser = BrowserApp(self) |
1720 | + with self.smem.probe('Browser started'): |
1721 | + browser.launch() |
1722 | + self.smem.pids.append(browser.app.pid) |
1723 | + |
1724 | + with self.smem.probe('Browser finished loading'): |
1725 | + url = 'http://www.cnn.com/' |
1726 | + browser.go_to_url(url) |
1727 | + browser.assert_page_eventually_loaded(url) |
1728 | + |
1729 | + camera = CameraApp(self) |
1730 | + with self.smem.probe('Camera app started'): |
1731 | + camera.launch() |
1732 | + self.smem.pids.append(camera.app.pid) |
1733 | + |
1734 | + with self.smem.probe('Camera app picture taken'): |
1735 | + camera.take_picture() |
1736 | + |
1737 | + with self.smem.probe('Gallery app started'): |
1738 | + gallery = GalleryApp(self) |
1739 | + gallery.launch() |
1740 | + self.smem.pids.append(gallery.app.pid) |
1741 | + |
1742 | + with self.smem.probe('Media player app started'): |
1743 | + media_player = MediaPlayerApp(self) |
1744 | + media_player.launch() |
1745 | + self.smem.pids.append(media_player.app.pid) |
1746 | + |
1747 | + with self.smem.probe('Media player app finished playback'): |
1748 | + media_player = MediaPlayerApp(self) |
1749 | + media_player.launch('small.mp4') |
1750 | + self.smem.pids.append(media_player.app.pid) |
1751 | + media_player.assert_playback_finished() |
1752 | + |
1753 | + summary_msg = '\n'.join( |
1754 | + ['- {}: {}'.format(event, pids) |
1755 | + for event, pids in self.smem.threshold_exceeded_summary]) |
1756 | + self.assertListEqual( |
1757 | + self.smem.threshold_exceeded_summary, |
1758 | + [], |
1759 | + 'Threshold(s) exceded:\n{}'.format(summary_msg)) |
1760 | + |
1761 | + def _write_report(self): |
1762 | + """Write report to to results directory.""" |
1763 | + report_filename = '/var/cache/utah-probes/memory_usage.json' |
1764 | + with open(report_filename, 'w') as report_file: |
1765 | + json.dump(self.smem.report, report_file, |
1766 | + indent=4, sort_keys=True) |
1767 | + LOGGER.debug('Report written to {}'.format(report_file.name)) |
1768 | |
1769 | === added directory 'messaging-app-autopilot' |
1770 | === added file 'messaging-app-autopilot/master.run' |
1771 | --- messaging-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
1772 | +++ messaging-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
1773 | @@ -0,0 +1,15 @@ |
1774 | +--- |
1775 | +testsuites: |
1776 | + - name: settle-before |
1777 | + fetch_method: dev |
1778 | + fetch_location: ../systemsettle |
1779 | + include_tests: |
1780 | + - systemsettle-before |
1781 | + - name: messaging-app-autopilot |
1782 | + fetch_method: dev |
1783 | + fetch_location: ./ |
1784 | + - name: settle-after |
1785 | + fetch_method: dev |
1786 | + fetch_location: ../systemsettle |
1787 | + include_tests: |
1788 | + - systemsettle-after |
1789 | |
1790 | === added file 'messaging-app-autopilot/ts_control' |
1791 | --- messaging-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
1792 | +++ messaging-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
1793 | @@ -0,0 +1,1 @@ |
1794 | +ts_setup: PKGS="messaging-app-autopilot ubuntu-ui-toolkit-autopilot" prepare-autopilot-test.sh |
1795 | |
1796 | === added file 'messaging-app-autopilot/tslist.auto' |
1797 | --- messaging-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
1798 | +++ messaging-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
1799 | @@ -0,0 +1,4 @@ |
1800 | +- |
1801 | + discovery_cmd: autopilot-list messaging_app |
1802 | + test_cmd: autopilot-run messaging_app.tests.{} |
1803 | + |
1804 | |
1805 | === added directory 'music-app-autopilot' |
1806 | === added file 'music-app-autopilot/master.run' |
1807 | --- music-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
1808 | +++ music-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
1809 | @@ -0,0 +1,15 @@ |
1810 | +--- |
1811 | +testsuites: |
1812 | + - name: settle-before |
1813 | + fetch_method: dev |
1814 | + fetch_location: ../systemsettle |
1815 | + include_tests: |
1816 | + - systemsettle-before |
1817 | + - name: music-app-autopilot |
1818 | + fetch_method: dev |
1819 | + fetch_location: ./ |
1820 | + - name: settle-after |
1821 | + fetch_method: dev |
1822 | + fetch_location: ../systemsettle |
1823 | + include_tests: |
1824 | + - systemsettle-after |
1825 | |
1826 | === added file 'music-app-autopilot/ts_control' |
1827 | --- music-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
1828 | +++ music-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
1829 | @@ -0,0 +1,1 @@ |
1830 | +ts_setup: PKGS=music-app-autopilot prepare-autopilot-test.sh |
1831 | |
1832 | === added file 'music-app-autopilot/tslist.auto' |
1833 | --- music-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
1834 | +++ music-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
1835 | @@ -0,0 +1,4 @@ |
1836 | +- |
1837 | + discovery_cmd: autopilot-list music_app |
1838 | + test_cmd: autopilot-run music_app.tests.{} |
1839 | + |
1840 | |
1841 | === added directory 'notes-app-autopilot' |
1842 | === added file 'notes-app-autopilot/master.run' |
1843 | --- notes-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
1844 | +++ notes-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
1845 | @@ -0,0 +1,15 @@ |
1846 | +--- |
1847 | +testsuites: |
1848 | + - name: settle-before |
1849 | + fetch_method: dev |
1850 | + fetch_location: ../systemsettle |
1851 | + include_tests: |
1852 | + - systemsettle-before |
1853 | + - name: notes-app-autopilot |
1854 | + fetch_method: dev |
1855 | + fetch_location: ./ |
1856 | + - name: settle-after |
1857 | + fetch_method: dev |
1858 | + fetch_location: ../systemsettle |
1859 | + include_tests: |
1860 | + - systemsettle-after |
1861 | |
1862 | === added file 'notes-app-autopilot/ts_control' |
1863 | --- notes-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
1864 | +++ notes-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
1865 | @@ -0,0 +1,1 @@ |
1866 | +ts_setup: PKGS=notes-app-autopilot prepare-autopilot-test.sh |
1867 | |
1868 | === added file 'notes-app-autopilot/tslist.auto' |
1869 | --- notes-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
1870 | +++ notes-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
1871 | @@ -0,0 +1,4 @@ |
1872 | +- |
1873 | + discovery_cmd: autopilot-list notes_app |
1874 | + test_cmd: autopilot-run notes_app.tests.{} |
1875 | + |
1876 | |
1877 | === added directory 'phone-app-connected-autopilot' |
1878 | === added file 'phone-app-connected-autopilot/master.run' |
1879 | --- phone-app-connected-autopilot/master.run 1970-01-01 00:00:00 +0000 |
1880 | +++ phone-app-connected-autopilot/master.run 2013-08-29 18:33:39 +0000 |
1881 | @@ -0,0 +1,5 @@ |
1882 | +--- |
1883 | +testsuites: |
1884 | + - name: phone-app-connected-autopilot |
1885 | + fetch_method: dev |
1886 | + fetch_location: ./ |
1887 | |
1888 | === added file 'phone-app-connected-autopilot/setup.sh' |
1889 | --- phone-app-connected-autopilot/setup.sh 1970-01-01 00:00:00 +0000 |
1890 | +++ phone-app-connected-autopilot/setup.sh 2013-08-29 18:33:39 +0000 |
1891 | @@ -0,0 +1,36 @@ |
1892 | +#!/bin/sh |
1893 | + |
1894 | +set -ex |
1895 | + |
1896 | +# we have issues with running the test too soon, this is a hack: |
1897 | +echo "SLEEPING 60 TO HELP MAKE SURE PHONE IS READY" |
1898 | +sleep 60 |
1899 | + |
1900 | + |
1901 | +if [ -z $ANDROID_SERIAL ] ; then |
1902 | + # set up the config file for the test |
1903 | + NUMBER=$(./sms_self.py --list) |
1904 | + cat ./testnumbers.cfg | sed -e "s/TODO/+$NUMBER/" > /home/phablet/.testnumbers.cfg |
1905 | + |
1906 | + # remove old logs so the receive test will work |
1907 | + rm /home/phablet/.local/share/TpLogger/logs/ofono_ofono_account0/* -rf |
1908 | + |
1909 | + # now send an sms to ourself |
1910 | + ./sms_self.py |
1911 | +else |
1912 | + echo "test running from host" |
1913 | + adb push ./sms_self.py /home/phablet/autopilot/ |
1914 | + |
1915 | + # set up the config file for the test |
1916 | + NUMBER=$(adb-shell /home/phablet/autopilot/sms_self.py --list | head -n1) |
1917 | + cat ./testnumbers.cfg | sed -e "s/TODO/+$NUMBER/" > .testnumbers.cfg |
1918 | + adb push .testnumbers.cfg /home/phablet/.testnumbers.cfg |
1919 | + rm .testnumbers.cfg |
1920 | + |
1921 | + # remove old logs so the receive test will work |
1922 | + adb-shell rm /home/phablet/.local/share/TpLogger/logs/ofono_ofono_account0/* -rf |
1923 | + adb-shell /home/phablet/autopilot/sms_self.py |
1924 | +fi |
1925 | + |
1926 | +sleep 10s # try and let the message come through |
1927 | +PKGS="phone-app-connected-autopilot" prepare-autopilot-test.sh |
1928 | |
1929 | === added file 'phone-app-connected-autopilot/sms_self.py' |
1930 | --- phone-app-connected-autopilot/sms_self.py 1970-01-01 00:00:00 +0000 |
1931 | +++ phone-app-connected-autopilot/sms_self.py 2013-08-29 18:33:39 +0000 |
1932 | @@ -0,0 +1,34 @@ |
1933 | +#!/usr/bin/env python |
1934 | + |
1935 | +import argparse |
1936 | +import dbus |
1937 | + |
1938 | + |
1939 | +def _get_parser(): |
1940 | + parser = argparse.ArgumentParser( |
1941 | + description='Send an SMS message to yourself via the ofono API') |
1942 | + parser.add_argument('-m', '--modem', default='/ril_0', |
1943 | + help='The modem to use. Default: %(default)s') |
1944 | + parser.add_argument('message', nargs='?', default='hello world', |
1945 | + help='Message to send. Default "%(default)s"') |
1946 | + parser.add_argument('--list', action='store_true', |
1947 | + help='Just print the number of this cell phone.') |
1948 | + return parser |
1949 | + |
1950 | + |
1951 | +def _main(args): |
1952 | + bus = dbus.SystemBus() |
1953 | + obj = bus.get_object('org.ofono', args.modem) |
1954 | + |
1955 | + mgr = dbus.Interface(obj, 'org.ofono.SimManager') |
1956 | + local_sms = str(mgr.GetProperties()['SubscriberNumbers'][0]) |
1957 | + |
1958 | + if args.list: |
1959 | + print local_sms |
1960 | + else: |
1961 | + mgr = dbus.Interface(obj, 'org.ofono.MessageManager') |
1962 | + mgr.SendMessage(local_sms, args.message) |
1963 | + |
1964 | + |
1965 | +if __name__ == '__main__': |
1966 | + _main(_get_parser().parse_args()) |
1967 | |
1968 | === added file 'phone-app-connected-autopilot/testnumbers.cfg' |
1969 | --- phone-app-connected-autopilot/testnumbers.cfg 1970-01-01 00:00:00 +0000 |
1970 | +++ phone-app-connected-autopilot/testnumbers.cfg 2013-08-29 18:33:39 +0000 |
1971 | @@ -0,0 +1,23 @@ |
1972 | +[connected_variables] |
1973 | + |
1974 | +#number to dial |
1975 | +dial_number = 77777 |
1976 | + |
1977 | +#number to send sms to (doanac's google voice) |
1978 | +sms_send_number = 4322350086 |
1979 | + |
1980 | +#expected to receive sms from |
1981 | +sms_receive_num = TODO |
1982 | + |
1983 | +#time (in seconds) allowed for the outgoing call |
1984 | +outgoing_call_duration = 20 |
1985 | + |
1986 | +#time (in seconds) to wait till the call is not received |
1987 | +call_wait_time = 2 |
1988 | + |
1989 | +#text to send in the sms |
1990 | +sms_send_text = Hey there |
1991 | + |
1992 | +#expected text to be received in sms |
1993 | +sms_expect_text = Ubuntu Rocks |
1994 | + |
1995 | |
1996 | === added file 'phone-app-connected-autopilot/ts_control' |
1997 | --- phone-app-connected-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
1998 | +++ phone-app-connected-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
1999 | @@ -0,0 +1,1 @@ |
2000 | +ts_setup: sh ./setup.sh |
2001 | |
2002 | === added file 'phone-app-connected-autopilot/tslist.auto' |
2003 | --- phone-app-connected-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2004 | +++ phone-app-connected-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2005 | @@ -0,0 +1,4 @@ |
2006 | +- |
2007 | + discovery_cmd: autopilot-list connected_tests test_communication_panel |
2008 | + test_cmd: autopilot-run connected_tests.tests.{} |
2009 | + |
2010 | |
2011 | === added directory 'share-app-autopilot' |
2012 | === added file 'share-app-autopilot/master.run' |
2013 | --- share-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2014 | +++ share-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
2015 | @@ -0,0 +1,15 @@ |
2016 | +--- |
2017 | +testsuites: |
2018 | + - name: settle-before |
2019 | + fetch_method: dev |
2020 | + fetch_location: ../systemsettle |
2021 | + include_tests: |
2022 | + - systemsettle-before |
2023 | + - name: share-app-autopilot |
2024 | + fetch_method: dev |
2025 | + fetch_location: ./ |
2026 | + - name: settle-after |
2027 | + fetch_method: dev |
2028 | + fetch_location: ../systemsettle |
2029 | + include_tests: |
2030 | + - systemsettle-after |
2031 | |
2032 | === added file 'share-app-autopilot/ts_control' |
2033 | --- share-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2034 | +++ share-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
2035 | @@ -0,0 +1,1 @@ |
2036 | +ts_setup: PKGS=share-app-autopilot prepare-autopilot-test.sh |
2037 | |
2038 | === added file 'share-app-autopilot/tslist.auto' |
2039 | --- share-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2040 | +++ share-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2041 | @@ -0,0 +1,4 @@ |
2042 | +- |
2043 | + discovery_cmd: autopilot-list share_app |
2044 | + test_cmd: autopilot-run share_app.tests.{} |
2045 | + |
2046 | |
2047 | === added directory 'systemsettle' |
2048 | === added directory 'systemsettle/systemsettle-after' |
2049 | === added file 'systemsettle/systemsettle-after/tc_control' |
2050 | --- systemsettle/systemsettle-after/tc_control 1970-01-01 00:00:00 +0000 |
2051 | +++ systemsettle/systemsettle-after/tc_control 2013-08-29 18:33:39 +0000 |
2052 | @@ -0,0 +1,9 @@ |
2053 | +description: check if system settles to idle average > 99.25% |
2054 | +dependencies: none |
2055 | +action: | |
2056 | + 1. Take CPU load samples for 10s, do this up to 10 times until idle is over 99% |
2057 | +expected_results: | |
2058 | + 1. When doing nothing, system calms down to at least 99% idle level |
2059 | +type: userland |
2060 | +timeout: 120 |
2061 | +command: ../systemsettle.sh -c5 -d2 -p 97.5 -l _after |
2062 | |
2063 | === added directory 'systemsettle/systemsettle-before' |
2064 | === added file 'systemsettle/systemsettle-before/tc_control' |
2065 | --- systemsettle/systemsettle-before/tc_control 1970-01-01 00:00:00 +0000 |
2066 | +++ systemsettle/systemsettle-before/tc_control 2013-08-29 18:33:39 +0000 |
2067 | @@ -0,0 +1,9 @@ |
2068 | +description: check if system settles to idle average > 99.25% |
2069 | +dependencies: none |
2070 | +action: | |
2071 | + 1. Take CPU load samples for 10s, do this up to 10 times until idle is over 99% |
2072 | +expected_results: | |
2073 | + 1. When doing nothing, system calms down to at least 99% idle level |
2074 | +type: userland |
2075 | +timeout: 120 |
2076 | +command: ../systemsettle.sh -c5 -d2 -p 97.5 -l _before |
2077 | |
2078 | === added file 'systemsettle/systemsettle.sh' |
2079 | --- systemsettle/systemsettle.sh 1970-01-01 00:00:00 +0000 |
2080 | +++ systemsettle/systemsettle.sh 2013-08-29 18:33:39 +0000 |
2081 | @@ -0,0 +1,119 @@ |
2082 | +#!/bin/bash |
2083 | + |
2084 | +# Configuration variables: |
2085 | +# TARGET_PREFIX - Allows this to be run from the host, by providings something |
2086 | +# like TARGET_PREFIX="adb shell" |
2087 | +# UTAH_PROBE_DIR - optionally where to save log files so utah will grab them |
2088 | + |
2089 | +set -e |
2090 | + |
2091 | +[ -z $UTAH_PROBE_DIR ] && UTAH_PROBE_DIR="/tmp" |
2092 | + |
2093 | +# default exit code storage |
2094 | +dump_error=1 |
2095 | + |
2096 | +calc () { awk "BEGIN{ print $* }" ;} |
2097 | + |
2098 | +function show_usage() { |
2099 | + echo "Usage:" |
2100 | + echo " $0 [options]" |
2101 | + echo "Options:" |
2102 | + echo " -r run forever without exiting" |
2103 | + echo " -p minimum idle percent to wait for (Default: 99)" |
2104 | + echo " -c number of times to run top at each iteration (Default: 10)" |
2105 | + echo " -d seconds to delay between each top iteration (Default: 6)" |
2106 | + echo " -i top measurements to ignore from each loop (Default: 1)" |
2107 | + echo " -m maximum loops of top before giving up if minimum idle" |
2108 | + echo " percent is not reached (Default: 10)" |
2109 | + echo " -l label to include for the top_log file" |
2110 | + exit 129 |
2111 | +} |
2112 | + |
2113 | +while getopts "h?rp:c:d:i:m:l:" opt; do |
2114 | + case "$opt" in |
2115 | + h|\?) show_usage |
2116 | + ;; |
2117 | + r) settle_prefix='-' |
2118 | + ;; |
2119 | + p) idle_avg_min=$OPTARG |
2120 | + ;; |
2121 | + c) top_repeat=$OPTARG |
2122 | + ;; |
2123 | + d) top_wait=$OPTARG |
2124 | + ;; |
2125 | + i) top_ignore=$OPTARG |
2126 | + ;; |
2127 | + m) settle_max=$OPTARG |
2128 | + ;; |
2129 | + l) top_log_label=$OPTARG |
2130 | + ;; |
2131 | + esac |
2132 | +done |
2133 | + |
2134 | +# minimum average idle level required to succeed |
2135 | +idle_avg_min=${idle_avg_min:-99} |
2136 | +# measurement details: top $top_wait $top_repeat |
2137 | +top_repeat=${top_repeat:-10} |
2138 | +top_wait=${top_wait:-6} |
2139 | +# how many samples to ignore |
2140 | +top_ignore=${top_ignore:-1} |
2141 | +# how many total attempts to settle the system |
2142 | +settle_max=${settle_max:-10} |
2143 | + |
2144 | +top_log="$UTAH_PROBE_DIR/top$top_log_label.log" |
2145 | + |
2146 | +# set and calc more runtime values |
2147 | +top_tail=`calc $top_repeat - $top_ignore` |
2148 | +settle_count=0 |
2149 | +idle_avg=0 |
2150 | + |
2151 | +echo "System Settle run - quiesce the system" |
2152 | +echo "--------------------------------------" |
2153 | +echo |
2154 | +echo " idle_avg_min = '$idle_avg_min'" |
2155 | +echo " top_repeat = '$top_repeat'" |
2156 | +echo " top_wait = '$top_wait'" |
2157 | +echo " top_ignore = '$top_ignore'" |
2158 | +echo " settle_max = '$settle_max'" |
2159 | +echo " run_forever = '$settle_prefix' (- = yes)" |
2160 | +echo " log files = $top_log $top_log.reduced" |
2161 | +echo |
2162 | + |
2163 | +while test `calc $idle_avg '<' $idle_avg_min` = 1 -a "$settle_prefix$settle_count" -lt "$settle_max"; do |
2164 | + echo -n "Starting system idle measurement (run: $settle_count) ... " |
2165 | + |
2166 | + # get top |
2167 | + echo "TOP DUMP (after settle run: $settle_count)" >> $top_log |
2168 | + echo "========================" >> $top_log |
2169 | + ${TARGET_PREFIX} top -b -d $top_wait -n $top_repeat >> $top_log |
2170 | + cat $top_log | grep '.Cpu.*' | tail -n $top_tail > $top_log.reduced |
2171 | + echo >> $top_log |
2172 | + |
2173 | + # calc average of idle field for this measurement |
2174 | + sum=0 |
2175 | + count=0 |
2176 | + while read line; do |
2177 | + idle=`echo $line | sed -e 's/.* \([0-9\.]*\) id.*/\1/'` |
2178 | + sum=`calc $sum + $idle` |
2179 | + count=`calc $count + 1` |
2180 | + done < $top_log.reduced |
2181 | + |
2182 | + idle_avg=`calc $sum / $count` |
2183 | + settle_count=`calc $settle_count + 1` |
2184 | + |
2185 | + echo " DONE." |
2186 | + echo |
2187 | + echo "Measurement:" |
2188 | + echo " + idle level: $idle_avg" |
2189 | + echo " + idle sum: $sum / count: $count" |
2190 | + echo |
2191 | +done |
2192 | + |
2193 | +if test `calc $idle_avg '<' $idle_avg_min` = 1; then |
2194 | + echo "system not settled. FAIL" |
2195 | + exit 1 |
2196 | +else |
2197 | + echo "system settled. SUCCESS" |
2198 | + exit 0 |
2199 | +fi |
2200 | + |
2201 | |
2202 | === added file 'systemsettle/tslist.run' |
2203 | --- systemsettle/tslist.run 1970-01-01 00:00:00 +0000 |
2204 | +++ systemsettle/tslist.run 2013-08-29 18:33:39 +0000 |
2205 | @@ -0,0 +1,2 @@ |
2206 | +- test: systemsettle-before |
2207 | +- test: systemsettle-after |
2208 | |
2209 | === added directory 'ubuntu-calculator-app-autopilot' |
2210 | === added file 'ubuntu-calculator-app-autopilot/master.run' |
2211 | --- ubuntu-calculator-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2212 | +++ ubuntu-calculator-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
2213 | @@ -0,0 +1,15 @@ |
2214 | +--- |
2215 | +testsuites: |
2216 | + - name: settle-before |
2217 | + fetch_method: dev |
2218 | + fetch_location: ../systemsettle |
2219 | + include_tests: |
2220 | + - systemsettle-before |
2221 | + - name: ubuntu-calculator-app-autopilot |
2222 | + fetch_method: dev |
2223 | + fetch_location: ./ |
2224 | + - name: settle-after |
2225 | + fetch_method: dev |
2226 | + fetch_location: ../systemsettle |
2227 | + include_tests: |
2228 | + - systemsettle-after |
2229 | |
2230 | === added file 'ubuntu-calculator-app-autopilot/ts_control' |
2231 | --- ubuntu-calculator-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2232 | +++ ubuntu-calculator-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
2233 | @@ -0,0 +1,1 @@ |
2234 | +ts_setup: PKGS=ubuntu-calculator-app-autopilot prepare-autopilot-test.sh |
2235 | |
2236 | === added file 'ubuntu-calculator-app-autopilot/tslist.auto' |
2237 | --- ubuntu-calculator-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2238 | +++ ubuntu-calculator-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2239 | @@ -0,0 +1,4 @@ |
2240 | +- |
2241 | + discovery_cmd: autopilot-list ubuntu_calculator_app |
2242 | + test_cmd: autopilot-run ubuntu_calculator_app.tests.{} |
2243 | + |
2244 | |
2245 | === added directory 'ubuntu-clock-app-autopilot' |
2246 | === added file 'ubuntu-clock-app-autopilot/master.run' |
2247 | --- ubuntu-clock-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2248 | +++ ubuntu-clock-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
2249 | @@ -0,0 +1,15 @@ |
2250 | +--- |
2251 | +testsuites: |
2252 | + - name: settle-before |
2253 | + fetch_method: dev |
2254 | + fetch_location: ../systemsettle |
2255 | + include_tests: |
2256 | + - systemsettle-before |
2257 | + - name: ubuntu-clock-app-autopilot |
2258 | + fetch_method: dev |
2259 | + fetch_location: ./ |
2260 | + - name: settle-after |
2261 | + fetch_method: dev |
2262 | + fetch_location: ../systemsettle |
2263 | + include_tests: |
2264 | + - systemsettle-after |
2265 | |
2266 | === added file 'ubuntu-clock-app-autopilot/ts_control' |
2267 | --- ubuntu-clock-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2268 | +++ ubuntu-clock-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
2269 | @@ -0,0 +1,1 @@ |
2270 | +ts_setup: PKGS=ubuntu-clock-app-autopilot prepare-autopilot-test.sh |
2271 | |
2272 | === added file 'ubuntu-clock-app-autopilot/tslist.auto' |
2273 | --- ubuntu-clock-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2274 | +++ ubuntu-clock-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2275 | @@ -0,0 +1,4 @@ |
2276 | +- |
2277 | + discovery_cmd: autopilot-list ubuntu_clock_app |
2278 | + test_cmd: autopilot-run ubuntu_clock_app.tests.{} |
2279 | + |
2280 | |
2281 | === added directory 'ubuntu-docviewer-app-autopilot' |
2282 | === added file 'ubuntu-docviewer-app-autopilot/master.run' |
2283 | --- ubuntu-docviewer-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2284 | +++ ubuntu-docviewer-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
2285 | @@ -0,0 +1,15 @@ |
2286 | +--- |
2287 | +testsuites: |
2288 | + - name: settle-before |
2289 | + fetch_method: dev |
2290 | + fetch_location: ../systemsettle |
2291 | + include_tests: |
2292 | + - systemsettle-before |
2293 | + - name: ubuntu-docviewer-app-autopilot |
2294 | + fetch_method: dev |
2295 | + fetch_location: ./ |
2296 | + - name: settle-after |
2297 | + fetch_method: dev |
2298 | + fetch_location: ../systemsettle |
2299 | + include_tests: |
2300 | + - systemsettle-after |
2301 | |
2302 | === added file 'ubuntu-docviewer-app-autopilot/ts_control' |
2303 | --- ubuntu-docviewer-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2304 | +++ ubuntu-docviewer-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
2305 | @@ -0,0 +1,1 @@ |
2306 | +ts_setup: PKGS=ubuntu-docviewer-app-autopilot prepare-autopilot-test.sh |
2307 | |
2308 | === added file 'ubuntu-docviewer-app-autopilot/tslist.auto' |
2309 | --- ubuntu-docviewer-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2310 | +++ ubuntu-docviewer-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2311 | @@ -0,0 +1,4 @@ |
2312 | +- |
2313 | + discovery_cmd: autopilot-list ubuntu_docviewer_app |
2314 | + test_cmd: autopilot-run ubuntu_docviewer_app.tests.{} |
2315 | + |
2316 | |
2317 | === added directory 'ubuntu-filemanager-app-autopilot' |
2318 | === added file 'ubuntu-filemanager-app-autopilot/master.run' |
2319 | --- ubuntu-filemanager-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2320 | +++ ubuntu-filemanager-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
2321 | @@ -0,0 +1,15 @@ |
2322 | +--- |
2323 | +testsuites: |
2324 | + - name: settle-before |
2325 | + fetch_method: dev |
2326 | + fetch_location: ../systemsettle |
2327 | + include_tests: |
2328 | + - systemsettle-before |
2329 | + - name: ubuntu-filemanager-app-autopilot |
2330 | + fetch_method: dev |
2331 | + fetch_location: ./ |
2332 | + - name: settle-after |
2333 | + fetch_method: dev |
2334 | + fetch_location: ../systemsettle |
2335 | + include_tests: |
2336 | + - systemsettle-after |
2337 | |
2338 | === added file 'ubuntu-filemanager-app-autopilot/ts_control' |
2339 | --- ubuntu-filemanager-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2340 | +++ ubuntu-filemanager-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
2341 | @@ -0,0 +1,1 @@ |
2342 | +ts_setup: PKGS=ubuntu-filemanager-app-autopilot prepare-autopilot-test.sh |
2343 | |
2344 | === added file 'ubuntu-filemanager-app-autopilot/tslist.auto' |
2345 | --- ubuntu-filemanager-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2346 | +++ ubuntu-filemanager-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2347 | @@ -0,0 +1,4 @@ |
2348 | +- |
2349 | + discovery_cmd: autopilot-list ubuntu_filemanager_app |
2350 | + test_cmd: autopilot-run ubuntu_filemanager_app.tests.{} |
2351 | + |
2352 | |
2353 | === added directory 'ubuntu-rssreader-app-autopilot' |
2354 | === added file 'ubuntu-rssreader-app-autopilot/master.run' |
2355 | --- ubuntu-rssreader-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2356 | +++ ubuntu-rssreader-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
2357 | @@ -0,0 +1,15 @@ |
2358 | +--- |
2359 | +testsuites: |
2360 | + - name: settle-before |
2361 | + fetch_method: dev |
2362 | + fetch_location: ../systemsettle |
2363 | + include_tests: |
2364 | + - systemsettle-before |
2365 | + - name: ubuntu-rssreader-app-autopilot |
2366 | + fetch_method: dev |
2367 | + fetch_location: ./ |
2368 | + - name: settle-after |
2369 | + fetch_method: dev |
2370 | + fetch_location: ../systemsettle |
2371 | + include_tests: |
2372 | + - systemsettle-after |
2373 | |
2374 | === added file 'ubuntu-rssreader-app-autopilot/ts_control' |
2375 | --- ubuntu-rssreader-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2376 | +++ ubuntu-rssreader-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
2377 | @@ -0,0 +1,1 @@ |
2378 | +ts_setup: PKGS=ubuntu-rssreader-app-autopilot prepare-autopilot-test.sh |
2379 | |
2380 | === added file 'ubuntu-rssreader-app-autopilot/tslist.auto' |
2381 | --- ubuntu-rssreader-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2382 | +++ ubuntu-rssreader-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2383 | @@ -0,0 +1,4 @@ |
2384 | +- |
2385 | + discovery_cmd: autopilot-list ubuntu_rssreader_app |
2386 | + test_cmd: autopilot-run ubuntu_rssreader_app.tests.{} |
2387 | + |
2388 | |
2389 | === added directory 'ubuntu-terminal-app-autopilot' |
2390 | === added file 'ubuntu-terminal-app-autopilot/master.run' |
2391 | --- ubuntu-terminal-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2392 | +++ ubuntu-terminal-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
2393 | @@ -0,0 +1,15 @@ |
2394 | +--- |
2395 | +testsuites: |
2396 | + - name: settle-before |
2397 | + fetch_method: dev |
2398 | + fetch_location: ../systemsettle |
2399 | + include_tests: |
2400 | + - systemsettle-before |
2401 | + - name: ubuntu-terminal-app-autopilot |
2402 | + fetch_method: dev |
2403 | + fetch_location: ./ |
2404 | + - name: settle-after |
2405 | + fetch_method: dev |
2406 | + fetch_location: ../systemsettle |
2407 | + include_tests: |
2408 | + - systemsettle-after |
2409 | |
2410 | === added file 'ubuntu-terminal-app-autopilot/ts_control' |
2411 | --- ubuntu-terminal-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2412 | +++ ubuntu-terminal-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
2413 | @@ -0,0 +1,1 @@ |
2414 | +ts_setup: PKGS=ubuntu-terminal-app-autopilot prepare-autopilot-test.sh |
2415 | |
2416 | === added file 'ubuntu-terminal-app-autopilot/tslist.auto' |
2417 | --- ubuntu-terminal-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2418 | +++ ubuntu-terminal-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2419 | @@ -0,0 +1,4 @@ |
2420 | +- |
2421 | + discovery_cmd: autopilot-list ubuntu_terminal_app |
2422 | + test_cmd: autopilot-run ubuntu_terminal_app.tests.{} |
2423 | + |
2424 | |
2425 | === added directory 'ubuntu-weather-app-autopilot' |
2426 | === added file 'ubuntu-weather-app-autopilot/master.run' |
2427 | --- ubuntu-weather-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2428 | +++ ubuntu-weather-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
2429 | @@ -0,0 +1,15 @@ |
2430 | +--- |
2431 | +testsuites: |
2432 | + - name: settle-before |
2433 | + fetch_method: dev |
2434 | + fetch_location: ../systemsettle |
2435 | + include_tests: |
2436 | + - systemsettle-before |
2437 | + - name: ubuntu-weather-app-autopilot |
2438 | + fetch_method: dev |
2439 | + fetch_location: ./ |
2440 | + - name: settle-after |
2441 | + fetch_method: dev |
2442 | + fetch_location: ../systemsettle |
2443 | + include_tests: |
2444 | + - systemsettle-after |
2445 | |
2446 | === added file 'ubuntu-weather-app-autopilot/ts_control' |
2447 | --- ubuntu-weather-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2448 | +++ ubuntu-weather-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
2449 | @@ -0,0 +1,1 @@ |
2450 | +ts_setup: PKGS=ubuntu-weather-app-autopilot prepare-autopilot-test.sh |
2451 | |
2452 | === added file 'ubuntu-weather-app-autopilot/tslist.auto' |
2453 | --- ubuntu-weather-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2454 | +++ ubuntu-weather-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2455 | @@ -0,0 +1,4 @@ |
2456 | +- |
2457 | + discovery_cmd: autopilot-list ubuntu_weather_app |
2458 | + test_cmd: autopilot-run ubuntu_weather_app.tests.{} |
2459 | + |
2460 | |
2461 | === added directory 'unity8-autopilot' |
2462 | === added file 'unity8-autopilot/master.run' |
2463 | --- unity8-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2464 | +++ unity8-autopilot/master.run 2013-08-29 18:33:39 +0000 |
2465 | @@ -0,0 +1,15 @@ |
2466 | +--- |
2467 | +testsuites: |
2468 | + - name: settle-before |
2469 | + fetch_method: dev |
2470 | + fetch_location: ../systemsettle |
2471 | + include_tests: |
2472 | + - systemsettle-before |
2473 | + - name: unity8-autopilot |
2474 | + fetch_method: dev |
2475 | + fetch_location: ./ |
2476 | + - name: settle-after |
2477 | + fetch_method: dev |
2478 | + fetch_location: ../systemsettle |
2479 | + include_tests: |
2480 | + - systemsettle-after |
2481 | |
2482 | === added file 'unity8-autopilot/setup.sh' |
2483 | --- unity8-autopilot/setup.sh 1970-01-01 00:00:00 +0000 |
2484 | +++ unity8-autopilot/setup.sh 2013-08-29 18:33:39 +0000 |
2485 | @@ -0,0 +1,6 @@ |
2486 | +#!/bin/sh |
2487 | + |
2488 | +set -e |
2489 | + |
2490 | +NO_UNLOCK=1 PKGS="unity8-autopilot" prepare-autopilot-test.sh |
2491 | +$TARGET_PREFIX sudo -i -u phablet stop unity8 |
2492 | |
2493 | === added file 'unity8-autopilot/ts_control' |
2494 | --- unity8-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2495 | +++ unity8-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
2496 | @@ -0,0 +1,2 @@ |
2497 | +ts_setup: TARGET_PREFIX=$TARGET_PREFIX ./setup.sh |
2498 | +ts_cleanup: $TARGET_PREFIX sudo -i -u phablet start unity8 |
2499 | |
2500 | === added file 'unity8-autopilot/tslist.auto' |
2501 | --- unity8-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2502 | +++ unity8-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2503 | @@ -0,0 +1,4 @@ |
2504 | +- |
2505 | + discovery_cmd: autopilot-list unity8 unity8 unity8. |
2506 | + test_cmd: autopilot-run unity8.{} |
2507 | + |
2508 | |
2509 | === added directory 'upgrade' |
2510 | === added file 'upgrade/README' |
2511 | --- upgrade/README 1970-01-01 00:00:00 +0000 |
2512 | +++ upgrade/README 2013-08-29 18:33:39 +0000 |
2513 | @@ -0,0 +1,3 @@ |
2514 | +NOTE: This test is intended to be run by UTAH using the "--from-host" |
2515 | +method. This is different from other tests in this repository and should |
2516 | +not be run with jenkins.sh |
2517 | |
2518 | === added directory 'upgrade/install_old' |
2519 | === added file 'upgrade/install_old/run.sh' |
2520 | --- upgrade/install_old/run.sh 1970-01-01 00:00:00 +0000 |
2521 | +++ upgrade/install_old/run.sh 2013-08-29 18:33:39 +0000 |
2522 | @@ -0,0 +1,27 @@ |
2523 | +#!/bin/bash |
2524 | + |
2525 | +## Puts an older build on the device |
2526 | +## Intersting environment variables that must be set: |
2527 | +## ANDROID_SERIAL - specify another android device |
2528 | +## NETWORK_FILE - specify an alternative network file |
2529 | +## UPGRADE_FROM - the revision to upgrade from, eg -1 |
2530 | + |
2531 | +set -eux |
2532 | + |
2533 | +BASEDIR=$(dirname $(readlink -f $0)) |
2534 | + |
2535 | +RESDIR=`pwd`/clientlogs |
2536 | + |
2537 | +UTAH_PHABLET_CMD="${UTAH_PHABLET_CMD-/usr/share/utah/examples/run_utah_phablet.py}" |
2538 | +ANDROID_SERIAL="${ANDROID_SERIAL-015d1884b20c1c0f}" #doanac's nexus7 at home |
2539 | +NETWORK_FILE="${NETWORK_FILE-/home/ubuntu/magners-wifi}" |
2540 | +UPGRADE_FROM="${UPGRADE_FROM--1}" |
2541 | +CLIENT_LOGS="${CLIENT_LOGS-/tmp}" |
2542 | + |
2543 | +echo "INSTALLING OLD BUILD..." |
2544 | +$UTAH_PHABLET_CMD -s $ANDROID_SERIAL \ |
2545 | + --ubuntu-bootstrap -r $UPGRADE_FROM \ |
2546 | + --network-file $NETWORK_FILE \ |
2547 | + --skip-utah \ |
2548 | + --pull /var/crash \ |
2549 | + --results-dir=${CLIENT_LOGS} |
2550 | |
2551 | === added file 'upgrade/install_old/tc_control' |
2552 | --- upgrade/install_old/tc_control 1970-01-01 00:00:00 +0000 |
2553 | +++ upgrade/install_old/tc_control 2013-08-29 18:33:39 +0000 |
2554 | @@ -0,0 +1,9 @@ |
2555 | +description: sets up a previous days build on the target |
2556 | +dependencies: n/a |
2557 | +action: | |
2558 | + 1. install an older system image |
2559 | +expected_results: | |
2560 | + 1. an older system image will be installed |
2561 | +type: userland |
2562 | +timeout: 1800 |
2563 | +command: ./run.sh |
2564 | |
2565 | === added file 'upgrade/master.run' |
2566 | --- upgrade/master.run 1970-01-01 00:00:00 +0000 |
2567 | +++ upgrade/master.run 2013-08-29 18:33:39 +0000 |
2568 | @@ -0,0 +1,5 @@ |
2569 | +--- |
2570 | +testsuites: |
2571 | + - name: upgrade |
2572 | + fetch_method: dev |
2573 | + fetch_location: ./ |
2574 | |
2575 | === added file 'upgrade/tslist.run' |
2576 | --- upgrade/tslist.run 1970-01-01 00:00:00 +0000 |
2577 | +++ upgrade/tslist.run 2013-08-29 18:33:39 +0000 |
2578 | @@ -0,0 +1,2 @@ |
2579 | +- test: install_old |
2580 | +- test: upgrade |
2581 | |
2582 | === added directory 'upgrade/upgrade' |
2583 | === added file 'upgrade/upgrade/tc_control' |
2584 | --- upgrade/upgrade/tc_control 1970-01-01 00:00:00 +0000 |
2585 | +++ upgrade/upgrade/tc_control 2013-08-29 18:33:39 +0000 |
2586 | @@ -0,0 +1,9 @@ |
2587 | +description: performs an upgrade using system-image-cli |
2588 | +dependencies: a touch read-only image |
2589 | +action: | |
2590 | + 1. execute upgrade |
2591 | +expected_results: | |
2592 | + 1. it will reboot into recovery, upgrade, and boot up |
2593 | +type: userland |
2594 | +timeout: 1800 |
2595 | +command: ./upgrade.sh |
2596 | |
2597 | === added file 'upgrade/upgrade/upgrade.sh' |
2598 | --- upgrade/upgrade/upgrade.sh 1970-01-01 00:00:00 +0000 |
2599 | +++ upgrade/upgrade/upgrade.sh 2013-08-29 18:33:39 +0000 |
2600 | @@ -0,0 +1,79 @@ |
2601 | +#!/bin/sh |
2602 | + |
2603 | +## upgrades the given target |
2604 | +## Intersting environment variables that must be set: |
2605 | +## ANDROID_SERIAL - specify another android device |
2606 | +ANDROID_SERIAL="${ANDROID_SERIAL-015d1884b20c1c0f}" #doanac's nexus7 at home |
2607 | + |
2608 | +set -eux |
2609 | + |
2610 | +export ANDROID_SERIAL=$ANDROID_SERIAL |
2611 | + |
2612 | +phablet_reboot_wait() { |
2613 | + # TODO get this into phablet-tools |
2614 | + adb reboot |
2615 | + adb shell stop android-tools-adbd 2>/dev/null || true |
2616 | + adb wait-for-device |
2617 | + # sometimes wait-for-device comes back too quick, so wait once more |
2618 | + sleep 4s |
2619 | + adb wait-for-device |
2620 | +} |
2621 | + |
2622 | +# try and get the system up with an actual wlan0 |
2623 | +phablet_get_interface() { |
2624 | + if ! adb shell ifconfig -a | grep wlan0 >/dev/null ; then |
2625 | + return 1 |
2626 | + fi |
2627 | +} |
2628 | + |
2629 | +# try and try and try to get an IP |
2630 | +# network is flaky, this seems to help: |
2631 | +phablet_get_ip() { |
2632 | + adb shell nmcli c list |
2633 | + uuid=$(adb shell nmcli c list | grep 802-11-wireless | tail -n1 | grep -o -E "[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}") |
2634 | + tmp=$(mktemp) |
2635 | + adb shell sh -c "nmcli c up uuid $uuid ; echo ANDROID_RC=$?" | tee $tmp |
2636 | + rc=1 |
2637 | + if grep "ANDROID_RC=0" $tmp >/dev/null; then |
2638 | + rc=0 |
2639 | + fi |
2640 | + rm $tmp |
2641 | + return $rc |
2642 | +} |
2643 | + |
2644 | +retry() { |
2645 | + cmd=$1 |
2646 | + retries=$2 |
2647 | + |
2648 | + for i in $(seq $retries) ; do |
2649 | + if $cmd ; then |
2650 | + return 0 |
2651 | + fi |
2652 | + times=$(($retries - $i)) |
2653 | + if [ $times -ne 0 ] ; then |
2654 | + echo "$cmd: failed, retrying $(($retries - $i)) more times" |
2655 | + [ -z $reboot ] || phablet_reboot_wait |
2656 | + sleep 60 |
2657 | + else |
2658 | + echo "$cmd: failed after $retries attempts" |
2659 | + fi |
2660 | + done |
2661 | + return 1 |
2662 | +} |
2663 | + |
2664 | +orig_version=$(adb shell system-image-cli -b) |
2665 | +echo $orig_version | sed -e 's/build number/UPGRADING FROM VERSION/' |
2666 | + |
2667 | +reboot=1 retry phablet_get_interface 4 |
2668 | +sleep 60 |
2669 | +retry phablet_get_ip 4 |
2670 | + |
2671 | +adb shell system-image-cli -v |
2672 | +adb wait-for-device |
2673 | +new_version=$(adb shell system-image-cli -b) |
2674 | +echo $new_version | sed -e 's/build number/UPGRADED TO VERSION/' |
2675 | + |
2676 | +if [ "$new_version" = "$orig_version" ] ; then |
2677 | + echo "UPGRADE FAILED" |
2678 | + exit 1 |
2679 | +fi |
2680 | |
2681 | === added directory 'utils' |
2682 | === added directory 'utils/host' |
2683 | === added file 'utils/host/adb-shell' |
2684 | --- utils/host/adb-shell 1970-01-01 00:00:00 +0000 |
2685 | +++ utils/host/adb-shell 2013-08-29 18:33:39 +0000 |
2686 | @@ -0,0 +1,20 @@ |
2687 | +#!/bin/bash |
2688 | + |
2689 | +# The "adb shell" command doesn't return an error if the command you execute |
2690 | +# resulted in an error. This is a wrapper to return the command's true return code. |
2691 | + |
2692 | +# NOTE: This script uses some specific bash'isms to keep things short and simple |
2693 | + |
2694 | +set -eu |
2695 | + |
2696 | +pat='ADB_RC=([[:digit:]]+)' |
2697 | + |
2698 | +{ |
2699 | + adb -s $ANDROID_SERIAL shell "$* ; echo ADB_RC=\$?" |
2700 | +} | while read line; do |
2701 | + echo $line |
2702 | + if [[ $line =~ $pat ]] ; then |
2703 | + rc=${BASH_REMATCH[1]} |
2704 | + exit $rc |
2705 | + fi |
2706 | +done |
2707 | |
2708 | === added file 'utils/host/autopilot-list' |
2709 | --- utils/host/autopilot-list 1970-01-01 00:00:00 +0000 |
2710 | +++ utils/host/autopilot-list 2013-08-29 18:33:39 +0000 |
2711 | @@ -0,0 +1,18 @@ |
2712 | +#!/bin/sh |
2713 | + |
2714 | +set -e |
2715 | + |
2716 | +app=$1 |
2717 | +pat=$app |
2718 | +rep=$app.tests. |
2719 | + |
2720 | +if [ -z "$app" ] ; then |
2721 | + echo "USAGE: $0 <app> [pattern] [replace]" |
2722 | + exit 1 |
2723 | +fi |
2724 | +[ -z "$2" ] || pat=$2 |
2725 | +[ -z "$3" ] || rep=$3 |
2726 | + |
2727 | +#NOTE we just use adb shell here, because we don't have to catch errors. the greps |
2728 | +# will work around that |
2729 | +adb shell sudo -i -u phablet bash -ic \"PYTHONPATH=/home/phablet/autopilot autopilot list $app\" | grep $pat | sed -e "s/^.*${rep}//" |
2730 | |
2731 | === added file 'utils/host/autopilot-run' |
2732 | --- utils/host/autopilot-run 1970-01-01 00:00:00 +0000 |
2733 | +++ utils/host/autopilot-run 2013-08-29 18:33:39 +0000 |
2734 | @@ -0,0 +1,3 @@ |
2735 | +#!/bin/sh |
2736 | + |
2737 | +adb-shell sudo -i -u phablet bash -ic \"PYTHONPATH=/home/phablet/autopilot autopilot run -v $*\" |
2738 | |
2739 | === added file 'utils/host/prepare-autopilot-test.sh' |
2740 | --- utils/host/prepare-autopilot-test.sh 1970-01-01 00:00:00 +0000 |
2741 | +++ utils/host/prepare-autopilot-test.sh 2013-08-29 18:33:39 +0000 |
2742 | @@ -0,0 +1,5 @@ |
2743 | +#!/bin/sh |
2744 | + |
2745 | +set -e |
2746 | + |
2747 | +adb-shell PKGS=\"$PKGS\" prepare-autopilot-test.sh |
2748 | |
2749 | === added directory 'utils/target' |
2750 | === added file 'utils/target/autopilot-list' |
2751 | --- utils/target/autopilot-list 1970-01-01 00:00:00 +0000 |
2752 | +++ utils/target/autopilot-list 2013-08-29 18:33:39 +0000 |
2753 | @@ -0,0 +1,13 @@ |
2754 | +#!/bin/sh |
2755 | + |
2756 | +app=$1 |
2757 | +pat=${2:-$app} |
2758 | +rep=${3:-$app.tests.} |
2759 | + |
2760 | +if [ -z "$app" ] ; then |
2761 | + echo "USAGE: $0 <app> [pattern] [replace]" |
2762 | + exit 1 |
2763 | +fi |
2764 | + |
2765 | +curdir=$(pwd) |
2766 | +sudo -i -u phablet bash -ic "PYTHONPATH=$curdir autopilot list $app" | grep $pat | sed -e "s/^.*${rep}//" |
2767 | |
2768 | === added file 'utils/target/autopilot-run' |
2769 | --- utils/target/autopilot-run 1970-01-01 00:00:00 +0000 |
2770 | +++ utils/target/autopilot-run 2013-08-29 18:33:39 +0000 |
2771 | @@ -0,0 +1,4 @@ |
2772 | +#!/bin/sh |
2773 | + |
2774 | +curdir=$(pwd) |
2775 | +sudo -i -u phablet bash -ic "PYTHONPATH=$curdir autopilot run -v $*" |
2776 | |
2777 | === added file 'utils/target/prepare-autopilot-test.sh' |
2778 | --- utils/target/prepare-autopilot-test.sh 1970-01-01 00:00:00 +0000 |
2779 | +++ utils/target/prepare-autopilot-test.sh 2013-08-29 18:33:39 +0000 |
2780 | @@ -0,0 +1,17 @@ |
2781 | +#!/bin/sh |
2782 | + |
2783 | +set -e |
2784 | + |
2785 | +#installs dependencies and unlocks screen so an autopilot test case can run |
2786 | + |
2787 | +if [ -n "$PKGS" ] ; then |
2788 | + MISSING=0 |
2789 | + dpkg -s $PKGS 2>/dev/null >/dev/null || MISSING=1 |
2790 | + if [ $MISSING -eq 1 ] ; then |
2791 | + apt-get install -yq --force-yes $PKGS |
2792 | + else |
2793 | + echo "setup not needed" |
2794 | + fi |
2795 | +fi |
2796 | +[ -z $NO_UNLOCK ] && unlock_screen.sh |
2797 | +exit 0 |
2798 | |
2799 | === added file 'utils/target/unlock_screen.py' |
2800 | --- utils/target/unlock_screen.py 1970-01-01 00:00:00 +0000 |
2801 | +++ utils/target/unlock_screen.py 2013-08-29 18:33:39 +0000 |
2802 | @@ -0,0 +1,87 @@ |
2803 | +#!/usr/bin/env python |
2804 | + |
2805 | +from autopilot import introspection |
2806 | +from autopilot.display import Display |
2807 | +from autopilot.input import Pointer, Touch |
2808 | +import os |
2809 | +import sys |
2810 | + |
2811 | + |
2812 | +def help(): |
2813 | + print "Usage:" |
2814 | + print "Run the script without any argument to unlock with assertion" |
2815 | + print "" |
2816 | + print "option -q:" |
2817 | + print "Execute with parameter -q to unlock the screen quickly without introspection" |
2818 | + |
2819 | + |
2820 | +def start_unity_in_testability(): |
2821 | + override_file = "~/.config/upstart/unity8.override" |
2822 | + |
2823 | + os.system('echo "exec unity8 -testability" > ~/.config/upstart/unity8.override') |
2824 | + |
2825 | + print "----------------------------------------------------------------------" |
2826 | + print "Stopping Unity" |
2827 | + os.system('/sbin/stop unity8') |
2828 | + print "Unity stopped" |
2829 | + |
2830 | + print "----------------------------------------------------------------------" |
2831 | + print "Starting Unity with testability" |
2832 | + os.system('/sbin/start unity8') |
2833 | + print "Unity started" |
2834 | + |
2835 | + print "----------------------------------------------------------------------" |
2836 | + if os.path.exists(override_file): |
2837 | + os.remove(override_file) |
2838 | + print "Cleaned up upstart override" |
2839 | + print "----------------------------------------------------------------------" |
2840 | + |
2841 | + print "Turning on the screen" |
2842 | + print "" |
2843 | + |
2844 | + |
2845 | +def unlock_screen(): |
2846 | + input_device = Touch.create() |
2847 | + pointing_device = Pointer(input_device) |
2848 | + conn = "com.canonical.Shell.BottomBarVisibilityCommunicator" |
2849 | + unity8 = introspection.get_proxy_object_for_existing_process(connection_name=conn) |
2850 | + greeter = unity8.select_single("Greeter") |
2851 | + x, y, w, h = greeter.globalRect |
2852 | + tx = x + w |
2853 | + ty = y + (h / 2) |
2854 | + |
2855 | + pointing_device.drag(tx, ty, tx / 2, ty) |
2856 | + try: |
2857 | + greeter.shown.wait_for(False) |
2858 | + except AssertionError: |
2859 | + print "----------------------------------------------------------------------" |
2860 | + print "THE SCREEN DIDN'T UNLOCK THE FIRST TRY, NOW ATTEMPTING A BLIND SWIPE" |
2861 | + unlock_screen_blind(greeter) |
2862 | + |
2863 | + |
2864 | +def unlock_screen_blind(greeter=None): |
2865 | + input_device = Touch.create() |
2866 | + pointing_device = Pointer(input_device) |
2867 | + x, y, w, h = Display.create(preferred_backend='UPA').get_screen_geometry(0) |
2868 | + tx = x + w |
2869 | + ty = y + (h / 2) |
2870 | + |
2871 | + pointing_device.drag(tx, ty, tx / 2, ty) |
2872 | + if greeter is not None: |
2873 | + try: |
2874 | + greeter.shown.wait_for(False) |
2875 | + if greeter.shown is False: |
2876 | + print "" |
2877 | + print "THE SCREEN IS NOW UNLOCKED" |
2878 | + except AssertionError: |
2879 | + print "----------------------------------------------------------------------" |
2880 | + "THE SCREEN DIDN'T UNLOCK, RESTART THE DEVICE AND RUN THE SCRIPT AGAIN" |
2881 | + |
2882 | + |
2883 | +if len(sys.argv) >= 2 and sys.argv[1] == '-q': |
2884 | + unlock_screen_blind() |
2885 | +elif len(sys.argv) >= 2 and sys.argv[1] == '-h': |
2886 | + help() |
2887 | +else: |
2888 | + start_unity_in_testability() |
2889 | + unlock_screen() |
2890 | |
2891 | === added file 'utils/target/unlock_screen.sh' |
2892 | --- utils/target/unlock_screen.sh 1970-01-01 00:00:00 +0000 |
2893 | +++ utils/target/unlock_screen.sh 2013-08-29 18:33:39 +0000 |
2894 | @@ -0,0 +1,7 @@ |
2895 | +#!/bin/sh |
2896 | + |
2897 | +basedir=$(dirname $(readlink -f $0)) |
2898 | + |
2899 | +#temporary workaround for bug #1207386 |
2900 | +chmod 666 /dev/uinput |
2901 | +sudo -i -u phablet bash -ic "PYTHONPATH=$(pwd) ${basedir}/unlock_screen.py" |
2902 | |
2903 | === added directory 'webbrowser-app-autopilot' |
2904 | === added file 'webbrowser-app-autopilot/master.run' |
2905 | --- webbrowser-app-autopilot/master.run 1970-01-01 00:00:00 +0000 |
2906 | +++ webbrowser-app-autopilot/master.run 2013-08-29 18:33:39 +0000 |
2907 | @@ -0,0 +1,15 @@ |
2908 | +--- |
2909 | +testsuites: |
2910 | + - name: settle-before |
2911 | + fetch_method: dev |
2912 | + fetch_location: ../systemsettle |
2913 | + include_tests: |
2914 | + - systemsettle-before |
2915 | + - name: webbrowser-app-autopilot |
2916 | + fetch_method: dev |
2917 | + fetch_location: ./ |
2918 | + - name: settle-after |
2919 | + fetch_method: dev |
2920 | + fetch_location: ../systemsettle |
2921 | + include_tests: |
2922 | + - systemsettle-after |
2923 | |
2924 | === added file 'webbrowser-app-autopilot/ts_control' |
2925 | --- webbrowser-app-autopilot/ts_control 1970-01-01 00:00:00 +0000 |
2926 | +++ webbrowser-app-autopilot/ts_control 2013-08-29 18:33:39 +0000 |
2927 | @@ -0,0 +1,1 @@ |
2928 | +ts_setup: PKGS=webbrowser-app-autopilot prepare-autopilot-test.sh |
2929 | |
2930 | === added file 'webbrowser-app-autopilot/tslist.auto' |
2931 | --- webbrowser-app-autopilot/tslist.auto 1970-01-01 00:00:00 +0000 |
2932 | +++ webbrowser-app-autopilot/tslist.auto 2013-08-29 18:33:39 +0000 |
2933 | @@ -0,0 +1,4 @@ |
2934 | +- |
2935 | + discovery_cmd: autopilot-list webbrowser_app |
2936 | + test_cmd: autopilot-run webbrowser_app.tests.{} |
2937 | + |