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

Side by Side Diff: build/android/pylib/android_commands.py

Issue 13799010: [Android] Reduce test logging verbosity. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 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
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Provides an interface to communicate with the device via the adb command. 5 """Provides an interface to communicate with the device via the adb command.
6 6
7 Assumes adb binary is currently on system path. 7 Assumes adb binary is currently on system path.
8 """ 8 """
9 9
10 import collections 10 import collections
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 emulator-5554 offline 102 emulator-5554 offline
103 """ 103 """
104 re_device = re.compile('^([a-zA-Z0-9_:.-]+)\tdevice$', re.MULTILINE) 104 re_device = re.compile('^([a-zA-Z0-9_:.-]+)\tdevice$', re.MULTILINE)
105 devices = re_device.findall(cmd_helper.GetCmdOutput(['adb', 'devices'])) 105 devices = re_device.findall(cmd_helper.GetCmdOutput(['adb', 'devices']))
106 preferred_device = os.environ.get('ANDROID_SERIAL') 106 preferred_device = os.environ.get('ANDROID_SERIAL')
107 if preferred_device in devices: 107 if preferred_device in devices:
108 devices.remove(preferred_device) 108 devices.remove(preferred_device)
109 devices.insert(0, preferred_device) 109 devices.insert(0, preferred_device)
110 return devices 110 return devices
111 111
112
112 def IsDeviceAttached(device): 113 def IsDeviceAttached(device):
113 return device in GetAttachedDevices() 114 return device in GetAttachedDevices()
114 115
116
115 def _GetFilesFromRecursiveLsOutput(path, ls_output, re_file, utc_offset=None): 117 def _GetFilesFromRecursiveLsOutput(path, ls_output, re_file, utc_offset=None):
116 """Gets a list of files from `ls` command output. 118 """Gets a list of files from `ls` command output.
117 119
118 Python's os.walk isn't used because it doesn't work over adb shell. 120 Python's os.walk isn't used because it doesn't work over adb shell.
119 121
120 Args: 122 Args:
121 path: The path to list. 123 path: The path to list.
122 ls_output: A list of lines returned by an `ls -lR` command. 124 ls_output: A list of lines returned by an `ls -lR` command.
123 re_file: A compiled regular expression which parses a line into named groups 125 re_file: A compiled regular expression which parses a line into named groups
124 consisting of at minimum "filename", "date", "time", "size" and 126 consisting of at minimum "filename", "date", "time", "size" and
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 utc_offset = file_match.group('timezone') 159 utc_offset = file_match.group('timezone')
158 if isinstance(utc_offset, str) and len(utc_offset) == 5: 160 if isinstance(utc_offset, str) and len(utc_offset) == 5:
159 utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), 161 utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]),
160 minutes=int(utc_offset[3:5])) 162 minutes=int(utc_offset[3:5]))
161 if utc_offset[0:1] == '-': 163 if utc_offset[0:1] == '-':
162 utc_delta = -utc_delta 164 utc_delta = -utc_delta
163 lastmod -= utc_delta 165 lastmod -= utc_delta
164 files[filename] = (int(file_match.group('size')), lastmod) 166 files[filename] = (int(file_match.group('size')), lastmod)
165 return files 167 return files
166 168
169
167 def _ComputeFileListHash(md5sum_output): 170 def _ComputeFileListHash(md5sum_output):
168 """Returns a list of MD5 strings from the provided md5sum output.""" 171 """Returns a list of MD5 strings from the provided md5sum output."""
169 return [line.split(' ')[0] for line in md5sum_output] 172 return [line.split(' ')[0] for line in md5sum_output]
170 173
174
171 def _HasAdbPushSucceeded(command_output): 175 def _HasAdbPushSucceeded(command_output):
172 """Returns whether adb push has succeeded from the provided output.""" 176 """Returns whether adb push has succeeded from the provided output."""
173 if not command_output: 177 if not command_output:
174 return False 178 return False
175 # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)" 179 # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)"
176 # Errors look like this: "failed to copy ... " 180 # Errors look like this: "failed to copy ... "
177 if not re.search('^[0-9]', command_output.splitlines()[-1]): 181 if not re.search('^[0-9]', command_output.splitlines()[-1]):
178 logging.critical('PUSH FAILED: ' + command_output) 182 logging.critical('PUSH FAILED: ' + command_output)
179 return False 183 return False
180 return True 184 return True
181 185
186
182 def GetLogTimestamp(log_line, year): 187 def GetLogTimestamp(log_line, year):
183 """Returns the timestamp of the given |log_line| in the given year.""" 188 """Returns the timestamp of the given |log_line| in the given year."""
184 try: 189 try:
185 return datetime.datetime.strptime('%s-%s' % (year, log_line[:18]), 190 return datetime.datetime.strptime('%s-%s' % (year, log_line[:18]),
186 '%Y-%m-%d %H:%M:%S.%f') 191 '%Y-%m-%d %H:%M:%S.%f')
187 except (ValueError, IndexError): 192 except (ValueError, IndexError):
188 logging.critical('Error reading timestamp from ' + log_line) 193 logging.critical('Error reading timestamp from ' + log_line)
189 return None 194 return None
190 195
191 196
197 def _LogShell(cmd):
198 """Logs the adb shell command."""
199 logging.info('[device]> %s', cmd)
Isaac (away) 2013/04/10 19:12:53 It'd be great to include device serial number here
craigdh 2013/04/10 20:39:49 The logging format was just recently changed to in
frankf 2013/04/10 21:29:42 I added this anyways in case we do something on on
200
201
192 class AndroidCommands(object): 202 class AndroidCommands(object):
193 """Helper class for communicating with Android device via adb. 203 """Helper class for communicating with Android device via adb.
194 204
195 Args: 205 Args:
196 device: If given, adb commands are only send to the device of this ID. 206 device: If given, adb commands are only send to the device of this ID.
197 Otherwise commands are sent to all attached devices. 207 Otherwise commands are sent to all attached devices.
198 """ 208 """
199 209
200 def __init__(self, device=None): 210 def __init__(self, device=None):
201 self._adb = adb_interface.AdbInterface() 211 self._adb = adb_interface.AdbInterface()
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 """Uninstalls the specified package from the device. 320 """Uninstalls the specified package from the device.
311 321
312 Args: 322 Args:
313 package: Name of the package to remove. 323 package: Name of the package to remove.
314 324
315 Returns: 325 Returns:
316 A status string returned by adb uninstall 326 A status string returned by adb uninstall
317 """ 327 """
318 uninstall_command = 'uninstall %s' % package 328 uninstall_command = 'uninstall %s' % package
319 329
320 logging.info('>>> $' + uninstall_command) 330 _LogShell(uninstall_command)
321 return self._adb.SendCommand(uninstall_command, timeout_time=60) 331 return self._adb.SendCommand(uninstall_command, timeout_time=60)
322 332
323 def Install(self, package_file_path, reinstall=False): 333 def Install(self, package_file_path, reinstall=False):
324 """Installs the specified package to the device. 334 """Installs the specified package to the device.
325 335
326 Args: 336 Args:
327 package_file_path: Path to .apk file to install. 337 package_file_path: Path to .apk file to install.
328 reinstall: Reinstall an existing apk, keeping the data. 338 reinstall: Reinstall an existing apk, keeping the data.
329 339
330 Returns: 340 Returns:
331 A status string returned by adb install 341 A status string returned by adb install
332 """ 342 """
333 assert os.path.isfile(package_file_path), ('<%s> is not file' % 343 assert os.path.isfile(package_file_path), ('<%s> is not file' %
334 package_file_path) 344 package_file_path)
335 345
336 install_cmd = ['install'] 346 install_cmd = ['install']
337 347
338 if reinstall: 348 if reinstall:
339 install_cmd.append('-r') 349 install_cmd.append('-r')
340 350
341 install_cmd.append(package_file_path) 351 install_cmd.append(package_file_path)
342 install_cmd = ' '.join(install_cmd) 352 install_cmd = ' '.join(install_cmd)
343 353
344 logging.info('>>> $' + install_cmd) 354 _LogShell(install_cmd)
345 return self._adb.SendCommand(install_cmd, 355 return self._adb.SendCommand(install_cmd,
346 timeout_time=2 * 60, 356 timeout_time=2 * 60,
347 retry_count=0) 357 retry_count=0)
348 358
349 def ManagedInstall(self, apk_path, keep_data=False, package_name=None, 359 def ManagedInstall(self, apk_path, keep_data=False, package_name=None,
350 reboots_on_failure=2): 360 reboots_on_failure=2):
351 """Installs specified package and reboots device on timeouts. 361 """Installs specified package and reboots device on timeouts.
352 362
353 Args: 363 Args:
354 apk_path: Path to .apk file to install. 364 apk_path: Path to .apk file to install.
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 command: String containing the shell command to send. Must not include 475 command: String containing the shell command to send. Must not include
466 the single quotes as we use them to escape the whole command. 476 the single quotes as we use them to escape the whole command.
467 timeout_time: Number of seconds to wait for command to respond before 477 timeout_time: Number of seconds to wait for command to respond before
468 retrying, used by AdbInterface.SendShellCommand. 478 retrying, used by AdbInterface.SendShellCommand.
469 log_result: Boolean to indicate whether we should log the result of the 479 log_result: Boolean to indicate whether we should log the result of the
470 shell command. 480 shell command.
471 481
472 Returns: 482 Returns:
473 list containing the lines of output received from running the command 483 list containing the lines of output received from running the command
474 """ 484 """
475 logging.info('>>> $' + command) 485 _LogShell(command)
476 if "'" in command: logging.warning(command + " contains ' quotes") 486 if "'" in command: logging.warning(command + " contains ' quotes")
477 result = self._adb.SendShellCommand( 487 result = self._adb.SendShellCommand(
478 "'%s'" % command, timeout_time).splitlines() 488 "'%s'" % command, timeout_time).splitlines()
479 if ['error: device not found'] == result: 489 if ['error: device not found'] == result:
480 raise errors.DeviceUnresponsiveError('device not found') 490 raise errors.DeviceUnresponsiveError('device not found')
481 if log_result: 491 if log_result:
482 logging.info('\n>>> '.join(result)) 492 _LogShell('\n'.join(result))
483 return result 493 return result
484 494
485 def GetShellCommandStatusAndOutput(self, command, timeout_time=20, 495 def GetShellCommandStatusAndOutput(self, command, timeout_time=20,
486 log_result=False): 496 log_result=False):
487 """See RunShellCommand() above. 497 """See RunShellCommand() above.
488 498
489 Returns: 499 Returns:
490 The tuple (exit code, list of output lines). 500 The tuple (exit code, list of output lines).
491 """ 501 """
492 lines = self.RunShellCommand( 502 lines = self.RunShellCommand(
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
690 return 700 return
691 701
692 # They don't match, so remove everything first and then create it. 702 # They don't match, so remove everything first and then create it.
693 if os.path.isdir(local_path): 703 if os.path.isdir(local_path):
694 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60) 704 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60)
695 self.RunShellCommand('mkdir -p %s' % device_path) 705 self.RunShellCommand('mkdir -p %s' % device_path)
696 706
697 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of 707 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of
698 # 60 seconds which isn't sufficient for a lot of users of this method. 708 # 60 seconds which isn't sufficient for a lot of users of this method.
699 push_command = 'push %s %s' % (local_path, device_path) 709 push_command = 'push %s %s' % (local_path, device_path)
700 logging.info('>>> $' + push_command) 710 _LogShell(push_command)
701 output = self._adb.SendCommand(push_command, timeout_time=30 * 60) 711 output = self._adb.SendCommand(push_command, timeout_time=30 * 60)
702 assert _HasAdbPushSucceeded(output) 712 assert _HasAdbPushSucceeded(output)
703 713
704 714
705 def GetFileContents(self, filename, log_result=False): 715 def GetFileContents(self, filename, log_result=False):
706 """Gets contents from the file specified by |filename|.""" 716 """Gets contents from the file specified by |filename|."""
707 return self.RunShellCommand('cat "%s" 2>/dev/null' % filename, 717 return self.RunShellCommand('cat "%s" 2>/dev/null' % filename,
708 log_result=log_result) 718 log_result=log_result)
709 719
710 def SetFileContents(self, filename, contents): 720 def SetFileContents(self, filename, contents):
(...skipping 535 matching lines...) Expand 10 before | Expand all | Expand 10 after
1246 1256
1247 Args: 1257 Args:
1248 test: Test class/method. 1258 test: Test class/method.
1249 test_package: Name of the test jar. 1259 test_package: Name of the test jar.
1250 timeout: Timeout time in seconds. 1260 timeout: Timeout time in seconds.
1251 1261
1252 Returns: 1262 Returns:
1253 An instance of am_instrument_parser.TestResult object. 1263 An instance of am_instrument_parser.TestResult object.
1254 """ 1264 """
1255 cmd = 'uiautomator runtest %s -e class %s' % (test_package, test) 1265 cmd = 'uiautomator runtest %s -e class %s' % (test_package, test)
1256 logging.info('>>> $' + cmd) 1266 _LogShell(cmd)
1257 output = self._adb.SendShellCommand(cmd, timeout_time=timeout) 1267 output = self._adb.SendShellCommand(cmd, timeout_time=timeout)
1258 # uiautomator doesn't fully conform to the instrumenation test runner 1268 # uiautomator doesn't fully conform to the instrumenation test runner
1259 # convention and doesn't terminate with INSTRUMENTATION_CODE. 1269 # convention and doesn't terminate with INSTRUMENTATION_CODE.
1260 # Just assume the first result is valid. 1270 # Just assume the first result is valid.
1261 (test_results, _) = am_instrument_parser.ParseAmInstrumentOutput(output) 1271 (test_results, _) = am_instrument_parser.ParseAmInstrumentOutput(output)
1262 return test_results[0] 1272 return test_results[0]
1263 1273
1264 1274
1265 class NewLineNormalizer(object): 1275 class NewLineNormalizer(object):
1266 """A file-like object to normalize EOLs to '\n'. 1276 """A file-like object to normalize EOLs to '\n'.
1267 1277
1268 Pexpect runs adb within a pseudo-tty device (see 1278 Pexpect runs adb within a pseudo-tty device (see
1269 http://www.noah.org/wiki/pexpect), so any '\n' printed by adb is written 1279 http://www.noah.org/wiki/pexpect), so any '\n' printed by adb is written
1270 as '\r\n' to the logfile. Since adb already uses '\r\n' to terminate 1280 as '\r\n' to the logfile. Since adb already uses '\r\n' to terminate
1271 lines, the log ends up having '\r\r\n' at the end of each line. This 1281 lines, the log ends up having '\r\r\n' at the end of each line. This
1272 filter replaces the above with a single '\n' in the data stream. 1282 filter replaces the above with a single '\n' in the data stream.
1273 """ 1283 """
1274 def __init__(self, output): 1284 def __init__(self, output):
1275 self._output = output 1285 self._output = output
1276 1286
1277 def write(self, data): 1287 def write(self, data):
1278 data = data.replace('\r\r\n', '\n') 1288 data = data.replace('\r\r\n', '\n')
1279 self._output.write(data) 1289 self._output.write(data)
1280 1290
1281 def flush(self): 1291 def flush(self):
1282 self._output.flush() 1292 self._output.flush()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698