diff options
author | Bruno Oliveira <nicoddemus@gmail.com> | 2020-01-06 21:16:23 -0300 |
---|---|---|
committer | Bruno Oliveira <nicoddemus@gmail.com> | 2020-01-06 22:04:38 -0300 |
commit | 0e0006934019aba7a3bbec95e2fac7c1b82d1063 (patch) | |
tree | 23082977dbe4952b334beddb8249be4d02793846 /testing/test_reports.py | |
parent | 26a2e1aba7d9e157b4537bbeb24ad372e8f8b919 (diff) | |
download | pytest-0e0006934019aba7a3bbec95e2fac7c1b82d1063.tar.gz |
Fix serialization of 'None' reprcrashes
Tracebacks coming from remote processes crated by the multiprocess module
will contain "RemoteTracebacks" which don't have a 'reprcrash' attribute
Fix #5971
Diffstat (limited to 'testing/test_reports.py')
-rw-r--r-- | testing/test_reports.py | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/testing/test_reports.py b/testing/test_reports.py index ff813543c..f695965e9 100644 --- a/testing/test_reports.py +++ b/testing/test_reports.py @@ -305,6 +305,8 @@ class TestReportSerialization: data = report._to_json() loaded_report = report_class._from_json(data) + + assert loaded_report.failed check_longrepr(loaded_report.longrepr) # make sure we don't blow up on ``toterminal`` call; we don't test the actual output because it is very @@ -312,6 +314,66 @@ class TestReportSerialization: # elsewhere and we do check the contents of the longrepr object after loading it. loaded_report.longrepr.toterminal(tw_mock) + def test_chained_exceptions_no_reprcrash( + self, testdir, tw_mock, + ): + """Regression test for tracebacks without a reprcrash (#5971) + + This happens notably on exceptions raised by multiprocess.pool: the exception transfer + from subprocess to main process creates an artificial exception which, ExceptionInfo + can't obtain the ReprFileLocation from. + """ + testdir.makepyfile( + """ + # equivalent of multiprocessing.pool.RemoteTraceback + class RemoteTraceback(Exception): + def __init__(self, tb): + self.tb = tb + def __str__(self): + return self.tb + + def test_a(): + try: + raise ValueError('value error') + except ValueError as e: + # equivalent to how multiprocessing.pool.rebuild_exc does it + e.__cause__ = RemoteTraceback('runtime error') + raise e + """ + ) + reprec = testdir.inline_run() + + reports = reprec.getreports("pytest_runtest_logreport") + + def check_longrepr(longrepr): + assert isinstance(longrepr, ExceptionChainRepr) + assert len(longrepr.chain) == 2 + entry1, entry2 = longrepr.chain + tb1, fileloc1, desc1 = entry1 + tb2, fileloc2, desc2 = entry2 + + assert "RemoteTraceback: runtime error" in str(tb1) + assert "ValueError('value error')" in str(tb2) + + assert fileloc1 is None + assert fileloc2.message == "ValueError: value error" + + # 3 reports: setup/call/teardown: get the call report + assert len(reports) == 3 + report = reports[1] + + assert report.failed + check_longrepr(report.longrepr) + + data = report._to_json() + loaded_report = TestReport._from_json(data) + + assert loaded_report.failed + check_longrepr(loaded_report.longrepr) + + # for same reasons as previous test, ensure we don't blow up here + loaded_report.longrepr.toterminal(tw_mock) + class TestHooks: """Test that the hooks are working correctly for plugins""" |