| # Copyright 2017 Google Inc. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import io |
| import mock |
| import subprocess |
| |
| from collections import OrderedDict |
| from future.tests.base import unittest |
| from mobly.controllers.android_device_lib import adb |
| |
| # Mock parameters for instrumentation. |
| MOCK_INSTRUMENTATION_PACKAGE = 'com.my.instrumentation.tests' |
| MOCK_INSTRUMENTATION_RUNNER = 'com.my.instrumentation.runner' |
| MOCK_INSTRUMENTATION_OPTIONS = OrderedDict([ |
| ('option1', 'value1'), |
| ('option2', 'value2'), |
| ]) |
| # Mock android instrumentation commands. |
| MOCK_BASIC_INSTRUMENTATION_COMMAND = ('am instrument -r -w com.my' |
| '.instrumentation.tests/com.android' |
| '.common.support.test.runner' |
| '.AndroidJUnitRunner') |
| MOCK_RUNNER_INSTRUMENTATION_COMMAND = ('am instrument -r -w com.my' |
| '.instrumentation.tests/com.my' |
| '.instrumentation.runner') |
| MOCK_OPTIONS_INSTRUMENTATION_COMMAND = ('am instrument -r -w -e option1 value1' |
| ' -e option2 value2 com.my' |
| '.instrumentation.tests/com.android' |
| '.common.support.test.runner' |
| '.AndroidJUnitRunner') |
| |
| # Mock root command outputs. |
| MOCK_ROOT_SUCCESS_OUTPUT = 'adbd is already running as root' |
| MOCK_ROOT_ERROR_OUTPUT = ( |
| 'adb: unable to connect for root: closed'.encode('utf-8')) |
| |
| # Mock Shell Command |
| MOCK_SHELL_COMMAND = 'ls' |
| MOCK_COMMAND_OUTPUT = '/system/bin/ls'.encode('utf-8') |
| MOCK_DEFAULT_STDOUT = 'out' |
| MOCK_DEFAULT_STDERR = 'err' |
| MOCK_DEFAULT_COMMAND_OUTPUT = MOCK_DEFAULT_STDOUT.encode('utf-8') |
| MOCK_ADB_SHELL_COMMAND_CHECK = 'adb shell command -v ls' |
| |
| |
| class AdbTest(unittest.TestCase): |
| """Unit tests for mobly.controllers.android_device_lib.adb. |
| """ |
| |
| def _mock_process(self, mock_psutil_process, mock_popen): |
| # the created proc object in adb._exec_cmd() |
| mock_proc = mock.Mock() |
| mock_popen.return_value = mock_proc |
| |
| # the created process object in adb._exec_cmd() |
| mock_psutil_process.return_value = mock.Mock() |
| |
| mock_proc.communicate = mock.Mock( |
| return_value=(MOCK_DEFAULT_STDOUT.encode('utf-8'), |
| MOCK_DEFAULT_STDERR.encode('utf-8'))) |
| mock_proc.returncode = 0 |
| return (mock_psutil_process, mock_popen) |
| |
| def _mock_execute_and_process_stdout_process(self, mock_popen): |
| # the created proc object in adb._execute_and_process_stdout() |
| mock_proc = mock.Mock() |
| mock_popen.return_value = mock_proc |
| |
| mock_popen.return_value.stdout.readline.side_effect = [''] |
| |
| mock_proc.communicate = mock.Mock( |
| return_value=('', MOCK_DEFAULT_STDERR.encode('utf-8'))) |
| mock_proc.returncode = 0 |
| return mock_popen |
| |
| @mock.patch('mobly.utils.run_command') |
| def test_exec_cmd_no_timeout_success(self, mock_run_command): |
| mock_run_command.return_value = (0, |
| MOCK_DEFAULT_STDOUT.encode('utf-8'), |
| MOCK_DEFAULT_STDERR.encode('utf-8')) |
| out = adb.AdbProxy()._exec_cmd(['fake_cmd'], |
| shell=False, |
| timeout=None, |
| stderr=None) |
| self.assertEqual(MOCK_DEFAULT_STDOUT, out.decode('utf-8')) |
| mock_run_command.assert_called_with(['fake_cmd'], |
| shell=False, |
| timeout=None) |
| |
| @mock.patch('mobly.utils.run_command') |
| def test_exec_cmd_error_with_serial(self, mock_run_command): |
| # Return 1 for retcode for error. |
| mock_run_command.return_value = (1, |
| MOCK_DEFAULT_STDOUT.encode('utf-8'), |
| MOCK_DEFAULT_STDERR.encode('utf-8')) |
| mock_serial = 'ABCD1234' |
| with self.assertRaisesRegex(adb.AdbError, |
| 'Error executing adb cmd .*') as context: |
| adb.AdbProxy(mock_serial).fake_cmd() |
| self.assertEqual(context.exception.serial, mock_serial) |
| self.assertIn(mock_serial, context.exception.cmd) |
| |
| @mock.patch('mobly.utils.run_command') |
| def test_exec_cmd_error_without_serial(self, mock_run_command): |
| # Return 1 for retcode for error. |
| mock_run_command.return_value = (1, |
| MOCK_DEFAULT_STDOUT.encode('utf-8'), |
| MOCK_DEFAULT_STDERR.encode('utf-8')) |
| with self.assertRaisesRegex(adb.AdbError, |
| 'Error executing adb cmd .*') as context: |
| adb.AdbProxy()._exec_cmd(['fake_cmd'], |
| shell=False, |
| timeout=None, |
| stderr=None) |
| self.assertFalse(context.exception.serial) |
| mock_run_command.assert_called_with(['fake_cmd'], |
| shell=False, |
| timeout=None) |
| |
| @mock.patch('mobly.utils.run_command') |
| def test_exec_cmd_with_timeout_success(self, mock_run_command): |
| mock_run_command.return_value = (0, |
| MOCK_DEFAULT_STDOUT.encode('utf-8'), |
| MOCK_DEFAULT_STDERR.encode('utf-8')) |
| |
| out = adb.AdbProxy()._exec_cmd(['fake_cmd'], |
| shell=False, |
| timeout=1, |
| stderr=None) |
| self.assertEqual(MOCK_DEFAULT_STDOUT, out.decode('utf-8')) |
| mock_run_command.assert_called_with(['fake_cmd'], |
| shell=False, |
| timeout=1) |
| |
| @mock.patch('mobly.utils.run_command') |
| def test_exec_cmd_timed_out(self, mock_run_command): |
| mock_run_command.side_effect = adb.psutil.TimeoutExpired('Timed out') |
| mock_serial = '1234Abcd' |
| with self.assertRaisesRegex( |
| adb.AdbTimeoutError, 'Timed out executing command "adb -s ' |
| '1234Abcd fake-cmd" after 0.01s.') as context: |
| adb.AdbProxy(mock_serial).fake_cmd(timeout=0.01) |
| self.assertEqual(context.exception.serial, mock_serial) |
| self.assertIn(mock_serial, context.exception.cmd) |
| |
| @mock.patch('mobly.utils.run_command') |
| def test_exec_cmd_timed_out_without_serial(self, mock_run_command): |
| mock_run_command.side_effect = adb.psutil.TimeoutExpired('Timed out') |
| with self.assertRaisesRegex( |
| adb.AdbTimeoutError, 'Timed out executing command "adb ' |
| 'fake-cmd" after 0.01s.') as context: |
| adb.AdbProxy().fake_cmd(timeout=0.01) |
| |
| def test_exec_cmd_with_negative_timeout_value(self): |
| with self.assertRaisesRegex(ValueError, |
| 'Timeout is not a positive value: -1'): |
| adb.AdbProxy()._exec_cmd(['fake_cmd'], |
| shell=False, |
| timeout=-1, |
| stderr=None) |
| |
| @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') |
| def test_execute_and_process_stdout_reads_stdout(self, mock_popen): |
| self._mock_execute_and_process_stdout_process(mock_popen) |
| mock_popen.return_value.stdout.readline.side_effect = ['1', '2', ''] |
| mock_handler = mock.MagicMock() |
| |
| err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], |
| shell=False, |
| handler=mock_handler) |
| self.assertEqual(mock_handler.call_count, 2) |
| mock_handler.assert_any_call('1') |
| mock_handler.assert_any_call('2') |
| |
| @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') |
| def test_execute_and_process_stdout_reads_unexpected_stdout( |
| self, mock_popen): |
| unexpected_stdout = MOCK_DEFAULT_STDOUT.encode('utf-8') |
| |
| self._mock_execute_and_process_stdout_process(mock_popen) |
| mock_handler = mock.MagicMock() |
| mock_popen.return_value.communicate = mock.Mock( |
| return_value=(unexpected_stdout, |
| MOCK_DEFAULT_STDERR.encode('utf-8'))) |
| |
| err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], |
| shell=False, |
| handler=mock_handler) |
| self.assertEqual(mock_handler.call_count, 1) |
| mock_handler.assert_called_with(unexpected_stdout) |
| |
| @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') |
| @mock.patch('logging.debug') |
| def test_execute_and_process_stdout_logs_cmd(self, mock_debug_logger, |
| mock_popen): |
| raw_expected_stdout = '' |
| expected_stdout = '[elided, processed via handler]' |
| expected_stderr = MOCK_DEFAULT_STDERR.encode('utf-8') |
| self._mock_execute_and_process_stdout_process(mock_popen) |
| mock_popen.return_value.communicate = mock.Mock( |
| return_value=(raw_expected_stdout, expected_stderr)) |
| |
| err = adb.AdbProxy()._execute_and_process_stdout( |
| ['fake_cmd'], shell=False, handler=mock.MagicMock()) |
| mock_debug_logger.assert_called_with( |
| 'cmd: %s, stdout: %s, stderr: %s, ret: %s', 'fake_cmd', |
| expected_stdout, expected_stderr, 0) |
| |
| @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') |
| @mock.patch('logging.debug') |
| def test_execute_and_process_stdout_logs_cmd_with_unexpected_stdout( |
| self, mock_debug_logger, mock_popen): |
| raw_expected_stdout = MOCK_DEFAULT_STDOUT.encode('utf-8') |
| expected_stdout = '[unexpected stdout] %s' % raw_expected_stdout |
| expected_stderr = MOCK_DEFAULT_STDERR.encode('utf-8') |
| |
| self._mock_execute_and_process_stdout_process(mock_popen) |
| mock_popen.return_value.communicate = mock.Mock( |
| return_value=(raw_expected_stdout, expected_stderr)) |
| |
| err = adb.AdbProxy()._execute_and_process_stdout( |
| ['fake_cmd'], shell=False, handler=mock.MagicMock()) |
| mock_debug_logger.assert_called_with( |
| 'cmd: %s, stdout: %s, stderr: %s, ret: %s', 'fake_cmd', |
| expected_stdout, expected_stderr, 0) |
| |
| @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') |
| def test_execute_and_process_stdout_despite_cmd_exits(self, mock_popen): |
| self._mock_execute_and_process_stdout_process(mock_popen) |
| mock_popen.return_value.poll.side_effect = [None, 0] |
| mock_popen.return_value.stdout.readline.side_effect = [ |
| '1', '2', '3', '' |
| ] |
| mock_handler = mock.MagicMock() |
| |
| err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], |
| shell=False, |
| handler=mock_handler) |
| |
| self.assertEqual(mock_handler.call_count, 3) |
| mock_handler.assert_any_call('1') |
| mock_handler.assert_any_call('2') |
| mock_handler.assert_any_call('3') |
| |
| @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') |
| def test_execute_and_process_stdout_when_cmd_eof(self, mock_popen): |
| self._mock_execute_and_process_stdout_process(mock_popen) |
| mock_popen.return_value.stdout.readline.side_effect = [ |
| '1', '2', '3', '' |
| ] |
| mock_handler = mock.MagicMock() |
| |
| err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], |
| shell=False, |
| handler=mock_handler) |
| |
| self.assertEqual(mock_handler.call_count, 3) |
| mock_handler.assert_any_call('1') |
| mock_handler.assert_any_call('2') |
| mock_handler.assert_any_call('3') |
| |
| @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') |
| def test_execute_and_process_stdout_returns_stderr(self, mock_popen): |
| self._mock_execute_and_process_stdout_process(mock_popen) |
| |
| err = adb.AdbProxy()._execute_and_process_stdout( |
| ['fake_cmd'], shell=False, handler=mock.MagicMock()) |
| self.assertEqual(MOCK_DEFAULT_STDERR, err.decode('utf-8')) |
| |
| @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') |
| def test_execute_and_process_stdout_raises_adb_error(self, mock_popen): |
| self._mock_execute_and_process_stdout_process(mock_popen) |
| mock_popen.return_value.returncode = 1 |
| |
| with self.assertRaisesRegex(adb.AdbError, |
| 'Error executing adb cmd .*'): |
| err = adb.AdbProxy()._execute_and_process_stdout( |
| ['fake_cmd'], shell=False, handler=mock.MagicMock()) |
| |
| @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') |
| def test_execute_and_process_stdout_when_handler_crash(self, mock_popen): |
| self._mock_execute_and_process_stdout_process(mock_popen) |
| mock_popen.return_value.stdout.readline.side_effect = [ |
| '1', '2', '3', '' |
| ] |
| mock_handler = mock.MagicMock() |
| mock_handler.side_effect = ['', TypeError('fake crash'), '', ''] |
| |
| with self.assertRaisesRegex(TypeError, 'fake crash'): |
| err = adb.AdbProxy()._execute_and_process_stdout( |
| ['fake_cmd'], shell=False, handler=mock_handler) |
| |
| mock_popen.return_value.communicate.assert_called_once_with() |
| |
| def test_construct_adb_cmd(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', |
| 'arg1', |
| shell=False) |
| self.assertEqual(adb_cmd, ['adb', 'shell', 'arg1']) |
| |
| def test_construct_adb_cmd_with_one_command(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd( |
| 'shell ls /asdafsfd/asdf-asfd/asa', [], shell=False) |
| self.assertEqual(adb_cmd, ['adb', 'shell ls /asdafsfd/asdf-asfd/asa']) |
| |
| def test_construct_adb_cmd_with_one_arg_command(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd( |
| 'shell', 'ls /asdafsfd/asdf-asfd/asa', shell=False) |
| self.assertEqual(adb_cmd, |
| ['adb', 'shell', 'ls /asdafsfd/asdf-asfd/asa']) |
| |
| def test_construct_adb_cmd_with_one_arg_command_list(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd( |
| 'shell', ['ls /asdafsfd/asdf-asfd/asa'], shell=False) |
| self.assertEqual(adb_cmd, |
| ['adb', 'shell', 'ls /asdafsfd/asdf-asfd/asa']) |
| |
| def test_construct_adb_cmd_with_special_characters(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', |
| ['a b', '"blah"', r'\/\/'], |
| shell=False) |
| self.assertEqual(adb_cmd, ['adb', 'shell', 'a b', '"blah"', r"\/\/"]) |
| |
| def test_construct_adb_cmd_with_serial(self): |
| adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd('shell', |
| 'arg1', |
| shell=False) |
| self.assertEqual(adb_cmd, ['adb', '-s', '12345', 'shell', 'arg1']) |
| |
| def test_construct_adb_cmd_with_list(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', ['arg1', 'arg2'], |
| shell=False) |
| self.assertEqual(adb_cmd, ['adb', 'shell', 'arg1', 'arg2']) |
| |
| def test_construct_adb_cmd_with_serial_with_list(self): |
| adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd('shell', |
| ['arg1', 'arg2'], |
| shell=False) |
| self.assertEqual(adb_cmd, |
| ['adb', '-s', '12345', 'shell', 'arg1', 'arg2']) |
| |
| def test_construct_adb_cmd_with_shell_true(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', |
| 'arg1 arg2', |
| shell=True) |
| self.assertEqual(adb_cmd, '"adb" shell arg1 arg2') |
| |
| def test_construct_adb_cmd_with_shell_true_with_one_command(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd( |
| 'shell ls /asdafsfd/asdf-asfd/asa', [], shell=True) |
| self.assertEqual(adb_cmd, '"adb" shell ls /asdafsfd/asdf-asfd/asa ') |
| |
| def test_construct_adb_cmd_with_shell_true_with_one_arg_command(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd( |
| 'shell', 'ls /asdafsfd/asdf-asfd/asa', shell=True) |
| self.assertEqual(adb_cmd, '"adb" shell ls /asdafsfd/asdf-asfd/asa') |
| |
| def test_construct_adb_cmd_with_shell_true_with_one_arg_command_list(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd( |
| 'shell', ['ls /asdafsfd/asdf-asfd/asa'], shell=True) |
| self.assertEqual(adb_cmd, '"adb" shell \'ls /asdafsfd/asdf-asfd/asa\'') |
| |
| def test_construct_adb_cmd_with_shell_true_with_auto_quotes(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', |
| ['a b', '"blah"', r'\/\/'], |
| shell=True) |
| self.assertEqual(adb_cmd, '"adb" shell \'a b\' \'"blah"\' \'\\/\\/\'') |
| |
| def test_construct_adb_cmd_with_shell_true_with_serial(self): |
| adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd('shell', |
| 'arg1 arg2', |
| shell=True) |
| self.assertEqual(adb_cmd, '"adb" -s "12345" shell arg1 arg2') |
| |
| def test_construct_adb_cmd_with_shell_true_with_list(self): |
| adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', ['arg1', 'arg2'], |
| shell=True) |
| self.assertEqual(adb_cmd, '"adb" shell arg1 arg2') |
| |
| def test_construct_adb_cmd_with_shell_true_with_serial_with_list(self): |
| adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd('shell', |
| ['arg1', 'arg2'], |
| shell=True) |
| self.assertEqual(adb_cmd, '"adb" -s "12345" shell arg1 arg2') |
| |
| def test_exec_adb_cmd(self): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT |
| adb.AdbProxy().shell(['arg1', 'arg2']) |
| mock_exec_cmd.assert_called_once_with( |
| ['adb', 'shell', 'arg1', 'arg2'], |
| shell=False, |
| timeout=None, |
| stderr=None) |
| |
| def test_exec_adb_cmd_with_shell_true(self): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT |
| adb.AdbProxy().shell('arg1 arg2', shell=True) |
| mock_exec_cmd.assert_called_once_with('"adb" shell arg1 arg2', |
| shell=True, |
| timeout=None, |
| stderr=None) |
| |
| def test_exec_adb_cmd_formats_command(self): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| with mock.patch.object( |
| adb.AdbProxy, |
| '_construct_adb_cmd') as mock_construct_adb_cmd: |
| mock_adb_cmd = mock.MagicMock() |
| mock_adb_args = mock.MagicMock() |
| mock_construct_adb_cmd.return_value = mock_adb_cmd |
| mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT |
| |
| adb.AdbProxy().shell(mock_adb_args) |
| mock_construct_adb_cmd.assert_called_once_with('shell', |
| mock_adb_args, |
| shell=False) |
| mock_exec_cmd.assert_called_once_with(mock_adb_cmd, |
| shell=False, |
| timeout=None, |
| stderr=None) |
| |
| def test_exec_adb_cmd_formats_command_with_shell_true(self): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| with mock.patch.object( |
| adb.AdbProxy, |
| '_construct_adb_cmd') as mock_construct_adb_cmd: |
| mock_adb_cmd = mock.MagicMock() |
| mock_adb_args = mock.MagicMock() |
| mock_construct_adb_cmd.return_value = mock_adb_cmd |
| |
| adb.AdbProxy().shell(mock_adb_args, shell=True) |
| mock_construct_adb_cmd.assert_called_once_with('shell', |
| mock_adb_args, |
| shell=True) |
| mock_exec_cmd.assert_called_once_with(mock_adb_cmd, |
| shell=True, |
| timeout=None, |
| stderr=None) |
| |
| def test_execute_adb_and_process_stdout_formats_command(self): |
| with mock.patch.object(adb.AdbProxy, '_execute_and_process_stdout' |
| ) as mock_execute_and_process_stdout: |
| with mock.patch.object( |
| adb.AdbProxy, |
| '_construct_adb_cmd') as mock_construct_adb_cmd: |
| mock_adb_cmd = mock.MagicMock() |
| mock_adb_args = mock.MagicMock() |
| mock_handler = mock.MagicMock() |
| mock_construct_adb_cmd.return_value = mock_adb_cmd |
| |
| adb.AdbProxy()._execute_adb_and_process_stdout( |
| 'shell', mock_adb_args, shell=False, handler=mock_handler) |
| mock_construct_adb_cmd.assert_called_once_with('shell', |
| mock_adb_args, |
| shell=False) |
| mock_execute_and_process_stdout.assert_called_once_with( |
| mock_adb_cmd, shell=False, handler=mock_handler) |
| |
| @mock.patch('mobly.utils.run_command') |
| def test_exec_adb_cmd_with_stderr_pipe(self, mock_run_command): |
| mock_run_command.return_value = (0, |
| MOCK_DEFAULT_STDOUT.encode('utf-8'), |
| MOCK_DEFAULT_STDERR.encode('utf-8')) |
| stderr_redirect = io.BytesIO() |
| out = adb.AdbProxy().shell('arg1 arg2', |
| shell=True, |
| stderr=stderr_redirect) |
| self.assertEqual(MOCK_DEFAULT_STDOUT, out.decode('utf-8')) |
| self.assertEqual(MOCK_DEFAULT_STDERR, |
| stderr_redirect.getvalue().decode('utf-8')) |
| |
| def test_getprop(self): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| mock_exec_cmd.return_value = b'blah' |
| self.assertEqual(adb.AdbProxy().getprop('haha'), 'blah') |
| mock_exec_cmd.assert_called_once_with( |
| ['adb', 'shell', 'getprop', 'haha'], |
| shell=False, |
| stderr=None, |
| timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC) |
| |
| def test__parse_getprop_output_special_values(self): |
| mock_adb_output = ( |
| b'[selinux.restorecon_recursive]: [/data/misc_ce/10]\n' |
| b'[selinux.abc]: [key: value]\n' # "key: value" as value |
| b'[persist.sys.boot.reason.history]: [reboot,adb,1558549857\n' |
| b'reboot,factory_reset,1558483886\n' # multi-line value |
| b'reboot,1558483823]\n' |
| b'[persist.something]: [haha\n' |
| b']\n' |
| b'[[wrapped.key]]: [[wrapped value]]\n' |
| b'[persist.byte]: [J\xaa\x8bb\xab\x9dP\x0f]\n' # non-decodable |
| ) |
| parsed_props = adb.AdbProxy()._parse_getprop_output(mock_adb_output) |
| expected_output = { |
| 'persist.sys.boot.reason.history': |
| ('reboot,adb,1558549857\nreboot,factory_reset,1558483886\n' |
| 'reboot,1558483823'), |
| 'selinux.abc': |
| 'key: value', |
| 'persist.something': |
| 'haha\n', |
| 'selinux.restorecon_recursive': |
| '/data/misc_ce/10', |
| '[wrapped.key]': |
| '[wrapped value]', |
| 'persist.byte': |
| 'JbP\x0f', |
| } |
| self.assertEqual(parsed_props, expected_output) |
| |
| def test__parse_getprop_output_malformat_output(self): |
| mock_adb_output = ( |
| b'[selinux.restorecon_recursive][/data/misc_ce/10]\n' # Malformat |
| b'[persist.sys.boot.reason]: [reboot,adb,1558549857]\n' |
| b'[persist.something]: [haha]\n') |
| parsed_props = adb.AdbProxy()._parse_getprop_output(mock_adb_output) |
| expected_output = { |
| 'persist.sys.boot.reason': 'reboot,adb,1558549857', |
| 'persist.something': 'haha' |
| } |
| self.assertEqual(parsed_props, expected_output) |
| |
| def test__parse_getprop_output_special_line_separator(self): |
| mock_adb_output = ( |
| b'[selinux.restorecon_recursive][/data/misc_ce/10]\r\n' # Malformat |
| b'[persist.sys.boot.reason]: [reboot,adb,1558549857]\r\n' |
| b'[persist.something]: [haha]\r\n') |
| parsed_props = adb.AdbProxy()._parse_getprop_output(mock_adb_output) |
| expected_output = { |
| 'persist.sys.boot.reason': 'reboot,adb,1558549857', |
| 'persist.something': 'haha' |
| } |
| self.assertEqual(parsed_props, expected_output) |
| |
| @mock.patch('time.sleep', return_value=mock.MagicMock()) |
| def test_getprops(self, mock_sleep): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| mock_exec_cmd.return_value = ( |
| b'\n[sendbug.preferred.domain]: [google.com]\n' |
| b'[sys.uidcpupower]: []\n' |
| b'[sys.wifitracing.started]: [1]\n' |
| b'[telephony.lteOnCdmaDevice]: [1]\n\n') |
| actual_output = adb.AdbProxy().getprops([ |
| 'sys.wifitracing.started', # "numeric" value |
| 'sys.uidcpupower', # empty value |
| 'sendbug.preferred.domain', # string value |
| 'nonExistentProp' |
| ]) |
| self.assertEqual( |
| actual_output, { |
| 'sys.wifitracing.started': '1', |
| 'sys.uidcpupower': '', |
| 'sendbug.preferred.domain': 'google.com' |
| }) |
| mock_exec_cmd.assert_called_once_with( |
| ['adb', 'shell', 'getprop'], |
| shell=False, |
| stderr=None, |
| timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC) |
| mock_sleep.assert_not_called() |
| |
| @mock.patch('time.sleep', return_value=mock.MagicMock()) |
| def test_getprops_when_empty_string_randomly_returned(self, mock_sleep): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| mock_exec_cmd.side_effect = [ |
| b'', |
| (b'\n[ro.build.id]: [AB42]\n' |
| b'[ro.build.type]: [userdebug]\n\n') |
| ] |
| actual_output = adb.AdbProxy().getprops(['ro.build.id']) |
| self.assertEqual(actual_output, { |
| 'ro.build.id': 'AB42', |
| }) |
| self.assertEqual(mock_exec_cmd.call_count, 2) |
| mock_exec_cmd.assert_called_with( |
| ['adb', 'shell', 'getprop'], |
| shell=False, |
| stderr=None, |
| timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC) |
| self.assertEqual(mock_sleep.call_count, 1) |
| mock_sleep.assert_called_with(1) |
| |
| @mock.patch('time.sleep', return_value=mock.MagicMock()) |
| def test_getprops_when_empty_string_always_returned(self, mock_sleep): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| mock_exec_cmd.return_value = b'' |
| actual_output = adb.AdbProxy().getprops(['ro.build.id']) |
| self.assertEqual(actual_output, {}) |
| self.assertEqual(mock_exec_cmd.call_count, 3) |
| mock_exec_cmd.assert_called_with( |
| ['adb', 'shell', 'getprop'], |
| shell=False, |
| stderr=None, |
| timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC) |
| self.assertEqual(mock_sleep.call_count, 2) |
| mock_sleep.assert_called_with(1) |
| |
| def test_forward(self): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| adb.AdbProxy().forward(MOCK_SHELL_COMMAND) |
| |
| def test_instrument_without_parameters(self): |
| """Verifies the AndroidDevice object's instrument command is correct in |
| the basic case. |
| """ |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| output = adb.AdbProxy().instrument(MOCK_INSTRUMENTATION_PACKAGE) |
| mock_exec_cmd.assert_called_once_with( |
| ['adb', 'shell', MOCK_BASIC_INSTRUMENTATION_COMMAND], |
| shell=False, |
| timeout=None, |
| stderr=None) |
| self.assertEqual(output, mock_exec_cmd.return_value) |
| |
| def test_instrument_with_runner(self): |
| """Verifies the AndroidDevice object's instrument command is correct |
| with a runner specified. |
| """ |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| stdout = adb.AdbProxy().instrument( |
| MOCK_INSTRUMENTATION_PACKAGE, |
| runner=MOCK_INSTRUMENTATION_RUNNER) |
| mock_exec_cmd.assert_called_once_with( |
| ['adb', 'shell', MOCK_RUNNER_INSTRUMENTATION_COMMAND], |
| shell=False, |
| timeout=None, |
| stderr=None) |
| self.assertEqual(stdout, mock_exec_cmd.return_value) |
| |
| def test_instrument_with_options(self): |
| """Verifies the AndroidDevice object's instrument command is correct |
| with options. |
| """ |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| stdout = adb.AdbProxy().instrument( |
| MOCK_INSTRUMENTATION_PACKAGE, |
| options=MOCK_INSTRUMENTATION_OPTIONS) |
| mock_exec_cmd.assert_called_once_with( |
| ['adb', 'shell', MOCK_OPTIONS_INSTRUMENTATION_COMMAND], |
| shell=False, |
| timeout=None, |
| stderr=None) |
| self.assertEqual(stdout, mock_exec_cmd.return_value) |
| |
| def test_instrument_with_handler(self): |
| """Verifies the AndroidDevice object's instrument command is correct |
| with a handler passed in. |
| """ |
| |
| def mock_handler(raw_line): |
| pass |
| |
| with mock.patch.object(adb.AdbProxy, '_execute_and_process_stdout' |
| ) as mock_execute_and_process_stdout: |
| stderr = adb.AdbProxy().instrument(MOCK_INSTRUMENTATION_PACKAGE, |
| handler=mock_handler) |
| mock_execute_and_process_stdout.assert_called_once_with( |
| ['adb', 'shell', MOCK_BASIC_INSTRUMENTATION_COMMAND], |
| shell=False, |
| handler=mock_handler) |
| self.assertEqual(stderr, |
| mock_execute_and_process_stdout.return_value) |
| |
| def test_instrument_with_handler_with_runner(self): |
| """Verifies the AndroidDevice object's instrument command is correct |
| with a handler passed in and a runner specified. |
| """ |
| |
| def mock_handler(raw_line): |
| pass |
| |
| with mock.patch.object(adb.AdbProxy, '_execute_and_process_stdout' |
| ) as mock_execute_and_process_stdout: |
| stderr = adb.AdbProxy().instrument( |
| MOCK_INSTRUMENTATION_PACKAGE, |
| runner=MOCK_INSTRUMENTATION_RUNNER, |
| handler=mock_handler) |
| mock_execute_and_process_stdout.assert_called_once_with( |
| ['adb', 'shell', MOCK_RUNNER_INSTRUMENTATION_COMMAND], |
| shell=False, |
| handler=mock_handler) |
| self.assertEqual(stderr, |
| mock_execute_and_process_stdout.return_value) |
| |
| def test_instrument_with_handler_with_options(self): |
| """Verifies the AndroidDevice object's instrument command is correct |
| with a handler passed in and options. |
| """ |
| |
| def mock_handler(raw_line): |
| pass |
| |
| with mock.patch.object(adb.AdbProxy, '_execute_and_process_stdout' |
| ) as mock_execute_and_process_stdout: |
| stderr = adb.AdbProxy().instrument( |
| MOCK_INSTRUMENTATION_PACKAGE, |
| options=MOCK_INSTRUMENTATION_OPTIONS, |
| handler=mock_handler) |
| mock_execute_and_process_stdout.assert_called_once_with( |
| ['adb', 'shell', MOCK_OPTIONS_INSTRUMENTATION_COMMAND], |
| shell=False, |
| handler=mock_handler) |
| self.assertEqual(stderr, |
| mock_execute_and_process_stdout.return_value) |
| |
| @mock.patch.object(adb.AdbProxy, '_exec_cmd') |
| def test_root_success(self, mock_exec_cmd): |
| mock_exec_cmd.return_value = MOCK_ROOT_SUCCESS_OUTPUT |
| output = adb.AdbProxy().root() |
| mock_exec_cmd.assert_called_once_with( |
| ['adb', 'root'], |
| shell=False, |
| timeout=None, |
| stderr=None) |
| self.assertEqual(output, MOCK_ROOT_SUCCESS_OUTPUT) |
| |
| @mock.patch('time.sleep', return_value=mock.MagicMock()) |
| @mock.patch.object(adb.AdbProxy, '_exec_cmd') |
| def test_root_success_with_retry(self, mock_exec_cmd, mock_sleep): |
| mock_exec_cmd.side_effect = [ |
| adb.AdbError('adb root', '', MOCK_ROOT_ERROR_OUTPUT, 1), |
| MOCK_ROOT_SUCCESS_OUTPUT] |
| output = adb.AdbProxy().root() |
| mock_exec_cmd.assert_called_with( |
| ['adb', 'root'], |
| shell=False, |
| timeout=None, |
| stderr=None) |
| self.assertEqual(output, MOCK_ROOT_SUCCESS_OUTPUT) |
| self.assertEqual(mock_sleep.call_count, 1) |
| mock_sleep.assert_called_with(10) |
| |
| @mock.patch('time.sleep', return_value=mock.MagicMock()) |
| @mock.patch.object(adb.AdbProxy, '_exec_cmd') |
| def test_root_raises_adb_error_when_all_retries_failed(self, mock_exec_cmd, |
| mock_sleep): |
| mock_exec_cmd.side_effect = adb.AdbError('adb root', |
| '', |
| MOCK_ROOT_ERROR_OUTPUT, |
| 1) |
| expected_msg = ('Error executing adb cmd "adb root". ' |
| 'ret: 1, stdout: , stderr: %s' % |
| MOCK_ROOT_ERROR_OUTPUT) |
| with self.assertRaisesRegex(adb.AdbError, expected_msg): |
| adb.AdbProxy().root() |
| mock_exec_cmd.assert_called_with( |
| ['adb', 'root'], |
| shell=False, |
| timeout=None, |
| stderr=None) |
| self.assertEqual(mock_sleep.call_count, 2) |
| mock_sleep.assert_called_with(10) |
| |
| def test_has_shell_command_called_correctly(self): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT |
| adb.AdbProxy().has_shell_command(MOCK_SHELL_COMMAND) |
| mock_exec_cmd.assert_called_once_with( |
| ['adb', 'shell', 'command', '-v', MOCK_SHELL_COMMAND], |
| shell=False, |
| timeout=None, |
| stderr=None) |
| |
| def test_has_shell_command_with_existing_command(self): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| mock_exec_cmd.return_value = MOCK_COMMAND_OUTPUT |
| self.assertTrue( |
| adb.AdbProxy().has_shell_command(MOCK_SHELL_COMMAND)) |
| |
| def test_has_shell_command_with_missing_command_on_older_devices(self): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT |
| mock_exec_cmd.side_effect = adb.AdbError( |
| MOCK_ADB_SHELL_COMMAND_CHECK, '', '', 0) |
| self.assertFalse( |
| adb.AdbProxy().has_shell_command(MOCK_SHELL_COMMAND)) |
| |
| def test_has_shell_command_with_missing_command_on_newer_devices(self): |
| with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: |
| mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT |
| mock_exec_cmd.side_effect = adb.AdbError( |
| MOCK_ADB_SHELL_COMMAND_CHECK, '', '', 1) |
| self.assertFalse( |
| adb.AdbProxy().has_shell_command(MOCK_SHELL_COMMAND)) |
| |
| @mock.patch.object(adb.AdbProxy, 'getprop') |
| @mock.patch.object(adb.AdbProxy, '_exec_cmd') |
| def test_current_user_id_25_and_above(self, mock_exec_cmd, mock_getprop): |
| mock_getprop.return_value = b'25' |
| mock_exec_cmd.return_value = b'123' |
| user_id = adb.AdbProxy().current_user_id |
| mock_exec_cmd.assert_called_once_with( |
| ['adb', 'shell', 'am', 'get-current-user'], |
| shell=False, |
| stderr=None, |
| timeout=None) |
| self.assertEqual(user_id, 123) |
| |
| @mock.patch.object(adb.AdbProxy, 'getprop') |
| @mock.patch.object(adb.AdbProxy, '_exec_cmd') |
| def test_current_user_id_between_21_and_24(self, mock_exec_cmd, |
| mock_getprop): |
| mock_getprop.return_value = b'23' |
| mock_exec_cmd.return_value = (b'Users:\n' |
| b'UserInfo{123:Owner:13} serialNo=0\n' |
| b'Created: <unknown>\n' |
| b'Last logged in: +1h22m12s497ms ago\n' |
| b'UserInfo{456:Owner:14} serialNo=0\n' |
| b'Created: <unknown>\n' |
| b'Last logged in: +1h01m12s497ms ago\n') |
| user_id = adb.AdbProxy().current_user_id |
| mock_exec_cmd.assert_called_once_with( |
| ['adb', 'shell', 'dumpsys', 'user'], |
| shell=False, |
| stderr=None, |
| timeout=None) |
| self.assertEqual(user_id, 123) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |