From 7afc30d1300990b96f8199c05bc9442ee17917a7 Mon Sep 17 00:00:00 2001 From: arigo Date: Fri, 12 Sep 2008 22:35:18 +0200 Subject: [PATCH] [svn r58095] (pedronis, arigo) KeyboardInterrupt handling: * in --verbose mode, print a detailed traceback at the end of the report. * in non-verbose mode, only print the file name and line number where the KeyboardInterrupt occurred. That's the minimal amount of information that is of any help at all to locate an infinite loop somewhere. --HG-- branch : trunk --- py/test/event.py | 6 ++++- py/test/report/terminal.py | 9 +++++++ py/test/report/testing/test_terminal.py | 32 ++++++++++++++++++------- py/test/session.py | 9 ++++--- 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/py/test/event.py b/py/test/event.py index 7301e49d9..95ef8771c 100644 --- a/py/test/event.py +++ b/py/test/event.py @@ -45,8 +45,12 @@ class TestrunStart(BaseEvent): self.timestart = time.time() class TestrunFinish(BaseEvent): - def __init__(self, exitstatus=0): + def __init__(self, exitstatus=0, excinfo=None): self.exitstatus = exitstatus + if excinfo is None: + self.excrepr = None + else: + self.excrepr = excinfo.getrepr() self.timeend = time.time() class InternalException(BaseEvent): diff --git a/py/test/report/terminal.py b/py/test/report/terminal.py index d183b6ad2..1f1519ab4 100644 --- a/py/test/report/terminal.py +++ b/py/test/report/terminal.py @@ -132,6 +132,8 @@ class TerminalReporter(BaseReporter): if ev.exitstatus in (0, 1, 2): self.summary_failures() self.summary_skips() + if ev.excrepr is not None: + self.summary_final_exc(ev.excrepr) if ev.exitstatus == 2: self.write_sep("!", "KEYBOARD INTERRUPT") self.summary_deselected() @@ -201,6 +203,13 @@ class TerminalReporter(BaseReporter): for num, fspath, lineno, reason in folded_skips: self._tw.line("%s:%d: [%d] %s" %(fspath, lineno, num, reason)) + def summary_final_exc(self, excrepr): + self.write_sep("!") + if self.config.option.verbose: + excrepr.toterminal(self._tw) + else: + excrepr.reprcrash.toterminal(self._tw) + def out_hostinfo(self): self._tw.line("host 0: %s %s - Python %s" % (py.std.sys.platform, diff --git a/py/test/report/testing/test_terminal.py b/py/test/report/testing/test_terminal.py index 827bae738..0baaccb0a 100644 --- a/py/test/report/testing/test_terminal.py +++ b/py/test/report/testing/test_terminal.py @@ -207,25 +207,41 @@ class TestTerminal(InlineCollection): print s assert s.find("test_show_path_before_running_test.py") != -1 - def test_keyboard_interrupt(self): + def test_keyboard_interrupt(self, verbose=False): modcol = self.getmodulecol(""" def test_foobar(): assert 0 def test_spamegg(): import py; py.test.skip('skip me please!') - """, configargs=("--showskipsummary",), withsession=True) + def test_interrupt_me(): + raise KeyboardInterrupt # simulating the user + """, configargs=("--showskipsummary",) + ("-v",)*verbose, + withsession=True) stringio = py.std.cStringIO.StringIO() rep = TerminalReporter(modcol._config, bus=self.session.bus, file=stringio) rep.processevent(event.TestrunStart()) - for item in self.session.genitems([modcol]): - ev = basic_run_report(item) - rep.processevent(ev) + try: + for item in self.session.genitems([modcol]): + ev = basic_run_report(item) + rep.processevent(ev) + except KeyboardInterrupt: + excinfo = py.code.ExceptionInfo() + else: + py.test.fail("no KeyboardInterrupt??") s = popvalue(stringio) - assert s.find("test_keyboard_interrupt.py Fs") != -1 - rep.processevent(event.TestrunFinish(exitstatus=2)) + if not verbose: + assert s.find("_keyboard_interrupt.py Fs") != -1 + rep.processevent(event.TestrunFinish(exitstatus=2, excinfo=excinfo)) assert_stringio_contains_lines(stringio, [ " def test_foobar():", "> assert 0", "E assert 0", ]) - assert "Skipped: 'skip me please!'" in stringio.getvalue() + text = stringio.getvalue() + assert "Skipped: 'skip me please!'" in text + assert "_keyboard_interrupt.py:6: KeyboardInterrupt" in text + see_details = "raise KeyboardInterrupt # simulating the user" in text + assert see_details == verbose + + def test_verbose_keyboard_interrupt(self): + self.test_keyboard_interrupt(verbose=True) diff --git a/py/test/session.py b/py/test/session.py index 6c6e05287..daafe4f70 100644 --- a/py/test/session.py +++ b/py/test/session.py @@ -103,9 +103,10 @@ class Session(object): if self.config.option.exitfirst: self.shouldstop = True - def sessionfinishes(self, exitstatus=0): + def sessionfinishes(self, exitstatus=0, excinfo=None): """ teardown any resources after a test run. """ - self.bus.notify(event.TestrunFinish(exitstatus=exitstatus)) + self.bus.notify(event.TestrunFinish(exitstatus=exitstatus, + excinfo=excinfo)) self.bus.unsubscribe(self._processfailures) #self.reporter.deactivate() return self._failurelist @@ -123,6 +124,7 @@ class Session(object): self.sessionstarts() self.bus.notify(makehostup()) exitstatus = outcome.EXIT_OK + captured_excinfo = None try: for item in self.collect(colitems): if self.shouldstop: @@ -131,13 +133,14 @@ class Session(object): self.runtest(item) py.test.collect.Item._setupstate.teardown_all() except KeyboardInterrupt: + captured_excinfo = py.code.ExceptionInfo() exitstatus = outcome.EXIT_INTERRUPTED except: self.bus.notify(event.InternalException()) exitstatus = outcome.EXIT_INTERNALERROR if self._failurelist and exitstatus == 0: exitstatus = outcome.EXIT_TESTSFAILED - self.sessionfinishes(exitstatus=exitstatus) + self.sessionfinishes(exitstatus=exitstatus, excinfo=captured_excinfo) return exitstatus def runpdb(self, excinfo):