Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: third_party/android/testrunner/adb_interface.py

Issue 8322008: Upstream: Test script library from Android (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add a way to checkout specific version Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/python2.4
2 #
3 #
4 # Copyright 2008, The Android Open Source Project
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17
18 """Provides an interface to communicate with the device via the adb command.
19
20 Assumes adb binary is currently on system path.
21 """
22 # Python imports
23 import os
24 import string
25 import time
26
27 # local imports
28 import am_instrument_parser
29 import errors
30 import logger
31 import run_command
32
33
34 class AdbInterface:
35 """Helper class for communicating with Android device via adb."""
36
37 # argument to pass to adb, to direct command to specific device
38 _target_arg = ""
39
40 DEVICE_TRACE_DIR = "/data/test_results/"
41
42 def SetEmulatorTarget(self):
43 """Direct all future commands to the only running emulator."""
44 self._target_arg = "-e"
45
46 def SetDeviceTarget(self):
47 """Direct all future commands to the only connected USB device."""
48 self._target_arg = "-d"
49
50 def SetTargetSerial(self, serial):
51 """Direct all future commands to Android target with the given serial."""
52 self._target_arg = "-s %s" % serial
53
54 def SendCommand(self, command_string, timeout_time=20, retry_count=3):
55 """Send a command via adb.
56
57 Args:
58 command_string: adb command to run
59 timeout_time: number of seconds to wait for command to respond before
60 retrying
61 retry_count: number of times to retry command before raising
62 WaitForResponseTimedOutError
63 Returns:
64 string output of command
65
66 Raises:
67 WaitForResponseTimedOutError if device does not respond to command within time
68 """
69 adb_cmd = "adb %s %s" % (self._target_arg, command_string)
70 logger.SilentLog("about to run %s" % adb_cmd)
71 return run_command.RunCommand(adb_cmd, timeout_time=timeout_time,
72 retry_count=retry_count)
73
74 def SendShellCommand(self, cmd, timeout_time=20, retry_count=3):
75 """Send a adb shell command.
76
77 Args:
78 cmd: adb shell command to run
79 timeout_time: number of seconds to wait for command to respond before
80 retrying
81 retry_count: number of times to retry command before raising
82 WaitForResponseTimedOutError
83
84 Returns:
85 string output of command
86
87 Raises:
88 WaitForResponseTimedOutError: if device does not respond to command
89 """
90 return self.SendCommand("shell %s" % cmd, timeout_time=timeout_time,
91 retry_count=retry_count)
92
93 def BugReport(self, path):
94 """Dumps adb bugreport to the file specified by the path.
95
96 Args:
97 path: Path of the file where adb bugreport is dumped to.
98 """
99 bug_output = self.SendShellCommand("bugreport", timeout_time=60)
100 bugreport_file = open(path, "w")
101 bugreport_file.write(bug_output)
102 bugreport_file.close()
103
104 def Push(self, src, dest):
105 """Pushes the file src onto the device at dest.
106
107 Args:
108 src: file path of host file to push
109 dest: destination absolute file path on device
110 """
111 self.SendCommand("push %s %s" % (src, dest), timeout_time=60)
112
113 def Pull(self, src, dest):
114 """Pulls the file src on the device onto dest on the host.
115
116 Args:
117 src: absolute file path of file on device to pull
118 dest: destination file path on host
119
120 Returns:
121 True if success and False otherwise.
122 """
123 # Create the base dir if it doesn't exist already
124 if not os.path.exists(os.path.dirname(dest)):
125 os.makedirs(os.path.dirname(dest))
126
127 if self.DoesFileExist(src):
128 self.SendCommand("pull %s %s" % (src, dest), timeout_time=60)
129 return True
130 else:
131 logger.Log("ADB Pull Failed: Source file %s does not exist." % src)
132 return False
133
134 def DoesFileExist(self, src):
135 """Checks if the given path exists on device target.
136
137 Args:
138 src: file path to be checked.
139
140 Returns:
141 True if file exists
142 """
143
144 output = self.SendShellCommand("ls %s" % src)
145 error = "No such file or directory"
146
147 if error in output:
148 return False
149 return True
150
151 def EnableAdbRoot(self):
152 """Enable adb root on device."""
153 output = self.SendCommand("root")
154 if "adbd is already running as root" in output:
155 return True
156 elif "restarting adbd as root" in output:
157 # device will disappear from adb, wait for it to come back
158 self.SendCommand("wait-for-device")
159 return True
160 else:
161 logger.Log("Unrecognized output from adb root: %s" % output)
162 return False
163
164 def StartInstrumentationForPackage(
165 self, package_name, runner_name, timeout_time=60*10,
166 no_window_animation=False, instrumentation_args={}):
167 """Run instrumentation test for given package and runner.
168
169 Equivalent to StartInstrumentation, except instrumentation path is
170 separated into its package and runner components.
171 """
172 instrumentation_path = "%s/%s" % (package_name, runner_name)
173 return self.StartInstrumentation(instrumentation_path, timeout_time=timeout_ time,
174 no_window_animation=no_window_animation,
175 instrumentation_args=instrumentation_args)
176
177 def StartInstrumentation(
178 self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
179 profile=False, instrumentation_args={}):
180
181 """Runs an instrumentation class on the target.
182
183 Returns a dictionary containing the key value pairs from the
184 instrumentations result bundle and a list of TestResults. Also handles the
185 interpreting of error output from the device and raises the necessary
186 exceptions.
187
188 Args:
189 instrumentation_path: string. It should be the fully classified package
190 name, and instrumentation test runner, separated by "/"
191 e.g. com.android.globaltimelaunch/.GlobalTimeLaunch
192 timeout_time: Timeout value for the am command.
193 no_window_animation: boolean, Whether you want window animations enabled
194 or disabled
195 profile: If True, profiling will be turned on for the instrumentation.
196 instrumentation_args: Dictionary of key value bundle arguments to pass to
197 instrumentation.
198
199 Returns:
200 (test_results, inst_finished_bundle)
201
202 test_results: a list of TestResults
203 inst_finished_bundle (dict): Key/value pairs contained in the bundle that
204 is passed into ActivityManager.finishInstrumentation(). Included in this
205 bundle is the return code of the Instrumentation process, any error
206 codes reported by the activity manager, and any results explicitly added
207 by the instrumentation code.
208
209 Raises:
210 WaitForResponseTimedOutError: if timeout occurred while waiting for
211 response to adb instrument command
212 DeviceUnresponsiveError: if device system process is not responding
213 InstrumentationError: if instrumentation failed to run
214 """
215
216 command_string = self._BuildInstrumentationCommandPath(
217 instrumentation_path, no_window_animation=no_window_animation,
218 profile=profile, raw_mode=True,
219 instrumentation_args=instrumentation_args)
220 logger.Log(command_string)
221 (test_results, inst_finished_bundle) = (
222 am_instrument_parser.ParseAmInstrumentOutput(
223 self.SendShellCommand(command_string, timeout_time=timeout_time,
224 retry_count=2)))
225
226 if "code" not in inst_finished_bundle:
227 raise errors.InstrumentationError("no test results... device setup "
228 "correctly?")
229
230 if inst_finished_bundle["code"] == "0":
231 short_msg_result = "no error message"
232 if "shortMsg" in inst_finished_bundle:
233 short_msg_result = inst_finished_bundle["shortMsg"]
234 logger.Log("Error! Test run failed: %s" % short_msg_result)
235 raise errors.InstrumentationError(short_msg_result)
236
237 if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
238 logger.Log("INSTRUMENTATION ABORTED!")
239 raise errors.DeviceUnresponsiveError
240
241 return (test_results, inst_finished_bundle)
242
243 def StartInstrumentationNoResults(
244 self, package_name, runner_name, no_window_animation=False,
245 raw_mode=False, instrumentation_args={}):
246 """Runs instrumentation and dumps output to stdout.
247
248 Equivalent to StartInstrumentation, but will dump instrumentation
249 'normal' output to stdout, instead of parsing return results. Command will
250 never timeout.
251 """
252 adb_command_string = self.PreviewInstrumentationCommand(
253 package_name, runner_name, no_window_animation=no_window_animation,
254 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
255 logger.Log(adb_command_string)
256 run_command.RunCommand(adb_command_string, return_output=False)
257
258 def PreviewInstrumentationCommand(
259 self, package_name, runner_name, no_window_animation=False,
260 raw_mode=False, instrumentation_args={}):
261 """Returns a string of adb command that will be executed."""
262 inst_command_string = self._BuildInstrumentationCommand(
263 package_name, runner_name, no_window_animation=no_window_animation,
264 raw_mode=raw_mode, instrumentation_args=instrumentation_args)
265 command_string = "adb %s shell %s" % (self._target_arg, inst_command_string)
266 return command_string
267
268 def _BuildInstrumentationCommand(
269 self, package, runner_name, no_window_animation=False, profile=False,
270 raw_mode=True, instrumentation_args={}):
271 instrumentation_path = "%s/%s" % (package, runner_name)
272
273 return self._BuildInstrumentationCommandPath(
274 instrumentation_path, no_window_animation=no_window_animation,
275 profile=profile, raw_mode=raw_mode,
276 instrumentation_args=instrumentation_args)
277
278 def _BuildInstrumentationCommandPath(
279 self, instrumentation_path, no_window_animation=False, profile=False,
280 raw_mode=True, instrumentation_args={}):
281 command_string = "am instrument"
282 if no_window_animation:
283 command_string += " --no_window_animation"
284 if profile:
285 self._CreateTraceDir()
286 command_string += (
287 " -p %s/%s.dmtrace" %
288 (self.DEVICE_TRACE_DIR, instrumentation_path.split(".")[-1]))
289
290 for key, value in instrumentation_args.items():
291 command_string += " -e %s '%s'" % (key, value)
292 if raw_mode:
293 command_string += " -r"
294 command_string += " -w %s" % instrumentation_path
295 return command_string
296
297 def _CreateTraceDir(self):
298 ls_response = self.SendShellCommand("ls /data/trace")
299 if ls_response.strip("#").strip(string.whitespace) != "":
300 self.SendShellCommand("create /data/trace", "mkdir /data/trace")
301 self.SendShellCommand("make /data/trace world writeable",
302 "chmod 777 /data/trace")
303
304 def WaitForDevicePm(self, wait_time=120):
305 """Waits for targeted device's package manager to be up.
306
307 Args:
308 wait_time: time in seconds to wait
309
310 Raises:
311 WaitForResponseTimedOutError if wait_time elapses and pm still does not
312 respond.
313 """
314 logger.Log("Waiting for device package manager...")
315 self.SendCommand("wait-for-device")
316 # Now the device is there, but may not be running.
317 # Query the package manager with a basic command
318 try:
319 self._WaitForShellCommandContents("pm path android", "package:",
320 wait_time)
321 except errors.WaitForResponseTimedOutError:
322 raise errors.WaitForResponseTimedOutError(
323 "Package manager did not respond after %s seconds" % wait_time)
324
325 def WaitForInstrumentation(self, package_name, runner_name, wait_time=120):
326 """Waits for given instrumentation to be present on device
327
328 Args:
329 wait_time: time in seconds to wait
330
331 Raises:
332 WaitForResponseTimedOutError if wait_time elapses and instrumentation
333 still not present.
334 """
335 instrumentation_path = "%s/%s" % (package_name, runner_name)
336 logger.Log("Waiting for instrumentation to be present")
337 # Query the package manager
338 try:
339 command = "pm list instrumentation | grep %s" % instrumentation_path
340 self._WaitForShellCommandContents(command, "instrumentation:", wait_time,
341 raise_abort=False)
342 except errors.WaitForResponseTimedOutError :
343 logger.Log(
344 "Could not find instrumentation %s on device. Does the "
345 "instrumentation in test's AndroidManifest.xml match definition"
346 "in test_defs.xml?" % instrumentation_path)
347 raise
348
349 def WaitForProcess(self, name, wait_time=120):
350 """Wait until a process is running on the device.
351
352 Args:
353 name: the process name as it appears in `ps`
354 wait_time: time in seconds to wait
355
356 Raises:
357 WaitForResponseTimedOutError if wait_time elapses and the process is
358 still not running
359 """
360 logger.Log("Waiting for process %s" % name)
361 self.SendCommand("wait-for-device")
362 self._WaitForShellCommandContents("ps", name, wait_time)
363
364 def WaitForProcessEnd(self, name, wait_time=120):
365 """Wait until a process is no longer running on the device.
366
367 Args:
368 name: the process name as it appears in `ps`
369 wait_time: time in seconds to wait
370
371 Raises:
372 WaitForResponseTimedOutError if wait_time elapses and the process is
373 still running
374 """
375 logger.Log("Waiting for process %s to end" % name)
376 self._WaitForShellCommandContents("ps", name, wait_time, invert=True)
377
378 def _WaitForShellCommandContents(self, command, expected, wait_time,
379 raise_abort=True, invert=False):
380 """Wait until the response to a command contains a given output.
381
382 Assumes that a only successful execution of "adb shell <command>" contains
383 the substring expected. Assumes that a device is present.
384
385 Args:
386 command: adb shell command to execute
387 expected: the string that should appear to consider the
388 command successful.
389 wait_time: time in seconds to wait
390 raise_abort: if False, retry when executing the command raises an
391 AbortError, rather than failing.
392 invert: if True, wait until the command output no longer contains the
393 expected contents.
394
395 Raises:
396 WaitForResponseTimedOutError: If wait_time elapses and the command has not
397 returned an output containing expected yet.
398 """
399 # Query the device with the command
400 success = False
401 attempts = 0
402 wait_period = 5
403 while not success and (attempts*wait_period) < wait_time:
404 # assume the command will always contain expected in the success case
405 try:
406 output = self.SendShellCommand(command, retry_count=1)
407 if ((not invert and expected in output)
408 or (invert and expected not in output)):
409 success = True
410 except errors.AbortError, e:
411 if raise_abort:
412 raise
413 # ignore otherwise
414
415 if not success:
416 time.sleep(wait_period)
417 attempts += 1
418
419 if not success:
420 raise errors.WaitForResponseTimedOutError()
421
422 def WaitForBootComplete(self, wait_time=120):
423 """Waits for targeted device's bootcomplete flag to be set.
424
425 Args:
426 wait_time: time in seconds to wait
427
428 Raises:
429 WaitForResponseTimedOutError if wait_time elapses and pm still does not
430 respond.
431 """
432 logger.Log("Waiting for boot complete...")
433 self.SendCommand("wait-for-device")
434 # Now the device is there, but may not be running.
435 # Query the package manager with a basic command
436 boot_complete = False
437 attempts = 0
438 wait_period = 5
439 while not boot_complete and (attempts*wait_period) < wait_time:
440 output = self.SendShellCommand("getprop dev.bootcomplete", retry_count=1)
441 output = output.strip()
442 if output == "1":
443 boot_complete = True
444 else:
445 time.sleep(wait_period)
446 attempts += 1
447 if not boot_complete:
448 raise errors.WaitForResponseTimedOutError(
449 "dev.bootcomplete flag was not set after %s seconds" % wait_time)
450
451 def Sync(self, retry_count=3, runtime_restart=False):
452 """Perform a adb sync.
453
454 Blocks until device package manager is responding.
455
456 Args:
457 retry_count: number of times to retry sync before failing
458 runtime_restart: stop runtime during sync and restart afterwards, useful
459 for syncing system libraries (core, framework etc)
460
461 Raises:
462 WaitForResponseTimedOutError if package manager does not respond
463 AbortError if unrecoverable error occurred
464 """
465 output = ""
466 error = None
467 if runtime_restart:
468 self.SendShellCommand("setprop ro.monkey 1", retry_count=retry_count)
469 # manual rest bootcomplete flag
470 self.SendShellCommand("setprop dev.bootcomplete 0",
471 retry_count=retry_count)
472 self.SendShellCommand("stop", retry_count=retry_count)
473
474 try:
475 output = self.SendCommand("sync", retry_count=retry_count)
476 except errors.AbortError, e:
477 error = e
478 output = e.msg
479 if "Read-only file system" in output:
480 logger.SilentLog(output)
481 logger.Log("Remounting read-only filesystem")
482 self.SendCommand("remount")
483 output = self.SendCommand("sync", retry_count=retry_count)
484 elif "No space left on device" in output:
485 logger.SilentLog(output)
486 logger.Log("Restarting device runtime")
487 self.SendShellCommand("stop", retry_count=retry_count)
488 output = self.SendCommand("sync", retry_count=retry_count)
489 self.SendShellCommand("start", retry_count=retry_count)
490 elif error is not None:
491 # exception occurred that cannot be recovered from
492 raise error
493 logger.SilentLog(output)
494 if runtime_restart:
495 # start runtime and wait till boot complete flag is set
496 self.SendShellCommand("start", retry_count=retry_count)
497 self.WaitForBootComplete()
498 # press the MENU key, this will disable key guard if runtime is started
499 # with ro.monkey set to 1
500 self.SendShellCommand("input keyevent 82", retry_count=retry_count)
501 else:
502 self.WaitForDevicePm()
503 return output
504
505 def GetSerialNumber(self):
506 """Returns the serial number of the targeted device."""
507 return self.SendCommand("get-serialno").strip()
OLDNEW
« no previous file with comments | « third_party/android/testrunner/README.chromium ('k') | third_party/android/testrunner/am_instrument_parser.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698