def _unschedule(self, coro): """Unschedule a coroutine. Unprime any pending triggers""" if coro in self._pending_coros: assert not coro.has_started() self._pending_coros.remove(coro) # Close coroutine so there is no RuntimeWarning that it was never awaited coro.close() return # Unprime the trigger this coroutine is waiting on trigger = coro._trigger if trigger is not None: coro._trigger = None if coro in self._trigger2coros.setdefault(trigger, []): self._trigger2coros[trigger].remove(coro) if not self._trigger2coros[trigger]: trigger.unprime() del self._trigger2coros[trigger] assert self._test is not None if coro is self._test: if _debug: self.log.debug(f"Unscheduling test {coro}") if not self._terminate: self._terminate = True self._cleanup() elif Join(coro) in self._trigger2coros: self._react(Join(coro)) else: try: # throws an error if the background coroutine errored # and no one was monitoring it coro._outcome.get() except (TestComplete, AssertionError) as e: coro.log.info("Test stopped by this forked coroutine") e = remove_traceback_frames(e, ["_unschedule", "get"]) self._abort_test(e) except Exception as e: coro.log.error("Exception raised by this forked coroutine") e = remove_traceback_frames(e, ["_unschedule", "get"]) warnings.warn( '"Unwatched" tasks that throw exceptions will not cause the test to fail. ' "See issue #2664 for more details.", FutureWarning, ) self._abort_test(e)
def _advance(self, outcome): """Advance to the next yield in this coroutine. Args: outcome: The :any:`outcomes.Outcome` object to resume with. Returns: The object yielded from the coroutine Raises: CoroutineComplete: If the coroutine returns or throws an error, self._outcome is set, and :exc:`CoroutineComplete` is thrown. """ try: self._started = True return outcome.send(self._coro) except ReturnValue as e: self._outcome = outcomes.Value(e.retval) raise CoroutineComplete() except StopIteration as e: retval = getattr(e, 'value', None) # for python >=3.3 self._outcome = outcomes.Value(retval) raise CoroutineComplete() except BaseException as e: self._outcome = outcomes.Error(remove_traceback_frames(e, ['_advance', 'send'])) raise CoroutineComplete()
def capture(fn, *args, **kwargs): """ Obtain an `Outcome` representing the result of a function call """ try: return Value(fn(*args, **kwargs)) except BaseException as e: e = remove_traceback_frames(e, ['capture']) return Error(e)
def _score_test(self, test: Test, outcome: Outcome) -> Tuple[bool, bool]: """ Given a test and the test's outcome, determine if the test met expectations and log pertinent information """ # scoring outcomes result_pass = True sim_failed = False try: outcome.get() except Exception as e: result = remove_traceback_frames(e, ["_score_test", "get"]) else: result = TestSuccess() if (isinstance(result, TestSuccess) and not test.expect_fail and not test.expect_error): self._log_test_passed(test, None, None) elif isinstance(result, AssertionError) and test.expect_fail: self._log_test_passed(test, result, "failed as expected") elif isinstance(result, TestSuccess) and test.expect_error: self._log_test_failed(test, None, "passed but we expected an error") result_pass = False elif isinstance(result, TestSuccess): self._log_test_failed(test, None, "passed but we expected a failure") result_pass = False elif isinstance(result, SimFailure): if isinstance(result, test.expect_error): self._log_test_passed(test, result, "errored as expected") else: self.log.error( "Test error has lead to simulator shutting us down") result_pass = False # whether we expected it or not, the simulation has failed unrecoverably sim_failed = True elif test.expect_error: if isinstance(result, test.expect_error): self._log_test_passed(test, result, "errored as expected") else: self._log_test_failed(test, result, "errored with unexpected type ") result_pass = False else: self._log_test_failed(test, result, None) result_pass = False if _pdb_on_exception: pdb.post_mortem(result.__traceback__) return result_pass, sim_failed
def _wait_callback(trigger, callback): """ Wait for a trigger, and call `callback` with the outcome of the yield. """ try: ret = outcomes.Value((yield trigger)) except BaseException as exc: # hide this from the traceback ret = outcomes.Error(remove_traceback_frames(exc, ['_wait_callback'])) callback(ret)
def unschedule(self, coro): """Unschedule a coroutine. Unprime any pending triggers""" # Unprime the trigger this coroutine is waiting on try: trigger = self._coro2trigger.pop(coro) except KeyError: # coroutine probably finished pass else: if coro in self._trigger2coros.setdefault(trigger, []): self._trigger2coros[trigger].remove(coro) if not self._trigger2coros[trigger]: trigger.unprime() del self._trigger2coros[trigger] assert self._test is not None if coro is self._test: if _debug: self.log.debug("Unscheduling test {}".format(coro)) if not self._terminate: self._terminate = True self.cleanup() elif Join(coro) in self._trigger2coros: self.react(Join(coro)) else: try: # throws an error if the background coroutine errored # and no one was monitoring it coro._outcome.get() except (TestComplete, AssertionError) as e: coro.log.info("Test stopped by this forked coroutine") outcome = outcomes.Error( remove_traceback_frames(e, ['unschedule', 'get'])) self._test._force_outcome(outcome) except Exception as e: coro.log.error("Exception raised by this forked coroutine") outcome = outcomes.Error( remove_traceback_frames(e, ['unschedule', 'get'])) self._test._force_outcome(outcome)
async def _wait_callback(trigger, callback): """ Wait for a trigger, and call `callback` with the outcome of the await. """ try: ret = outcomes.Value(await trigger) except BaseException as exc: # hide this from the traceback ret = outcomes.Error(remove_traceback_frames(exc, ["_wait_callback"])) callback(ret)
def _unschedule(self, coro): """Unschedule a coroutine. Unprime any pending triggers""" # Unprime the trigger this coroutine is waiting on trigger = coro._trigger if trigger is not None: coro._trigger = None if coro in self._trigger2coros.setdefault(trigger, []): self._trigger2coros[trigger].remove(coro) if not self._trigger2coros[trigger]: trigger.unprime() del self._trigger2coros[trigger] assert self._test is not None if coro is self._test: if _debug: self.log.debug(f"Unscheduling test {coro}") if not self._terminate: self._terminate = True self._cleanup() elif Join(coro) in self._trigger2coros: self._react(Join(coro)) else: try: # throws an error if the background coroutine errored # and no one was monitoring it coro._outcome.get() except (TestComplete, AssertionError) as e: coro.log.info("Test stopped by this forked coroutine") e = remove_traceback_frames(e, ['_unschedule', 'get']) self._test.abort(e) except Exception as e: coro.log.error("Exception raised by this forked coroutine") e = remove_traceback_frames(e, ['_unschedule', 'get']) self._test.abort(e)
def _advance(self, outcome: outcomes.Outcome) -> typing.Any: """Advance to the next yield in this coroutine. Args: outcome: The :any:`outcomes.Outcome` object to resume with. Returns: The object yielded from the coroutine or None if coroutine finished """ try: self._started = True return outcome.send(self._coro) except ReturnValue as e: self._outcome = outcomes.Value(e.retval) except StopIteration as e: self._outcome = outcomes.Value(e.value) except BaseException as e: self._outcome = outcomes.Error( remove_traceback_frames(e, ["_advance", "send"]))
def handle_result(self, test): """Handle a test completing. Dump result to XML and schedule the next test (if any). Args: test: The test that completed """ assert test is self._running_test real_time = time.time() - test.start_time sim_time_ns = get_sim_time('ns') - test.start_sim_time ratio_time = self._safe_divide(sim_time_ns, real_time) self.xunit.add_testcase(name=test.funcname, classname=test.module, time=repr(real_time), sim_time_ns=repr(sim_time_ns), ratio_time=repr(ratio_time)) # Helper for logging result def _result_was(): result_was = ("{} (result was {})".format( test.funcname, result.__class__.__name__)) return result_was result_pass = True # check what exception the test threw try: test._outcome.get() except Exception as e: if sys.version_info >= (3, 5): result = remove_traceback_frames(e, ['handle_result', 'get']) # newer versions of the `logging` module accept plain exception objects exc_info = result elif sys.version_info >= (3, ): result = remove_traceback_frames(e, ['handle_result', 'get']) # newer versions of python have Exception.__traceback__ exc_info = (type(result), result, result.__traceback__) else: # Python 2 result = e exc_info = remove_traceback_frames(sys.exc_info(), ['handle_result', 'get']) else: result = TestSuccess() if (isinstance(result, TestSuccess) and not test.expect_fail and not test.expect_error): self.log.info("Test Passed: %s" % test.funcname) elif (isinstance(result, AssertionError) and test.expect_fail): self.log.info("Test failed as expected: " + _result_was()) elif (isinstance(result, TestSuccess) and test.expect_error): self.log.error("Test passed but we expected an error: " + _result_was()) self._add_failure(result) result_pass = False elif isinstance(result, TestSuccess): self.log.error("Test passed but we expected a failure: " + _result_was()) self._add_failure(result) result_pass = False elif isinstance(result, SimFailure): if isinstance(result, test.expect_error): self.log.info("Test errored as expected: " + _result_was()) else: self.log.error( "Test error has lead to simulator shutting us " "down", exc_info=exc_info) self._add_failure(result) self._store_test_result(test.module, test.funcname, False, sim_time_ns, real_time, ratio_time) self.tear_down() return elif test.expect_error: if isinstance(result, test.expect_error): self.log.info("Test errored as expected: " + _result_was()) else: self.log.info("Test errored with unexpected type: " + _result_was()) self._add_failure(result) result_pass = False else: self.log.error("Test Failed: " + _result_was(), exc_info=exc_info) self._add_failure(result) result_pass = False self._store_test_result(test.module, test.funcname, result_pass, sim_time_ns, real_time, ratio_time) self.execute()
def _score_test(self, test: Test, outcome: Outcome) -> Tuple[bool, bool]: """ Given a test and the test's outcome, determine if the test met expectations and log pertinent information """ # Helper for logging result def _result_was(): result_was = ("{} (result was {})".format( test.__qualname__, type(result).__qualname__)) return result_was # scoring outcomes result_pass = True sim_failed = False try: outcome.get() except Exception as e: result = remove_traceback_frames(e, ['_score_test', 'get']) else: result = TestSuccess() if (isinstance(result, TestSuccess) and not test.expect_fail and not test.expect_error): self.log.info("Test Passed: %s" % test.__qualname__) elif (isinstance(result, AssertionError) and test.expect_fail): self.log.info("Test failed as expected: " + _result_was()) elif (isinstance(result, TestSuccess) and test.expect_error): self.log.error("Test passed but we expected an error: " + _result_was()) result_pass = False elif isinstance(result, TestSuccess): self.log.error("Test passed but we expected a failure: " + _result_was()) result_pass = False elif isinstance(result, SimFailure): if isinstance(result, test.expect_error): self.log.info("Test errored as expected: " + _result_was()) else: self.log.error( "Test error has lead to simulator shutting us " "down", exc_info=result) result_pass = False # whether we expected it or not, the simulation has failed unrecoverably sim_failed = True elif test.expect_error: if isinstance(result, test.expect_error): self.log.info("Test errored as expected: " + _result_was()) else: self.log.error("Test errored with unexpected type: " + _result_was(), exc_info=result) result_pass = False else: self.log.error("Test Failed: " + _result_was(), exc_info=result) result_pass = False if _pdb_on_exception: pdb.post_mortem(result.__traceback__) return result_pass, sim_failed
def _score_test(self, test, outcome): """ Given a test and the test's outcome, determine if the test met expectations and log pertinent information """ # Helper for logging result def _result_was(): result_was = ("{} (result was {})".format( test.__name__, result.__class__.__name__)) return result_was # scoring outcomes result_pass = True sim_failed = False try: outcome.get() except Exception as e: if sys.version_info >= (3, 5): result = remove_traceback_frames(e, ['_score_test', 'get']) # newer versions of the `logging` module accept plain exception objects exc_info = result elif sys.version_info >= (3, ): result = remove_traceback_frames(e, ['_score_test', 'get']) # newer versions of python have Exception.__traceback__ exc_info = (type(result), result, result.__traceback__) else: # Python 2 result = e exc_info = remove_traceback_frames(sys.exc_info(), ['_score_test', 'get']) else: result = TestSuccess() if (isinstance(result, TestSuccess) and not test.expect_fail and not test.expect_error): self.log.info("Test Passed: %s" % test.__name__) elif (isinstance(result, AssertionError) and test.expect_fail): self.log.info("Test failed as expected: " + _result_was()) elif (isinstance(result, TestSuccess) and test.expect_error): self.log.error("Test passed but we expected an error: " + _result_was()) result_pass = False elif isinstance(result, TestSuccess): self.log.error("Test passed but we expected a failure: " + _result_was()) result_pass = False elif isinstance(result, SimFailure): if isinstance(result, test.expect_error): self.log.info("Test errored as expected: " + _result_was()) else: self.log.error( "Test error has lead to simulator shutting us " "down", exc_info=exc_info) result_pass = False # whether we expected it or not, the simulation has failed unrecoverably sim_failed = True elif test.expect_error: if isinstance(result, test.expect_error): self.log.info("Test errored as expected: " + _result_was()) else: self.log.error("Test errored with unexpected type: " + _result_was(), exc_info=exc_info) result_pass = False else: self.log.error("Test Failed: " + _result_was(), exc_info=exc_info) result_pass = False if _pdb_on_exception: if sys.version_info >= (3, 5): traceback = exc_info.__traceback__ else: traceback = exc_info[2] pdb.post_mortem(traceback) return result_pass, sim_failed
def without_frames(self, frame_names): ret = copy.copy(self) ret.error_tb = remove_traceback_frames(ret.error_tb, frame_names) return ret
def without_frames(self, frame_names): return Error(remove_traceback_frames(self.error, frame_names))