def test_check_app_installed_fail_not_instrumented(self): sc = self._make_client( mock_android_device.MockAdbProxy( installed_packages=[MOCK_PACKAGE_NAME])) expected_msg = ('.* %s is installed, but it is not instrumented.' % MOCK_PACKAGE_NAME) with self.assertRaisesRegex(snippet_client.AppStartPreCheckError, expected_msg): sc._check_app_installed()
def test_check_app_installed_fail_target_not_installed(self): sc = self._make_client( mock_android_device.MockAdbProxy(instrumented_packages=[( MOCK_PACKAGE_NAME, snippet_client._INSTRUMENTATION_RUNNER_PACKAGE, MOCK_MISSING_PACKAGE_NAME)])) expected_msg = ('.* Instrumentation target %s is not installed.' % MOCK_MISSING_PACKAGE_NAME) with self.assertRaisesRegex(snippet_client.AppStartPreCheckError, expected_msg): sc._check_app_installed()
def test_app_not_installed(self, mock_get_port, mock_start_standing_subprocess, mock_create_connection): self.setup_mock_socket_file(mock_create_connection) self._setup_mock_instrumentation_cmd(mock_start_standing_subprocess, resp_lines=[b'\n']) client = self._make_client( adb_proxy=mock_android_device.MockAdbProxy()) with self.assertRaisesRegex(jsonrpc_client_base.AppStartError, '.* SL4A is not installed on .*'): client.start_app_and_connect()
def _make_client(self, adb_proxy=None): adb_proxy = adb_proxy or mock_android_device.MockAdbProxy( installed_packages=['com.googlecode.android_scripting']) ad = mock.Mock() ad.adb = adb_proxy ad.build_info = { 'build_version_codename': ad.adb.getprop('ro.build.version.codename'), 'build_version_sdk': ad.adb.getprop('ro.build.version.sdk'), } return sl4a_client.Sl4aClient(ad=ad)
def _make_client(self, adb_proxy=None): adb_proxy = adb_proxy or mock_android_device.MockAdbProxy( instrumented_packages=[(MOCK_PACKAGE_NAME, snippet_client._INSTRUMENTATION_RUNNER_PACKAGE, MOCK_PACKAGE_NAME)]) ad = mock.Mock() ad.adb = adb_proxy ad.adb.current_user_id = MOCK_USER_ID ad.build_info = { 'build_version_codename': ad.adb.getprop('ro.build.version.codename'), 'build_version_sdk': ad.adb.getprop('ro.build.version.sdk'), } return snippet_client.SnippetClient(package=MOCK_PACKAGE_NAME, ad=ad)
class LogcatTest(unittest.TestCase): """Tests for Logcat service and its integration with AndroidDevice.""" def setUp(self): # Set log_path to logging since mobly logger setup is not called. if not hasattr(logging, 'log_path'): setattr(logging, 'log_path', '/tmp/logs') # Creates a temp dir to be used by tests in this test class. self.tmp_dir = tempfile.mkdtemp() def tearDown(self): """Removes the temp dir. """ shutil.rmtree(self.tmp_dir) def AssertFileContains(self, content, file_path): with open(file_path, 'r') as f: output = f.read() self.assertIn(content, output) def AssertFileDoesNotContain(self, content, file_path): with open(file_path, 'r') as f: output = f.read() self.assertNotIn(content, output) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch('mobly.logger.get_log_file_timestamp') def test_start_and_stop(self, get_timestamp_mock, stop_proc_mock, start_proc_mock, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies the steps of collecting adb logcat on an AndroidDevice object, including various function calls and the expected behaviors of the calls. """ mock_serial = '1' get_timestamp_mock.return_value = '123' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service.start() # Verify start did the correct operations. self.assertTrue(logcat_service._adb_logcat_process) expected_log_path = os.path.join( logging.log_path, 'AndroidDevice%s' % ad.serial, 'logcat,%s,fakemodel,123.txt' % ad.serial) create_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) adb_cmd = '"adb" -s %s logcat -v threadtime >> %s' start_proc_mock.assert_called_with( adb_cmd % (ad.serial, '"%s"' % expected_log_path), shell=True) self.assertEqual(logcat_service.adb_logcat_file_path, expected_log_path) expected_msg = ( 'Logcat thread is already running, cannot start another' ' one.') # Expect error if start is called back to back. with self.assertRaisesRegex(logcat.Error, expected_msg): logcat_service.start() # Verify stop did the correct operations. logcat_service.stop() stop_proc_mock.assert_called_with('process') self.assertIsNone(logcat_service._adb_logcat_process) self.assertEqual(logcat_service.adb_logcat_file_path, expected_log_path) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_update_config(self, stop_proc_mock, start_proc_mock, create_dir_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service.start() logcat_service.stop() new_log_params = '-a -b -c' new_file_path = 'some/path/log.txt' new_config = logcat.Config(logcat_params=new_log_params, output_file_path=new_file_path) logcat_service.update_config(new_config) logcat_service.start() self.assertTrue(logcat_service._adb_logcat_process) create_dir_mock.assert_has_calls([mock.call('some/path')]) expected_adb_cmd = ('"adb" -s 1 logcat -v threadtime -a -b -c >> ' '"some/path/log.txt"') start_proc_mock.assert_called_with(expected_adb_cmd, shell=True) self.assertEqual(logcat_service.adb_logcat_file_path, 'some/path/log.txt') @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_update_config_while_running(self, stop_proc_mock, start_proc_mock, create_dir_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service.start() new_config = logcat.Config(logcat_params='-blah', output_file_path='some/path/file.txt') with self.assertRaisesRegex( logcat.Error, 'Logcat thread is already running, cannot start another one'): logcat_service.update_config(new_config) self.assertTrue(logcat_service.is_alive) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch( 'mobly.controllers.android_device_lib.services.logcat.Logcat.clear_adb_log', return_value=mock_android_device.MockAdbProxy('1')) def test_pause_and_resume(self, clear_adb_mock, stop_proc_mock, start_proc_mock, create_dir_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad, logcat.Config(clear_log=True)) logcat_service.start() clear_adb_mock.assert_called_once_with() self.assertTrue(logcat_service.is_alive) logcat_service.pause() self.assertFalse(logcat_service.is_alive) stop_proc_mock.assert_called_with('process') self.assertIsNone(logcat_service._adb_logcat_process) clear_adb_mock.reset_mock() logcat_service.resume() self.assertTrue(logcat_service.is_alive) clear_adb_mock.assert_not_called() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch( 'mobly.controllers.android_device_lib.services.logcat.Logcat.clear_adb_log', return_value=mock_android_device.MockAdbProxy('1')) def test_logcat_service_create_excerpt(self, clear_adb_mock, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service.start() FILE_CONTENT = 'Some log.\n' with open(logcat_service.adb_logcat_file_path, 'w') as f: f.write(FILE_CONTENT) test_output_dir = os.path.join(self.tmp_dir, 'test_foo') mock_record = mock.MagicMock() mock_record.begin_time = 123 test_run_info = runtime_test_info.RuntimeTestInfo( 'test_foo', test_output_dir, mock_record) actual_path1 = logcat_service.create_output_excerpts(test_run_info)[0] expected_path1 = os.path.join(test_output_dir, 'test_foo-123', 'logcat,1,fakemodel,test_foo-123.txt') self.assertEqual(expected_path1, actual_path1) self.assertTrue(os.path.exists(expected_path1)) self.AssertFileContains(FILE_CONTENT, expected_path1) self.assertFalse(os.path.exists(logcat_service.adb_logcat_file_path)) # Generate some new logs and do another excerpt. FILE_CONTENT = 'Some more logs!!!\n' with open(logcat_service.adb_logcat_file_path, 'w') as f: f.write(FILE_CONTENT) test_output_dir = os.path.join(self.tmp_dir, 'test_bar') mock_record = mock.MagicMock() mock_record.begin_time = 456 test_run_info = runtime_test_info.RuntimeTestInfo( 'test_bar', test_output_dir, mock_record) actual_path2 = logcat_service.create_output_excerpts(test_run_info)[0] expected_path2 = os.path.join(test_output_dir, 'test_bar-456', 'logcat,1,fakemodel,test_bar-456.txt') self.assertEqual(expected_path2, actual_path2) self.assertTrue(os.path.exists(expected_path2)) self.AssertFileContains(FILE_CONTENT, expected_path2) self.AssertFileDoesNotContain(FILE_CONTENT, expected_path1) self.assertFalse(os.path.exists(logcat_service.adb_logcat_file_path)) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch( 'mobly.controllers.android_device_lib.services.logcat.Logcat.clear_adb_log', return_value=mock_android_device.MockAdbProxy('1')) def test_logcat_service_create_output_excerpts(self, clear_adb_mock, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service.start() FILE_CONTENT = 'Some log.\n' with open(logcat_service.adb_logcat_file_path, 'w') as f: f.write(FILE_CONTENT) test_output_dir = os.path.join(self.tmp_dir, 'test_foo') mock_record = mock.MagicMock() mock_record.begin_time = 123 test_run_info = runtime_test_info.RuntimeTestInfo( 'test_foo', test_output_dir, mock_record) actual_path1 = logcat_service.create_output_excerpts(test_run_info)[0] expected_path1 = os.path.join(test_output_dir, 'test_foo-123', 'logcat,1,fakemodel,test_foo-123.txt') self.assertEqual(actual_path1, expected_path1) self.assertTrue(os.path.exists(expected_path1)) self.AssertFileContains(FILE_CONTENT, expected_path1) self.assertFalse(os.path.exists(logcat_service.adb_logcat_file_path)) # Generate some new logs and do another excerpt. FILE_CONTENT = 'Some more logs!!!\n' with open(logcat_service.adb_logcat_file_path, 'w') as f: f.write(FILE_CONTENT) test_output_dir = os.path.join(self.tmp_dir, 'test_bar') mock_record = mock.MagicMock() mock_record.begin_time = 456 test_run_info = runtime_test_info.RuntimeTestInfo( 'test_bar', test_output_dir, mock_record) actual_path2 = logcat_service.create_output_excerpts(test_run_info)[0] expected_path2 = os.path.join(test_output_dir, 'test_bar-456', 'logcat,1,fakemodel,test_bar-456.txt') self.assertEqual(actual_path2, expected_path2) self.assertTrue(os.path.exists(expected_path2)) self.AssertFileContains(FILE_CONTENT, expected_path2) self.AssertFileDoesNotContain(FILE_CONTENT, expected_path1) self.assertFalse(os.path.exists(logcat_service.adb_logcat_file_path)) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch('mobly.logger.get_log_file_timestamp') def test_take_logcat_with_extra_params(self, get_timestamp_mock, stop_proc_mock, start_proc_mock, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies the steps of collecting adb logcat on an AndroidDevice object, including various function calls and the expected behaviors of the calls. """ mock_serial = '1' get_timestamp_mock.return_value = '123' ad = android_device.AndroidDevice(serial=mock_serial) configs = logcat.Config() configs.logcat_params = '-b radio' logcat_service = logcat.Logcat(ad, configs) logcat_service.start() # Verify start did the correct operations. self.assertTrue(logcat_service._adb_logcat_process) expected_log_path = os.path.join( logging.log_path, 'AndroidDevice%s' % ad.serial, 'logcat,%s,fakemodel,123.txt' % ad.serial) create_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) adb_cmd = '"adb" -s %s logcat -v threadtime -b radio >> %s' start_proc_mock.assert_called_with( adb_cmd % (ad.serial, '"%s"' % expected_log_path), shell=True) self.assertEqual(logcat_service.adb_logcat_file_path, expected_log_path) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_instantiation(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) self.assertIsNone(logcat_service._adb_logcat_process) self.assertIsNone(logcat_service.adb_logcat_file_path) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch('mobly.logger.get_log_line_timestamp', return_value=MOCK_ADB_LOGCAT_END_TIME) def test_cat_adb_log(self, mock_timestamp_getter, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): """Verifies that AndroidDevice.cat_adb_log loads the correct adb log file, locates the correct adb log lines within the given time range, and writes the lines to the correct output file. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() # Direct the log path of the ad to a temp dir to avoid racing. logcat_service._ad._log_path = self.tmp_dir # Expect error if attempted to cat adb log before starting adb logcat. expected_msg = ('.* Attempting to cat adb log when none' ' has been collected.') with self.assertRaisesRegex(logcat.Error, expected_msg): logcat_service.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME) logcat_service.start() utils.create_dir(ad.log_path) mock_adb_log_path = logcat_service.adb_logcat_file_path with io.open(mock_adb_log_path, 'w', encoding='utf-8') as f: f.write(MOCK_ADB_LOGCAT) cat_file_path = logcat_service.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME) with io.open(cat_file_path, 'r', encoding='utf-8') as f: actual_cat = f.read() self.assertEqual(actual_cat, ''.join(MOCK_ADB_LOGCAT_CAT_RESULT)) # Stops adb logcat. logcat_service.stop() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch('mobly.logger.get_log_line_timestamp', return_value=MOCK_ADB_LOGCAT_END_TIME) def test_cat_adb_log_with_unicode(self, mock_timestamp_getter, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): """Verifies that AndroidDevice.cat_adb_log loads the correct adb log file, locates the correct adb log lines within the given time range, and writes the lines to the correct output file. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() # Direct the log path of the ad to a temp dir to avoid racing. logcat_service._ad._log_path = self.tmp_dir # Expect error if attempted to cat adb log before starting adb logcat. expected_msg = ('.* Attempting to cat adb log when none' ' has been collected.') with self.assertRaisesRegex(logcat.Error, expected_msg): logcat_service.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME) logcat_service.start() utils.create_dir(ad.log_path) mock_adb_log_path = logcat_service.adb_logcat_file_path with io.open(mock_adb_log_path, 'w', encoding='utf-8') as f: f.write(MOCK_ADB_UNICODE_LOGCAT) cat_file_path = logcat_service.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME) with io.open(cat_file_path, 'r', encoding='utf-8') as f: actual_cat = f.read() self.assertEqual(actual_cat, ''.join(MOCK_ADB_UNICODE_LOGCAT_CAT_RESULT)) # Stops adb logcat. logcat_service.stop() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test__enable_logpersist_with_logpersist(self, MockFastboot, MockAdbProxy): mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { 'ro.build.id': 'AB42', 'ro.build.type': 'userdebug', 'ro.debuggable': '1', } mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': True, 'logpersist.stop': True, }[command] ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_has_calls([ mock.call('logpersist.stop --clear'), mock.call('logpersist.start'), ]) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test__enable_logpersist_with_user_build_device(self, MockFastboot, MockAdbProxy): mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { 'ro.build.id': 'AB42', 'ro.build.type': 'user', 'ro.debuggable': '0', } mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': True, 'logpersist.stop': True, }[command] ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_not_called() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test__enable_logpersist_with_missing_all_logpersist( self, MockFastboot, MockAdbProxy): def adb_shell_helper(command): if command == 'logpersist.start': raise MOCK_LOGPERSIST_START_MISSING_ADB_ERROR elif command == 'logpersist.stop --clear': raise MOCK_LOGPERSIST_STOP_MISSING_ADB_ERROR else: return b'' mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { 'ro.build.id': 'AB42', 'ro.build.type': 'userdebug', 'ro.debuggable': '1', } mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': False, 'logpersist.stop': False, }[command] mock_adb_proxy.shell.side_effect = adb_shell_helper ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_not_called() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test__enable_logpersist_with_missing_logpersist_stop( self, MockFastboot, MockAdbProxy): def adb_shell_helper(command): if command == 'logpersist.stop --clear': raise MOCK_LOGPERSIST_STOP_MISSING_ADB_ERROR else: return b'' mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { 'ro.build.id': 'AB42', 'ro.build.type': 'userdebug', 'ro.debuggable': '1', } mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': True, 'logpersist.stop': False, }[command] mock_adb_proxy.shell.side_effect = adb_shell_helper ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_has_calls([ mock.call('logpersist.stop --clear'), ]) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test__enable_logpersist_with_missing_logpersist_start( self, MockFastboot, MockAdbProxy): def adb_shell_helper(command): if command == 'logpersist.start': raise MOCK_LOGPERSIST_START_MISSING_ADB_ERROR else: return b'' mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { 'ro.build.id': 'AB42', 'ro.build.type': 'userdebug', 'ro.debuggable': '1', } mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': False, 'logpersist.stop': True, }[command] mock_adb_proxy.shell.side_effect = adb_shell_helper ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_not_called() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy') @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_clear_adb_log(self, MockFastboot, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) ad.adb.logcat = mock.MagicMock() ad.adb.logcat.side_effect = adb.AdbError( cmd='cmd', stdout=b'', stderr=b'failed to clear "main" log', ret_code=1) logcat_service = logcat.Logcat(ad) logcat_service.clear_adb_log()
def test_check_app_installed_fail_app_not_installed(self): sc = self._make_client(mock_android_device.MockAdbProxy()) expected_msg = '.* %s is not installed.' % MOCK_PACKAGE_NAME with self.assertRaisesRegex(snippet_client.AppStartPreCheckError, expected_msg): sc._check_app_installed()
class TestRunnerTest(unittest.TestCase): """This test class has unit tests for the implementation of everything under mobly.test_runner. """ def setUp(self): self.tmp_dir = tempfile.mkdtemp() self.base_mock_test_config = config_parser.TestRunConfig() self.base_mock_test_config.test_bed_name = 'SampleTestBed' self.base_mock_test_config.controller_configs = {} self.base_mock_test_config.user_params = { 'icecream': 42, 'extra_param': 'haha' } self.base_mock_test_config.log_path = self.tmp_dir self.log_dir = self.base_mock_test_config.log_path self.test_bed_name = self.base_mock_test_config.test_bed_name def tearDown(self): shutil.rmtree(self.tmp_dir) def test_register_controller_no_config(self): tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) with self.assertRaisesRegex(signals.ControllerError, 'No corresponding config found for'): tr._register_controller(self.base_mock_test_config, mock_controller) def test_register_controller_no_config_no_register(self): tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) self.assertIsNone( tr._register_controller(self.base_mock_test_config, mock_controller, required=False)) def test_register_controller_dup_register(self): """Verifies correctness of registration, internal tally of controllers objects, and the right error happen when a controller module is registered twice. """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME mock_test_config.controller_configs = { mock_ctrlr_config_name: ['magic1', 'magic2'] } tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr._register_controller(mock_test_config, mock_controller) registered_name = 'mock_controller' self.assertTrue(registered_name in tr._controller_registry) mock_ctrlrs = tr._controller_registry[registered_name] self.assertEqual(mock_ctrlrs[0].magic, 'magic1') self.assertEqual(mock_ctrlrs[1].magic, 'magic2') self.assertTrue(tr._controller_destructors[registered_name]) expected_msg = 'Controller module .* has already been registered.' with self.assertRaisesRegex(signals.ControllerError, expected_msg): tr._register_controller(mock_test_config, mock_controller) def test_register_controller_no_get_info(self): mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME get_info = getattr(mock_controller, 'get_info') delattr(mock_controller, 'get_info') try: mock_test_config.controller_configs = { mock_ctrlr_config_name: ['magic1', 'magic2'] } tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr._register_controller(mock_test_config, mock_controller) self.assertEqual(tr.results.controller_info, {}) finally: setattr(mock_controller, 'get_info', get_info) def test_register_controller_return_value(self): mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME mock_test_config.controller_configs = { mock_ctrlr_config_name: ['magic1', 'magic2'] } tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) magic_devices = tr._register_controller(mock_test_config, mock_controller) self.assertEqual(magic_devices[0].magic, 'magic1') self.assertEqual(magic_devices[1].magic, 'magic2') def test_register_controller_change_return_value(self): mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME mock_test_config.controller_configs = { mock_ctrlr_config_name: ['magic1', 'magic2'] } tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) magic_devices = tr._register_controller(mock_test_config, mock_controller) magic1 = magic_devices.pop(0) self.assertIs(magic1, tr._controller_registry['mock_controller'][0]) self.assertEqual(len(tr._controller_registry['mock_controller']), 2) def test_register_controller_less_than_min_number(self): mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME mock_test_config.controller_configs = { mock_ctrlr_config_name: ['magic1', 'magic2'] } tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) expected_msg = 'Expected to get at least 3 controller objects, got 2.' with self.assertRaisesRegex(signals.ControllerError, expected_msg): tr._register_controller(mock_test_config, mock_controller, min_number=3) def test_run_twice(self): """Verifies that: 1. Repeated run works properly. 2. The original configuration is not altered if a test controller module modifies configuration. """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME my_config = [{ 'serial': 'xxxx', 'magic': 'Magic1' }, { 'serial': 'xxxx', 'magic': 'Magic2' }] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr.add_test_class(mock_test_config, integration_test.IntegrationTest) tr.run() self.assertFalse(tr._controller_registry) self.assertFalse(tr._controller_destructors) self.assertTrue( mock_test_config.controller_configs[mock_ctrlr_config_name][0]) tr.run() self.assertFalse(tr._controller_registry) self.assertFalse(tr._controller_destructors) results = tr.results.summary_dict() self.assertEqual(results['Requested'], 2) self.assertEqual(results['Executed'], 2) self.assertEqual(results['Passed'], 2) expected_info = { 'MagicDevice': [{ 'MyMagic': { 'magic': 'Magic1' } }, { 'MyMagic': { 'magic': 'Magic2' } }] } self.assertEqual(tr.results.controller_info, expected_info) def test_summary_file_entries(self): """Verifies the output summary's file format. This focuses on the format of the file instead of the content of entries, which is covered in base_test_test. """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME my_config = [{ 'serial': 'xxxx', 'magic': 'Magic1' }, { 'serial': 'xxxx', 'magic': 'Magic2' }] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr.add_test_class(mock_test_config, integration_test.IntegrationTest) tr.run() summary_path = os.path.join(mock_test_config.log_path, mock_test_config.test_bed_name, 'latest', records.OUTPUT_FILE_SUMMARY) with open(summary_path, 'r') as f: summary_entries = list(yaml.load_all(f)) self.assertEqual(len(summary_entries), 4) # Verify the first entry is the list of test names. self.assertEqual(summary_entries[0]['Type'], records.TestSummaryEntryType.TEST_NAME_LIST.value) self.assertEqual(summary_entries[1]['Type'], records.TestSummaryEntryType.RECORD.value) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.controllers.android_device.list_adb_devices', return_value=['1']) @mock.patch('mobly.controllers.android_device.get_all_instances', return_value=mock_android_device.get_mock_ads(1)) def test_run_two_test_classes(self, mock_get_all, mock_list_adb, mock_fastboot, mock_adb): """Verifies that running more than one test class in one test run works properly. This requires using a built-in controller module. Using AndroidDevice module since it has all the mocks needed already. """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME my_config = [{ 'serial': 'xxxx', 'magic': 'Magic1' }, { 'serial': 'xxxx', 'magic': 'Magic2' }] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config mock_test_config.controller_configs['AndroidDevice'] = [{ 'serial': '1' }] tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr.add_test_class(mock_test_config, integration2_test.Integration2Test) tr.add_test_class(mock_test_config, integration_test.IntegrationTest) tr.run() self.assertFalse(tr._controller_registry) self.assertFalse(tr._controller_destructors) results = tr.results.summary_dict() self.assertEqual(results['Requested'], 2) self.assertEqual(results['Executed'], 2) self.assertEqual(results['Passed'], 2) def test_run_two_test_classes_different_configs(self): """Verifies that running more than one test class in one test run with different configs works properly. """ config1 = self.base_mock_test_config.copy() config1.controller_configs[ mock_controller.MOBLY_CONTROLLER_CONFIG_NAME] = [{ 'serial': 'xxxx' }] config2 = config1.copy() config2.user_params['icecream'] = 10 tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr.add_test_class(config1, integration_test.IntegrationTest) tr.add_test_class(config2, integration_test.IntegrationTest) tr.run() results = tr.results.summary_dict() self.assertEqual(results['Requested'], 2) self.assertEqual(results['Executed'], 2) self.assertEqual(results['Passed'], 1) self.assertEqual(results['Failed'], 1) self.assertEqual(tr.results.failed[0].details, '10 != 42') def test_run_with_abort_all(self): mock_test_config = self.base_mock_test_config.copy() tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr.add_test_class(mock_test_config, integration3_test.Integration3Test) with self.assertRaises(signals.TestAbortAll): tr.run() results = tr.results.summary_dict() self.assertEqual(results['Requested'], 1) self.assertEqual(results['Executed'], 0) self.assertEqual(results['Passed'], 0) self.assertEqual(results['Failed'], 0) def test_add_test_class_mismatched_log_path(self): tr = test_runner.TestRunner('/different/log/dir', self.test_bed_name) with self.assertRaisesRegex( test_runner.Error, 'TestRunner\'s log folder is "/different/log/dir", but a test ' r'config with a different log folder \("%s"\) was added.' % self.log_dir): tr.add_test_class(self.base_mock_test_config, integration_test.IntegrationTest) def test_add_test_class_mismatched_test_bed_name(self): tr = test_runner.TestRunner(self.log_dir, 'different_test_bed') with self.assertRaisesRegex( test_runner.Error, 'TestRunner\'s test bed is "different_test_bed", but a test ' r'config with a different test bed \("%s"\) was added.' % self.test_bed_name): tr.add_test_class(self.base_mock_test_config, integration_test.IntegrationTest) def test_teardown_logger_before_setup_logger(self): tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) with self.assertRaisesRegex( test_runner.Error, 'TestRunner\._teardown_logger\(\) called before ' 'TestRunner\.setup_logger\(\)!'): tr._teardown_logger() def test_run_no_tests(self): tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) with self.assertRaisesRegex(test_runner.Error, 'No tests to execute.'): tr.run() def test_verify_controller_module(self): test_runner.verify_controller_module(mock_controller) def test_verify_controller_module_null_attr(self): try: tmp = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME mock_controller.MOBLY_CONTROLLER_CONFIG_NAME = None msg = 'Controller interface .* in .* cannot be null.' with self.assertRaisesRegex(signals.ControllerError, msg): test_runner.verify_controller_module(mock_controller) finally: mock_controller.MOBLY_CONTROLLER_CONFIG_NAME = tmp def test_verify_controller_module_missing_attr(self): try: tmp = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME delattr(mock_controller, 'MOBLY_CONTROLLER_CONFIG_NAME') msg = 'Module .* missing required controller module attribute' with self.assertRaisesRegex(signals.ControllerError, msg): test_runner.verify_controller_module(mock_controller) finally: setattr(mock_controller, 'MOBLY_CONTROLLER_CONFIG_NAME', tmp) @mock.patch('mobly.test_runner._find_test_class', return_value=type('SampleTest', (), {})) @mock.patch('mobly.test_runner.config_parser.load_test_config_file', return_value=[config_parser.TestRunConfig()]) @mock.patch('mobly.test_runner.TestRunner', return_value=mock.MagicMock()) def test_main_parse_args(self, mock_test_runner, mock_config, mock_find_test): test_runner.main(['-c', 'some/path/foo.yaml', '-b', 'hello']) mock_config.assert_called_with('some/path/foo.yaml', None)
class AndroidDeviceTest(unittest.TestCase): """This test class has unit tests for the implementation of everything under mobly.controllers.android_device. """ def setUp(self): # Set log_path to logging since mobly logger setup is not called. if not hasattr(logging, 'log_path'): setattr(logging, 'log_path', '/tmp/logs') # Creates a temp dir to be used by tests in this test class. self.tmp_dir = tempfile.mkdtemp() def tearDown(self): """Removes the temp dir. """ shutil.rmtree(self.tmp_dir) # Tests for android_device module functions. # These tests use mock AndroidDevice instances. @mock.patch.object(android_device, 'get_all_instances', new=mock_android_device.get_all_instances) @mock.patch.object(android_device, 'list_adb_devices', new=mock_android_device.list_adb_devices) @mock.patch.object(android_device, 'list_adb_devices_by_usb_id', new=mock_android_device.list_adb_devices) def test_create_with_pickup_all(self): pick_all_token = android_device.ANDROID_DEVICE_PICK_ALL_TOKEN actual_ads = android_device.create(pick_all_token) for actual, expected in zip(actual_ads, mock_android_device.get_mock_ads(5)): self.assertEqual(actual.serial, expected.serial) @mock.patch.object(android_device, 'get_instances', new=mock_android_device.get_instances) @mock.patch.object(android_device, 'list_adb_devices', new=mock_android_device.list_adb_devices) @mock.patch.object(android_device, 'list_adb_devices_by_usb_id', new=mock_android_device.list_adb_devices) def test_create_with_string_list(self): string_list = [u'1', '2'] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2']): self.assertEqual(actual_ad.serial, expected_serial) @mock.patch.object(android_device, 'get_instances_with_configs', new=mock_android_device.get_instances_with_configs) @mock.patch.object(android_device, 'list_adb_devices', new=mock_android_device.list_adb_devices) @mock.patch.object(android_device, 'list_adb_devices_by_usb_id', new=mock_android_device.list_adb_devices) def test_create_with_dict_list(self): string_list = [{'serial': '1'}, {'serial': '2'}] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2']): self.assertEqual(actual_ad.serial, expected_serial) @mock.patch.object(android_device, 'get_instances_with_configs', new=mock_android_device.get_instances_with_configs) @mock.patch.object(android_device, 'list_adb_devices', new=mock_android_device.list_adb_devices) @mock.patch.object(android_device, 'list_adb_devices_by_usb_id', return_value=['usb:1']) def test_create_with_usb_id(self, mock_list_adb_devices_by_usb_id): string_list = [{'serial': '1'}, {'serial': '2'}, {'serial': 'usb:1'}] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2', 'usb:1']): self.assertEqual(actual_ad.serial, expected_serial) def test_create_with_empty_config(self): expected_msg = android_device.ANDROID_DEVICE_EMPTY_CONFIG_MSG with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.create([]) def test_create_with_not_list_config(self): expected_msg = android_device.ANDROID_DEVICE_NOT_LIST_CONFIG_MSG with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.create('HAHA') def test_create_with_no_valid_config(self): expected_msg = 'No valid config found in: .*' with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.create([1]) def test_get_devices_success_with_extra_field(self): ads = mock_android_device.get_mock_ads(5) expected_label = 'selected' expected_count = 2 for ad in ads[:expected_count]: ad.label = expected_label selected_ads = android_device.get_devices(ads, label=expected_label) self.assertEqual(expected_count, len(selected_ads)) for ad in selected_ads: self.assertEqual(ad.label, expected_label) def test_get_devices_no_match(self): ads = mock_android_device.get_mock_ads(5) expected_msg = ('Could not find a target device that matches condition' ": {'label': 'selected'}.") with self.assertRaisesRegex(android_device.Error, expected_msg): selected_ads = android_device.get_devices(ads, label='selected') def test_get_device_success_with_serial(self): ads = mock_android_device.get_mock_ads(5) expected_serial = '0' ad = android_device.get_device(ads, serial=expected_serial) self.assertEqual(ad.serial, expected_serial) def test_get_device_success_with_serial_and_extra_field(self): ads = mock_android_device.get_mock_ads(5) expected_serial = '1' expected_h_port = 5555 ads[1].h_port = expected_h_port ad = android_device.get_device(ads, serial=expected_serial, h_port=expected_h_port) self.assertEqual(ad.serial, expected_serial) self.assertEqual(ad.h_port, expected_h_port) def test_get_device_no_match(self): ads = mock_android_device.get_mock_ads(5) expected_msg = ('Could not find a target device that matches condition' ": {'serial': 5}.") with self.assertRaisesRegex(android_device.Error, expected_msg): ad = android_device.get_device(ads, serial=len(ads)) def test_get_device_too_many_matches(self): ads = mock_android_device.get_mock_ads(5) target_serial = ads[1].serial = ads[0].serial expected_msg = r"More than one device matched: \['0', '0'\]" with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.get_device(ads, serial=target_serial) def test_start_services_on_ads(self): """Makes sure when an AndroidDevice fails to start some services, all AndroidDevice objects get cleaned up. """ msg = 'Some error happened.' ads = mock_android_device.get_mock_ads(3) ads[0].services.register = mock.MagicMock() ads[0].services.stop_all = mock.MagicMock() ads[1].services.register = mock.MagicMock() ads[1].services.stop_all = mock.MagicMock() ads[2].services.register = mock.MagicMock( side_effect=android_device.Error(msg)) ads[2].services.stop_all = mock.MagicMock() with self.assertRaisesRegex(android_device.Error, msg): android_device._start_services_on_ads(ads) ads[0].services.stop_all.assert_called_once_with() ads[1].services.stop_all.assert_called_once_with() ads[2].services.stop_all.assert_called_once_with() def test_start_services_on_ads_skip_logcat(self): ads = mock_android_device.get_mock_ads(3) ads[0].services.logcat.start = mock.MagicMock() ads[1].services.logcat.start = mock.MagicMock() ads[2].services.logcat.start = mock.MagicMock( side_effect=Exception('Should not have called this.')) ads[2].skip_logcat = True android_device._start_services_on_ads(ads) def test_take_bug_reports(self): ads = mock_android_device.get_mock_ads(3) android_device.take_bug_reports(ads, 'test_something', 'sometime') ads[0].take_bug_report.assert_called_once_with( test_name='test_something', begin_time='sometime', destination=None) ads[1].take_bug_report.assert_called_once_with( test_name='test_something', begin_time='sometime', destination=None) ads[2].take_bug_report.assert_called_once_with( test_name='test_something', begin_time='sometime', destination=None) # Tests for android_device.AndroidDevice class. # These tests mock out any interaction with the OS and real android device # in AndroidDeivce. @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_instantiation(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) self.assertEqual(ad.serial, '1') self.assertEqual(ad.model, 'fakemodel') expected_lp = os.path.join(logging.log_path, 'AndroidDevice%s' % mock_serial) self.assertEqual(ad.log_path, expected_lp) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_build_info(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. """ ad = android_device.AndroidDevice(serial='1') build_info = ad.build_info self.assertEqual(build_info['build_id'], 'AB42') self.assertEqual(build_info['build_type'], 'userdebug') self.assertEqual(build_info['build_version_codename'], 'Z') self.assertEqual(build_info['build_version_sdk'], '28') self.assertEqual(build_info['build_product'], 'FakeModel') self.assertEqual(build_info['product_name'], 'FakeModel') self.assertEqual(build_info['debuggable'], '1') self.assertEqual(len(build_info), len(android_device.CACHED_SYSTEM_PROPS)) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy( '1', mock_properties={ 'ro.build.id': 'AB42', 'ro.build.type': 'userdebug', })) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_build_info_with_minimal_properties( self, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') build_info = ad.build_info self.assertEqual(build_info['build_id'], 'AB42') self.assertEqual(build_info['build_type'], 'userdebug') self.assertEqual(build_info['build_version_codename'], '') self.assertEqual(build_info['build_version_sdk'], '') self.assertEqual(build_info['build_product'], '') self.assertEqual(build_info['product_name'], '') self.assertEqual(build_info['debuggable'], '') @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_build_info_cached(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. """ ad = android_device.AndroidDevice(serial='1') _ = ad.build_info _ = ad.build_info _ = ad.build_info self.assertEqual(ad.adb.getprops_call_count, 1) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy( '1', mock_properties={ 'ro.build.id': 'AB42', 'ro.build.type': 'userdebug', 'ro.debuggable': '1', })) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_is_rootable_when_userdebug_device( self, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') self.assertTrue(ad.is_rootable) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy( '1', mock_properties={ 'ro.build.id': 'AB42', 'ro.build.type': 'user', 'ro.debuggable': '0', })) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_is_rootable_when_user_device( self, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') self.assertFalse(ad.is_rootable) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_device_info(self, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial=1) device_info = ad.device_info self.assertEqual(device_info['serial'], '1') self.assertEqual(device_info['model'], 'fakemodel') self.assertEqual(device_info['build_info']['build_id'], 'AB42') self.assertEqual(device_info['build_info']['build_type'], 'userdebug') ad.add_device_info('sim_type', 'Fi') ad.add_device_info('build_id', 'CD42') device_info = ad.device_info self.assertEqual(device_info['user_added_info']['sim_type'], 'Fi') self.assertEqual(device_info['user_added_info']['build_id'], 'CD42') @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_serial_is_valid(self, MockFastboot, MockAdbProxy): """Verifies that the serial is a primitive string type and serializable. """ ad = android_device.AndroidDevice(serial=1) # In py2, checks that ad.serial is not the backported py3 str type, # which is not dumpable by yaml in py2. # In py3, new_str is equivalent to str, so this check is not # appropirate in py3. if sys.version_info < (3, 0): self.assertFalse(isinstance(ad.serial, new_str)) self.assertTrue(isinstance(ad.serial, str)) yaml.safe_dump(ad.serial) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report(self, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies AndroidDevice.take_bug_report calls the correct adb command and writes the bugreport file to the correct path. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report(test_name='test_something', begin_time='sometime') expected_path = os.path.join(logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports') create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, os.path.join(expected_path, 'test_something,sometime,1.zip')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1', fail_br=True)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_fail(self, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies AndroidDevice.take_bug_report writes out the correct message when taking bugreport fails. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) expected_msg = '.* Failed to take bugreport.' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.take_bug_report(test_name='test_something', begin_time='sometime') @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.get_current_epoch_time') @mock.patch('mobly.logger.epoch_to_log_line_timestamp') def test_AndroidDevice_take_bug_report_without_args( self, epoch_to_log_line_timestamp_mock, get_current_epoch_time_mock, create_dir_mock, FastbootProxy, MockAdbProxy): get_current_epoch_time_mock.return_value = 1557446629606 epoch_to_log_line_timestamp_mock.return_value = '05-09 17:03:49.606' mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report() expected_path = os.path.join(logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports') create_dir_mock.assert_called_with(expected_path) epoch_to_log_line_timestamp_mock.assert_called_once_with(1557446629606) self.assertEqual( output_path, os.path.join(expected_path, 'bugreport,05-09_17-03-49.606,1.zip')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.get_current_epoch_time') @mock.patch('mobly.logger.epoch_to_log_line_timestamp') def test_AndroidDevice_take_bug_report_with_only_test_name( self, epoch_to_log_line_timestamp_mock, get_current_epoch_time_mock, create_dir_mock, FastbootProxy, MockAdbProxy): get_current_epoch_time_mock.return_value = 1557446629606 epoch_to_log_line_timestamp_mock.return_value = '05-09 17:03:49.606' mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report(test_name='test_something') expected_path = os.path.join(logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports') create_dir_mock.assert_called_with(expected_path) epoch_to_log_line_timestamp_mock.assert_called_once_with(1557446629606) self.assertEqual( output_path, os.path.join(expected_path, 'test_something,05-09_17-03-49.606,1.zip')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_with_only_begin_time( self, create_dir_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report(begin_time='sometime') expected_path = os.path.join(logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports') create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, os.path.join(expected_path, 'bugreport,sometime,1.zip')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_with_positional_args( self, create_dir_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report('test_something', 'sometime') expected_path = os.path.join(logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports') create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, os.path.join(expected_path, 'test_something,sometime,1.zip')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_with_destination( self, create_dir_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) dest = tempfile.gettempdir() output_path = ad.take_bug_report(test_name="test_something", begin_time="sometime", destination=dest) expected_path = os.path.join(dest) create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, os.path.join(expected_path, 'test_something,sometime,1.zip')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy( '1', fail_br_before_N=True)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_fallback(self, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies AndroidDevice.take_bug_report falls back to traditional bugreport on builds that do not have bugreportz. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report(test_name='test_something', begin_time='sometime') expected_path = os.path.join(logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports') create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, os.path.join(expected_path, 'test_something,sometime,1.txt')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_change_log_path(self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') old_path = ad.log_path new_log_path = tempfile.mkdtemp() ad.log_path = new_log_path self.assertTrue(os.path.exists(new_log_path)) self.assertFalse(os.path.exists(old_path)) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_change_log_path_no_log_exists( self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') old_path = ad.log_path new_log_path = tempfile.mkdtemp() ad.log_path = new_log_path self.assertTrue(os.path.exists(new_log_path)) self.assertFalse(os.path.exists(old_path)) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('127.0.0.1:5557') ) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('127.0.0.1:5557')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_with_reserved_character_in_serial_log_path( self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='127.0.0.1:5557') base_log_path = os.path.basename(ad.log_path) self.assertEqual(base_log_path, 'AndroidDevice127.0.0.1-5557') @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_change_log_path_with_service( self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.services.register('logcat', logcat.Logcat) new_log_path = tempfile.mkdtemp() expected_msg = '.* Cannot change `log_path` when there is service running.' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.log_path = new_log_path @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_change_log_path_with_existing_file( self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') new_log_path = tempfile.mkdtemp() new_file_path = os.path.join(new_log_path, 'file.txt') with io.open(new_file_path, 'w', encoding='utf-8') as f: f.write(u'hahah.') expected_msg = '.* Logs already exist .*' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.log_path = new_log_path @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_update_serial(self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.update_serial('2') self.assertEqual(ad.serial, '2') self.assertEqual(ad.debug_tag, ad.serial) self.assertEqual(ad.adb.serial, ad.serial) self.assertEqual(ad.fastboot.serial, ad.serial) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_update_serial_with_service_running( self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.services.register('logcat', logcat.Logcat) expected_msg = '.* Cannot change device serial number when there is service running.' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.update_serial('2') @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet(self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) self.assertTrue(hasattr(ad, 'snippet')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_getattr(self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) value = {'value': 42} actual_value = getattr(ad, 'some_attr', value) self.assertEqual(actual_value, value) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient', return_value=MockSnippetClient) @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_dup_package(self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) expected_msg = ('Snippet package "%s" has already been loaded under ' 'name "snippet".') % MOCK_SNIPPET_PACKAGE_NAME with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('snippet2', MOCK_SNIPPET_PACKAGE_NAME) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient', return_value=MockSnippetClient) @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_dup_snippet_name( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) expected_msg = '.* Attribute "snippet" already exists, please use a different name.' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME + 'haha') @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_dup_attribute_name( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') expected_msg = ('Attribute "%s" already exists, please use a different' ' name') % 'adb' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('adb', MOCK_SNIPPET_PACKAGE_NAME) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_start_app_fails( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): """Verifies that the correct exception is raised if start app failed. It's possible that the `stop_app` call as part of the start app failure teardown also fails. So we want the exception from the start app failure. """ expected_e = Exception('start failed.') MockSnippetClient.start_app_and_connect = mock.Mock( side_effect=expected_e) MockSnippetClient.stop_app = mock.Mock( side_effect=Exception('stop failed.')) ad = android_device.AndroidDevice(serial='1') try: ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) except Exception as e: assertIs(e, expected_e) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_unload_snippet(self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) ad.unload_snippet('snippet') self.assertFalse(hasattr(ad, 'snippet')) with self.assertRaisesRegex( android_device.SnippetError, '<AndroidDevice|1> No snippet registered with name "snippet"'): ad.unload_snippet('snippet') # Loading the same snippet again should succeed ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) self.assertTrue(hasattr(ad, 'snippet')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_snippet_cleanup(self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.services.start_all() ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) ad.unload_snippet('snippet') self.assertFalse(hasattr(ad, 'snippet')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_debug_tag(self, MockFastboot, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) self.assertEqual(ad.debug_tag, '1') try: raise android_device.DeviceError(ad, 'Something') except android_device.DeviceError as e: self.assertEqual('<AndroidDevice|1> Something', str(e)) # Verify that debug tag's setter updates the debug prefix correctly. ad.debug_tag = 'Mememe' try: raise android_device.DeviceError(ad, 'Something') except android_device.DeviceError as e: self.assertEqual('<AndroidDevice|Mememe> Something', str(e)) # Verify that repr is changed correctly. try: raise Exception(ad, 'Something') except Exception as e: self.assertEqual("(<AndroidDevice|Mememe>, 'Something')", str(e)) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_handle_usb_disconnect(self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): class MockService(base_service.BaseService): def __init__(self, device, configs=None): self._alive = False self.pause_called = False self.resume_called = False @property def is_alive(self): return self._alive def start(self, configs=None): self._alive = True def stop(self): self._alive = False def pause(self): self._alive = False self.pause_called = True def resume(self): self._alive = True self.resume_called = True ad = android_device.AndroidDevice(serial='1') ad.services.start_all() ad.services.register('mock_service', MockService) with ad.handle_usb_disconnect(): self.assertFalse(ad.services.is_any_alive) self.assertTrue(ad.services.mock_service.pause_called) self.assertFalse(ad.services.mock_service.resume_called) self.assertTrue(ad.services.is_any_alive) self.assertTrue(ad.services.mock_service.resume_called) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_handle_reboot(self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): class MockService(base_service.BaseService): def __init__(self, device, configs=None): self._alive = False self.pause_called = False self.resume_called = False @property def is_alive(self): return self._alive def start(self, configs=None): self._alive = True def stop(self): self._alive = False def pause(self): self._alive = False self.pause_called = True def resume(self): self._alive = True self.resume_called = True ad = android_device.AndroidDevice(serial='1') ad.services.start_all() ad.services.register('mock_service', MockService) with ad.handle_reboot(): self.assertFalse(ad.services.is_any_alive) self.assertFalse(ad.services.mock_service.pause_called) self.assertFalse(ad.services.mock_service.resume_called) self.assertTrue(ad.services.is_any_alive) self.assertFalse(ad.services.mock_service.resume_called) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_handle_reboot_changes_build_info( self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') with ad.handle_reboot(): ad.adb.mock_properties['ro.build.type'] = 'user' ad.adb.mock_properties['ro.debuggable'] = '0' self.assertEqual(ad.build_info['build_type'], 'user') self.assertEqual(ad.build_info['debuggable'], '0') self.assertFalse(ad.is_rootable) self.assertEqual(ad.adb.getprops_call_count, 2) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_handle_reboot_changes_build_info_with_caching( self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') # Call getprops 1. rootable_states = [ad.is_rootable] with ad.handle_reboot(): rootable_states.append(ad.is_rootable) # Call getprops 2. ad.adb.mock_properties['ro.debuggable'] = '0' rootable_states.append(ad.is_rootable) # Call getprops 3. # Call getprops 4, on context manager end. rootable_states.append(ad.is_rootable) # Cached call. rootable_states.append(ad.is_rootable) # Cached call. self.assertEqual(ad.adb.getprops_call_count, 4) self.assertEqual(rootable_states, [True, True, False, False, False]) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device.AndroidDevice.is_boot_completed', side_effect=[ False, False, adb.AdbTimeoutError(['adb', 'shell', 'getprop sys.boot_completed'], timeout=5, serial=1), True ]) @mock.patch('time.sleep', return_value=None) @mock.patch('time.time', side_effect=[0, 5, 10, 15, 20, 25, 30]) def test_AndroidDevice_wait_for_completion_completed( self, MockTime, MockSleep, MockIsBootCompleted, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') raised = False try: ad.wait_for_boot_completion() except (adb.AdbError, adb.AdbTimeoutError): raised = True self.assertFalse( raised, 'adb.AdbError or adb.AdbTimeoutError exception raised but not handled.' ) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device.AndroidDevice.is_boot_completed', side_effect=[ False, False, adb.AdbTimeoutError(['adb', 'shell', 'getprop sys.boot_completed'], timeout=5, serial=1), False, False, False, False ]) @mock.patch('time.sleep', return_value=None) @mock.patch('time.time', side_effect=[0, 5, 10, 15, 20, 25, 30]) def test_AndroidDevice_wait_for_completion_never_boot( self, MockTime, MockSleep, MockIsBootCompleted, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') raised = False try: with self.assertRaises(android_device.DeviceError): ad.wait_for_boot_completion(timeout=20) except (adb.AdbError, adb.AdbTimeoutError): raised = True self.assertFalse( raised, 'adb.AdbError or adb.AdbTimeoutError exception raised but not handled.' )
class TestRunnerTest(unittest.TestCase): """This test class has unit tests for the implementation of everything under mobly.test_runner. """ def setUp(self): self.tmp_dir = tempfile.mkdtemp() self.base_mock_test_config = config_parser.TestRunConfig() self.base_mock_test_config.test_bed_name = 'SampleTestBed' self.base_mock_test_config.controller_configs = {} self.base_mock_test_config.user_params = { 'icecream': 42, 'extra_param': 'haha' } self.base_mock_test_config.log_path = self.tmp_dir self.log_dir = self.base_mock_test_config.log_path self.test_bed_name = self.base_mock_test_config.test_bed_name def tearDown(self): shutil.rmtree(self.tmp_dir) def _assertControllerInfoEqual(self, info, expected_info_dict): self.assertEqual(expected_info_dict['Controller Name'], info.controller_name) self.assertEqual(expected_info_dict['Test Class'], info.test_class) self.assertEqual(expected_info_dict['Controller Info'], info.controller_info) def test_run_twice(self): """Verifies that: 1. Repeated run works properly. 2. The original configuration is not altered if a test controller module modifies configuration. """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME my_config = [{ 'serial': 'xxxx', 'magic': 'Magic1' }, { 'serial': 'xxxx', 'magic': 'Magic2' }] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr.add_test_class(mock_test_config, integration_test.IntegrationTest) tr.run() self.assertTrue( mock_test_config.controller_configs[mock_ctrlr_config_name][0]) tr.run() results = tr.results.summary_dict() self.assertEqual(results['Requested'], 2) self.assertEqual(results['Executed'], 2) self.assertEqual(results['Passed'], 2) expected_info_dict = { 'Controller Info': [{ 'MyMagic': { 'magic': 'Magic1' } }, { 'MyMagic': { 'magic': 'Magic2' } }], 'Controller Name': 'MagicDevice', 'Test Class': 'IntegrationTest', } self._assertControllerInfoEqual(tr.results.controller_info[0], expected_info_dict) self._assertControllerInfoEqual(tr.results.controller_info[1], expected_info_dict) self.assertNotEqual(tr.results.controller_info[0], tr.results.controller_info[1]) def test_summary_file_entries(self): """Verifies the output summary's file format. This focuses on the format of the file instead of the content of entries, which is covered in base_test_test. """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME my_config = [{ 'serial': 'xxxx', 'magic': 'Magic1' }, { 'serial': 'xxxx', 'magic': 'Magic2' }] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr.add_test_class(mock_test_config, integration_test.IntegrationTest) tr.run() summary_path = os.path.join(logging.log_path, records.OUTPUT_FILE_SUMMARY) with io.open(summary_path, 'r', encoding='utf-8') as f: summary_entries = list(yaml.safe_load_all(f)) self.assertEqual(len(summary_entries), 4) # Verify the first entry is the list of test names. self.assertEqual(summary_entries[0]['Type'], records.TestSummaryEntryType.TEST_NAME_LIST.value) self.assertEqual(summary_entries[1]['Type'], records.TestSummaryEntryType.RECORD.value) self.assertEqual(summary_entries[2]['Type'], records.TestSummaryEntryType.CONTROLLER_INFO.value) self.assertEqual(summary_entries[3]['Type'], records.TestSummaryEntryType.SUMMARY.value) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.controllers.android_device.list_adb_devices', return_value=['1']) @mock.patch('mobly.controllers.android_device.get_all_instances', return_value=mock_android_device.get_mock_ads(1)) def test_run_two_test_classes(self, mock_get_all, mock_list_adb, mock_fastboot, mock_adb): """Verifies that running more than one test class in one test run works properly. This requires using a built-in controller module. Using AndroidDevice module since it has all the mocks needed already. """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME my_config = [{ 'serial': 'xxxx', 'magic': 'Magic1' }, { 'serial': 'xxxx', 'magic': 'Magic2' }] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config mock_test_config.controller_configs['AndroidDevice'] = [{ 'serial': '1' }] tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr.add_test_class(mock_test_config, integration2_test.Integration2Test) tr.add_test_class(mock_test_config, integration_test.IntegrationTest) tr.run() results = tr.results.summary_dict() self.assertEqual(results['Requested'], 2) self.assertEqual(results['Executed'], 2) self.assertEqual(results['Passed'], 2) # Tag of the test class defaults to the class name. record1 = tr.results.executed[0] record2 = tr.results.executed[1] self.assertEqual(record1.test_class, 'Integration2Test') self.assertEqual(record2.test_class, 'IntegrationTest') def test_run_two_test_classes_different_configs_and_aliases(self): """Verifies that running more than one test class in one test run with different configs works properly. """ config1 = self.base_mock_test_config.copy() config1.controller_configs[ mock_controller.MOBLY_CONTROLLER_CONFIG_NAME] = [{ 'serial': 'xxxx' }] config2 = config1.copy() config2.user_params['icecream'] = 10 tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr.add_test_class(config1, integration_test.IntegrationTest, name_suffix='FirstConfig') tr.add_test_class(config2, integration_test.IntegrationTest, name_suffix='SecondConfig') tr.run() results = tr.results.summary_dict() self.assertEqual(results['Requested'], 2) self.assertEqual(results['Executed'], 2) self.assertEqual(results['Passed'], 1) self.assertEqual(results['Failed'], 1) self.assertEqual(tr.results.failed[0].details, '10 != 42') record1 = tr.results.executed[0] record2 = tr.results.executed[1] self.assertEqual(record1.test_class, 'IntegrationTest_FirstConfig') self.assertEqual(record2.test_class, 'IntegrationTest_SecondConfig') def test_run_with_abort_all(self): mock_test_config = self.base_mock_test_config.copy() tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) tr.add_test_class(mock_test_config, integration3_test.Integration3Test) with self.assertRaises(signals.TestAbortAll): tr.run() results = tr.results.summary_dict() self.assertEqual(results['Requested'], 1) self.assertEqual(results['Executed'], 0) self.assertEqual(results['Passed'], 0) self.assertEqual(results['Failed'], 0) def test_add_test_class_mismatched_log_path(self): tr = test_runner.TestRunner('/different/log/dir', self.test_bed_name) with self.assertRaisesRegex( test_runner.Error, 'TestRunner\'s log folder is "/different/log/dir", but a test ' r'config with a different log folder \("%s"\) was added.' % re.escape(self.log_dir)): tr.add_test_class(self.base_mock_test_config, integration_test.IntegrationTest) def test_add_test_class_mismatched_test_bed_name(self): tr = test_runner.TestRunner(self.log_dir, 'different_test_bed') with self.assertRaisesRegex( test_runner.Error, 'TestRunner\'s test bed is "different_test_bed", but a test ' r'config with a different test bed \("%s"\) was added.' % self.test_bed_name): tr.add_test_class(self.base_mock_test_config, integration_test.IntegrationTest) def test_teardown_logger_before_setup_logger(self): tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) with self.assertRaisesRegex( test_runner.Error, r'TestRunner\._teardown_logger\(\) called before ' r'TestRunner\.setup_logger\(\)!'): tr._teardown_logger() def test_run_no_tests(self): tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) with self.assertRaisesRegex(test_runner.Error, 'No tests to execute.'): tr.run() @mock.patch('mobly.test_runner._find_test_class', return_value=type('SampleTest', (), {})) @mock.patch('mobly.test_runner.config_parser.load_test_config_file', return_value=[config_parser.TestRunConfig()]) @mock.patch('mobly.test_runner.TestRunner', return_value=mock.MagicMock()) def test_main_parse_args(self, mock_test_runner, mock_config, mock_find_test): test_runner.main(['-c', 'some/path/foo.yaml', '-b', 'hello']) mock_config.assert_called_with('some/path/foo.yaml', None)
class TestRunnerTest(unittest.TestCase): """This test class has unit tests for the implementation of everything under mobly.test_runner. """ def setUp(self): self.tmp_dir = tempfile.mkdtemp() self.base_mock_test_config = config_parser.TestRunConfig() self.base_mock_test_config.test_bed_name = 'SampleTestBed' self.base_mock_test_config.controller_configs = {} self.base_mock_test_config.user_params = { 'icecream': 42, 'extra_param': 'haha' } self.base_mock_test_config.log_path = self.tmp_dir self.mock_run_list = [('SampleTest', None)] def tearDown(self): shutil.rmtree(self.tmp_dir) def test_register_controller_no_config(self): tr = test_runner.TestRunner(self.base_mock_test_config, self.mock_run_list) with self.assertRaisesRegexp(signals.ControllerError, 'No corresponding config found for'): tr.register_controller(mock_controller) def test_register_controller_no_config_no_register(self): tr = test_runner.TestRunner(self.base_mock_test_config, self.mock_run_list) self.assertIsNone( tr.register_controller(mock_controller, required=False)) def test_register_controller_dup_register(self): """Verifies correctness of registration, internal tally of controllers objects, and the right error happen when a controller module is registered twice. """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME mock_test_config.controller_configs = { mock_ctrlr_config_name: ['magic1', 'magic2'] } tr = test_runner.TestRunner(mock_test_config, self.mock_run_list) tr.register_controller(mock_controller) registered_name = 'mock_controller' self.assertTrue(registered_name in tr.controller_registry) mock_ctrlrs = tr.controller_registry[registered_name] self.assertEqual(mock_ctrlrs[0].magic, 'magic1') self.assertEqual(mock_ctrlrs[1].magic, 'magic2') self.assertTrue(tr.controller_destructors[registered_name]) expected_msg = 'Controller module .* has already been registered.' with self.assertRaisesRegexp(signals.ControllerError, expected_msg): tr.register_controller(mock_controller) def test_register_controller_no_get_info(self): mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME mock_ref_name = 'haha' get_info = getattr(mock_controller, 'get_info') delattr(mock_controller, 'get_info') try: mock_test_config.controller_configs = { mock_ctrlr_config_name: ['magic1', 'magic2'] } tr = test_runner.TestRunner(mock_test_config, self.mock_run_list) tr.register_controller(mock_controller) self.assertEqual(tr.results.controller_info, {}) finally: setattr(mock_controller, 'get_info', get_info) def test_register_controller_return_value(self): mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME mock_test_config.controller_configs = { mock_ctrlr_config_name: ['magic1', 'magic2'] } tr = test_runner.TestRunner(mock_test_config, self.mock_run_list) magic_devices = tr.register_controller(mock_controller) self.assertEqual(magic_devices[0].magic, 'magic1') self.assertEqual(magic_devices[1].magic, 'magic2') def test_register_controller_less_than_min_number(self): mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME mock_test_config.controller_configs = { mock_ctrlr_config_name: ['magic1', 'magic2'] } tr = test_runner.TestRunner(mock_test_config, self.mock_run_list) expected_msg = 'Expected to get at least 3 controller objects, got 2.' with self.assertRaisesRegexp(signals.ControllerError, expected_msg): tr.register_controller(mock_controller, min_number=3) def test_run_twice(self): """Verifies that: 1. Repeated run works properly. 2. The original configuration is not altered if a test controller module modifies configuration. """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME my_config = [{ 'serial': 'xxxx', 'magic': 'Magic1' }, { 'serial': 'xxxx', 'magic': 'Magic2' }] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config tr = test_runner.TestRunner(mock_test_config, [('IntegrationTest', None)]) tr.run([integration_test.IntegrationTest]) self.assertFalse(tr.controller_registry) self.assertFalse(tr.controller_destructors) self.assertTrue( mock_test_config.controller_configs[mock_ctrlr_config_name][0]) tr.run([integration_test.IntegrationTest]) tr.stop() self.assertFalse(tr.controller_registry) self.assertFalse(tr.controller_destructors) results = tr.results.summary_dict() self.assertEqual(results['Requested'], 2) self.assertEqual(results['Executed'], 2) self.assertEqual(results['Passed'], 2) expected_info = { 'MagicDevice': [{ 'MyMagic': { 'magic': 'Magic1' } }, { 'MyMagic': { 'magic': 'Magic2' } }] } self.assertEqual(tr.results.controller_info, expected_info) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.controllers.android_device.list_adb_devices', return_value=['1']) @mock.patch('mobly.controllers.android_device.get_all_instances', return_value=mock_android_device.get_mock_ads(1)) def test_run_two_test_classes( self, mock_get_all, mock_list_adb, mock_fastboot, mock_adb, ): """Verifies that runing more than one test class in one test run works proerly. This requires using a built-in controller module. Using AndroidDevice module since it has all the mocks needed already. """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME my_config = [{ 'serial': 'xxxx', 'magic': 'Magic1' }, { 'serial': 'xxxx', 'magic': 'Magic2' }] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config mock_test_config.controller_configs['AndroidDevice'] = [{ 'serial': '1' }] tr = test_runner.TestRunner(mock_test_config, [('Integration2Test', None), ('IntegrationTest', None)]) tr.run([ integration_test.IntegrationTest, integration2_test.Integration2Test ]) tr.stop() self.assertFalse(tr.controller_registry) self.assertFalse(tr.controller_destructors) results = tr.results.summary_dict() self.assertEqual(results['Requested'], 2) self.assertEqual(results['Executed'], 2) self.assertEqual(results['Passed'], 2) def test_verify_controller_module(self): test_runner.TestRunner.verify_controller_module(mock_controller) def test_verify_controller_module_null_attr(self): try: tmp = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME mock_controller.MOBLY_CONTROLLER_CONFIG_NAME = None msg = 'Controller interface .* in .* cannot be null.' with self.assertRaisesRegexp(signals.ControllerError, msg): test_runner.TestRunner.verify_controller_module( mock_controller) finally: mock_controller.MOBLY_CONTROLLER_CONFIG_NAME = tmp def test_verify_controller_module_missing_attr(self): try: tmp = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME delattr(mock_controller, 'MOBLY_CONTROLLER_CONFIG_NAME') msg = 'Module .* missing required controller module attribute' with self.assertRaisesRegexp(signals.ControllerError, msg): test_runner.TestRunner.verify_controller_module( mock_controller) finally: setattr(mock_controller, 'MOBLY_CONTROLLER_CONFIG_NAME', tmp)
class AndroidDeviceTest(unittest.TestCase): """This test class has unit tests for the implementation of everything under mobly.controllers.android_device. """ def setUp(self): # Set log_path to logging since mobly logger setup is not called. if not hasattr(logging, 'log_path'): setattr(logging, 'log_path', '/tmp/logs') # Creates a temp dir to be used by tests in this test class. self.tmp_dir = tempfile.mkdtemp() def tearDown(self): """Removes the temp dir. """ shutil.rmtree(self.tmp_dir) # Tests for android_device module functions. # These tests use mock AndroidDevice instances. @mock.patch.object( android_device, 'get_all_instances', new=mock_android_device.get_all_instances) @mock.patch.object( android_device, 'list_adb_devices', new=mock_android_device.list_adb_devices) @mock.patch.object( android_device, 'list_adb_devices_by_usb_id', new=mock_android_device.list_adb_devices) def test_create_with_pickup_all(self): pick_all_token = android_device.ANDROID_DEVICE_PICK_ALL_TOKEN actual_ads = android_device.create(pick_all_token) for actual, expected in zip(actual_ads, mock_android_device.get_mock_ads(5)): self.assertEqual(actual.serial, expected.serial) @mock.patch.object( android_device, 'get_instances', new=mock_android_device.get_instances) @mock.patch.object( android_device, 'list_adb_devices', new=mock_android_device.list_adb_devices) @mock.patch.object( android_device, 'list_adb_devices_by_usb_id', new=mock_android_device.list_adb_devices) def test_create_with_string_list(self): string_list = [u'1', '2'] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2']): self.assertEqual(actual_ad.serial, expected_serial) @mock.patch.object( android_device, 'get_instances_with_configs', new=mock_android_device.get_instances_with_configs) @mock.patch.object( android_device, 'list_adb_devices', new=mock_android_device.list_adb_devices) @mock.patch.object( android_device, 'list_adb_devices_by_usb_id', new=mock_android_device.list_adb_devices) def test_create_with_dict_list(self): string_list = [{'serial': '1'}, {'serial': '2'}] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2']): self.assertEqual(actual_ad.serial, expected_serial) @mock.patch.object( android_device, 'get_instances_with_configs', new=mock_android_device.get_instances_with_configs) @mock.patch.object( android_device, 'list_adb_devices', new=mock_android_device.list_adb_devices) @mock.patch.object( android_device, 'list_adb_devices_by_usb_id', return_value=['usb:1']) def test_create_with_usb_id(self, mock_list_adb_devices_by_usb_id): string_list = [{'serial': '1'}, {'serial': '2'}, {'serial': 'usb:1'}] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2', 'usb:1']): self.assertEqual(actual_ad.serial, expected_serial) def test_create_with_empty_config(self): expected_msg = android_device.ANDROID_DEVICE_EMPTY_CONFIG_MSG with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.create([]) def test_create_with_not_list_config(self): expected_msg = android_device.ANDROID_DEVICE_NOT_LIST_CONFIG_MSG with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.create('HAHA') def test_create_with_no_valid_config(self): expected_msg = 'No valid config found in: .*' with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.create([1]) def test_get_devices_success_with_extra_field(self): ads = mock_android_device.get_mock_ads(5) expected_label = 'selected' expected_count = 2 for ad in ads[:expected_count]: ad.label = expected_label selected_ads = android_device.get_devices(ads, label=expected_label) self.assertEqual(expected_count, len(selected_ads)) for ad in selected_ads: self.assertEqual(ad.label, expected_label) def test_get_devices_no_match(self): ads = mock_android_device.get_mock_ads(5) expected_msg = ('Could not find a target device that matches condition' ": {'label': 'selected'}.") with self.assertRaisesRegex(android_device.Error, expected_msg): selected_ads = android_device.get_devices(ads, label='selected') def test_get_device_success_with_serial(self): ads = mock_android_device.get_mock_ads(5) expected_serial = '0' ad = android_device.get_device(ads, serial=expected_serial) self.assertEqual(ad.serial, expected_serial) def test_get_device_success_with_serial_and_extra_field(self): ads = mock_android_device.get_mock_ads(5) expected_serial = '1' expected_h_port = 5555 ads[1].h_port = expected_h_port ad = android_device.get_device( ads, serial=expected_serial, h_port=expected_h_port) self.assertEqual(ad.serial, expected_serial) self.assertEqual(ad.h_port, expected_h_port) def test_get_device_no_match(self): ads = mock_android_device.get_mock_ads(5) expected_msg = ('Could not find a target device that matches condition' ": {'serial': 5}.") with self.assertRaisesRegex(android_device.Error, expected_msg): ad = android_device.get_device(ads, serial=len(ads)) def test_get_device_too_many_matches(self): ads = mock_android_device.get_mock_ads(5) target_serial = ads[1].serial = ads[0].serial expected_msg = "More than one device matched: \['0', '0'\]" with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.get_device(ads, serial=target_serial) def test_start_services_on_ads(self): """Makes sure when an AndroidDevice fails to start some services, all AndroidDevice objects get cleaned up. """ msg = 'Some error happened.' ads = mock_android_device.get_mock_ads(3) ads[0].start_services = mock.MagicMock() ads[0].stop_services = mock.MagicMock() ads[1].start_services = mock.MagicMock() ads[1].stop_services = mock.MagicMock() ads[2].start_services = mock.MagicMock( side_effect=android_device.Error(msg)) ads[2].stop_services = mock.MagicMock() with self.assertRaisesRegex(android_device.Error, msg): android_device._start_services_on_ads(ads) ads[0].stop_services.assert_called_once_with() ads[1].stop_services.assert_called_once_with() ads[2].stop_services.assert_called_once_with() def test_start_services_on_ads_skip_logcat(self): ads = mock_android_device.get_mock_ads(3) ads[0].start_services = mock.MagicMock() ads[1].start_services = mock.MagicMock() ads[2].start_services = mock.MagicMock( side_effect=Exception('Should not have called this.')) ads[2].skip_logcat = True android_device._start_services_on_ads(ads) # Tests for android_device.AndroidDevice class. # These tests mock out any interaction with the OS and real android device # in AndroidDeivce. @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_instantiation(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) self.assertEqual(ad.serial, '1') self.assertEqual(ad.model, 'fakemodel') self.assertIsNone(ad._adb_logcat_process) self.assertIsNone(ad.adb_logcat_file_path) expected_lp = os.path.join(logging.log_path, 'AndroidDevice%s' % mock_serial) self.assertEqual(ad.log_path, expected_lp) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_build_info(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. """ ad = android_device.AndroidDevice(serial='1') build_info = ad.build_info self.assertEqual(build_info['build_id'], 'AB42') self.assertEqual(build_info['build_type'], 'userdebug') @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_device_info(self, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial=1) device_info = ad.device_info self.assertEqual(device_info['serial'], '1') self.assertEqual(device_info['model'], 'fakemodel') self.assertEqual(device_info['build_info']['build_id'], 'AB42') self.assertEqual(device_info['build_info']['build_type'], 'userdebug') ad.add_device_info('sim_type', 'Fi') ad.add_device_info('build_id', 'CD42') device_info = ad.device_info self.assertEqual(device_info['user_added_info']['sim_type'], 'Fi') self.assertEqual(device_info['user_added_info']['build_id'], 'CD42') @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_serial_is_valid(self, MockFastboot, MockAdbProxy): """Verifies that the serial is a primitive string type and serializable. """ ad = android_device.AndroidDevice(serial=1) # In py2, checks that ad.serial is not the backported py3 str type, # which is not dumpable by yaml in py2. # In py3, new_str is equivalent to str, so this check is not # appropirate in py3. if sys.version_info < (3, 0): self.assertFalse(isinstance(ad.serial, new_str)) self.assertTrue(isinstance(ad.serial, str)) yaml.safe_dump(ad.serial) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report(self, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies AndroidDevice.take_bug_report calls the correct adb command and writes the bugreport file to the correct path. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) ad.take_bug_report('test_something', 'sometime') expected_path = os.path.join( logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports') create_dir_mock.assert_called_with(expected_path) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1', fail_br=True)) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_fail(self, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies AndroidDevice.take_bug_report writes out the correct message when taking bugreport fails. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) expected_msg = '.* Failed to take bugreport.' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.take_bug_report('test_something', 'sometime') @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_with_destination( self, create_dir_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) dest = tempfile.gettempdir() ad.take_bug_report("test_something", "sometime", destination=dest) expected_path = os.path.join(dest) create_dir_mock.assert_called_with(expected_path) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy( '1', fail_br_before_N=True)) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_fallback( self, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies AndroidDevice.take_bug_report falls back to traditional bugreport on builds that do not have bugreportz. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) ad.take_bug_report('test_something', 'sometime') expected_path = os.path.join( logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports') create_dir_mock.assert_called_with(expected_path) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch( 'mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_take_logcat(self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): """Verifies the steps of collecting adb logcat on an AndroidDevice object, including various function calls and the expected behaviors of the calls. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) expected_msg = '.* No ongoing adb logcat collection found.' # Expect error if stop is called before start. with self.assertRaisesRegex(android_device.Error, expected_msg): ad.stop_adb_logcat() ad.start_adb_logcat() # Verify start did the correct operations. self.assertTrue(ad._adb_logcat_process) expected_log_path = os.path.join(logging.log_path, 'AndroidDevice%s' % ad.serial, 'adblog,fakemodel,%s.txt' % ad.serial) creat_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) adb_cmd = '"adb" -s %s logcat -v threadtime >> %s' start_proc_mock.assert_called_with( adb_cmd % (ad.serial, '"%s"' % expected_log_path), shell=True) self.assertEqual(ad.adb_logcat_file_path, expected_log_path) expected_msg = ( 'Logcat thread is already running, cannot start another' ' one.') # Expect error if start is called back to back. with self.assertRaisesRegex(android_device.Error, expected_msg): ad.start_adb_logcat() # Verify stop did the correct operations. ad.stop_adb_logcat() stop_proc_mock.assert_called_with('process') self.assertIsNone(ad._adb_logcat_process) self.assertEqual(ad.adb_logcat_file_path, expected_log_path) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch( 'mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_take_logcat_with_user_param( self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): """Verifies the steps of collecting adb logcat on an AndroidDevice object, including various function calls and the expected behaviors of the calls. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) ad.adb_logcat_param = '-b radio' expected_msg = '.* No ongoing adb logcat collection found.' # Expect error if stop is called before start. with self.assertRaisesRegex(android_device.Error, expected_msg): ad.stop_adb_logcat() ad.start_adb_logcat() # Verify start did the correct operations. self.assertTrue(ad._adb_logcat_process) expected_log_path = os.path.join(logging.log_path, 'AndroidDevice%s' % ad.serial, 'adblog,fakemodel,%s.txt' % ad.serial) creat_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) adb_cmd = '"adb" -s %s logcat -v threadtime -b radio >> %s' start_proc_mock.assert_called_with( adb_cmd % (ad.serial, '"%s"' % expected_log_path), shell=True) self.assertEqual(ad.adb_logcat_file_path, expected_log_path) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_change_log_path(self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.start_adb_logcat() ad.stop_adb_logcat() old_path = ad.log_path new_log_path = tempfile.mkdtemp() ad.log_path = new_log_path self.assertTrue(os.path.exists(new_log_path)) self.assertFalse(os.path.exists(old_path)) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_change_log_path_no_log_exists( self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') old_path = ad.log_path new_log_path = tempfile.mkdtemp() ad.log_path = new_log_path self.assertTrue(os.path.exists(new_log_path)) self.assertFalse(os.path.exists(old_path)) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch( 'mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_change_log_path_with_service( self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.start_adb_logcat() new_log_path = tempfile.mkdtemp() expected_msg = '.* Cannot change `log_path` when there is service running.' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.log_path = new_log_path @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch( 'mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_change_log_path_with_existing_file( self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') new_log_path = tempfile.mkdtemp() new_file_path = os.path.join(new_log_path, 'file.txt') with io.open(new_file_path, 'w', encoding='utf-8') as f: f.write(u'hahah.') expected_msg = '.* Logs already exist .*' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.log_path = new_log_path @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch( 'mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_update_serial(self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.update_serial('2') self.assertEqual(ad.serial, '2') self.assertEqual(ad.debug_tag, ad.serial) self.assertEqual(ad.adb.serial, ad.serial) self.assertEqual(ad.fastboot.serial, ad.serial) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch( 'mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_update_serial_with_service_running( self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.start_adb_logcat() expected_msg = '.* Cannot change device serial number when there is service running.' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.update_serial('2') @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch( 'mobly.logger.get_log_line_timestamp', return_value=MOCK_ADB_LOGCAT_END_TIME) def test_AndroidDevice_cat_adb_log(self, mock_timestamp_getter, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): """Verifies that AndroidDevice.cat_adb_log loads the correct adb log file, locates the correct adb log lines within the given time range, and writes the lines to the correct output file. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) # Direct the log path of the ad to a temp dir to avoid racing. ad._log_path_base = self.tmp_dir # Expect error if attempted to cat adb log before starting adb logcat. expected_msg = ('.* Attempting to cat adb log when none' ' has been collected.') with self.assertRaisesRegex(android_device.Error, expected_msg): ad.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME) ad.start_adb_logcat() utils.create_dir(ad.log_path) mock_adb_log_path = os.path.join(ad.log_path, 'adblog,%s,%s.txt' % (ad.model, ad.serial)) with io.open(mock_adb_log_path, 'w', encoding='utf-8') as f: f.write(MOCK_ADB_LOGCAT) ad.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME) cat_file_path = os.path.join( ad.log_path, 'AdbLogExcerpts', ('some_test,02-29 14-02-20.123,%s,%s.txt') % (ad.model, ad.serial)) with io.open(cat_file_path, 'r', encoding='utf-8') as f: actual_cat = f.read() self.assertEqual(actual_cat, ''.join(MOCK_ADB_LOGCAT_CAT_RESULT)) # Stops adb logcat. ad.stop_adb_logcat() @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch( 'mobly.logger.get_log_line_timestamp', return_value=MOCK_ADB_LOGCAT_END_TIME) def test_AndroidDevice_cat_adb_log_with_unicode( self, mock_timestamp_getter, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): """Verifies that AndroidDevice.cat_adb_log loads the correct adb log file, locates the correct adb log lines within the given time range, and writes the lines to the correct output file. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) # Direct the log path of the ad to a temp dir to avoid racing. ad._log_path_base = self.tmp_dir # Expect error if attempted to cat adb log before starting adb logcat. expected_msg = ('.* Attempting to cat adb log when none' ' has been collected.') with self.assertRaisesRegex(android_device.Error, expected_msg): ad.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME) ad.start_adb_logcat() utils.create_dir(ad.log_path) mock_adb_log_path = os.path.join(ad.log_path, 'adblog,%s,%s.txt' % (ad.model, ad.serial)) with io.open(mock_adb_log_path, 'w', encoding='utf-8') as f: f.write(MOCK_ADB_UNICODE_LOGCAT) ad.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME) cat_file_path = os.path.join( ad.log_path, 'AdbLogExcerpts', ('some_test,02-29 14-02-20.123,%s,%s.txt') % (ad.model, ad.serial)) with io.open(cat_file_path, 'r', encoding='utf-8') as f: actual_cat = f.read() self.assertEqual(actual_cat, ''.join(MOCK_ADB_UNICODE_LOGCAT_CAT_RESULT)) # Stops adb logcat. ad.stop_adb_logcat() @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice__enable_logpersist_with_logpersist( self, MockFastboot, MockAdbProxy): mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprop.return_value = 'userdebug' mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': True, 'logpersist.stop': True, }[command] ad = android_device.AndroidDevice(serial=mock_serial) ad._enable_logpersist() mock_adb_proxy.shell.assert_has_calls([ mock.call('logpersist.stop --clear'), mock.call('logpersist.start'), ]) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice__enable_logpersist_with_missing_all_logpersist( self, MockFastboot, MockAdbProxy): def adb_shell_helper(command): if command == 'logpersist.start': raise MOCK_LOGPERSIST_START_MISSING_ADB_ERROR elif command == 'logpersist.stop --clear': raise MOCK_LOGPERSIST_STOP_MISSING_ADB_ERROR else: return '' mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprop.return_value = 'userdebug' mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': False, 'logpersist.stop': False, }[command] mock_adb_proxy.shell.side_effect = adb_shell_helper ad = android_device.AndroidDevice(serial=mock_serial) ad._enable_logpersist() @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice__enable_logpersist_with_missing_logpersist_stop( self, MockFastboot, MockAdbProxy): def adb_shell_helper(command): if command == 'logpersist.stop --clear': raise MOCK_LOGPERSIST_STOP_MISSING_ADB_ERROR else: return '' mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprop.return_value = 'userdebug' mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': True, 'logpersist.stop': False, }[command] mock_adb_proxy.shell.side_effect = adb_shell_helper ad = android_device.AndroidDevice(serial=mock_serial) ad._enable_logpersist() @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice__enable_logpersist_with_missing_logpersist_start( self, MockFastboot, MockAdbProxy): def adb_shell_helper(command): if command == 'logpersist.start': raise MOCK_LOGPERSIST_START_MISSING_ADB_ERROR else: return '' mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprop.return_value = 'userdebug' mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': False, 'logpersist.stop': True, }[command] mock_adb_proxy.shell.side_effect = adb_shell_helper ad = android_device.AndroidDevice(serial=mock_serial) ad._enable_logpersist() @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet(self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) self.assertTrue(hasattr(ad, 'snippet')) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_failure( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') client = mock.MagicMock() client.start_app_and_connect.side_effect = Exception( 'Something went wrong.') MockSnippetClient.return_value = client with self.assertRaisesRegex(Exception, 'Something went wrong.'): ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) client.stop_app.assert_called_once_with() @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_precheck_failure( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') client = mock.MagicMock() client.start_app_and_connect.side_effect = snippet_client.AppStartPreCheckError( mock.MagicMock, 'Something went wrong in precheck.') MockSnippetClient.return_value = client with self.assertRaisesRegex(snippet_client.AppStartPreCheckError, 'Something went wrong in precheck.'): ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) client.stop_app.assert_not_called() @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_fail_cleanup_also_fail( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') client = mock.MagicMock() client.start_app_and_connect.side_effect = Exception( 'Something went wrong in start app.') client.stop_app.side_effect = Exception('Stop app also failed.') MockSnippetClient.return_value = client with self.assertRaisesRegex(Exception, 'Something went wrong in start app.'): ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) client.stop_app.assert_called_once_with() @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient', return_value=MockSnippetClient) @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_dup_package( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) expected_msg = ('Snippet package "%s" has already been loaded under ' 'name "snippet".') % MOCK_SNIPPET_PACKAGE_NAME with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('snippet2', MOCK_SNIPPET_PACKAGE_NAME) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient', return_value=MockSnippetClient) @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_dup_snippet_name( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) expected_msg = ('Attribute "%s" is already registered with package ' '"%s", it cannot be used again.') % ( 'snippet', MOCK_SNIPPET_PACKAGE_NAME) with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME + 'haha') @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_dup_attribute_name( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') expected_msg = ('Attribute "%s" already exists, please use a different' ' name') % 'adb' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('adb', MOCK_SNIPPET_PACKAGE_NAME) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_start_app_fails( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): """Verifies that the correct exception is raised if start app failed. It's possible that the `stop_app` call as part of the start app failure teardown also fails. So we want the exception from the start app failure. """ expected_e = Exception('start failed.') MockSnippetClient.start_app_and_connect = mock.Mock( side_effect=expected_e) MockSnippetClient.stop_app = mock.Mock( side_effect=Exception('stop failed.')) ad = android_device.AndroidDevice(serial='1') try: ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) except Exception as e: assertIs(e, expected_e) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_unload_snippet(self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) ad.unload_snippet('snippet') self.assertFalse(hasattr(ad, 'snippet')) with self.assertRaisesRegex( android_device.SnippetError, '<AndroidDevice|1> No snippet registered with name "snippet"'): ad.unload_snippet('snippet') # Loading the same snippet again should succeed ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) self.assertTrue(hasattr(ad, 'snippet')) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_snippet_cleanup( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) ad.stop_services() self.assertFalse(hasattr(ad, 'snippet')) @mock.patch( 'mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_AndroidDevice_debug_tag(self, MockFastboot, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) self.assertEqual(ad.debug_tag, '1') try: raise android_device.DeviceError(ad, 'Something') except android_device.DeviceError as e: self.assertEqual('<AndroidDevice|1> Something', str(e)) # Verify that debug tag's setter updates the debug prefix correctly. ad.debug_tag = 'Mememe' try: raise android_device.DeviceError(ad, 'Something') except android_device.DeviceError as e: self.assertEqual('<AndroidDevice|Mememe> Something', str(e)) # Verify that repr is changed correctly. try: raise Exception(ad, 'Something') except Exception as e: self.assertEqual("(<AndroidDevice|Mememe>, 'Something')", str(e))
class AndroidDeviceTest(unittest.TestCase): """This test class has unit tests for the implementation of everything under mobly.controllers.android_device. """ def setUp(self): # Set log_path to logging since mobly logger setup is not called. if not hasattr(logging, "log_path"): setattr(logging, "log_path", "/tmp/logs") # Creates a temp dir to be used by tests in this test class. self.tmp_dir = tempfile.mkdtemp() def tearDown(self): """Removes the temp dir. """ shutil.rmtree(self.tmp_dir) # Tests for android_device module functions. # These tests use mock AndroidDevice instances. @mock.patch.object(android_device, "get_all_instances", new=mock_android_device.get_all_instances) @mock.patch.object(android_device, "list_adb_devices", new=mock_android_device.list_adb_devices) @mock.patch.object(android_device, "list_adb_devices_by_usb_id", new=mock_android_device.list_adb_devices) def test_create_with_pickup_all(self): pick_all_token = android_device.ANDROID_DEVICE_PICK_ALL_TOKEN actual_ads = android_device.create(pick_all_token) for actual, expected in zip(actual_ads, mock_android_device.get_mock_ads(5)): self.assertEqual(actual.serial, expected.serial) @mock.patch.object(android_device, "get_instances", new=mock_android_device.get_instances) @mock.patch.object(android_device, "list_adb_devices", new=mock_android_device.list_adb_devices) @mock.patch.object(android_device, "list_adb_devices_by_usb_id", new=mock_android_device.list_adb_devices) def test_create_with_string_list(self): string_list = [u'1', '2'] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2']): self.assertEqual(actual_ad.serial, expected_serial) @mock.patch.object(android_device, "get_instances_with_configs", new=mock_android_device.get_instances_with_configs) @mock.patch.object(android_device, "list_adb_devices", new=mock_android_device.list_adb_devices) @mock.patch.object(android_device, "list_adb_devices_by_usb_id", new=mock_android_device.list_adb_devices) def test_create_with_dict_list(self): string_list = [{'serial': '1'}, {'serial': '2'}] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2']): self.assertEqual(actual_ad.serial, expected_serial) @mock.patch.object(android_device, "get_instances_with_configs", new=mock_android_device.get_instances_with_configs) @mock.patch.object(android_device, "list_adb_devices", new=mock_android_device.list_adb_devices) @mock.patch.object(android_device, "list_adb_devices_by_usb_id", return_value=['usb:1']) def test_create_with_usb_id(self, mock_list_adb_devices_by_usb_id): string_list = [{'serial': '1'}, {'serial': '2'}, {'serial': 'usb:1'}] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2', 'usb:1']): self.assertEqual(actual_ad.serial, expected_serial) def test_create_with_empty_config(self): expected_msg = android_device.ANDROID_DEVICE_EMPTY_CONFIG_MSG with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.create([]) def test_create_with_not_list_config(self): expected_msg = android_device.ANDROID_DEVICE_NOT_LIST_CONFIG_MSG with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.create("HAHA") def test_create_with_no_valid_config(self): expected_msg = "No valid config found in: .*" with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.create([1]) def test_get_device_success_with_serial(self): ads = mock_android_device.get_mock_ads(5) expected_serial = '0' ad = android_device.get_device(ads, serial=expected_serial) self.assertEqual(ad.serial, expected_serial) def test_get_device_success_with_serial_and_extra_field(self): ads = mock_android_device.get_mock_ads(5) expected_serial = '1' expected_h_port = 5555 ads[1].h_port = expected_h_port ad = android_device.get_device(ads, serial=expected_serial, h_port=expected_h_port) self.assertEqual(ad.serial, expected_serial) self.assertEqual(ad.h_port, expected_h_port) def test_get_device_no_match(self): ads = mock_android_device.get_mock_ads(5) expected_msg = ("Could not find a target device that matches condition" ": {'serial': 5}.") with self.assertRaisesRegex(android_device.Error, expected_msg): ad = android_device.get_device(ads, serial=len(ads)) def test_get_device_too_many_matches(self): ads = mock_android_device.get_mock_ads(5) target_serial = ads[1].serial = ads[0].serial expected_msg = "More than one device matched: \['0', '0'\]" with self.assertRaisesRegex(android_device.Error, expected_msg): android_device.get_device(ads, serial=target_serial) def test_start_services_on_ads(self): """Makes sure when an AndroidDevice fails to start some services, all AndroidDevice objects get cleaned up. """ msg = "Some error happened." ads = mock_android_device.get_mock_ads(3) ads[0].start_services = mock.MagicMock() ads[0].stop_services = mock.MagicMock() ads[1].start_services = mock.MagicMock() ads[1].stop_services = mock.MagicMock() ads[2].start_services = mock.MagicMock( side_effect=android_device.Error(msg)) ads[2].stop_services = mock.MagicMock() with self.assertRaisesRegex(android_device.Error, msg): android_device._start_services_on_ads(ads) ads[0].stop_services.assert_called_once_with() ads[1].stop_services.assert_called_once_with() ads[2].stop_services.assert_called_once_with() # Tests for android_device.AndroidDevice class. # These tests mock out any interaction with the OS and real android device # in AndroidDeivce. @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) def test_AndroidDevice_instantiation(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) self.assertEqual(ad.serial, 1) self.assertEqual(ad.model, "fakemodel") self.assertIsNone(ad._adb_logcat_process) self.assertIsNone(ad.adb_logcat_file_path) expected_lp = os.path.join(logging.log_path, "AndroidDevice%s" % mock_serial) self.assertEqual(ad.log_path, expected_lp) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) def test_AndroidDevice_build_info(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. """ ad = android_device.AndroidDevice(serial=1) build_info = ad.build_info self.assertEqual(build_info["build_id"], "AB42") self.assertEqual(build_info["build_type"], "userdebug") @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report(self, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies AndroidDevice.take_bug_report calls the correct adb command and writes the bugreport file to the correct path. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) ad.take_bug_report("test_something", "sometime") expected_path = os.path.join(logging.log_path, "AndroidDevice%s" % ad.serial, "BugReports") create_dir_mock.assert_called_with(expected_path) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1, fail_br=True)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_fail(self, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies AndroidDevice.take_bug_report writes out the correct message when taking bugreport fails. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) expected_msg = ".* Failed to take bugreport." with self.assertRaisesRegex(android_device.Error, expected_msg): ad.take_bug_report("test_something", "sometime") @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy( 1, fail_br_before_N=True)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_fallback(self, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies AndroidDevice.take_bug_report falls back to traditional bugreport on builds that do not have bugreportz. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) ad.take_bug_report("test_something", "sometime") expected_path = os.path.join(logging.log_path, "AndroidDevice%s" % ad.serial, "BugReports") create_dir_mock.assert_called_with(expected_path) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value="process") @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_take_logcat(self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): """Verifies the steps of collecting adb logcat on an AndroidDevice object, including various function calls and the expected behaviors of the calls. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) expected_msg = ".* No ongoing adb logcat collection found." # Expect error if stop is called before start. with self.assertRaisesRegex(android_device.Error, expected_msg): ad.stop_adb_logcat() ad.start_adb_logcat() # Verify start did the correct operations. self.assertTrue(ad._adb_logcat_process) expected_log_path = os.path.join(logging.log_path, "AndroidDevice%s" % ad.serial, "adblog,fakemodel,%s.txt" % ad.serial) creat_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) adb_cmd = '"adb" -s %s logcat -v threadtime >> %s' start_proc_mock.assert_called_with(adb_cmd % (ad.serial, expected_log_path), shell=True) self.assertEqual(ad.adb_logcat_file_path, expected_log_path) expected_msg = ( 'Logcat thread is already running, cannot start another' ' one.') # Expect error if start is called back to back. with self.assertRaisesRegex(android_device.Error, expected_msg): ad.start_adb_logcat() # Verify stop did the correct operations. ad.stop_adb_logcat() stop_proc_mock.assert_called_with("process") self.assertIsNone(ad._adb_logcat_process) self.assertEqual(ad.adb_logcat_file_path, expected_log_path) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value="process") @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_take_logcat_with_user_param(self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, MockAdbProxy): """Verifies the steps of collecting adb logcat on an AndroidDevice object, including various function calls and the expected behaviors of the calls. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) ad.adb_logcat_param = "-b radio" expected_msg = '.* No ongoing adb logcat collection found.' # Expect error if stop is called before start. with self.assertRaisesRegex(android_device.Error, expected_msg): ad.stop_adb_logcat() ad.start_adb_logcat() # Verify start did the correct operations. self.assertTrue(ad._adb_logcat_process) expected_log_path = os.path.join(logging.log_path, "AndroidDevice%s" % ad.serial, "adblog,fakemodel,%s.txt" % ad.serial) creat_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) adb_cmd = '"adb" -s %s logcat -v threadtime -b radio >> %s' start_proc_mock.assert_called_with(adb_cmd % (ad.serial, expected_log_path), shell=True) self.assertEqual(ad.adb_logcat_file_path, expected_log_path) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch('mobly.utils.start_standing_subprocess', return_value="process") @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch('mobly.logger.get_log_line_timestamp', return_value=MOCK_ADB_LOGCAT_END_TIME) def test_AndroidDevice_cat_adb_log(self, mock_timestamp_getter, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): """Verifies that AndroidDevice.cat_adb_log loads the correct adb log file, locates the correct adb log lines within the given time range, and writes the lines to the correct output file. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) # Expect error if attempted to cat adb log before starting adb logcat. expected_msg = (".* Attempting to cat adb log when none" " has been collected.") with self.assertRaisesRegex(android_device.Error, expected_msg): ad.cat_adb_log("some_test", MOCK_ADB_LOGCAT_BEGIN_TIME) ad.start_adb_logcat() # Direct the log path of the ad to a temp dir to avoid racing. ad.log_path = os.path.join(self.tmp_dir, ad.log_path) mock_adb_log_path = os.path.join( ad.log_path, "adblog,%s,%s.txt" % (ad.model, ad.serial)) with open(mock_adb_log_path, 'w') as f: f.write(MOCK_ADB_LOGCAT) ad.cat_adb_log("some_test", MOCK_ADB_LOGCAT_BEGIN_TIME) cat_file_path = os.path.join( ad.log_path, "AdbLogExcerpts", ("some_test,02-29 14:02:20.123,%s,%s.txt") % (ad.model, ad.serial)) with open(cat_file_path, 'r') as f: actual_cat = f.read() self.assertEqual(actual_cat, ''.join(MOCK_ADB_LOGCAT_CAT_RESULT)) # Stops adb logcat. ad.stop_adb_logcat() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet(self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial=1) ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) self.assertTrue(hasattr(ad, 'snippet')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient', return_value=MockSnippetClient) @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_dup_package(self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial=1) ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) expected_msg = ('Snippet package "%s" has already been loaded under ' 'name "snippet".') % MOCK_SNIPPET_PACKAGE_NAME with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('snippet2', MOCK_SNIPPET_PACKAGE_NAME) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient', return_value=MockSnippetClient) @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_dup_snippet_name( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial=1) ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) expected_msg = ('Attribute "%s" is already registered with package ' '"%s", it cannot be used again.') % ( 'snippet', MOCK_SNIPPET_PACKAGE_NAME) with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME + 'haha') @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_dup_attribute_name( self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial=1) expected_msg = ('Attribute "%s" already exists, please use a different' ' name') % 'adb' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('adb', MOCK_SNIPPET_PACKAGE_NAME) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient') @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_snippet_cleanup(self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial=1) ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) ad.stop_services() self.assertFalse(hasattr(ad, 'snippet')) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy(1)) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy(1)) def test_AndroidDevice_debug_tag(self, MockFastboot, MockAdbProxy): mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) self.assertEqual(ad.debug_tag, 1) try: raise android_device.DeviceError(ad, 'Something') except android_device.DeviceError as e: self.assertEqual('<AndroidDevice|1> Something', str(e)) # Verify that debug tag's setter updates the debug prefix correctly. ad.debug_tag = 'Mememe' try: raise android_device.DeviceError(ad, 'Something') except android_device.DeviceError as e: self.assertEqual('<AndroidDevice|Mememe> Something', str(e)) # Verify that repr is changed correctly. try: raise Exception(ad, 'Something') except Exception as e: self.assertEqual("(<AndroidDevice|Mememe>, 'Something')", str(e))
class LogcatTest(unittest.TestCase): """Tests for Logcat service and its integration with AndroidDevice.""" def setUp(self): # Set log_path to logging since mobly logger setup is not called. if not hasattr(logging, 'log_path'): setattr(logging, 'log_path', '/tmp/logs') # Creates a temp dir to be used by tests in this test class. self.tmp_dir = tempfile.mkdtemp() def tearDown(self): """Removes the temp dir. """ shutil.rmtree(self.tmp_dir) def AssertFileContains(self, content, file_path): with open(file_path, 'r') as f: output = f.read() self.assertIn(content, output) def AssertFileDoesNotContain(self, content, file_path): with open(file_path, 'r') as f: output = f.read() self.assertNotIn(content, output) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') @mock.patch('mobly.logger.get_log_file_timestamp') def test_start_and_stop(self, get_timestamp_mock, open_logcat_mock, stop_proc_mock, start_proc_mock, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies the steps of collecting adb logcat on an AndroidDevice object, including various function calls and the expected behaviors of the calls. """ mock_serial = '1' get_timestamp_mock.return_value = '123' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service.start() # Verify start did the correct operations. self.assertTrue(logcat_service._adb_logcat_process) expected_log_path = os.path.join( logging.log_path, 'AndroidDevice%s' % ad.serial, 'logcat,%s,fakemodel,123.txt' % ad.serial) create_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) adb_cmd = ' "adb" -s %s logcat -v threadtime -T 1 >> %s' start_proc_mock.assert_called_with( adb_cmd % (ad.serial, '"%s" ' % expected_log_path), shell=True) self.assertEqual(logcat_service.adb_logcat_file_path, expected_log_path) expected_msg = ( 'Logcat thread is already running, cannot start another' ' one.') # Expect error if start is called back to back. with self.assertRaisesRegex(logcat.Error, expected_msg): logcat_service.start() # Verify stop did the correct operations. logcat_service.stop() stop_proc_mock.assert_called_with('process') self.assertIsNone(logcat_service._adb_logcat_process) self.assertEqual(logcat_service.adb_logcat_file_path, expected_log_path) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') def test_update_config(self, open_logcat_mock, stop_proc_mock, start_proc_mock, create_dir_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service.start() logcat_service.stop() new_log_params = '-a -b -c' new_file_path = 'some/path/log.txt' new_config = logcat.Config(logcat_params=new_log_params, output_file_path=new_file_path) logcat_service.update_config(new_config) logcat_service.start() self.assertTrue(logcat_service._adb_logcat_process) create_dir_mock.assert_has_calls([mock.call('some/path')]) expected_adb_cmd = ( ' "adb" -s 1 logcat -v threadtime -T 1 -a -b -c >> ' '"some/path/log.txt" ') start_proc_mock.assert_called_with(expected_adb_cmd, shell=True) self.assertEqual(logcat_service.adb_logcat_file_path, 'some/path/log.txt') logcat_service.stop() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') def test_update_config_while_running(self, open_logcat_mock, stop_proc_mock, start_proc_mock, create_dir_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service.start() new_config = logcat.Config(logcat_params='-blah', output_file_path='some/path/file.txt') with self.assertRaisesRegex( logcat.Error, 'Logcat thread is already running, cannot start another one'): logcat_service.update_config(new_config) self.assertTrue(logcat_service.is_alive) logcat_service.stop() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') @mock.patch( 'mobly.controllers.android_device_lib.services.logcat.Logcat.clear_adb_log', return_value=mock_android_device.MockAdbProxy('1')) def test_pause_and_resume(self, clear_adb_mock, open_logcat_mock, stop_proc_mock, start_proc_mock, create_dir_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad, logcat.Config(clear_log=True)) logcat_service.start() clear_adb_mock.assert_called_once_with() self.assertTrue(logcat_service.is_alive) logcat_service.pause() self.assertFalse(logcat_service.is_alive) stop_proc_mock.assert_called_with('process') self.assertIsNone(logcat_service._adb_logcat_process) clear_adb_mock.reset_mock() logcat_service.resume() self.assertTrue(logcat_service.is_alive) clear_adb_mock.assert_not_called() logcat_service.stop() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch( 'mobly.controllers.android_device_lib.services.logcat.Logcat.clear_adb_log', return_value=mock_android_device.MockAdbProxy('1')) def test_logcat_service_create_output_excerpts(self, clear_adb_mock, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._start() def _write_logcat_file_and_assert_excerpts_exists( logcat_file_content, test_begin_time, test_name): with open(logcat_service.adb_logcat_file_path, 'a') as f: f.write(logcat_file_content) test_output_dir = os.path.join(self.tmp_dir, test_name) mock_record = records.TestResultRecord(test_name) mock_record.begin_time = test_begin_time mock_record.signature = f'{test_name}-{test_begin_time}' test_run_info = runtime_test_info.RuntimeTestInfo( test_name, test_output_dir, mock_record) actual_path = logcat_service.create_output_excerpts( test_run_info)[0] expected_path = os.path.join( test_output_dir, '{test_name}-{test_begin_time}'.format( test_name=test_name, test_begin_time=test_begin_time), 'logcat,{mock_serial},fakemodel,{test_name}-{test_begin_time}.txt' .format(mock_serial=mock_serial, test_name=test_name, test_begin_time=test_begin_time)) self.assertEqual(actual_path, expected_path) self.assertTrue(os.path.exists(expected_path)) return expected_path # Generate logs before the file pointer is created. # This message will not be captured in the excerpt. NOT_IN_EXCERPT = 'Not in excerpt.\n' with open(logcat_service.adb_logcat_file_path, 'a') as f: f.write(NOT_IN_EXCERPT) # With the file pointer created, generate logs and make an excerpt. logcat_service._open_logcat_file() FILE_CONTENT = 'Some log.\n' expected_path1 = _write_logcat_file_and_assert_excerpts_exists( logcat_file_content=FILE_CONTENT, test_begin_time=123, test_name='test_foo', ) self.AssertFileContains(FILE_CONTENT, expected_path1) self.AssertFileDoesNotContain(NOT_IN_EXCERPT, expected_path1) # Generate some new logs and do another excerpt. FILE_CONTENT = 'Some more logs!!!\n' expected_path2 = _write_logcat_file_and_assert_excerpts_exists( logcat_file_content=FILE_CONTENT, test_begin_time=456, test_name='test_bar', ) self.AssertFileContains(FILE_CONTENT, expected_path2) self.AssertFileDoesNotContain(FILE_CONTENT, expected_path1) # Simulate devices accidentally go offline, logcat service stopped. logcat_service.stop() FILE_CONTENT = 'Whatever logs\n' expected_path3 = _write_logcat_file_and_assert_excerpts_exists( logcat_file_content=FILE_CONTENT, test_begin_time=789, test_name='test_offline', ) self.assertEqual(os.stat(expected_path3).st_size, 0) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') @mock.patch('mobly.logger.get_log_file_timestamp') def test_take_logcat_with_extra_params(self, get_timestamp_mock, open_logcat_mock, stop_proc_mock, start_proc_mock, create_dir_mock, FastbootProxy, MockAdbProxy): """Verifies the steps of collecting adb logcat on an AndroidDevice object, including various function calls and the expected behaviors of the calls. """ mock_serial = '1' get_timestamp_mock.return_value = '123' ad = android_device.AndroidDevice(serial=mock_serial) configs = logcat.Config() configs.logcat_params = '-b radio' logcat_service = logcat.Logcat(ad, configs) logcat_service.start() # Verify start did the correct operations. self.assertTrue(logcat_service._adb_logcat_process) expected_log_path = os.path.join( logging.log_path, 'AndroidDevice%s' % ad.serial, 'logcat,%s,fakemodel,123.txt' % ad.serial) create_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) adb_cmd = ' "adb" -s %s logcat -v threadtime -T 1 -b radio >> %s' start_proc_mock.assert_called_with( adb_cmd % (ad.serial, '"%s" ' % expected_log_path), shell=True) self.assertEqual(logcat_service.adb_logcat_file_path, expected_log_path) logcat_service.stop() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock_android_device.MockAdbProxy('1')) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_instantiation(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. """ mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) self.assertIsNone(logcat_service._adb_logcat_process) self.assertIsNone(logcat_service.adb_logcat_file_path) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test__enable_logpersist_with_logpersist(self, MockFastboot, MockAdbProxy): mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { 'ro.build.id': 'AB42', 'ro.build.type': 'userdebug', 'ro.debuggable': '1', } mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': True, 'logpersist.stop': True, }[command] ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_has_calls([ mock.call('logpersist.stop --clear'), mock.call('logpersist.start'), ]) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test__enable_logpersist_with_user_build_device(self, MockFastboot, MockAdbProxy): mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { 'ro.build.id': 'AB42', 'ro.build.type': 'user', 'ro.debuggable': '0', } mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': True, 'logpersist.stop': True, }[command] ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_not_called() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test__enable_logpersist_with_missing_all_logpersist( self, MockFastboot, MockAdbProxy): def adb_shell_helper(command): if command == 'logpersist.start': raise MOCK_LOGPERSIST_START_MISSING_ADB_ERROR elif command == 'logpersist.stop --clear': raise MOCK_LOGPERSIST_STOP_MISSING_ADB_ERROR else: return b'' mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { 'ro.build.id': 'AB42', 'ro.build.type': 'userdebug', 'ro.debuggable': '1', } mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': False, 'logpersist.stop': False, }[command] mock_adb_proxy.shell.side_effect = adb_shell_helper ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_not_called() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test__enable_logpersist_with_missing_logpersist_stop( self, MockFastboot, MockAdbProxy): def adb_shell_helper(command): if command == 'logpersist.stop --clear': raise MOCK_LOGPERSIST_STOP_MISSING_ADB_ERROR else: return b'' mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { 'ro.build.id': 'AB42', 'ro.build.type': 'userdebug', 'ro.debuggable': '1', } mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': True, 'logpersist.stop': False, }[command] mock_adb_proxy.shell.side_effect = adb_shell_helper ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_has_calls([ mock.call('logpersist.stop --clear'), ]) @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', return_value=mock.MagicMock()) @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test__enable_logpersist_with_missing_logpersist_start( self, MockFastboot, MockAdbProxy): def adb_shell_helper(command): if command == 'logpersist.start': raise MOCK_LOGPERSIST_START_MISSING_ADB_ERROR else: return b'' mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { 'ro.build.id': 'AB42', 'ro.build.type': 'userdebug', 'ro.debuggable': '1', } mock_adb_proxy.has_shell_command.side_effect = lambda command: { 'logpersist.start': False, 'logpersist.stop': True, }[command] mock_adb_proxy.shell.side_effect = adb_shell_helper ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_not_called() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy') @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', return_value=mock_android_device.MockFastbootProxy('1')) def test_clear_adb_log(self, MockFastboot, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) ad.adb.logcat = mock.MagicMock() ad.adb.logcat.side_effect = adb.AdbError( cmd='cmd', stdout=b'', stderr=b'failed to clear "main" log', ret_code=1) logcat_service = logcat.Logcat(ad) logcat_service.clear_adb_log()