[Android] Switch to DeviceUtils versions of GetPid, TakeScreenshot, and GetIoStats.
BUG=267773 Review URL: https://codereview.chromium.org/386053002 git-svn-id: http://src.chromium.org/svn/trunk/src/build@283731 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
This commit is contained in:
Родитель
c4afee99f3
Коммит
494c5b76a1
|
@ -81,12 +81,12 @@ class DeviceUtils(object):
|
|||
"""Checks whether the device is online.
|
||||
|
||||
Args:
|
||||
timeout: An integer containing the number of seconds to wait for the
|
||||
operation to complete.
|
||||
retries: An integer containing the number of times the operation should
|
||||
be retried if it fails.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
True if the device is online, False otherwise.
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
"""
|
||||
return self.old_interface.IsOnline()
|
||||
|
||||
|
@ -95,21 +95,26 @@ class DeviceUtils(object):
|
|||
"""Checks whether or not adbd has root privileges.
|
||||
|
||||
Args:
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
True if adbd has root privileges, False otherwise.
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
return self._HasRootImpl()
|
||||
|
||||
def _HasRootImpl(self):
|
||||
""" Implementation of HasRoot.
|
||||
"""Implementation of HasRoot.
|
||||
|
||||
This is split from HasRoot to allow other DeviceUtils methods to call
|
||||
HasRoot without spawning a new timeout thread.
|
||||
|
||||
Returns:
|
||||
Same as for |HasRoot|.
|
||||
Raises:
|
||||
Same as for |HasRoot|.
|
||||
"""
|
||||
return self.old_interface.IsRootEnabled()
|
||||
|
||||
|
@ -118,10 +123,11 @@ class DeviceUtils(object):
|
|||
"""Restarts adbd with root privileges.
|
||||
|
||||
Args:
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandFailedError if root could not be enabled.
|
||||
CommandTimeoutError on timeout.
|
||||
"""
|
||||
if not self.old_interface.EnableAdbRoot():
|
||||
raise device_errors.CommandFailedError(
|
||||
|
@ -132,10 +138,14 @@ class DeviceUtils(object):
|
|||
"""Get the device's path to its SD card.
|
||||
|
||||
Args:
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
The device's path to its SD card.
|
||||
Raises:
|
||||
CommandFailedError if the external storage path could not be determined.
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
try:
|
||||
return self.old_interface.GetExternalStorage()
|
||||
|
@ -153,16 +163,17 @@ class DeviceUtils(object):
|
|||
|
||||
Args:
|
||||
wifi: A boolean indicating if we should wait for wifi to come up or not.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandFailedError on failure.
|
||||
CommandTimeoutError if one of the component waits times out.
|
||||
DeviceUnreachableError if the device becomes unresponsive.
|
||||
"""
|
||||
self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout)
|
||||
|
||||
def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None):
|
||||
""" Implementation of WaitUntilFullyBooted.
|
||||
"""Implementation of WaitUntilFullyBooted.
|
||||
|
||||
This is split from WaitUntilFullyBooted to allow other DeviceUtils methods
|
||||
to call WaitUntilFullyBooted without spawning a new timeout thread.
|
||||
|
@ -172,7 +183,7 @@ class DeviceUtils(object):
|
|||
|
||||
Args:
|
||||
wifi: Same as for |WaitUntilFullyBooted|.
|
||||
timeout: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
Raises:
|
||||
Same as for |WaitUntilFullyBooted|.
|
||||
"""
|
||||
|
@ -197,8 +208,11 @@ class DeviceUtils(object):
|
|||
|
||||
Args:
|
||||
block: A boolean indicating if we should wait for the reboot to complete.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
self.old_interface.Reboot()
|
||||
if block:
|
||||
|
@ -218,11 +232,12 @@ class DeviceUtils(object):
|
|||
Args:
|
||||
apk_path: A string containing the path to the APK to install.
|
||||
reinstall: A boolean indicating if we should keep any existing app data.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandFailedError if the installation fails.
|
||||
CommandTimeoutError if the installation times out.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
package_name = apk_helper.GetPackageName(apk_path)
|
||||
device_path = self.old_interface.GetApplicationPath(package_name)
|
||||
|
@ -266,12 +281,14 @@ class DeviceUtils(object):
|
|||
be checked.
|
||||
as_root: A boolean indicating whether the shell command should be run
|
||||
with root privileges.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
Raises:
|
||||
CommandFailedError if check_return is True and the return code is nozero.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
The output of the command.
|
||||
Raises:
|
||||
CommandFailedError if check_return is True and the return code is nozero.
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
return self._RunShellCommandImpl(cmd, check_return=check_return,
|
||||
as_root=as_root, timeout=timeout)
|
||||
|
@ -290,7 +307,7 @@ class DeviceUtils(object):
|
|||
cmd: Same as for |RunShellCommand|.
|
||||
check_return: Same as for |RunShellCommand|.
|
||||
as_root: Same as for |RunShellCommand|.
|
||||
timeout: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
Raises:
|
||||
Same as for |RunShellCommand|.
|
||||
Returns:
|
||||
|
@ -323,10 +340,12 @@ class DeviceUtils(object):
|
|||
root privileges.
|
||||
blocking: A boolean indicating whether we should wait until all processes
|
||||
with the given |process_name| are dead.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandFailedError if no process was killed.
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
pids = self.old_interface.ExtractPid(process_name)
|
||||
if len(pids) == 0:
|
||||
|
@ -357,10 +376,12 @@ class DeviceUtils(object):
|
|||
trace should be saved.
|
||||
force_stop: A boolean indicating whether we should stop the activity
|
||||
before starting it.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandFailedError if the activity could not be started.
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
single_category = (intent.category[0] if isinstance(intent.category, list)
|
||||
else intent.category)
|
||||
|
@ -379,8 +400,11 @@ class DeviceUtils(object):
|
|||
|
||||
Args:
|
||||
intent: An Intent to broadcast.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
package, old_intent = intent.action.rsplit('.', 1)
|
||||
if intent.extras is None:
|
||||
|
@ -395,8 +419,11 @@ class DeviceUtils(object):
|
|||
"""Return to the home screen.
|
||||
|
||||
Args:
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
self.old_interface.GoHome()
|
||||
|
||||
|
@ -406,8 +433,11 @@ class DeviceUtils(object):
|
|||
|
||||
Args:
|
||||
package: A string containing the name of the package to stop.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
self.old_interface.CloseApplication(package)
|
||||
|
||||
|
@ -417,8 +447,11 @@ class DeviceUtils(object):
|
|||
|
||||
Args:
|
||||
package: A string containing the name of the package to stop.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
self.old_interface.ClearApplicationState(package)
|
||||
|
||||
|
@ -430,8 +463,11 @@ class DeviceUtils(object):
|
|||
|
||||
Args:
|
||||
keycode: A integer keycode to send to the device.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
self.old_interface.SendKeyEvent(keycode)
|
||||
|
||||
|
@ -450,8 +486,12 @@ class DeviceUtils(object):
|
|||
on the host that should be minimally pushed to the device.
|
||||
device_path: A string containing the absolute path of the destination on
|
||||
the device.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandFailedError on failure.
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
self.old_interface.PushIfNeeded(host_path, device_path)
|
||||
|
||||
|
@ -462,10 +502,13 @@ class DeviceUtils(object):
|
|||
Args:
|
||||
device_path: A string containing the absolute path to the file on the
|
||||
device.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
True if the file exists on the device, False otherwise.
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
return self._FileExistsImpl(device_path)
|
||||
|
||||
|
@ -479,6 +522,8 @@ class DeviceUtils(object):
|
|||
device_path: Same as for |FileExists|.
|
||||
Returns:
|
||||
True if the file exists on the device, False otherwise.
|
||||
Raises:
|
||||
Same as for |FileExists|.
|
||||
"""
|
||||
return self.old_interface.FileExistsOnDevice(device_path)
|
||||
|
||||
|
@ -491,10 +536,17 @@ class DeviceUtils(object):
|
|||
from the device.
|
||||
host_path: A string containing the absolute path of the destination on
|
||||
the host.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandFailedError on failure.
|
||||
CommandTimeoutError on timeout.
|
||||
"""
|
||||
self.old_interface.PullFileFromDevice(device_path, host_path)
|
||||
try:
|
||||
self.old_interface.PullFileFromDevice(device_path, host_path)
|
||||
except AssertionError as e:
|
||||
raise device_errors.CommandFailedError(
|
||||
str(e), device=str(self)), None, sys.exc_info()[2]
|
||||
|
||||
@decorators.WithTimeoutAndRetriesFromInstance()
|
||||
def ReadFile(self, device_path, as_root=False, timeout=None, retries=None):
|
||||
|
@ -505,12 +557,14 @@ class DeviceUtils(object):
|
|||
from the device.
|
||||
as_root: A boolean indicating whether the read should be executed with
|
||||
root privileges.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
The contents of the file at |device_path| as a list of lines.
|
||||
Raises:
|
||||
CommandFailedError if the file can't be read.
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
# TODO(jbudorick) Evaluate whether we actually want to return a list of
|
||||
# lines after the implementation switch.
|
||||
|
@ -533,10 +587,12 @@ class DeviceUtils(object):
|
|||
contents: A string containing the data to write to the device.
|
||||
as_root: A boolean indicating whether the write should be executed with
|
||||
root privileges.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandFailedError if the file could not be written on the device.
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
if as_root:
|
||||
if not self.old_interface.CanAccessProtectedFileContents():
|
||||
|
@ -553,10 +609,13 @@ class DeviceUtils(object):
|
|||
Args:
|
||||
device_path: A string containing the path of the directory on the device
|
||||
to list.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
The contents of the directory specified by |device_path|.
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
return self.old_interface.ListPathContents(device_path)
|
||||
|
||||
|
@ -567,8 +626,10 @@ class DeviceUtils(object):
|
|||
Args:
|
||||
enabled: A boolean indicating whether Java asserts should be enabled
|
||||
or disabled.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
"""
|
||||
self.old_interface.SetJavaAssertsEnabled(enabled)
|
||||
|
||||
|
@ -579,10 +640,12 @@ class DeviceUtils(object):
|
|||
Args:
|
||||
property_name: A string containing the name of the property to get from
|
||||
the device.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
The value of the device's |property_name| property.
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
"""
|
||||
return self.old_interface.system_properties[property_name]
|
||||
|
||||
|
@ -595,11 +658,73 @@ class DeviceUtils(object):
|
|||
the device.
|
||||
value: A string containing the value to set to the property on the
|
||||
device.
|
||||
timeout: Same as for |IsOnline|.
|
||||
retries: Same as for |IsOnline|.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
"""
|
||||
self.old_interface.system_properties[property_name] = value
|
||||
|
||||
@decorators.WithTimeoutAndRetriesFromInstance()
|
||||
def GetPids(self, process_name, timeout=None, retries=None):
|
||||
"""Returns the PIDs of processes with the given name.
|
||||
|
||||
Note that the |process_name| is often the package name.
|
||||
|
||||
Args:
|
||||
process_name: A string containing the process name to get the PIDs for.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
A dict mapping process name to PID for each process that contained the
|
||||
provided |process_name|.
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
procs_pids = {}
|
||||
for line in self._RunShellCommandImpl('ps'):
|
||||
try:
|
||||
ps_data = line.split()
|
||||
if process_name in ps_data[-1]:
|
||||
procs_pids[ps_data[-1]] = ps_data[1]
|
||||
except IndexError:
|
||||
pass
|
||||
return procs_pids
|
||||
|
||||
@decorators.WithTimeoutAndRetriesFromInstance()
|
||||
def TakeScreenshot(self, host_path=None, timeout=None, retries=None):
|
||||
"""Takes a screenshot of the device.
|
||||
|
||||
Args:
|
||||
host_path: A string containing the path on the host to save the
|
||||
screenshot to. If None, a file name will be generated.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
The name of the file on the host to which the screenshot was saved.
|
||||
Raises:
|
||||
CommandFailedError on failure.
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
return self.old_interface.TakeScreenshot(host_path)
|
||||
|
||||
@decorators.WithTimeoutAndRetriesFromInstance()
|
||||
def GetIOStats(self, timeout=None, retries=None):
|
||||
"""Gets cumulative disk IO stats since boot for all processes.
|
||||
|
||||
Args:
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
Returns:
|
||||
A dict containing |num_reads|, |num_writes|, |read_ms|, and |write_ms|.
|
||||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
return self.old_interface.GetIoStats()
|
||||
|
||||
def __str__(self):
|
||||
"""Returns the device serial."""
|
||||
return self.old_interface.GetDevice()
|
||||
|
|
|
@ -72,6 +72,75 @@ class _PatchedFunction(object):
|
|||
self.mocked = mocked
|
||||
|
||||
|
||||
class MockFileSystem(object):
|
||||
|
||||
@staticmethod
|
||||
def osStatResult(
|
||||
st_mode=None, st_ino=None, st_dev=None, st_nlink=None, st_uid=None,
|
||||
st_gid=None, st_size=None, st_atime=None, st_mtime=None, st_ctime=None):
|
||||
MockOSStatResult = collections.namedtuple('MockOSStatResult', [
|
||||
'st_mode', 'st_ino', 'st_dev', 'st_nlink', 'st_uid', 'st_gid',
|
||||
'st_size', 'st_atime', 'st_mtime', 'st_ctime'])
|
||||
return MockOSStatResult(st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid,
|
||||
st_size, st_atime, st_mtime, st_ctime)
|
||||
|
||||
MOCKED_FUNCTIONS = [
|
||||
('os.path.abspath', ''),
|
||||
('os.path.dirname', ''),
|
||||
('os.path.exists', False),
|
||||
('os.path.getsize', 0),
|
||||
('os.path.isdir', False),
|
||||
('os.stat', osStatResult.__func__()),
|
||||
('os.walk', []),
|
||||
]
|
||||
|
||||
def _get(self, mocked, path, default_val):
|
||||
if self._verbose:
|
||||
logging.debug('%s(%s)' % (mocked, path))
|
||||
return (self.mock_file_info[path][mocked]
|
||||
if path in self.mock_file_info
|
||||
else default_val)
|
||||
|
||||
def _patched(self, target, default_val=None):
|
||||
r = lambda f: self._get(target, f, default_val)
|
||||
return _PatchedFunction(patched=mock.patch(target, side_effect=r))
|
||||
|
||||
def __init__(self, verbose=False):
|
||||
self.mock_file_info = {}
|
||||
self._patched_functions = [
|
||||
self._patched(m, d) for m, d in type(self).MOCKED_FUNCTIONS]
|
||||
self._verbose = verbose
|
||||
|
||||
def addMockFile(self, path, **kw):
|
||||
self._addMockThing(path, False, **kw)
|
||||
|
||||
def addMockDirectory(self, path, **kw):
|
||||
self._addMockThing(path, True, **kw)
|
||||
|
||||
def _addMockThing(self, path, is_dir, size=0, stat=None, walk=None):
|
||||
if stat is None:
|
||||
stat = self.osStatResult()
|
||||
if walk is None:
|
||||
walk = []
|
||||
self.mock_file_info[path] = {
|
||||
'os.path.abspath': path,
|
||||
'os.path.dirname': '/' + '/'.join(path.strip('/').split('/')[:-1]),
|
||||
'os.path.exists': True,
|
||||
'os.path.isdir': is_dir,
|
||||
'os.path.getsize': size,
|
||||
'os.stat': stat,
|
||||
'os.walk': walk,
|
||||
}
|
||||
|
||||
def __enter__(self):
|
||||
for p in self._patched_functions:
|
||||
p.mocked = p.patched.__enter__()
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
for p in self._patched_functions:
|
||||
p.patched.__exit__()
|
||||
|
||||
|
||||
class DeviceUtilsOldImplTest(unittest.TestCase):
|
||||
|
||||
class AndroidCommandsCalls(object):
|
||||
|
@ -787,68 +856,6 @@ class DeviceUtilsSendKeyEventTest(DeviceUtilsOldImplTest):
|
|||
|
||||
class DeviceUtilsPushChangedFilesTest(DeviceUtilsOldImplTest):
|
||||
|
||||
class MockFileSystem(object):
|
||||
|
||||
@staticmethod
|
||||
def osStatResult(
|
||||
st_mode=None, st_ino=None, st_dev=None, st_nlink=None, st_uid=None,
|
||||
st_gid=None, st_size=None, st_atime=None, st_mtime=None, st_ctime=None):
|
||||
MockOSStatResult = collections.namedtuple('MockOSStatResult', [
|
||||
'st_mode', 'st_ino', 'st_dev', 'st_nlink', 'st_uid', 'st_gid',
|
||||
'st_size', 'st_atime', 'st_mtime', 'st_ctime'])
|
||||
return MockOSStatResult(st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid,
|
||||
st_size, st_atime, st_mtime, st_ctime)
|
||||
|
||||
def _get(self, mocked, path, default_val):
|
||||
return (self.mock_file_info[path][mocked]
|
||||
if path in self.mock_file_info
|
||||
else default_val)
|
||||
|
||||
def _patched(self, target, default_val=None):
|
||||
r = lambda f: self._get(target, f, default_val)
|
||||
return _PatchedFunction(patched=mock.patch(target, side_effect=r))
|
||||
|
||||
def __init__(self):
|
||||
self.mock_file_info = {}
|
||||
self._os_path_exists = self._patched('os.path.exists', default_val=False)
|
||||
self._os_path_getsize = self._patched('os.path.getsize', default_val=0)
|
||||
self._os_path_isdir = self._patched('os.path.isdir', default_val=False)
|
||||
self._os_stat = self._patched('os.stat', default_val=self.osStatResult())
|
||||
self._os_walk = self._patched('os.walk', default_val=[])
|
||||
|
||||
def addMockFile(self, path, size, **kw):
|
||||
self._addMockThing(path, size, False, **kw)
|
||||
|
||||
def addMockDirectory(self, path, size, **kw):
|
||||
self._addMockThing(path, size, True, **kw)
|
||||
|
||||
def _addMockThing(self, path, size, is_dir, stat=None, walk=None):
|
||||
if stat is None:
|
||||
stat = self.osStatResult()
|
||||
if walk is None:
|
||||
walk = []
|
||||
self.mock_file_info[path] = {
|
||||
'os.path.exists': True,
|
||||
'os.path.isdir': is_dir,
|
||||
'os.path.getsize': size,
|
||||
'os.stat': stat,
|
||||
'os.walk': walk,
|
||||
}
|
||||
|
||||
def __enter__(self):
|
||||
self._os_path_exists.mocked = self._os_path_exists.patched.__enter__()
|
||||
self._os_path_getsize.mocked = self._os_path_getsize.patched.__enter__()
|
||||
self._os_path_isdir.mocked = self._os_path_isdir.patched.__enter__()
|
||||
self._os_stat.mocked = self._os_stat.patched.__enter__()
|
||||
self._os_walk.mocked = self._os_walk.patched.__enter__()
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self._os_walk.patched.__exit__()
|
||||
self._os_stat.patched.__exit__()
|
||||
self._os_path_isdir.patched.__exit__(exc_type, exc_val, exc_tb)
|
||||
self._os_path_getsize.patched.__exit__(exc_type, exc_val, exc_tb)
|
||||
self._os_path_exists.patched.__exit__(exc_type, exc_val, exc_tb)
|
||||
|
||||
|
||||
def testPushChangedFiles_noHostPath(self):
|
||||
with mock.patch('os.path.exists', return_value=False):
|
||||
|
@ -861,8 +868,8 @@ class DeviceUtilsPushChangedFilesTest(DeviceUtilsOldImplTest):
|
|||
host_file_path = '/test/host/path'
|
||||
device_file_path = '/test/device/path'
|
||||
|
||||
mock_fs = self.MockFileSystem()
|
||||
mock_fs.addMockFile(host_file_path, 100)
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockFile(host_file_path, size=100)
|
||||
|
||||
self.device.old_interface.GetFilesChanged = mock.Mock(return_value=[])
|
||||
|
||||
|
@ -877,10 +884,10 @@ class DeviceUtilsPushChangedFilesTest(DeviceUtilsOldImplTest):
|
|||
host_file_path = '/test/host/path'
|
||||
device_file_path = '/test/device/path'
|
||||
|
||||
mock_fs = self.MockFileSystem()
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockFile(
|
||||
host_file_path, 100,
|
||||
stat=self.MockFileSystem.osStatResult(st_mtime=1000000000))
|
||||
host_file_path, size=100,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000000))
|
||||
|
||||
self.device.old_interface.GetFilesChanged = mock.Mock(
|
||||
return_value=[('/test/host/path', '/test/device/path')])
|
||||
|
@ -896,16 +903,16 @@ class DeviceUtilsPushChangedFilesTest(DeviceUtilsOldImplTest):
|
|||
host_file_path = '/test/host/path'
|
||||
device_file_path = '/test/device/path'
|
||||
|
||||
mock_fs = self.MockFileSystem()
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockDirectory(
|
||||
host_file_path, 256,
|
||||
stat=self.MockFileSystem.osStatResult(st_mtime=1000000000))
|
||||
host_file_path, size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000000))
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file1', 251,
|
||||
stat=self.MockFileSystem.osStatResult(st_mtime=1000000001))
|
||||
host_file_path + '/file1', size=251,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000001))
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file2', 252,
|
||||
stat=self.MockFileSystem.osStatResult(st_mtime=1000000002))
|
||||
host_file_path + '/file2', size=252,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000002))
|
||||
|
||||
self.device.old_interface.GetFilesChanged = mock.Mock(return_value=[])
|
||||
|
||||
|
@ -921,17 +928,17 @@ class DeviceUtilsPushChangedFilesTest(DeviceUtilsOldImplTest):
|
|||
host_file_path = '/test/host/path'
|
||||
device_file_path = '/test/device/path'
|
||||
|
||||
mock_fs = self.MockFileSystem()
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockDirectory(
|
||||
host_file_path, 256,
|
||||
stat=self.MockFileSystem.osStatResult(st_mtime=1000000000),
|
||||
host_file_path, size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000000),
|
||||
walk=[('/test/host/path', [], ['file1', 'file2'])])
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file1', 256,
|
||||
stat=self.MockFileSystem.osStatResult(st_mtime=1000000001))
|
||||
host_file_path + '/file1', size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000001))
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file2', 256,
|
||||
stat=self.MockFileSystem.osStatResult(st_mtime=1000000002))
|
||||
host_file_path + '/file2', size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000002))
|
||||
|
||||
self.device.old_interface.GetFilesChanged = mock.Mock(
|
||||
return_value=[('/test/host/path/file1', '/test/device/path/file1')])
|
||||
|
@ -951,16 +958,16 @@ class DeviceUtilsPushChangedFilesTest(DeviceUtilsOldImplTest):
|
|||
host_file_path = '/test/host/path'
|
||||
device_file_path = '/test/device/path'
|
||||
|
||||
mock_fs = self.MockFileSystem()
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockDirectory(
|
||||
host_file_path, 256,
|
||||
stat=self.MockFileSystem.osStatResult(st_mtime=1000000000))
|
||||
host_file_path, size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000000))
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file1', 256,
|
||||
stat=self.MockFileSystem.osStatResult(st_mtime=1000000001))
|
||||
host_file_path + '/file1', size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000001))
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file2', 256,
|
||||
stat=self.MockFileSystem.osStatResult(st_mtime=1000000002))
|
||||
host_file_path + '/file2', size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000002))
|
||||
|
||||
self.device.old_interface.GetFilesChanged = mock.Mock(
|
||||
return_value=[('/test/host/path/file1', '/test/device/path/file1'),
|
||||
|
@ -1356,6 +1363,86 @@ class DeviceUtilsSetPropTest(DeviceUtilsOldImplTest):
|
|||
self.device.SetProp('this.is.a.test.property', 'test_property_value')
|
||||
|
||||
|
||||
class DeviceUtilsGetPidsTest(DeviceUtilsOldImplTest):
|
||||
|
||||
def testGetPids_noMatches(self):
|
||||
with self.assertCalls(
|
||||
"adb -s 0123456789abcdef shell 'ps'",
|
||||
'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
|
||||
'user 1000 100 1024 1024 ffffffff 00000000 no.match\r\n'):
|
||||
self.assertEqual({}, self.device.GetPids('does.not.match'))
|
||||
|
||||
def testGetPids_oneMatch(self):
|
||||
with self.assertCalls(
|
||||
"adb -s 0123456789abcdef shell 'ps'",
|
||||
'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
|
||||
'user 1000 100 1024 1024 ffffffff 00000000 not.a.match\r\n'
|
||||
'user 1001 100 1024 1024 ffffffff 00000000 one.match\r\n'):
|
||||
self.assertEqual({'one.match': '1001'}, self.device.GetPids('one.match'))
|
||||
|
||||
def testGetPids_mutlipleMatches(self):
|
||||
with self.assertCalls(
|
||||
"adb -s 0123456789abcdef shell 'ps'",
|
||||
'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
|
||||
'user 1000 100 1024 1024 ffffffff 00000000 not\r\n'
|
||||
'user 1001 100 1024 1024 ffffffff 00000000 one.match\r\n'
|
||||
'user 1002 100 1024 1024 ffffffff 00000000 two.match\r\n'
|
||||
'user 1003 100 1024 1024 ffffffff 00000000 three.match\r\n'):
|
||||
self.assertEqual(
|
||||
{'one.match': '1001', 'two.match': '1002', 'three.match': '1003'},
|
||||
self.device.GetPids('match'))
|
||||
|
||||
def testGetPids_exactMatch(self):
|
||||
with self.assertCalls(
|
||||
"adb -s 0123456789abcdef shell 'ps'",
|
||||
'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
|
||||
'user 1000 100 1024 1024 ffffffff 00000000 not.exact.match\r\n'
|
||||
'user 1234 100 1024 1024 ffffffff 00000000 exact.match\r\n'):
|
||||
self.assertEqual(
|
||||
{'not.exact.match': '1000', 'exact.match': '1234'},
|
||||
self.device.GetPids('exact.match'))
|
||||
|
||||
|
||||
class DeviceUtilsTakeScreenshotTest(DeviceUtilsOldImplTest):
|
||||
|
||||
def testTakeScreenshot_fileNameProvided(self):
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockDirectory('/test/host')
|
||||
mock_fs.addMockFile('/test/host/screenshot.png')
|
||||
|
||||
with mock_fs:
|
||||
with self.assertCallsSequence(
|
||||
cmd_ret=[
|
||||
(r"adb -s 0123456789abcdef shell 'echo \$EXTERNAL_STORAGE'",
|
||||
'/test/external/storage\r\n'),
|
||||
(r"adb -s 0123456789abcdef shell '/system/bin/screencap -p \S+'",
|
||||
''),
|
||||
(r"adb -s 0123456789abcdef shell ls \S+",
|
||||
'/test/external/storage/screenshot.png\r\n'),
|
||||
(r'adb -s 0123456789abcdef pull \S+ /test/host/screenshot.png',
|
||||
'100 B/s (100 B in 1.000s)\r\n'),
|
||||
(r"adb -s 0123456789abcdef shell 'rm -f \S+'", '')
|
||||
],
|
||||
comp=re.match):
|
||||
self.device.TakeScreenshot('/test/host/screenshot.png')
|
||||
|
||||
|
||||
class DeviceUtilsGetIOStatsTest(DeviceUtilsOldImplTest):
|
||||
|
||||
def testGetIOStats(self):
|
||||
with self.assertCalls(
|
||||
"adb -s 0123456789abcdef shell 'cat \"/proc/diskstats\" 2>/dev/null'",
|
||||
'179 0 mmcblk0 1 2 3 4 5 6 7 8 9 10 11\r\n'):
|
||||
self.assertEqual(
|
||||
{
|
||||
'num_reads': 1,
|
||||
'num_writes': 5,
|
||||
'read_ms': 4,
|
||||
'write_ms': 8,
|
||||
},
|
||||
self.device.GetIOStats())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
unittest.main(verbosity=2)
|
||||
|
|
|
@ -341,9 +341,7 @@ class Forwarder(object):
|
|||
# 'kill-server') is not running on the bots anymore.
|
||||
timeout_sec = 5
|
||||
try:
|
||||
device.KillAll(
|
||||
'device_forwarder', blocking=True, timeout=timeout_sec)
|
||||
device.KillAll('device_forwarder', blocking=True, timeout=timeout_sec)
|
||||
except device_errors.CommandFailedError:
|
||||
pids = device.old_interface.ExtractPid('device_forwarder')
|
||||
if pids:
|
||||
if device.GetPids('device_forwarder'):
|
||||
raise
|
||||
|
|
|
@ -142,7 +142,7 @@ class TestRunner(base_test_runner.BaseTestRunner):
|
|||
"""Takes a screenshot from the device."""
|
||||
screenshot_name = os.path.join(constants.SCREENSHOTS_DIR, '%s.png' % test)
|
||||
logging.info('Taking screenshot named %s', screenshot_name)
|
||||
self.device.old_interface.TakeScreenshot(screenshot_name)
|
||||
self.device.TakeScreenshot(screenshot_name)
|
||||
|
||||
def SetUp(self):
|
||||
"""Sets up the test harness and device before all tests are run."""
|
||||
|
|
|
@ -58,22 +58,22 @@ class TestRunner(base_test_runner.BaseTestRunner):
|
|||
|
||||
# Chrome crashes are not always caught by Monkey test runner.
|
||||
# Verify Chrome has the same PID before and after the test.
|
||||
before_pids = self.device.old_interface.ExtractPid(self._package)
|
||||
before_pids = self.device.GetPids(self._package)
|
||||
|
||||
# Run the test.
|
||||
output = ''
|
||||
if before_pids:
|
||||
output = '\n'.join(self._LaunchMonkeyTest())
|
||||
after_pids = self.device.old_interface.ExtractPid(self._package)
|
||||
after_pids = self.device.GetPids(self._package)
|
||||
|
||||
crashed = True
|
||||
if not before_pids:
|
||||
if not self._package in before_pids:
|
||||
logging.error('Failed to start the process.')
|
||||
elif not after_pids:
|
||||
logging.error('Process %s has died.', before_pids[0])
|
||||
elif before_pids[0] != after_pids[0]:
|
||||
elif not self._package in after_pids:
|
||||
logging.error('Process %s has died.', before_pids[self._package])
|
||||
elif before_pids[self._package] != after_pids[self._package]:
|
||||
logging.error('Detected process restart %s -> %s',
|
||||
before_pids[0], after_pids[0])
|
||||
before_pids[self._package], after_pids[self._package])
|
||||
else:
|
||||
crashed = False
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# found in the LICENSE file.
|
||||
|
||||
import os
|
||||
import signal
|
||||
import tempfile
|
||||
|
||||
from pylib import cmd_helper
|
||||
|
@ -33,7 +34,6 @@ class VideoRecorder(object):
|
|||
self._device_file = (
|
||||
'%s/screen-recording.mp4' % device.GetExternalStoragePath())
|
||||
self._recorder = None
|
||||
self._recorder_pids = None
|
||||
self._recorder_stdout = None
|
||||
self._is_started = False
|
||||
|
||||
|
@ -53,8 +53,7 @@ class VideoRecorder(object):
|
|||
self._recorder_stdout = tempfile.mkstemp()[1]
|
||||
self._recorder = cmd_helper.Popen(
|
||||
self._args, stdout=open(self._recorder_stdout, 'w'))
|
||||
self._recorder_pids = self._device.old_interface.ExtractPid('screenrecord')
|
||||
if not self._recorder_pids:
|
||||
if not self._device.GetPids('screenrecord'):
|
||||
raise RuntimeError('Recording failed. Is your device running Android '
|
||||
'KitKat or later?')
|
||||
|
||||
|
@ -70,17 +69,18 @@ class VideoRecorder(object):
|
|||
"""Stop recording video."""
|
||||
os.remove(self._recorder_stdout)
|
||||
self._is_started = False
|
||||
if not self._recorder or not self._recorder_pids:
|
||||
if not self._recorder:
|
||||
return
|
||||
self._device.RunShellCommand(
|
||||
'kill -SIGINT ' + ' '.join(self._recorder_pids))
|
||||
self._device.KillAll('screenrecord', signum=signal.SIGINT)
|
||||
self._recorder.wait()
|
||||
|
||||
def Pull(self, host_file):
|
||||
def Pull(self, host_file=None):
|
||||
"""Pull resulting video file from the device.
|
||||
|
||||
Args:
|
||||
host_file: Path to the video file to store on the host.
|
||||
Returns:
|
||||
Output video file name on the host.
|
||||
"""
|
||||
host_file_name = host_file or ('screen-recording-%s.mp4' %
|
||||
self._device.old_interface.GetTimestamp())
|
||||
|
@ -88,3 +88,4 @@ class VideoRecorder(object):
|
|||
self._device.old_interface.EnsureHostDirectory(host_file_name)
|
||||
self._device.PullFile(self._device_file, host_file_name)
|
||||
self._device.RunShellCommand('rm -f "%s"' % self._device_file)
|
||||
return host_file_name
|
||||
|
|
|
@ -21,7 +21,7 @@ def _PrintMessage(heading, eol='\n'):
|
|||
|
||||
|
||||
def _CaptureScreenshot(device, host_file):
|
||||
host_file = device.old_interface.TakeScreenshot(host_file)
|
||||
host_file = device.TakeScreenshot(host_file)
|
||||
_PrintMessage('Screenshot written to %s' % os.path.abspath(host_file))
|
||||
|
||||
|
||||
|
@ -37,7 +37,7 @@ def _CaptureVideo(device, host_file, options):
|
|||
raw_input()
|
||||
finally:
|
||||
recorder.Stop()
|
||||
recorder.Pull(host_file)
|
||||
host_file = recorder.Pull(host_file)
|
||||
_PrintMessage('Video written to %s' % os.path.abspath(host_file))
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче