def _CreateRunners(runner_factory, devices, timeout=None): """Creates a test runner for each device and calls SetUp() in parallel. Note: if a device is unresponsive the corresponding TestRunner will not be included in the returned list. Args: runner_factory: Callable that takes a device and index and returns a TestRunner object. devices: List of device serial numbers as strings. timeout: Watchdog timeout in seconds, defaults to the default timeout. Returns: A list of TestRunner objects. """ logging.warning('Creating %s test runners.' % len(devices)) runners = [] counter = _ThreadSafeCounter() threads = reraiser_thread.ReraiserThreadGroup([ reraiser_thread.ReraiserThread(_SetUp, [runner_factory, d, runners, counter], name=d[-4:]) for d in devices ]) threads.StartAll() threads.JoinAll(watchdog_timer.WatchdogTimer(timeout)) return runners
def _RunAllTests(runners, tests, num_retries, timeout=None): """Run all tests using the given TestRunners. Args: runners: a list of TestRunner objects. tests: a list of Tests to run using the given TestRunners. num_retries: number of retries for a test. timeout: watchdog timeout in seconds, defaults to the default timeout. Returns: A TestRunResults object. """ logging.warning('Running %s tests with %s test runners.' % (len(tests), len(runners))) tests_collection = _TestCollection([_Test(t) for t in tests]) results = [] watcher = watchdog_timer.WatchdogTimer(timeout) workers = reraiser_thread.ReraiserThreadGroup([ reraiser_thread.ReraiserThread( _RunTestsFromQueue, [r, tests_collection, results, watcher, num_retries], name=r.device[-4:]) for r in runners ]) workers.StartAll() workers.JoinAll(watcher) run_results = base_test_result.TestRunResults() for r in results: run_results.AddTestRunResults(r) return run_results
def __call__(self, *args, **kwargs): """Emulate calling |self| with |args| and |kwargs|. Note that this call is asynchronous. Call pFinish on the return value to block until the call finishes. Returns: A Parallelizer wrapping the ReraiserThreadGroup running the call in parallel. Raises: AttributeError if the wrapped objects aren't callable. """ self.pGet(None) if not self._objs: raise AttributeError('Nothing to call.') for o in self._objs: if not callable(o): raise AttributeError("'%s' is not callable" % o.__name__) r = type(self)(self._orig_objs) r._objs = reraiser_thread.ReraiserThreadGroup([ reraiser_thread.ReraiserThread(o, args=args, kwargs=kwargs, name='%s.%s' % (str(d), o.__name__)) for d, o in zip(self._orig_objs, self._objs) ]) r._objs.StartAll() # pylint: disable=W0212 return r
def pMap(self, f, *args, **kwargs): """Map a function across the current wrapped objects in parallel. This calls f(o, *args, **kwargs) for each o in the set of wrapped objects. Note that this call is asynchronous. Call pFinish on the return value to block until the call finishes. Args: f: The function to call. args: The positional args to pass to f. kwargs: The keyword args to pass to f. Returns: A Parallelizer wrapping the ReraiserThreadGroup running the map in parallel. """ self._assertNoShadow('pMap') r = type(self)(self._orig_objs) r._objs = reraiser_thread.ReraiserThreadGroup([ reraiser_thread.ReraiserThread(f, args=tuple([o] + list(args)), kwargs=kwargs, name='%s(%s)' % (f.__name__, d)) for d, o in zip(self._orig_objs, self._objs) ]) r._objs.StartAll() # pylint: disable=W0212 return r
def Run(func, timeout, retries, args=[], kwargs={}): """Runs the passed function in a separate thread with timeouts and retries. Args: func: the function to be wrapped. timeout: the timeout in seconds for each try. retries: the number of retries. args: list of positional args to pass to |func|. kwargs: dictionary of keyword args to pass to |func|. Returns: The return value of func(*args, **kwargs). """ # The return value uses a list because Python variables are references, not # values. Closures make a copy of the reference, so updating the closure's # reference wouldn't update where the original reference pointed. ret = [None] def RunOnTimeoutThread(): ret[0] = func(*args, **kwargs) while True: try: name = 'TimeoutThread-for-%s' % threading.current_thread().name thread_group = reraiser_thread.ReraiserThreadGroup([ reraiser_thread.ReraiserThread(RunOnTimeoutThread, name=name) ]) thread_group.StartAll() thread_group.JoinAll(watchdog_timer.WatchdogTimer(timeout)) return ret[0] except: if retries <= 0: raise retries -= 1
def _RunAllTests(runners, test_collection_factory, num_retries, timeout=None, tag_results_with_device=False): """Run all tests using the given TestRunners. Args: runners: A list of TestRunner objects. test_collection_factory: A callable to generate a _TestCollection object for each test runner. num_retries: Number of retries for a test. timeout: Watchdog timeout in seconds. tag_results_with_device: If True, appends the name of the device on which the test was run to the test name. Used when replicating to identify which device ran each copy of the test, and to ensure each copy of the test is recorded separately. Returns: A tuple of (TestRunResults object, exit code) """ logging.warning('Running tests with %s test runners.' % (len(runners))) results = [] exit_code = 0 run_results = base_test_result.TestRunResults() watcher = watchdog_timer.WatchdogTimer(timeout) test_collections = [test_collection_factory() for _ in runners] threads = [ reraiser_thread.ReraiserThread( _RunTestsFromQueue, [r, tc, results, watcher, num_retries, tag_results_with_device], name=r.device_serial[-4:]) for r, tc in zip(runners, test_collections) ] workers = reraiser_thread.ReraiserThreadGroup(threads) workers.StartAll() # Catch DeviceUnreachableErrors and set a warning exit code try: workers.JoinAll(watcher) except ( adb_wrapper.DeviceUnreachableError, # TODO(jbudorick) Remove this once the underlying implementations # for the above are switched or wrapped. android_commands.errors.DeviceUnresponsiveError) as e: logging.error(e) exit_code = constants.WARNING_EXIT_CODE assert all([len(tc) == 0 for tc in test_collections]), ( 'Some tests were not run, all devices are likely offline (ran %d tests)' % len(run_results.GetAll())) for r in results: run_results.AddTestRunResults(r) if not run_results.DidRunPass(): exit_code = constants.ERROR_EXIT_CODE return (run_results, exit_code)
def testJoinRaise(self): def f(): raise TestException group = reraiser_thread.ReraiserThreadGroup( [reraiser_thread.ReraiserThread(f) for _ in xrange(5)]) group.StartAll() with self.assertRaises(TestException): group.JoinAll()
def _RunAllTests(runners, test_collection_factory, num_retries, timeout=None, tag_results_with_device=False): """Run all tests using the given TestRunners. Args: runners: A list of TestRunner objects. test_collection_factory: A callable to generate a TestCollection object for each test runner. num_retries: Number of retries for a test. timeout: Watchdog timeout in seconds. tag_results_with_device: If True, appends the name of the device on which the test was run to the test name. Used when replicating to identify which device ran each copy of the test, and to ensure each copy of the test is recorded separately. Returns: A tuple of (TestRunResults object, exit code) """ logging.warning('Running tests with %s test runners.' % (len(runners))) results = [] exit_code = 0 run_results = base_test_result.TestRunResults() watcher = watchdog_timer.WatchdogTimer(timeout) test_collections = [test_collection_factory() for _ in runners] threads = [ reraiser_thread.ReraiserThread( _RunTestsFromQueue, [r, tc, results, watcher, num_retries, tag_results_with_device], name=r.device_serial[-4:]) for r, tc in zip(runners, test_collections)] workers = reraiser_thread.ReraiserThreadGroup(threads) workers.StartAll() try: workers.JoinAll(watcher) except device_errors.CommandFailedError: logging.exception('Command failed on device.') except device_errors.CommandFailedError: logging.exception('Command timed out on device.') except device_errors.DeviceUnreachableError: logging.exception('Device became unreachable.') if not all((len(tc) == 0 for tc in test_collections)): logging.error('Only ran %d tests (all devices are likely offline).' % len(results)) for tc in test_collections: run_results.AddResults(base_test_result.BaseTestResult( t, base_test_result.ResultType.UNKNOWN) for t in tc.test_names()) for r in results: run_results.AddTestRunResults(r) if not run_results.DidRunPass(): exit_code = constants.ERROR_EXIT_CODE return (run_results, exit_code)
def _TearDownRunners(runners): """Calls TearDown() for each test runner in parallel. Args: runners: a list of TestRunner objects. """ threads = reraiser_thread.ReraiserThreadGroup([ reraiser_thread.ReraiserThread(runner.TearDown) for runner in runners ]) threads.StartAll() threads.JoinAll()
def testInit(self): ran = [False] * 5 def f(i): ran[i] = True group = reraiser_thread.ReraiserThreadGroup( [reraiser_thread.ReraiserThread(f, args=[i]) for i in range(5)]) group.StartAll() group.JoinAll() for v in ran: self.assertTrue(v)
def _TearDownRunners(runners, timeout=None): """Calls TearDown() for each test runner in parallel. Args: runners: A list of TestRunner objects. timeout: Watchdog timeout in seconds, defaults to the default timeout. """ threads = reraiser_thread.ReraiserThreadGroup( [reraiser_thread.ReraiserThread(r.TearDown, name=r.device[-4:]) for r in runners]) threads.StartAll() threads.JoinAll(watchdog_timer.WatchdogTimer(timeout))
def testJoinTimeout(self): def f(): pass event = threading.Event() def g(): event.wait() group = reraiser_thread.ReraiserThreadGroup( [reraiser_thread.ReraiserThread(g), reraiser_thread.ReraiserThread(f)]) group.StartAll() with self.assertRaises(reraiser_thread.TimeoutError): group.JoinAll(watchdog_timer.WatchdogTimer(0.01)) event.set()
def _RunAllTests(runners, test_collection_factory, num_retries, timeout=None, tag_results_with_device=False): """Run all tests using the given TestRunners. Args: runners: A list of TestRunner objects. test_collection_factory: A callable to generate a _TestCollection object for each test runner. num_retries: Number of retries for a test. timeout: Watchdog timeout in seconds. tag_results_with_device: If True, appends the name of the device on which the test was run to the test name. Used when replicating to identify which device ran each copy of the test, and to ensure each copy of the test is recorded separately. Returns: A tuple of (TestRunResults object, exit code) """ logging.warning('Running tests with %s test runners.' % (len(runners))) results = [] exit_code = 0 watcher = watchdog_timer.WatchdogTimer(timeout) workers = reraiser_thread.ReraiserThreadGroup([ reraiser_thread.ReraiserThread(_RunTestsFromQueue, [ r, test_collection_factory(), results, watcher, num_retries, tag_results_with_device ], name=r.device[-4:]) for r in runners ]) run_results = base_test_result.TestRunResults() workers.StartAll() # Catch DeviceUnresponsiveErrors and set a warning exit code try: workers.JoinAll(watcher) except android_commands.errors.DeviceUnresponsiveError as e: logging.error(e) exit_code = constants.WARNING_EXIT_CODE for r in results: run_results.AddTestRunResults(r) if not run_results.DidRunPass(): exit_code = constants.ERROR_EXIT_CODE return (run_results, exit_code)
def Run(func, timeout, retries, args=None, kwargs=None): """Runs the passed function in a separate thread with timeouts and retries. Args: func: the function to be wrapped. timeout: the timeout in seconds for each try. retries: the number of retries. args: list of positional args to pass to |func|. kwargs: dictionary of keyword args to pass to |func|. Returns: The return value of func(*args, **kwargs). """ if not args: args = [] if not kwargs: kwargs = {} # The return value uses a list because Python variables are references, not # values. Closures make a copy of the reference, so updating the closure's # reference wouldn't update where the original reference pointed. ret = [None] def RunOnTimeoutThread(): ret[0] = func(*args, **kwargs) num_try = 1 while True: child_thread = TimeoutRetryThread( RunOnTimeoutThread, timeout, name='TimeoutThread-%d-for-%s' % (num_try, threading.current_thread().name)) try: thread_group = reraiser_thread.ReraiserThreadGroup([child_thread]) thread_group.StartAll() thread_group.JoinAll(child_thread.GetWatcher()) return ret[0] except: child_thread.LogTimeoutException() if num_try > retries: raise num_try += 1
def _RunAllTests(runners, tests): """Run all tests using the given TestRunners. Args: runners: a list of TestRunner objects. tests: a list of Tests to run using the given TestRunners. Returns: A TestResults object. """ logging.warning('****Running %s tests with %s test runners.' % (len(tests), len(runners))) tests_collection = _TestCollection([_Test(t) for t in tests]) results = [] workers = reraiser_thread.ReraiserThreadGroup([ reraiser_thread.ReraiserThread(_RunTestsFromQueue, [r, tests_collection, results]) for r in runners ]) workers.StartAll() workers.JoinAll() return test_result.TestResults.FromTestResults(results)
def _CreateRunners(runner_factory, devices): """Creates a test runner for each device and calls SetUp() in parallel. Note: if a device is unresponsive the corresponding TestRunner will not be included in the returned list. Args: runner_factory: callable that takes a device and returns a TestRunner. devices: list of device serial numbers as strings. Returns: A list of TestRunner objects. """ logging.warning('****Creating %s test runners.' % len(devices)) test_runners = [] threads = reraiser_thread.ReraiserThreadGroup([ reraiser_thread.ReraiserThread(_SetUp, [runner_factory, d, test_runners]) for d in devices ]) threads.StartAll() threads.JoinAll() return test_runners