blob: fa4ffaae40c19274dcdfb8cfcaae9be12bfac109 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Unit tests for the contents of device_utils.py (mostly DeviceUtils).
"""
# pylint: disable=C0321
# pylint: disable=W0212
# pylint: disable=W0613
import collections
import datetime
import logging
import os
import re
import signal
import sys
import unittest
from pylib import android_commands
from pylib import constants
from pylib.device import adb_wrapper
from pylib.device import device_errors
from pylib.device import device_utils
from pylib.device import intent
# RunCommand from third_party/android_testrunner/run_command.py is mocked
# below, so its path needs to be in sys.path.
sys.path.append(os.path.join(
constants.DIR_SOURCE_ROOT, 'third_party', 'android_testrunner'))
sys.path.append(os.path.join(
constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
import mock # pylint: disable=F0401
class DeviceUtilsTest(unittest.TestCase):
def testInitWithStr(self):
serial_as_str = str('0123456789abcdef')
d = device_utils.DeviceUtils('0123456789abcdef')
self.assertEqual(serial_as_str, d.old_interface.GetDevice())
def testInitWithUnicode(self):
serial_as_unicode = unicode('fedcba9876543210')
d = device_utils.DeviceUtils(serial_as_unicode)
self.assertEqual(serial_as_unicode, d.old_interface.GetDevice())
def testInitWithAdbWrapper(self):
serial = '123456789abcdef0'
a = adb_wrapper.AdbWrapper(serial)
d = device_utils.DeviceUtils(a)
self.assertEqual(serial, d.old_interface.GetDevice())
def testInitWithAndroidCommands(self):
serial = '0fedcba987654321'
a = android_commands.AndroidCommands(device=serial)
d = device_utils.DeviceUtils(a)
self.assertEqual(serial, d.old_interface.GetDevice())
def testInitWithNone(self):
d = device_utils.DeviceUtils(None)
self.assertIsNone(d.old_interface.GetDevice())
class _PatchedFunction(object):
def __init__(self, patched=None, mocked=None):
self.patched = patched
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.listdir', []),
('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, listdir=None, size=0, stat=None,
walk=None):
if listdir is None:
listdir = []
if stat is None:
stat = self.osStatResult()
if walk is None:
walk = []
dirname = os.sep.join(path.rstrip(os.sep).split(os.sep)[:-1])
if dirname and not dirname in self.mock_file_info:
self._addMockThing(dirname, True)
self.mock_file_info[path] = {
'os.listdir': listdir,
'os.path.abspath': path,
'os.path.dirname': dirname,
'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):
def __init__(self, test_case, cmd_ret, comp):
self._cmds = cmd_ret
self._comp = comp
self._run_command = _PatchedFunction()
self._test_case = test_case
self._total_received = 0
def __enter__(self):
self._run_command.patched = mock.patch(
'run_command.RunCommand',
side_effect=lambda c, **kw: self._ret(c))
self._run_command.mocked = self._run_command.patched.__enter__()
def _ret(self, actual_cmd):
if sys.exc_info()[0] is None:
on_failure_fmt = ('\n'
' received command: %s\n'
' expected command: %s')
self._test_case.assertGreater(
len(self._cmds), self._total_received,
msg=on_failure_fmt % (actual_cmd, None))
expected_cmd, ret = self._cmds[self._total_received]
self._total_received += 1
self._test_case.assertTrue(
self._comp(expected_cmd, actual_cmd),
msg=on_failure_fmt % (actual_cmd, expected_cmd))
return ret
return ''
def __exit__(self, exc_type, exc_val, exc_tb):
self._run_command.patched.__exit__(exc_type, exc_val, exc_tb)
if exc_type is None:
on_failure = "adb commands don't match.\nExpected:%s\nActual:%s" % (
''.join('\n %s' % c for c, _ in self._cmds),
''.join('\n %s' % a[0]
for _, a, kw in self._run_command.mocked.mock_calls))
self._test_case.assertEqual(
len(self._cmds), len(self._run_command.mocked.mock_calls),
msg=on_failure)
for (expected_cmd, _r), (_n, actual_args, actual_kwargs) in zip(
self._cmds, self._run_command.mocked.mock_calls):
self._test_case.assertEqual(1, len(actual_args), msg=on_failure)
self._test_case.assertTrue(self._comp(expected_cmd, actual_args[0]),
msg=on_failure)
self._test_case.assertTrue('timeout_time' in actual_kwargs,
msg=on_failure)
self._test_case.assertTrue('retry_count' in actual_kwargs,
msg=on_failure)
def assertNoAdbCalls(self):
return type(self).AndroidCommandsCalls(self, [], str.__eq__)
def assertCalls(self, cmd, ret, comp=str.__eq__):
return type(self).AndroidCommandsCalls(self, [(cmd, ret)], comp)
def assertCallsSequence(self, cmd_ret, comp=str.__eq__):
return type(self).AndroidCommandsCalls(self, cmd_ret, comp)
def setUp(self):
self.device = device_utils.DeviceUtils(
'0123456789abcdef', default_timeout=1, default_retries=0)
class Args:
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def __eq__(self, other):
return (self.args, self.kwargs) == (other.args, other.kwargs)
def __repr__(self):
return '%s(%s)' % (type(self).__name__, str(self))
def __str__(self):
toks = (['%r' % v for v in self.args] +
['%s=%r' % (k, self.kwargs[k]) for k in sorted(self.kwargs)])
return ', '.join(toks)
class MockCallSequence(object):
def __init__(self, test_case, obj, method, calls):
def assert_and_return(*args, **kwargs):
received_args = Args(*args, **kwargs)
test_case.assertTrue(
self._calls,
msg=('Unexpected call\n'
' received: %s(%s)\n' % (self._method, received_args)))
expected_args, return_value = self._calls.pop(0)
test_case.assertTrue(
received_args == expected_args,
msg=('Call does not match expected args\n'
' received: %s(%s)\n'
' expected: %s(%s)\n'
% (self._method, received_args,
self._method, expected_args)))
if isinstance(return_value, Exception):
raise return_value
else:
return return_value
self._calls = list(calls)
self._test_case = test_case
self._method = method
self._patched = mock.patch.object(obj, self._method,
side_effect=assert_and_return)
def __enter__(self):
return self._patched.__enter__()
def __exit__(self, exc_type, exc_val, exc_tb):
self._patched.__exit__(exc_type, exc_val, exc_tb)
if exc_type is None:
missing = ''.join(' expected: %s(%s)\n'
% (self._method, expected_args)
for expected_args, _ in self._calls)
self._test_case.assertTrue(
not missing,
msg=('Expected calls not found\n' + missing))
class _ShellError:
def __init__(self, output=None, return_code=1):
if output is None:
self.output = 'Permission denied\r\n'
else:
self.output = output
self.return_code = return_code
class _CmdTimeout:
def __init__(self, msg=None):
if msg is None:
self.msg = 'Operation timed out'
else:
self.msg = msg
class DeviceUtilsNewImplTest(unittest.TestCase):
def setUp(self):
test_serial = '0123456789abcdef'
self.adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
self.adb.__str__ = mock.Mock(return_value=test_serial)
self.adb.GetDeviceSerial.return_value = test_serial
self.device = device_utils.DeviceUtils(
self.adb, default_timeout=10, default_retries=0)
def assertShellCallSequence(self, calls):
'''Assert that we expect a sequence of calls to adb.Shell.
Args:
calls: a sequence of (cmd, return_value) pairs, where |cmd| is the
expected shell command to run on the device (with any quoting already
applied), and |return_value| is either a string to give as mock output
or a _ShellError object to raise an AdbShellCommandFailedError.
'''
def mk_expected_call(cmd, return_value):
expected_args = Args(cmd, expect_rc=0)
if isinstance(return_value, _ShellError):
return_value = device_errors.AdbShellCommandFailedError(cmd,
return_value.return_code, return_value.output, str(self.device))
elif isinstance(return_value, _CmdTimeout):
return_value = device_errors.CommandTimeoutError(return_value.msg,
str(self.device))
return (expected_args, return_value)
expected_calls = (mk_expected_call(a, r) for a, r in calls)
return MockCallSequence(self, self.adb, 'Shell', expected_calls)
def assertShellCall(self, cmd, return_value=''):
return self.assertShellCallSequence([(cmd, return_value)])
class DeviceUtilsHybridImplTest(DeviceUtilsOldImplTest):
def setUp(self):
super(DeviceUtilsHybridImplTest, self).setUp()
self.device.adb = self.adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
class DeviceUtilsIsOnlineTest(DeviceUtilsNewImplTest):
def testIsOnline_true(self):
self.adb.GetState = mock.Mock(return_value='device')
self.assertTrue(self.device.IsOnline())
self.adb.GetState.assert_called_once_with()
def testIsOnline_false(self):
self.adb.GetState = mock.Mock(return_value='offline')
self.assertFalse(self.device.IsOnline())
self.adb.GetState.assert_called_once_with()
def testIsOnline_error(self):
self.adb.GetState = mock.Mock(
side_effect=device_errors.CommandFailedError('falied'))
self.assertFalse(self.device.IsOnline())
self.adb.GetState.assert_called_once_with()
class DeviceUtilsHasRootTest(DeviceUtilsNewImplTest):
def testHasRoot_true(self):
with self.assertShellCall('ls /root', 'foo\r\n'):
self.assertTrue(self.device.HasRoot())
def testHasRoot_false(self):
with self.assertShellCall('ls /root', _ShellError()):
self.assertFalse(self.device.HasRoot())
class DeviceUtilsEnableRootTest(DeviceUtilsOldImplTest):
def testEnableRoot_succeeds(self):
with self.assertCallsSequence([
('adb -s 0123456789abcdef shell getprop ro.build.type',
'userdebug\r\n'),
('adb -s 0123456789abcdef root', 'restarting adbd as root\r\n'),
('adb -s 0123456789abcdef wait-for-device', ''),
('adb -s 0123456789abcdef wait-for-device', '')]):
self.device.EnableRoot()
def testEnableRoot_userBuild(self):
with self.assertCallsSequence([
('adb -s 0123456789abcdef shell getprop ro.build.type', 'user\r\n')]):
with self.assertRaises(device_errors.CommandFailedError):
self.device.EnableRoot()
def testEnableRoot_rootFails(self):
with self.assertCallsSequence([
('adb -s 0123456789abcdef shell getprop ro.build.type',
'userdebug\r\n'),
('adb -s 0123456789abcdef root', 'no\r\n'),
('adb -s 0123456789abcdef wait-for-device', '')]):
with self.assertRaises(device_errors.CommandFailedError):
self.device.EnableRoot()
class DeviceUtilsIsUserBuildTest(DeviceUtilsNewImplTest):
def testIsUserBuild_yes(self):
with self.assertShellCall('getprop ro.build.type', 'user\r\n'):
self.assertTrue(self.device.IsUserBuild())
def testIsUserBuild_no(self):
with self.assertShellCall('getprop ro.build.type', 'userdebug\r\n'):
self.assertFalse(self.device.IsUserBuild())
class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsNewImplTest):
def testGetExternalStoragePath_succeeds(self):
fakeStoragePath = '/fake/storage/path'
with self.assertShellCall('echo $EXTERNAL_STORAGE',
'%s\r\n' % fakeStoragePath):
self.assertEquals(fakeStoragePath,
self.device.GetExternalStoragePath())
def testGetExternalStoragePath_fails(self):
with self.assertShellCall('echo $EXTERNAL_STORAGE', '\r\n'):
with self.assertRaises(device_errors.CommandFailedError):
self.device.GetExternalStoragePath()
class DeviceUtilsGetApplicationPathTest(DeviceUtilsNewImplTest):
def testGetApplicationPath_exists(self):
with self.assertShellCall('pm path android',
'package:/path/to/android.apk\n'):
self.assertEquals('/path/to/android.apk',
self.device.GetApplicationPath('android'))
def testGetApplicationPath_notExists(self):
with self.assertShellCall('pm path not.installed.app',
''):
self.assertEquals(None,
self.device.GetApplicationPath('not.installed.app'))
def testGetApplicationPath_fails(self):
with self.assertShellCall('pm path android',
'ERROR. Is package manager running?\n'):
with self.assertRaises(device_errors.CommandFailedError):
self.device.GetApplicationPath('android')
class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsNewImplTest):
def testWaitUntilFullyBooted_succeedsNoWifi(self):
with self.assertShellCallSequence([
# sc_card_ready
('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
('test -d /fake/storage/path', ''),
# pm_ready
('pm path android', 'package:this.is.a.test.package\r\n'),
# boot_completed
('getprop sys.boot_completed', '1\r\n')]):
self.device.WaitUntilFullyBooted(wifi=False)
self.adb.WaitForDevice.assert_called_once_with()
def testWaitUntilFullyBooted_succeedsWithWifi(self):
with self.assertShellCallSequence([
# sc_card_ready
('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
('test -d /fake/storage/path', ''),
# pm_ready
('pm path android', 'package:this.is.a.test.package\r\n'),
# boot_completed
('getprop sys.boot_completed', '1\r\n'),
# wifi_enabled
('dumpsys wifi', 'stuff\r\nWi-Fi is enabled\r\nmore stuff\r\n')]):
self.device.WaitUntilFullyBooted(wifi=True)
self.adb.WaitForDevice.assert_called_once_with()
def testWaitUntilFullyBooted_sdCardReadyFails_noPath(self):
with self.assertShellCallSequence([
# sc_card_ready
('echo $EXTERNAL_STORAGE', '\r\n')]):
with self.assertRaises(device_errors.CommandFailedError):
self.device.WaitUntilFullyBooted(wifi=False)
def testWaitUntilFullyBooted_sdCardReadyFails_emptyPath(self):
with mock.patch('time.sleep'):
with self.assertShellCallSequence([
# sc_card_ready
('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
('test -d /fake/storage/path', _ShellError()),
# sc_card_ready
('test -d /fake/storage/path', _ShellError()),
# sc_card_ready
('test -d /fake/storage/path', _CmdTimeout())]):
with self.assertRaises(device_errors.CommandTimeoutError):
self.device.WaitUntilFullyBooted(wifi=False)
def testWaitUntilFullyBooted_devicePmFails(self):
with mock.patch('time.sleep'):
with self.assertShellCallSequence([
# sc_card_ready
('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
('test -d /fake/storage/path', ''),
# pm_ready
('pm path android', 'Error. Is package manager running?\r\n'),
# pm_ready
('pm path android', 'Error. Is package manager running?\r\n'),
# pm_ready
('pm path android', _CmdTimeout())]):
with self.assertRaises(device_errors.CommandTimeoutError):
self.device.WaitUntilFullyBooted(wifi=False)
def testWaitUntilFullyBooted_bootFails(self):
with mock.patch('time.sleep'):
with self.assertShellCallSequence([
# sc_card_ready
('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
('test -d /fake/storage/path', ''),
# pm_ready
('pm path android', 'package:this.is.a.test.package\r\n'),
# boot_completed
('getprop sys.boot_completed', '0\r\n'),
# boot_completed
('getprop sys.boot_completed', '0\r\n'),
# boot_completed
('getprop sys.boot_completed', _CmdTimeout())]):
with self.assertRaises(device_errors.CommandTimeoutError):
self.device.WaitUntilFullyBooted(wifi=False)
def testWaitUntilFullyBooted_wifiFails(self):
with mock.patch('time.sleep'):
with self.assertShellCallSequence([
# sc_card_ready
('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
('test -d /fake/storage/path', ''),
# pm_ready
('pm path android', 'package:this.is.a.test.package\r\n'),
# boot_completed
('getprop sys.boot_completed', '1\r\n'),
# wifi_enabled
('dumpsys wifi', 'stuff\r\nmore stuff\r\n'),
# wifi_enabled
('dumpsys wifi', 'stuff\r\nmore stuff\r\n'),
# wifi_enabled
('dumpsys wifi', _CmdTimeout())]):
with self.assertRaises(device_errors.CommandTimeoutError):
self.device.WaitUntilFullyBooted(wifi=True)
class DeviceUtilsRebootTest(DeviceUtilsNewImplTest):
def testReboot_nonBlocking(self):
self.adb.Reboot = mock.Mock()
self.device.IsOnline = mock.Mock(return_value=False)
self.device.Reboot(block=False)
self.adb.Reboot.assert_called_once_with()
self.device.IsOnline.assert_called_once_with()
def testReboot_blocking(self):
self.adb.Reboot = mock.Mock()
self.device.IsOnline = mock.Mock(return_value=False)
with self.assertShellCallSequence([
# sc_card_ready
('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
('test -d /fake/storage/path', ''),
# pm_ready
('pm path android', 'package:this.is.a.test.package\r\n'),
# boot_completed
('getprop sys.boot_completed', '1\r\n')]):
self.device.Reboot(block=True)
self.adb.Reboot.assert_called_once_with()
self.device.IsOnline.assert_called_once_with()
self.adb.WaitForDevice.assert_called_once_with()
class DeviceUtilsInstallTest(DeviceUtilsOldImplTest):
def testInstall_noPriorInstall(self):
with mock.patch('os.path.isfile', return_value=True), (
mock.patch('pylib.utils.apk_helper.GetPackageName',
return_value='this.is.a.test.package')):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'pm path this.is.a.test.package'",
''),
("adb -s 0123456789abcdef install /fake/test/app.apk",
'Success\r\n')]):
self.device.Install('/fake/test/app.apk', retries=0)
def testInstall_differentPriorInstall(self):
def mockGetFilesChanged(host_path, device_path, ignore_filenames):
return [(host_path, device_path)]
# Pylint raises a false positive "operator not preceded by a space"
# warning below.
# pylint: disable=C0322
with mock.patch('os.path.isfile', return_value=True), (
mock.patch('os.path.exists', return_value=True)), (
mock.patch('pylib.utils.apk_helper.GetPackageName',
return_value='this.is.a.test.package')), (
mock.patch('pylib.constants.GetOutDirectory',
return_value='/fake/test/out')), (
mock.patch('pylib.android_commands.AndroidCommands.GetFilesChanged',
side_effect=mockGetFilesChanged)):
# pylint: enable=C0322
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'pm path this.is.a.test.package'",
'package:/fake/data/app/this.is.a.test.package.apk\r\n'),
# GetFilesChanged is mocked, so its adb calls are omitted.
('adb -s 0123456789abcdef uninstall this.is.a.test.package',
'Success\r\n'),
('adb -s 0123456789abcdef install /fake/test/app.apk',
'Success\r\n')]):
self.device.Install('/fake/test/app.apk', retries=0)
def testInstall_differentPriorInstall_reinstall(self):
def mockGetFilesChanged(host_path, device_path, ignore_filenames):
return [(host_path, device_path)]
# Pylint raises a false positive "operator not preceded by a space"
# warning below.
# pylint: disable=C0322
with mock.patch('os.path.isfile', return_value=True), (
mock.patch('pylib.utils.apk_helper.GetPackageName',
return_value='this.is.a.test.package')), (
mock.patch('pylib.constants.GetOutDirectory',
return_value='/fake/test/out')), (
mock.patch('pylib.android_commands.AndroidCommands.GetFilesChanged',
side_effect=mockGetFilesChanged)):
# pylint: enable=C0322
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'pm path this.is.a.test.package'",
'package:/fake/data/app/this.is.a.test.package.apk\r\n'),
# GetFilesChanged is mocked, so its adb calls are omitted.
('adb -s 0123456789abcdef install -r /fake/test/app.apk',
'Success\r\n')]):
self.device.Install('/fake/test/app.apk', reinstall=True, retries=0)
def testInstall_identicalPriorInstall(self):
def mockGetFilesChanged(host_path, device_path, ignore_filenames):
return []
with mock.patch('pylib.utils.apk_helper.GetPackageName',
return_value='this.is.a.test.package'), (
mock.patch('pylib.android_commands.AndroidCommands.GetFilesChanged',
side_effect=mockGetFilesChanged)):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'pm path this.is.a.test.package'",
'package:/fake/data/app/this.is.a.test.package.apk\r\n')
# GetFilesChanged is mocked, so its adb calls are omitted.
]):
self.device.Install('/fake/test/app.apk', retries=0)
def testInstall_fails(self):
with mock.patch('os.path.isfile', return_value=True), (
mock.patch('pylib.utils.apk_helper.GetPackageName',
return_value='this.is.a.test.package')):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'pm path this.is.a.test.package'",
''),
("adb -s 0123456789abcdef install /fake/test/app.apk",
'Failure\r\n')]):
with self.assertRaises(device_errors.CommandFailedError):
self.device.Install('/fake/test/app.apk', retries=0)
class DeviceUtilsRunShellCommandTest(DeviceUtilsNewImplTest):
def testRunShellCommand_commandAsList(self):
with self.assertShellCall('pm list packages'):
self.device.RunShellCommand(['pm', 'list', 'packages'])
def testRunShellCommand_commandAsListQuoted(self):
with self.assertShellCall("echo 'hello world' '$10'"):
self.device.RunShellCommand(['echo', 'hello world', '$10'])
def testRunShellCommand_commandAsString(self):
with self.assertShellCall('echo "$VAR"'):
self.device.RunShellCommand('echo "$VAR"')
def testNewRunShellImpl_withEnv(self):
with self.assertShellCall('VAR=some_string echo "$VAR"'):
self.device.RunShellCommand('echo "$VAR"', env={'VAR': 'some_string'})
def testNewRunShellImpl_withEnvQuoted(self):
with self.assertShellCall('PATH="$PATH:/other/path" run_this'):
self.device.RunShellCommand('run_this', env={'PATH': '$PATH:/other/path'})
def testNewRunShellImpl_withEnv_failure(self):
with self.assertRaises(KeyError):
self.device.RunShellCommand('some_cmd', env={'INVALID NAME': 'value'})
def testNewRunShellImpl_withCwd(self):
with self.assertShellCall('cd /some/test/path && ls'):
self.device.RunShellCommand('ls', cwd='/some/test/path')
def testNewRunShellImpl_withCwdQuoted(self):
with self.assertShellCall("cd '/some test/path with/spaces' && ls"):
self.device.RunShellCommand('ls', cwd='/some test/path with/spaces')
def testRunShellCommand_withSu(self):
with self.assertShellCallSequence([
('su -c ls /root && ! ls /root', ''),
('su -c setprop service.adb.root 0', '')]):
self.device.RunShellCommand('setprop service.adb.root 0', as_root=True)
def testRunShellCommand_withRoot(self):
with self.assertShellCallSequence([
('su -c ls /root && ! ls /root', _ShellError()),
('setprop service.adb.root 0', '')]):
self.device.RunShellCommand('setprop service.adb.root 0', as_root=True)
def testRunShellCommand_manyLines(self):
cmd = 'ls /some/path'
with self.assertShellCall(cmd, 'file1\r\nfile2\r\nfile3\r\n'):
self.assertEquals(['file1', 'file2', 'file3'],
self.device.RunShellCommand(cmd))
def testRunShellCommand_singleLine_success(self):
cmd = 'echo $VALUE'
with self.assertShellCall(cmd, 'some value\r\n'):
self.assertEquals('some value',
self.device.RunShellCommand(cmd, single_line=True))
def testRunShellCommand_singleLine_successEmptyLine(self):
cmd = 'echo $VALUE'
with self.assertShellCall(cmd, '\r\n'):
self.assertEquals('',
self.device.RunShellCommand(cmd, single_line=True))
def testRunShellCommand_singleLine_successWithoutEndLine(self):
cmd = 'echo -n $VALUE'
with self.assertShellCall(cmd, 'some value'):
self.assertEquals('some value',
self.device.RunShellCommand(cmd, single_line=True))
def testRunShellCommand_singleLine_successNoOutput(self):
cmd = 'echo -n $VALUE'
with self.assertShellCall(cmd, ''):
self.assertEquals('',
self.device.RunShellCommand(cmd, single_line=True))
def testRunShellCommand_singleLine_failTooManyLines(self):
cmd = 'echo $VALUE'
with self.assertShellCall(cmd, 'some value\r\nanother value\r\n'):
with self.assertRaises(device_errors.CommandFailedError):
self.device.RunShellCommand(cmd, single_line=True)
def testRunShellCommand_checkReturn_success(self):
cmd = 'echo $ANDROID_DATA'
output = '/data\r\n'
with self.assertShellCall(cmd, output):
self.assertEquals([output.rstrip()],
self.device.RunShellCommand(cmd, check_return=True))
def testRunShellCommand_checkReturn_failure(self):
cmd = 'ls /root'
output = 'opendir failed, Permission denied\r\n'
with self.assertShellCall(cmd, _ShellError(output)):
with self.assertRaises(device_errors.AdbShellCommandFailedError):
self.device.RunShellCommand(cmd, check_return=True)
def testRunShellCommand_checkReturn_disabled(self):
cmd = 'ls /root'
output = 'opendir failed, Permission denied\r\n'
with self.assertShellCall(cmd, _ShellError(output)):
self.assertEquals([output.rstrip()],
self.device.RunShellCommand(cmd, check_return=False))
class DeviceUtilsKillAllTest(DeviceUtilsNewImplTest):
def testKillAll_noMatchingProcesses(self):
output = 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
with self.assertShellCallSequence([('ps', output)]):
with self.assertRaises(device_errors.CommandFailedError):
self.device.KillAll('test_process')
def testKillAll_nonblocking(self):
with self.assertShellCallSequence([
('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
'u0_a1 1234 174 123456 54321 ffffffff 456789ab '
'this.is.a.test.process\r\n'),
('kill -9 1234', '')]):
self.assertEquals(1,
self.device.KillAll('this.is.a.test.process', blocking=False))
def testKillAll_blocking(self):
with mock.patch('time.sleep'):
with self.assertShellCallSequence([
('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
'u0_a1 1234 174 123456 54321 ffffffff 456789ab '
'this.is.a.test.process\r\n'),
('kill -9 1234', ''),
('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
'u0_a1 1234 174 123456 54321 ffffffff 456789ab '
'this.is.a.test.process\r\n'),
('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n')]):
self.assertEquals(1,
self.device.KillAll('this.is.a.test.process', blocking=True))
def testKillAll_root(self):
with self.assertShellCallSequence([
('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
'u0_a1 1234 174 123456 54321 ffffffff 456789ab '
'this.is.a.test.process\r\n'),
('su -c ls /root && ! ls /root', ''),
('su -c kill -9 1234', '')]):
self.assertEquals(1,
self.device.KillAll('this.is.a.test.process', as_root=True))
def testKillAll_sigterm(self):
with self.assertShellCallSequence([
('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
'u0_a1 1234 174 123456 54321 ffffffff 456789ab '
'this.is.a.test.process\r\n'),
('kill -15 1234', '')]):
self.assertEquals(1,
self.device.KillAll('this.is.a.test.process', signum=signal.SIGTERM))
class DeviceUtilsStartActivityTest(DeviceUtilsOldImplTest):
def testStartActivity_actionOnly(self):
test_intent = intent.Intent(action='android.intent.action.VIEW')
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent)
def testStartActivity_success(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main')
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-n this.is.a.test.package/.Main'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent)
def testStartActivity_failure(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main')
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-n this.is.a.test.package/.Main'",
'Error: Failed to start test activity'):
with self.assertRaises(device_errors.CommandFailedError):
self.device.StartActivity(test_intent)
def testStartActivity_blocking(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main')
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-W "
"-n this.is.a.test.package/.Main'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent, blocking=True)
def testStartActivity_withCategory(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main',
category='android.intent.category.HOME')
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-c android.intent.category.HOME "
"-n this.is.a.test.package/.Main'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent)
def testStartActivity_withMultipleCategories(self):
# The new implementation will start the activity with all provided
# categories. The old one only uses the first category.
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main',
category=['android.intent.category.HOME',
'android.intent.category.BROWSABLE'])
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-c android.intent.category.HOME "
"-n this.is.a.test.package/.Main'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent)
def testStartActivity_withData(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main',
data='http://www.google.com/')
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-n this.is.a.test.package/.Main "
"-d \"http://www.google.com/\"'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent)
def testStartActivity_withStringExtra(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main',
extras={'foo': 'test'})
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-n this.is.a.test.package/.Main "
"--es foo test'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent)
def testStartActivity_withBoolExtra(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main',
extras={'foo': True})
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-n this.is.a.test.package/.Main "
"--ez foo True'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent)
def testStartActivity_withIntExtra(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main',
extras={'foo': 123})
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-n this.is.a.test.package/.Main "
"--ei foo 123'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent)
def testStartActivity_withTraceFile(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main')
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-n this.is.a.test.package/.Main "
"--start-profiler test_trace_file.out'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent,
trace_file_name='test_trace_file.out')
def testStartActivity_withForceStop(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main')
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-S "
"-n this.is.a.test.package/.Main'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent, force_stop=True)
def testStartActivity_withFlags(self):
test_intent = intent.Intent(action='android.intent.action.VIEW',
package='this.is.a.test.package',
activity='.Main',
flags='0x10000000')
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-a android.intent.action.VIEW "
"-n this.is.a.test.package/.Main "
"-f 0x10000000'",
'Starting: Intent { act=android.intent.action.VIEW }'):
self.device.StartActivity(test_intent)
class DeviceUtilsBroadcastIntentTest(DeviceUtilsOldImplTest):
def testBroadcastIntent_noExtras(self):
test_intent = intent.Intent(action='test.package.with.an.INTENT')
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am broadcast "
"-a test.package.with.an.INTENT '",
'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
self.device.BroadcastIntent(test_intent)
def testBroadcastIntent_withExtra(self):
test_intent = intent.Intent(action='test.package.with.an.INTENT',
extras={'foo': 'bar'})
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am broadcast "
"-a test.package.with.an.INTENT "
"-e foo \"bar\"'",
'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
self.device.BroadcastIntent(test_intent)
def testBroadcastIntent_withExtra_noValue(self):
test_intent = intent.Intent(action='test.package.with.an.INTENT',
extras={'foo': None})
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am broadcast "
"-a test.package.with.an.INTENT "
"-e foo'",
'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
self.device.BroadcastIntent(test_intent)
class DeviceUtilsGoHomeTest(DeviceUtilsOldImplTest):
def testGoHome(self):
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am start "
"-W "
"-a android.intent.action.MAIN "
"-c android.intent.category.HOME'",
'Starting: Intent { act=android.intent.action.MAIN }\r\n'):
self.device.GoHome()
class DeviceUtilsForceStopTest(DeviceUtilsOldImplTest):
def testForceStop(self):
with self.assertCalls(
"adb -s 0123456789abcdef shell 'am force-stop this.is.a.test.package'",
''):
self.device.ForceStop('this.is.a.test.package')
class DeviceUtilsClearApplicationStateTest(DeviceUtilsOldImplTest):
def testClearApplicationState_packageExists(self):
with self.assertCalls(
"adb -s 0123456789abcdef shell 'pm path this.package.does.not.exist'",
''):
self.device.ClearApplicationState('this.package.does.not.exist')
def testClearApplicationState_packageDoesntExist(self):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'pm path this.package.exists'",
'package:/data/app/this.package.exists.apk'),
("adb -s 0123456789abcdef shell 'pm clear this.package.exists'",
'Success\r\n')]):
self.device.ClearApplicationState('this.package.exists')
class DeviceUtilsSendKeyEventTest(DeviceUtilsOldImplTest):
def testSendKeyEvent(self):
with self.assertCalls(
"adb -s 0123456789abcdef shell 'input keyevent 66'",
''):
self.device.SendKeyEvent(66)
class DeviceUtilsPushChangedFilesIndividuallyTest(DeviceUtilsNewImplTest):
def testPushChangedFilesIndividually_empty(self):
test_files = []
self.device._PushChangedFilesIndividually(test_files)
self.assertEqual(0, self.adb.Push.call_count)
def testPushChangedFilesIndividually_single(self):
test_files = [('/test/host/path', '/test/device/path')]
self.device._PushChangedFilesIndividually(test_files)
self.adb.Push.assert_called_once_with(
'/test/host/path', '/test/device/path')
def testPushChangedFilesIndividually_multiple(self):
test_files = [
('/test/host/path/file1', '/test/device/path/file1'),
('/test/host/path/file2', '/test/device/path/file2')]
self.device._PushChangedFilesIndividually(test_files)
self.assertEqual(2, self.adb.Push.call_count)
self.adb.Push.assert_any_call(
'/test/host/path/file1', '/test/device/path/file1')
self.adb.Push.assert_any_call(
'/test/host/path/file2', '/test/device/path/file2')
@mock.patch('pylib.device.commands.install_commands.Installed', new=None)
@mock.patch('pylib.device.commands.install_commands.InstallCommands', new=None)
class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsHybridImplTest):
def setUp(self):
super(DeviceUtilsPushChangedFilesZippedTest, self).setUp()
def testPushChangedFilesZipped_empty(self):
test_files = []
self.device._PushChangedFilesZipped(test_files)
self.assertEqual(0, self.adb.Push.call_count)
def testPushChangedFilesZipped_single(self):
test_files = [('/test/host/path/file1', '/test/device/path/file1')]
self.device._GetExternalStoragePathImpl = mock.Mock(
return_value='/test/device/external_dir')
self.device.IsOnline = mock.Mock(return_value=True)
self.device.RunShellCommand = mock.Mock()
mock_zip_temp = mock.mock_open()
mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
with mock.patch('multiprocessing.Process') as mock_zip_proc, (
mock.patch('tempfile.NamedTemporaryFile', mock_zip_temp)):
self.device._PushChangedFilesZipped(test_files)
mock_zip_proc.assert_called_once_with(
target=device_utils.DeviceUtils._CreateDeviceZip,
args=('/test/temp/file/tmp.zip', test_files))
self.adb.Push.assert_called_once_with(
'/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip')
self.assertEqual(2, self.device.RunShellCommand.call_count)
self.device.RunShellCommand.assert_any_call(
['unzip', '/test/device/external_dir/tmp.zip'],
as_root=True,
env={'PATH': '$PATH:/data/local/tmp/bin'},
check_return=True)
self.device.RunShellCommand.assert_any_call(
['rm', '/test/device/external_dir/tmp.zip'], check_return=True)
def testPushChangedFilesZipped_multiple(self):
test_files = [('/test/host/path/file1', '/test/device/path/file1'),
('/test/host/path/file2', '/test/device/path/file2')]
self.device._GetExternalStoragePathImpl = mock.Mock(
return_value='/test/device/external_dir')
self.device.IsOnline = mock.Mock(return_value=True)
self.device.RunShellCommand = mock.Mock()
mock_zip_temp = mock.mock_open()
mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
with mock.patch('multiprocessing.Process') as mock_zip_proc, (
mock.patch('tempfile.NamedTemporaryFile', mock_zip_temp)):
self.device._PushChangedFilesZipped(test_files)
mock_zip_proc.assert_called_once_with(
target=device_utils.DeviceUtils._CreateDeviceZip,
args=('/test/temp/file/tmp.zip', test_files))
self.adb.Push.assert_called_once_with(
'/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip')
self.assertEqual(2, self.device.RunShellCommand.call_count)
self.device.RunShellCommand.assert_any_call(
['unzip', '/test/device/external_dir/tmp.zip'],
as_root=True,
env={'PATH': '$PATH:/data/local/tmp/bin'},
check_return=True)
self.device.RunShellCommand.assert_any_call(
['rm', '/test/device/external_dir/tmp.zip'], check_return=True)
class DeviceUtilsFileExistsTest(DeviceUtilsOldImplTest):
def testFileExists_usingTest_fileExists(self):
with self.assertCalls(
"adb -s 0123456789abcdef shell "
"'test -e \"/data/app/test.file.exists\"; echo $?'",
'0\r\n'):
self.assertTrue(self.device.FileExists('/data/app/test.file.exists'))
def testFileExists_usingTest_fileDoesntExist(self):
with self.assertCalls(
"adb -s 0123456789abcdef shell "
"'test -e \"/data/app/test.file.does.not.exist\"; echo $?'",
'1\r\n'):
self.assertFalse(self.device.FileExists(
'/data/app/test.file.does.not.exist'))
def testFileExists_usingLs_fileExists(self):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell "
"'test -e \"/data/app/test.file.exists\"; echo $?'",
'test: not found\r\n'),
("adb -s 0123456789abcdef shell "
"'ls \"/data/app/test.file.exists\" >/dev/null 2>&1; echo $?'",
'0\r\n')]):
self.assertTrue(self.device.FileExists('/data/app/test.file.exists'))
def testFileExists_usingLs_fileDoesntExist(self):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell "
"'test -e \"/data/app/test.file.does.not.exist\"; echo $?'",
'test: not found\r\n'),
("adb -s 0123456789abcdef shell "
"'ls \"/data/app/test.file.does.not.exist\" "
">/dev/null 2>&1; echo $?'",
'1\r\n')]):
self.assertFalse(self.device.FileExists(
'/data/app/test.file.does.not.exist'))
class DeviceUtilsPullFileTest(DeviceUtilsOldImplTest):
def testPullFile_existsOnDevice(self):
with mock.patch('os.path.exists', return_value=True):
with self.assertCallsSequence([
('adb -s 0123456789abcdef shell '
'ls /data/app/test.file.exists',
'/data/app/test.file.exists'),
('adb -s 0123456789abcdef pull '
'/data/app/test.file.exists /test/file/host/path',
'100 B/s (100 bytes in 1.000s)\r\n')]):
self.device.PullFile('/data/app/test.file.exists',
'/test/file/host/path')
def testPullFile_doesntExistOnDevice(self):
with mock.patch('os.path.exists', return_value=True):
with self.assertCalls(
'adb -s 0123456789abcdef shell '
'ls /data/app/test.file.does.not.exist',
'/data/app/test.file.does.not.exist: No such file or directory\r\n'):
with self.assertRaises(device_errors.CommandFailedError):
self.device.PullFile('/data/app/test.file.does.not.exist',
'/test/file/host/path')
class DeviceUtilsReadFileTest(DeviceUtilsOldImplTest):
def testReadFile_exists(self):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell "
"'cat \"/read/this/test/file\" 2>/dev/null'",
'this is a test file')]):
self.assertEqual(['this is a test file'],
self.device.ReadFile('/read/this/test/file'))
def testReadFile_doesNotExist(self):
with self.assertCalls(
"adb -s 0123456789abcdef shell "
"'cat \"/this/file/does.not.exist\" 2>/dev/null'",
''):
self.device.ReadFile('/this/file/does.not.exist')
def testReadFile_asRoot_withRoot(self):
self.device.old_interface._privileged_command_runner = (
self.device.old_interface.RunShellCommand)
self.device.old_interface._protected_file_access_method_initialized = True
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell "
"'cat \"/this/file/must.be.read.by.root\" 2> /dev/null'",
'this is a test file\nread by root')]):
self.assertEqual(
['this is a test file', 'read by root'],
self.device.ReadFile('/this/file/must.be.read.by.root',
as_root=True))
def testReadFile_asRoot_withSu(self):
self.device.old_interface._privileged_command_runner = (
self.device.old_interface.RunShellCommandWithSU)
self.device.old_interface._protected_file_access_method_initialized = True
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell "
"'su -c cat \"/this/file/can.be.read.with.su\" 2> /dev/null'",
'this is a test file\nread with su')]):
self.assertEqual(
['this is a test file', 'read with su'],
self.device.ReadFile('/this/file/can.be.read.with.su',
as_root=True))
def testReadFile_asRoot_rejected(self):
self.device.old_interface._privileged_command_runner = None
self.device.old_interface._protected_file_access_method_initialized = True
with self.assertRaises(device_errors.CommandFailedError):
self.device.ReadFile('/this/file/cannot.be.read.by.user',
as_root=True)
class DeviceUtilsWriteFileTest(DeviceUtilsOldImplTest):
def testWriteFile_basic(self):
mock_file = mock.MagicMock(spec=file)
mock_file.name = '/tmp/file/to.be.pushed'
mock_file.__enter__.return_value = mock_file
with mock.patch('tempfile.NamedTemporaryFile',
return_value=mock_file):
with self.assertCalls(
'adb -s 0123456789abcdef push '
'/tmp/file/to.be.pushed /test/file/written.to.device',
'100 B/s (100 bytes in 1.000s)\r\n'):
self.device.WriteFile('/test/file/written.to.device',
'new test file contents')
mock_file.write.assert_called_once_with('new test file contents')
def testWriteFile_asRoot_withRoot(self):
self.device.old_interface._external_storage = '/fake/storage/path'
self.device.old_interface._privileged_command_runner = (
self.device.old_interface.RunShellCommand)
self.device.old_interface._protected_file_access_method_initialized = True
mock_file = mock.MagicMock(spec=file)
mock_file.name = '/tmp/file/to.be.pushed'
mock_file.__enter__.return_value = mock_file
with mock.patch('tempfile.NamedTemporaryFile',
return_value=mock_file):
with self.assertCallsSequence(
cmd_ret=[
# Create temporary contents file
(r"adb -s 0123456789abcdef shell "
"'test -e \"/fake/storage/path/temp_file-\d+-\d+\"; "
"echo \$\?'",
'1\r\n'),
# Create temporary script file
(r"adb -s 0123456789abcdef shell "
"'test -e \"/fake/storage/path/temp_file-\d+-\d+\.sh\"; "
"echo \$\?'",
'1\r\n'),
# Set contents file
(r'adb -s 0123456789abcdef push /tmp/file/to\.be\.pushed '
'/fake/storage/path/temp_file-\d+\d+',
'100 B/s (100 bytes in 1.000s)\r\n'),
# Set script file
(r'adb -s 0123456789abcdef push /tmp/file/to\.be\.pushed '
'/fake/storage/path/temp_file-\d+\d+',
'100 B/s (100 bytes in 1.000s)\r\n'),
# Call script
(r"adb -s 0123456789abcdef shell "
"'sh /fake/storage/path/temp_file-\d+-\d+\.sh'", ''),
# Remove device temporaries
(r"adb -s 0123456789abcdef shell "
"'rm /fake/storage/path/temp_file-\d+-\d+\.sh'", ''),
(r"adb -s 0123456789abcdef shell "
"'rm /fake/storage/path/temp_file-\d+-\d+'", '')],
comp=re.match):
self.device.WriteFile('/test/file/written.to.device',
'new test file contents', as_root=True)
def testWriteFile_asRoot_withSu(self):
self.device.old_interface._external_storage = '/fake/storage/path'
self.device.old_interface._privileged_command_runner = (
self.device.old_interface.RunShellCommandWithSU)
self.device.old_interface._protected_file_access_method_initialized = True
mock_file = mock.MagicMock(spec=file)
mock_file.name = '/tmp/file/to.be.pushed'
mock_file.__enter__.return_value = mock_file
with mock.patch('tempfile.NamedTemporaryFile',
return_value=mock_file):
with self.assertCallsSequence(
cmd_ret=[
# Create temporary contents file
(r"adb -s 0123456789abcdef shell "
"'test -e \"/fake/storage/path/temp_file-\d+-\d+\"; "
"echo \$\?'",
'1\r\n'),
# Create temporary script file
(r"adb -s 0123456789abcdef shell "
"'test -e \"/fake/storage/path/temp_file-\d+-\d+\.sh\"; "
"echo \$\?'",
'1\r\n'),
# Set contents file
(r'adb -s 0123456789abcdef push /tmp/file/to\.be\.pushed '
'/fake/storage/path/temp_file-\d+\d+',
'100 B/s (100 bytes in 1.000s)\r\n'),
# Set script file
(r'adb -s 0123456789abcdef push /tmp/file/to\.be\.pushed '
'/fake/storage/path/temp_file-\d+\d+',
'100 B/s (100 bytes in 1.000s)\r\n'),
# Call script
(r"adb -s 0123456789abcdef shell "
"'su -c sh /fake/storage/path/temp_file-\d+-\d+\.sh'", ''),
# Remove device temporaries
(r"adb -s 0123456789abcdef shell "
"'rm /fake/storage/path/temp_file-\d+-\d+\.sh'", ''),
(r"adb -s 0123456789abcdef shell "
"'rm /fake/storage/path/temp_file-\d+-\d+'", '')],
comp=re.match):
self.device.WriteFile('/test/file/written.to.device',
'new test file contents', as_root=True)
def testWriteFile_asRoot_rejected(self):
self.device.old_interface._privileged_command_runner = None
self.device.old_interface._protected_file_access_method_initialized = True
with self.assertRaises(device_errors.CommandFailedError):
self.device.WriteFile('/test/file/no.permissions.to.write',
'new test file contents', as_root=True)
class DeviceUtilsWriteTextFileTest(DeviceUtilsNewImplTest):
def testWriteTextFileTest_basic(self):
with self.assertShellCall('echo some.string > /test/file/to.write'):
self.device.WriteTextFile('/test/file/to.write', 'some.string')
def testWriteTextFileTest_quoted(self):
with self.assertShellCall(
"echo 'some other string' > '/test/file/to write'"):
self.device.WriteTextFile('/test/file/to write', 'some other string')
def testWriteTextFileTest_asRoot(self):
with self.assertShellCallSequence([
('su -c ls /root && ! ls /root', ''),
('su -c echo string > /test/file', '')]):
self.device.WriteTextFile('/test/file', 'string', as_root=True)
class DeviceUtilsLsTest(DeviceUtilsOldImplTest):
def testLs_nothing(self):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'ls -lR /this/file/does.not.exist'",
'/this/file/does.not.exist: No such file or directory\r\n'),
("adb -s 0123456789abcdef shell 'date +%z'", '+0000')]):
self.assertEqual({}, self.device.Ls('/this/file/does.not.exist'))
def testLs_file(self):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'ls -lR /this/is/a/test.file'",
'-rw-rw---- testuser testgroup 4096 1970-01-01 00:00 test.file\r\n'),
("adb -s 0123456789abcdef shell 'date +%z'", '+0000')]):
self.assertEqual(
{'test.file': (4096, datetime.datetime(1970, 1, 1))},
self.device.Ls('/this/is/a/test.file'))
def testLs_directory(self):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'ls -lR /this/is/a/test.directory'",
'\r\n'
'/this/is/a/test.directory:\r\n'
'-rw-rw---- testuser testgroup 4096 1970-01-01 18:19 test.file\r\n'),
("adb -s 0123456789abcdef shell 'date +%z'", '+0000')]):
self.assertEqual(
{'test.file': (4096, datetime.datetime(1970, 1, 1, 18, 19))},
self.device.Ls('/this/is/a/test.directory'))
def testLs_directories(self):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'ls -lR /this/is/a/test.directory'",
'\r\n'
'/this/is/a/test.directory:\r\n'
'drwxr-xr-x testuser testgroup 1970-01-01 00:00 test.subdirectory\r\n'
'\r\n'
'/this/is/a/test.directory/test.subdirectory:\r\n'
'-rw-rw---- testuser testgroup 4096 1970-01-01 00:00 test.file\r\n'),
("adb -s 0123456789abcdef shell 'date +%z'", '-0700')]):
self.assertEqual(
{'test.subdirectory/test.file':
(4096, datetime.datetime(1970, 1, 1, 7, 0, 0))},
self.device.Ls('/this/is/a/test.directory'))
class DeviceUtilsSetJavaAssertsTest(DeviceUtilsOldImplTest):
@staticmethod
def mockNamedTemporary(name='/tmp/file/property.file',
read_contents=''):
mock_file = mock.MagicMock(spec=file)
mock_file.name = name
mock_file.__enter__.return_value = mock_file
mock_file.read.return_value = read_contents
return mock_file
def testSetJavaAsserts_enable(self):
mock_file = self.mockNamedTemporary()
with mock.patch('tempfile.NamedTemporaryFile',
return_value=mock_file), (
mock.patch('__builtin__.open', return_value=mock_file)):
with self.assertCallsSequence(
[('adb -s 0123456789abcdef shell ls %s' %
constants.DEVICE_LOCAL_PROPERTIES_PATH,
'%s\r\n' % constants.DEVICE_LOCAL_PROPERTIES_PATH),
('adb -s 0123456789abcdef pull %s %s' %
(constants.DEVICE_LOCAL_PROPERTIES_PATH, mock_file.name),
'100 B/s (100 bytes in 1.000s)\r\n'),
('adb -s 0123456789abcdef push %s %s' %
(mock_file.name, constants.DEVICE_LOCAL_PROPERTIES_PATH),
'100 B/s (100 bytes in 1.000s)\r\n'),
('adb -s 0123456789abcdef shell '
'getprop dalvik.vm.enableassertions',
'\r\n'),
('adb -s 0123456789abcdef shell '
'setprop dalvik.vm.enableassertions "all"',
'')]):
self.assertTrue(self.device.SetJavaAsserts(True))
def testSetJavaAsserts_disable(self):
mock_file = self.mockNamedTemporary(
read_contents='dalvik.vm.enableassertions=all\n')
with mock.patch('tempfile.NamedTemporaryFile',
return_value=mock_file), (
mock.patch('__builtin__.open', return_value=mock_file)):
with self.assertCallsSequence(
[('adb -s 0123456789abcdef shell ls %s' %
constants.DEVICE_LOCAL_PROPERTIES_PATH,
'%s\r\n' % constants.DEVICE_LOCAL_PROPERTIES_PATH),
('adb -s 0123456789abcdef pull %s %s' %
(constants.DEVICE_LOCAL_PROPERTIES_PATH, mock_file.name),
'100 B/s (100 bytes in 1.000s)\r\n'),
('adb -s 0123456789abcdef push %s %s' %
(mock_file.name, constants.DEVICE_LOCAL_PROPERTIES_PATH),
'100 B/s (100 bytes in 1.000s)\r\n'),
('adb -s 0123456789abcdef shell '
'getprop dalvik.vm.enableassertions',
'all\r\n'),
('adb -s 0123456789abcdef shell '
'setprop dalvik.vm.enableassertions ""',
'')]):
self.assertTrue(self.device.SetJavaAsserts(False))
def testSetJavaAsserts_alreadyEnabled(self):
mock_file = self.mockNamedTemporary(
read_contents='dalvik.vm.enableassertions=all\n')
with mock.patch('tempfile.NamedTemporaryFile',
return_value=mock_file), (
mock.patch('__builtin__.open', return_value=mock_file)):
with self.assertCallsSequence(
[('adb -s 0123456789abcdef shell ls %s' %
constants.DEVICE_LOCAL_PROPERTIES_PATH,
'%s\r\n' % constants.DEVICE_LOCAL_PROPERTIES_PATH),
('adb -s 0123456789abcdef pull %s %s' %
(constants.DEVICE_LOCAL_PROPERTIES_PATH, mock_file.name),
'100 B/s (100 bytes in 1.000s)\r\n'),
('adb -s 0123456789abcdef shell '
'getprop dalvik.vm.enableassertions',
'all\r\n')]):
self.assertFalse(self.device.SetJavaAsserts(True))
class DeviceUtilsGetPropTest(DeviceUtilsNewImplTest):
def testGetProp_exists(self):
with self.assertShellCall('getprop this.is.a.test.property',
'test_property_value\r\n'):
self.assertEqual('test_property_value',
self.device.GetProp('this.is.a.test.property'))
def testGetProp_doesNotExist(self):
with self.assertShellCall('getprop this.property.does.not.exist',
'\r\n'):
self.assertEqual('', self.device.GetProp('this.property.does.not.exist'))
def testGetProp_cachedRoProp(self):
with self.assertShellCall('getprop ro.build.type',
'userdebug\r\n'):
self.assertEqual('userdebug',
self.device.GetProp('ro.build.type', cache=True))
self.assertEqual('userdebug',
self.device.GetProp('ro.build.type', cache=True))
def testGetProp_retryAndCache(self):
with self.assertShellCallSequence([
('getprop ro.build.type', _ShellError()),
('getprop ro.build.type', _ShellError()),
('getprop ro.build.type', 'userdebug\r\n')]):
self.assertEqual('userdebug',
self.device.GetProp('ro.build.type',
cache=True, retries=3))
self.assertEqual('userdebug',
self.device.GetProp('ro.build.type',
cache=True, retries=3))
class DeviceUtilsSetPropTest(DeviceUtilsNewImplTest):
def testSetProp(self):
with self.assertShellCall(
"setprop this.is.a.test.property 'test property value'"):
self.device.SetProp('this.is.a.test.property', 'test property value')
class DeviceUtilsGetPidsTest(DeviceUtilsNewImplTest):
def testGetPids_noMatches(self):
with self.assertShellCall(
'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.assertShellCall(
'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.assertShellCall(
'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.assertShellCall(
'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())
class DeviceUtilsGetMemoryUsageForPidTest(DeviceUtilsOldImplTest):
def setUp(self):
super(DeviceUtilsGetMemoryUsageForPidTest, self).setUp()
self.device.old_interface._privileged_command_runner = (
self.device.old_interface.RunShellCommand)
self.device.old_interface._protected_file_access_method_initialized = True
def testGetMemoryUsageForPid_validPid(self):
with self.assertCallsSequence([
("adb -s 0123456789abcdef shell 'showmap 1234'",
'100 101 102 103 104 105 106 107 TOTAL\r\n'),
("adb -s 0123456789abcdef shell "
"'cat \"/proc/1234/status\" 2> /dev/null'",
'VmHWM: 1024 kB')
]):
self.assertEqual(
{
'Size': 100,
'Rss': 101,
'Pss': 102,
'Shared_Clean': 103,
'Shared_Dirty': 104,
'Private_Clean': 105,
'Private_Dirty': 106,
'VmHWM': 1024
},
self.device.GetMemoryUsageForPid(1234))
def testGetMemoryUsageForPid_invalidPid(self):
with self.assertCalls(
"adb -s 0123456789abcdef shell 'showmap 4321'",
'cannot open /proc/4321/smaps: No such file or directory\r\n'):
self.assertEqual({}, self.device.GetMemoryUsageForPid(4321))
class DeviceUtilsStrTest(DeviceUtilsOldImplTest):
def testStr_noAdbCalls(self):
with self.assertNoAdbCalls():
self.assertEqual('0123456789abcdef', str(self.device))
def testStr_noSerial(self):
self.device = device_utils.DeviceUtils(None)
with self.assertCalls('adb get-serialno', '0123456789abcdef'):
self.assertEqual('0123456789abcdef', str(self.device))
def testStr_noSerial_noDevices(self):
self.device = device_utils.DeviceUtils(None)
with self.assertCalls('adb get-serialno', 'unknown'), (
self.assertRaises(device_errors.NoDevicesError)):
str(self.device)
if __name__ == '__main__':
logging.getLogger().setLevel(logging.DEBUG)
unittest.main(verbosity=2)