def take_bug_reports(ads, test_name, begin_time): """Takes bug reports on a list of android devices. If you want to take a bug report, call this function with a list of android_device objects in on_fail. But reports will be taken on all the devices in the list concurrently. Bug report takes a relative long time to take, so use this cautiously. Args: ads: A list of AndroidDevice instances. test_name: Name of the test method that triggered this bug report. begin_time: timestamp taken when the test started, can be either string or int. """ begin_time = mobly_logger.normalize_log_line_timestamp(str(begin_time)) def take_br(test_name, begin_time, ad): ad.take_bug_report(test_name, begin_time) args = [(test_name, begin_time, ad) for ad in ads] utils.concurrent_exec(take_br, args)
def test_concurrent_exec_makes_all_calls(self): mock_function = mock.MagicMock() _ = utils.concurrent_exec(mock_function, [ (1, 1), (2, 2), (3, 3), ]) self.assertEqual(mock_function.call_count, 3) mock_function.assert_has_calls( [mock.call(1, 1), mock.call(2, 2), mock.call(3, 3)], any_order=True)
def test_concurrent_exec_when_custom_max_workers(self): def adder(a, b): return a + b with mock.patch.object( futures, 'ThreadPoolExecutor', wraps=futures.ThreadPoolExecutor) as thread_pool_spy: results = utils.concurrent_exec(adder, [(1, 1), (2, 2)], max_workers=1) thread_pool_spy.assert_called_once_with(max_workers=1) self.assertEqual(len(results), 2) self.assertIn(2, results) self.assertIn(4, results)
def test_concurrent_exec_when_multiple_exceptions_makes_all_calls(self): mock_call_recorder = mock.MagicMock() lock_call_count = threading.Lock() def fake_int(a, ): with lock_call_count: mock_call_recorder(a) return int(a) utils.concurrent_exec(fake_int, [ (1, ), ('not_int1', ), ('not_int2', ), (5435, ), ]) self.assertEqual(mock_call_recorder.call_count, 4) mock_call_recorder.assert_has_calls([ mock.call(1), mock.call('not_int1'), mock.call('not_int2'), mock.call(5435), ], any_order=True)
def test_concurrent_exec_when_exception_makes_all_calls(self): mock_call_recorder = mock.MagicMock() def fake_int(a, ): mock_call_recorder(a) return int(a) results = utils.concurrent_exec(fake_int, [ (1, ), ('123', ), ('not_int', ), (5435, ), ]) self.assertEqual(mock_call_recorder.call_count, 4) mock_call_recorder.assert_has_calls([ mock.call(1), mock.call('123'), mock.call('not_int'), mock.call(5435), ], any_order=True)
def test_concurrent_exec_when_exception_generates_results(self): mock_call_recorder = mock.MagicMock() def fake_int(a, ): mock_call_recorder(a) return int(a) results = utils.concurrent_exec(fake_int, [ (1, ), ('123', ), ('not_int', ), (5435, ), ]) self.assertEqual(len(results), 4) self.assertIn(1, results) self.assertIn(123, results) self.assertIn(5435, results) exceptions = [ result for result in results if isinstance(result, Exception) ] self.assertEqual(len(exceptions), 1) self.assertIsInstance(exceptions[0], ValueError)
def test_concurrent_exec_when_raising_exception_makes_all_calls(self): mock_call_recorder = mock.MagicMock() def fake_int(a, ): mock_call_recorder(a) return int(a) with self.assertRaisesRegex(RuntimeError, '.*not_int.*'): _ = utils.concurrent_exec(fake_int, [ (1, ), ('123', ), ('not_int', ), (5435, ), ], raise_on_exception=True) self.assertEqual(mock_call_recorder.call_count, 4) mock_call_recorder.assert_has_calls([ mock.call(1), mock.call('123'), mock.call('not_int'), mock.call(5435), ], any_order=True)
def test_concurrent_exec_when_multiple_exceptions_generates_results(self): mock_call_recorder = mock.MagicMock() lock_call_count = threading.Lock() def fake_int(a,): with lock_call_count: mock_call_recorder(a) return int(a) results = utils.concurrent_exec(fake_int, [ (1,), ('not_int1',), ('not_int2',), (5435,), ]) self.assertEqual(len(results), 4) self.assertIn(1, results) self.assertIn(5435, results) exceptions = [result for result in results if isinstance(result, Exception)] self.assertEqual(len(exceptions), 2) self.assertIsInstance(exceptions[0], ValueError) self.assertIsInstance(exceptions[1], ValueError) self.assertNotEqual(exceptions[0], exceptions[1])