diff options
Diffstat (limited to 'systrace/catapult/devil/devil/android/device_utils_test.py')
-rwxr-xr-x | systrace/catapult/devil/devil/android/device_utils_test.py | 350 |
1 files changed, 207 insertions, 143 deletions
diff --git a/systrace/catapult/devil/devil/android/device_utils_test.py b/systrace/catapult/devil/devil/android/device_utils_test.py index ebd3c62..b5660ac 100755 --- a/systrace/catapult/devil/devil/android/device_utils_test.py +++ b/systrace/catapult/devil/devil/android/device_utils_test.py @@ -10,6 +10,7 @@ Unit tests for the contents of device_utils.py (mostly DeviceUtils). # pylint: disable=protected-access # pylint: disable=unused-argument +import contextlib import json import logging import os @@ -31,6 +32,14 @@ with devil_env.SysPath(devil_env.PYMOCK_PATH): import mock # pylint: disable=import-error +def Process(name, pid, ppid='1'): + return device_utils.ProcessInfo(name=name, pid=pid, ppid=ppid) + + +def Processes(*args): + return [Process(*arg) for arg in args] + + class AnyStringWith(object): def __init__(self, value): self._value = value @@ -142,6 +151,21 @@ class MockTempFile(object): return self.file.name +class MockLogger(mock.Mock): + def __init__(self, *args, **kwargs): + super(MockLogger, self).__init__(*args, **kwargs) + # TODO(perezju): Consider adding traps for error, info, etc. + self.warnings = [] + + def warning(self, message, *args): + self.warnings.append(message % args) + + +def PatchLogger(): + return mock.patch( + 'devil.android.device_utils.logger', new_callable=MockLogger) + + class _PatchedFunction(object): def __init__(self, patched=None, mocked=None): @@ -383,7 +407,7 @@ class DeviceUtilsGetApplicationPathsInternalTest(DeviceUtilsTest): self.assertEquals([], self.device._GetApplicationPathsInternal('not.installed.app')) - def testGetApplicationPathsInternal_garbageFirstLine(self): + def testGetApplicationPathsInternal_garbageOutputRaises(self): with self.assertCalls( (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'), (self.call.device.RunShellCommand( @@ -392,6 +416,15 @@ class DeviceUtilsGetApplicationPathsInternalTest(DeviceUtilsTest): with self.assertRaises(device_errors.CommandFailedError): self.device._GetApplicationPathsInternal('android') + def testGetApplicationPathsInternal_outputWarningsIgnored(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'), + (self.call.device.RunShellCommand( + ['pm', 'path', 'not.installed.app'], check_return=True), + ['WARNING: some warning message from pm'])): + self.assertEquals([], + self.device._GetApplicationPathsInternal('not.installed.app')) + def testGetApplicationPathsInternal_fails(self): with self.assertCalls( (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'), @@ -1058,7 +1091,7 @@ class DeviceUtilsRunShellCommandTest(DeviceUtilsTest): def testRunShellCommand_largeOutput_enabled(self): cmd = 'echo $VALUE' temp_file = MockTempFile('/sdcard/temp-123') - cmd_redirect = '( %s )>%s' % (cmd, temp_file.name) + cmd_redirect = '( %s )>%s 2>&1' % (cmd, temp_file.name) with self.assertCalls( (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb), temp_file), @@ -1079,7 +1112,7 @@ class DeviceUtilsRunShellCommandTest(DeviceUtilsTest): def testRunShellCommand_largeOutput_disabledTrigger(self): cmd = 'echo $VALUE' temp_file = MockTempFile('/sdcard/temp-123') - cmd_redirect = '( %s )>%s' % (cmd, temp_file.name) + cmd_redirect = '( %s )>%s 2>&1' % (cmd, temp_file.name) with self.assertCalls( (self.call.adb.Shell(cmd), self.ShellError('', None)), (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb), @@ -1138,57 +1171,59 @@ class DeviceUtilsRunPipedShellCommandTest(DeviceUtilsTest): class DeviceUtilsKillAllTest(DeviceUtilsTest): def testKillAll_noMatchingProcessesFailure(self): - with self.assertCall(self.call.device.GetPids('test_process'), {}): + with self.assertCall(self.call.device.ListProcesses('test_process'), []): with self.assertRaises(device_errors.CommandFailedError): self.device.KillAll('test_process') def testKillAll_noMatchingProcessesQuiet(self): - with self.assertCall(self.call.device.GetPids('test_process'), {}): + with self.assertCall(self.call.device.ListProcesses('test_process'), []): self.assertEqual(0, self.device.KillAll('test_process', quiet=True)) def testKillAll_nonblocking(self): with self.assertCalls( - (self.call.device.GetPids('some.process'), - {'some.process': ['1234'], 'some.processing.thing': ['5678']}), + (self.call.device.ListProcesses('some.process'), + Processes(('some.process', 1234), ('some.process.thing', 5678))), (self.call.adb.Shell('kill -9 1234 5678'), '')): self.assertEquals( 2, self.device.KillAll('some.process', blocking=False)) def testKillAll_blocking(self): with self.assertCalls( - (self.call.device.GetPids('some.process'), - {'some.process': ['1234'], 'some.processing.thing': ['5678']}), + (self.call.device.ListProcesses('some.process'), + Processes(('some.process', 1234), ('some.process.thing', 5678))), (self.call.adb.Shell('kill -9 1234 5678'), ''), - (self.call.device.GetPids('some.process'), - {'some.processing.thing': ['5678']}), - (self.call.device.GetPids('some.process'), - {'some.process': ['1111']})): # Other instance with different pid. + (self.call.device.ListProcesses('some.process'), + Processes(('some.process.thing', 5678))), + (self.call.device.ListProcesses('some.process'), + # Other instance with different pid. + Processes(('some.process', 111)))): self.assertEquals( 2, self.device.KillAll('some.process', blocking=True)) def testKillAll_exactNonblocking(self): with self.assertCalls( - (self.call.device.GetPids('some.process'), - {'some.process': ['1234'], 'some.processing.thing': ['5678']}), + (self.call.device.ListProcesses('some.process'), + Processes(('some.process', 1234), ('some.process.thing', 5678))), (self.call.adb.Shell('kill -9 1234'), '')): self.assertEquals( 1, self.device.KillAll('some.process', exact=True, blocking=False)) def testKillAll_exactBlocking(self): with self.assertCalls( - (self.call.device.GetPids('some.process'), - {'some.process': ['1234'], 'some.processing.thing': ['5678']}), + (self.call.device.ListProcesses('some.process'), + Processes(('some.process', 1234), ('some.process.thing', 5678))), (self.call.adb.Shell('kill -9 1234'), ''), - (self.call.device.GetPids('some.process'), - {'some.process': ['1234'], 'some.processing.thing': ['5678']}), - (self.call.device.GetPids('some.process'), - {'some.processing.thing': ['5678']})): + (self.call.device.ListProcesses('some.process'), + Processes(('some.process', 1234), ('some.process.thing', 5678))), + (self.call.device.ListProcesses('some.process'), + Processes(('some.process.thing', 5678)))): self.assertEquals( 1, self.device.KillAll('some.process', exact=True, blocking=True)) def testKillAll_root(self): with self.assertCalls( - (self.call.device.GetPids('some.process'), {'some.process': ['1234']}), + (self.call.device.ListProcesses('some.process'), + Processes(('some.process', 1234))), (self.call.device.NeedsSU(), True), (self.call.device._Su("sh -c 'kill -9 1234'"), "su -c sh -c 'kill -9 1234'"), @@ -1198,16 +1233,16 @@ class DeviceUtilsKillAllTest(DeviceUtilsTest): def testKillAll_sigterm(self): with self.assertCalls( - (self.call.device.GetPids('some.process'), - {'some.process': ['1234']}), + (self.call.device.ListProcesses('some.process'), + Processes(('some.process', 1234))), (self.call.adb.Shell('kill -15 1234'), '')): self.assertEquals( 1, self.device.KillAll('some.process', signum=device_signal.SIGTERM)) def testKillAll_multipleInstances(self): with self.assertCalls( - (self.call.device.GetPids('some.process'), - {'some.process': ['1234', '4567']}), + (self.call.device.ListProcesses('some.process'), + Processes(('some.process', 1234), ('some.process', 4567))), (self.call.adb.Shell('kill -15 1234 4567'), '')): self.assertEquals( 2, self.device.KillAll('some.process', signum=device_signal.SIGTERM)) @@ -1541,7 +1576,7 @@ class DeviceUtilsForceStopTest(DeviceUtilsTest): def testForceStop(self): with self.assertCalls( - (self.call.device.GetPids('test.package'), {'test.package': [1111]}), + (self.call.device.GetApplicationPids('test.package'), [1111]), (self.call.device.RunShellCommand( ['am', 'force-stop', 'test.package'], check_return=True), @@ -1550,7 +1585,7 @@ class DeviceUtilsForceStopTest(DeviceUtilsTest): def testForceStop_NoProcessFound(self): with self.assertCall( - self.call.device.GetPids('test.package'), {}): + self.call.device.GetApplicationPids('test.package'), []): self.device.ForceStop('test.package') @@ -1640,32 +1675,28 @@ class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsTest): def testPushChangedFilesZipped_noUnzipCommand(self): test_files = [('/test/host/path/file1', '/test/device/path/file1')] - mock_zip_temp = mock.mock_open() - mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip' with self.assertCalls( - (mock.call.tempfile.NamedTemporaryFile(suffix='.zip'), mock_zip_temp), - (mock.call.multiprocessing.Process( - target=device_utils.DeviceUtils._CreateDeviceZip, - args=('/test/temp/file/tmp.zip', test_files)), mock.Mock()), (self.call.device._MaybeInstallCommands(), False)): self.assertFalse(self.device._PushChangedFilesZipped(test_files, ['/test/dir'])) def _testPushChangedFilesZipped_spec(self, test_files): - mock_zip_temp = mock.mock_open() - mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip' + @contextlib.contextmanager + def mock_zip_temp_dir(): + yield '/test/temp/dir' + with self.assertCalls( - (mock.call.tempfile.NamedTemporaryFile(suffix='.zip'), mock_zip_temp), - (mock.call.multiprocessing.Process( - target=device_utils.DeviceUtils._CreateDeviceZip, - args=('/test/temp/file/tmp.zip', test_files)), mock.Mock()), (self.call.device._MaybeInstallCommands(), True), + (mock.call.py_utils.tempfile_ext.NamedTemporaryDirectory(), + mock_zip_temp_dir), + (mock.call.devil.utils.zip_utils.WriteZipFile( + '/test/temp/dir/tmp.zip', test_files)), (self.call.device.NeedsSU(), True), (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb, suffix='.zip'), MockTempFile('/test/sdcard/foo123.zip')), self.call.adb.Push( - '/test/temp/file/tmp.zip', '/test/sdcard/foo123.zip'), + '/test/temp/dir/tmp.zip', '/test/sdcard/foo123.zip'), self.call.device.RunShellCommand( 'unzip /test/sdcard/foo123.zip&&chmod -R 777 /test/dir', shell=True, as_root=True, @@ -1980,6 +2011,8 @@ class DeviceUtilsStatDirectoryTest(DeviceUtilsTest): 'drwxr-xr-x 6 root root 1970-01-01 00:00 some_dir', '-rw-r--r-- 1 root root 723 1971-01-01 07:04 some_file', '-rw-r----- 1 root root 327 2009-02-13 23:30 My Music File', + # Some Android versions escape spaces in file names + '-rw-rw-rw- 1 root root 0 2018-01-11 13:35 Local\\ State', # Older Android versions do not print st_nlink 'lrwxrwxrwx root root 1970-01-01 00:00 lnk -> /some/path', 'srwxrwx--- system system 2016-05-31 17:25 a_socket1', @@ -1991,8 +2024,8 @@ class DeviceUtilsStatDirectoryTest(DeviceUtilsTest): ] FILENAMES = [ - 'some_dir', 'some_file', 'My Music File', 'lnk', 'a_socket1', - 'tmp', 'my_cmd', 'random', 'block_dev', 'silly'] + 'some_dir', 'some_file', 'My Music File', 'Local State', 'lnk', + 'a_socket1', 'tmp', 'my_cmd', 'random', 'block_dev', 'silly'] def getStatEntries(self, path_given='/', path_listed='/'): with self.assertCall( @@ -2290,23 +2323,23 @@ class DeviceUtilsSetPropTest(DeviceUtilsTest): self.device.SetProp('test.property', 'new_value', check=True) -class DeviceUtilsGetPidsTest(DeviceUtilsTest): +class DeviceUtilsListProcessesTest(DeviceUtilsTest): def setUp(self): - super(DeviceUtilsGetPidsTest, self).setUp() + super(DeviceUtilsListProcessesTest, self).setUp() self.sample_output = [ 'USER PID PPID VSIZE RSS WCHAN PC NAME', 'user 1001 100 1024 1024 ffffffff 00000000 one.match', 'user 1002 100 1024 1024 ffffffff 00000000 two.match', - 'user 1003 100 1024 1024 ffffffff 00000000 three.match', - 'user 1234 100 1024 1024 ffffffff 00000000 my$process', - 'user 1000 100 1024 1024 ffffffff 00000000 foo', + 'user 1003 101 1024 1024 ffffffff 00000000 three.match', + 'user 1234 101 1024 1024 ffffffff 00000000 my$process', 'user 1236 100 1024 1024 ffffffff 00000000 foo', + 'user 1578 1236 1024 1024 ffffffff 00000000 foo', ] def _grepOutput(self, substring): return [line for line in self.sample_output if substring in line] - def testGetPids_sdkGreaterThanNougatMR1(self): + def testListProcesses_sdkGreaterThanNougatMR1(self): with self.patch_call(self.call.device.build_version_sdk, return_value=(version_codes.NOUGAT_MR1 + 1)): with self.patch_call(self.call.device.build_id, @@ -2314,47 +2347,49 @@ class DeviceUtilsGetPidsTest(DeviceUtilsTest): with self.assertCall( self.call.device._RunPipedShellCommand( 'ps -e | grep -F example.process'), []): - self.device.GetPids('example.process') + self.device.ListProcesses('example.process') - def testGetPids_noMatches(self): + def testListProcesses_noMatches(self): with self.patch_call(self.call.device.build_version_sdk, return_value=version_codes.LOLLIPOP): with self.assertCall( self.call.device._RunPipedShellCommand('ps | grep -F does.not.match'), self._grepOutput('does.not.match')): - self.assertEqual({}, self.device.GetPids('does.not.match')) + self.assertEqual([], self.device.ListProcesses('does.not.match')) - def testGetPids_oneMatch(self): + def testListProcesses_oneMatch(self): with self.patch_call(self.call.device.build_version_sdk, return_value=version_codes.LOLLIPOP): with self.assertCall( self.call.device._RunPipedShellCommand('ps | grep -F one.match'), self._grepOutput('one.match')): self.assertEqual( - {'one.match': ['1001']}, - self.device.GetPids('one.match')) + Processes(('one.match', 1001, 100)), + self.device.ListProcesses('one.match')) - def testGetPids_multipleMatches(self): + def testListProcesses_multipleMatches(self): with self.patch_call(self.call.device.build_version_sdk, return_value=version_codes.LOLLIPOP): with self.assertCall( self.call.device._RunPipedShellCommand('ps | grep -F match'), self._grepOutput('match')): self.assertEqual( - {'one.match': ['1001'], - 'two.match': ['1002'], - 'three.match': ['1003']}, - self.device.GetPids('match')) + Processes(('one.match', 1001, 100), + ('two.match', 1002, 100), + ('three.match', 1003, 101)), + self.device.ListProcesses('match')) - def testGetPids_quotable(self): + def testListProcesses_quotable(self): with self.patch_call(self.call.device.build_version_sdk, return_value=version_codes.LOLLIPOP): with self.assertCall( self.call.device._RunPipedShellCommand("ps | grep -F 'my$process'"), self._grepOutput('my$process')): self.assertEqual( - {'my$process': ['1234']}, self.device.GetPids('my$process')) + Processes(('my$process', 1234, 101)), + self.device.ListProcesses('my$process')) + # Tests for the GetPids wrapper interface. def testGetPids_multipleInstances(self): with self.patch_call(self.call.device.build_version_sdk, return_value=version_codes.LOLLIPOP): @@ -2362,7 +2397,7 @@ class DeviceUtilsGetPidsTest(DeviceUtilsTest): self.call.device._RunPipedShellCommand('ps | grep -F foo'), self._grepOutput('foo')): self.assertEqual( - {'foo': ['1000', '1236']}, + {'foo': ['1236', '1578']}, self.device.GetPids('foo')) def testGetPids_allProcesses(self): @@ -2377,9 +2412,10 @@ class DeviceUtilsGetPidsTest(DeviceUtilsTest): 'two.match': ['1002'], 'three.match': ['1003'], 'my$process': ['1234'], - 'foo': ['1000', '1236']}, + 'foo': ['1236', '1578']}, self.device.GetPids()) + # Tests for the GetApplicationPids wrapper interface. def testGetApplicationPids_notFound(self): with self.patch_call(self.call.device.build_version_sdk, return_value=version_codes.LOLLIPOP): @@ -2395,7 +2431,7 @@ class DeviceUtilsGetPidsTest(DeviceUtilsTest): with self.assertCall( self.call.device._RunPipedShellCommand('ps | grep -F one.match'), self._grepOutput('one.match')): - self.assertEqual(['1001'], self.device.GetApplicationPids('one.match')) + self.assertEqual([1001], self.device.GetApplicationPids('one.match')) def testGetApplicationPids_foundMany(self): with self.patch_call(self.call.device.build_version_sdk, @@ -2404,7 +2440,7 @@ class DeviceUtilsGetPidsTest(DeviceUtilsTest): self.call.device._RunPipedShellCommand('ps | grep -F foo'), self._grepOutput('foo')): self.assertEqual( - ['1000', '1236'], + [1236, 1578], self.device.GetApplicationPids('foo')) def testGetApplicationPids_atMostOneNotFound(self): @@ -2425,7 +2461,7 @@ class DeviceUtilsGetPidsTest(DeviceUtilsTest): self.call.device._RunPipedShellCommand('ps | grep -F one.match'), self._grepOutput('one.match')): self.assertEqual( - '1001', + 1001, self.device.GetApplicationPids('one.match', at_most_one=True)) def testGetApplicationPids_atMostOneFoundTooMany(self): @@ -2503,60 +2539,6 @@ class DeviceUtilsTakeScreenshotTest(DeviceUtilsTest): self.device.TakeScreenshot('/test/host/screenshot.png') -class DeviceUtilsGetMemoryUsageForPidTest(DeviceUtilsTest): - - def setUp(self): - super(DeviceUtilsGetMemoryUsageForPidTest, self).setUp() - - def testGetMemoryUsageForPid_validPid(self): - with self.assertCalls( - (self.call.device._RunPipedShellCommand( - 'showmap 1234 | grep TOTAL', as_root=True), - ['100 101 102 103 104 105 106 107 TOTAL']), - (self.call.device.ReadFile('/proc/1234/status', as_root=True), - 'VmHWM: 1024 kB\n')): - 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_noSmaps(self): - with self.assertCalls( - (self.call.device._RunPipedShellCommand( - 'showmap 4321 | grep TOTAL', as_root=True), - ['cannot open /proc/4321/smaps: No such file or directory']), - (self.call.device.ReadFile('/proc/4321/status', as_root=True), - 'VmHWM: 1024 kb\n')): - self.assertEquals({'VmHWM': 1024}, self.device.GetMemoryUsageForPid(4321)) - - def testGetMemoryUsageForPid_noStatus(self): - with self.assertCalls( - (self.call.device._RunPipedShellCommand( - 'showmap 4321 | grep TOTAL', as_root=True), - ['100 101 102 103 104 105 106 107 TOTAL']), - (self.call.device.ReadFile('/proc/4321/status', as_root=True), - self.CommandError())): - self.assertEquals( - { - 'Size': 100, - 'Rss': 101, - 'Pss': 102, - 'Shared_Clean': 103, - 'Shared_Dirty': 104, - 'Private_Clean': 105, - 'Private_Dirty': 106, - }, - self.device.GetMemoryUsageForPid(4321)) - - class DeviceUtilsDismissCrashDialogIfNeededTest(DeviceUtilsTest): def testDismissCrashDialogIfNeeded_crashedPageckageNotFound(self): @@ -2682,7 +2664,7 @@ class DeviceUtilsHealthyDevicesTest(mock_calls.TestCase): (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), [_AdbWrapperMock(s) for s in test_serials])): with self.assertRaises(device_errors.NoDevicesError): - device_utils.DeviceUtils.HealthyDevices(device_arg=None) + device_utils.DeviceUtils.HealthyDevices(device_arg=None, retry=False) def testHealthyDevices_noneDeviceArg_multiple_attached_ANDROID_SERIAL(self): try: @@ -2721,7 +2703,17 @@ class DeviceUtilsHealthyDevicesTest(mock_calls.TestCase): (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), [_AdbWrapperMock(s) for s in test_serials])): with self.assertRaises(device_errors.NoDevicesError): - device_utils.DeviceUtils.HealthyDevices(device_arg=[]) + device_utils.DeviceUtils.HealthyDevices(device_arg=[], retry=False) + + def testHealthyDevices_EmptyListDeviceArg_no_attached_with_retry(self): + test_serials = [] + with self.assertCalls( + (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), + [_AdbWrapperMock(s) for s in test_serials]), + (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), + [_AdbWrapperMock(s) for s in test_serials])): + with self.assertRaises(device_errors.NoDevicesError): + device_utils.DeviceUtils.HealthyDevices(device_arg=[], retry=True) def testHealthyDevices_ListDeviceArg(self): device_arg = ['0123456789abcdef', 'fedcba9876543210'] @@ -2749,6 +2741,26 @@ class DeviceUtilsRestartAdbdTest(DeviceUtilsTest): class DeviceUtilsGrantPermissionsTest(DeviceUtilsTest): + def _PmGrantShellCall(self, package, permissions): + fragment = 'p=%s;for q in %s;' % (package, ' '.join(sorted(permissions))) + results = [] + for permission, result in sorted(permissions.iteritems()): + if result: + output, status = result + '\n', 1 + else: + output, status = '', 0 + results.append( + '{output}{sep}{permission}{sep}{status}{sep}\n'.format( + output=output, + permission=permission, + status=status, + sep=device_utils._SHELL_OUTPUT_SEPARATOR + )) + return ( + self.call.device.RunShellCommand( + AnyStringWith(fragment), + shell=True, raw_output=True, large_output=True, check_return=True), + ''.join(results)) def testGrantPermissions_none(self): self.device.GrantPermissions('package', []) @@ -2759,40 +2771,52 @@ class DeviceUtilsGrantPermissionsTest(DeviceUtilsTest): self.device.GrantPermissions('package', ['p1']) def testGrantPermissions_one(self): - permissions_cmd = 'pm grant package p1' with self.patch_call(self.call.device.build_version_sdk, return_value=version_codes.MARSHMALLOW): with self.assertCalls( - (self.call.device.RunShellCommand( - permissions_cmd, shell=True, check_return=True), [])): + self._PmGrantShellCall('package', {'p1': 0})): self.device.GrantPermissions('package', ['p1']) def testGrantPermissions_multiple(self): - permissions_cmd = 'pm grant package p1&&pm grant package p2' with self.patch_call(self.call.device.build_version_sdk, return_value=version_codes.MARSHMALLOW): with self.assertCalls( - (self.call.device.RunShellCommand( - permissions_cmd, shell=True, check_return=True), [])): + self._PmGrantShellCall('package', {'p1': 0, 'p2': 0})): self.device.GrantPermissions('package', ['p1', 'p2']) def testGrantPermissions_WriteExtrnalStorage(self): - permissions_cmd = ( - 'pm grant package android.permission.WRITE_EXTERNAL_STORAGE&&' - 'pm grant package android.permission.READ_EXTERNAL_STORAGE') - with self.patch_call(self.call.device.build_version_sdk, - return_value=version_codes.MARSHMALLOW): - with self.assertCalls( - (self.call.device.RunShellCommand( - permissions_cmd, shell=True, check_return=True), [])): - self.device.GrantPermissions( - 'package', ['android.permission.WRITE_EXTERNAL_STORAGE']) + WRITE = 'android.permission.WRITE_EXTERNAL_STORAGE' + READ = 'android.permission.READ_EXTERNAL_STORAGE' + with PatchLogger() as logger: + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.MARSHMALLOW): + with self.assertCalls( + self._PmGrantShellCall('package', {READ: 0, WRITE: 0})): + self.device.GrantPermissions('package', [WRITE]) + self.assertEqual(logger.warnings, []) def testGrantPermissions_BlackList(self): - with self.patch_call(self.call.device.build_version_sdk, - return_value=version_codes.MARSHMALLOW): - self.device.GrantPermissions( - 'package', ['android.permission.ACCESS_MOCK_LOCATION']) + with PatchLogger() as logger: + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.MARSHMALLOW): + with self.assertCalls( + self._PmGrantShellCall('package', {'p1': 0})): + self.device.GrantPermissions( + 'package', ['p1', 'foo.permission.C2D_MESSAGE']) + self.assertEqual(logger.warnings, []) + + def testGrantPermissions_unchangeablePermision(self): + error_message = ( + 'Operation not allowed: java.lang.SecurityException: ' + 'Permission UNCHANGEABLE is not a changeable permission type') + with PatchLogger() as logger: + with self.patch_call(self.call.device.build_version_sdk, + return_value=version_codes.MARSHMALLOW): + with self.assertCalls( + self._PmGrantShellCall('package', {'UNCHANGEABLE': error_message})): + self.device.GrantPermissions('package', ['UNCHANGEABLE']) + self.assertEqual( + logger.warnings, [mock.ANY, AnyStringWith('UNCHANGEABLE')]) class DeviecUtilsIsScreenOn(DeviceUtilsTest): @@ -2903,6 +2927,46 @@ class DeviecUtilsLoadCacheData(DeviceUtilsTest): self.assertTrue(self.device.LoadCacheData(json.dumps(data))) +class DeviceUtilsGetIMEITest(DeviceUtilsTest): + + def testSuccessfulDumpsys(self): + dumpsys_output = ( + 'Phone Subscriber Info:' + ' Phone Type = GSM' + ' Device ID = 123454321') + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'), + (self.call.adb.Shell('dumpsys iphonesubinfo'), dumpsys_output)): + self.assertEquals(self.device.GetIMEI(), '123454321') + + def testSuccessfulServiceCall(self): + service_output = """ + Result: Parcel(\n' + 0x00000000: 00000000 0000000f 00350033 00360033 '........7.6.5.4.' + 0x00000010: 00360032 00370030 00300032 00300039 '3.2.1.0.1.2.3.4.' + 0x00000020: 00380033 00000039 '5.6.7... ') + """ + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '24'), + (self.call.adb.Shell('service call iphonesubinfo 1'), service_output)): + self.assertEquals(self.device.GetIMEI(), '765432101234567') + + def testNoIMEI(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'), + (self.call.adb.Shell('dumpsys iphonesubinfo'), 'no device id')): + with self.assertRaises(device_errors.CommandFailedError): + self.device.GetIMEI() + + def testAdbError(self): + with self.assertCalls( + (self.call.device.GetProp('ro.build.version.sdk', cache=True), '24'), + (self.call.adb.Shell('service call iphonesubinfo 1'), + self.ShellError())): + with self.assertRaises(device_errors.CommandFailedError): + self.device.GetIMEI() + + if __name__ == '__main__': logging.getLogger().setLevel(logging.DEBUG) unittest.main(verbosity=2) |