__init__.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import py
  2. from _pytest import runner
  3. import pytest
  4. # copied from xdist remote
  5. def serialize_report(rep):
  6. import py
  7. d = rep.__dict__.copy()
  8. if hasattr(rep.longrepr, 'toterminal'):
  9. d['longrepr'] = str(rep.longrepr)
  10. else:
  11. d['longrepr'] = rep.longrepr
  12. for name in d:
  13. if isinstance(d[name], py.path.local):
  14. d[name] = str(d[name])
  15. elif name == "result":
  16. d[name] = None # for now
  17. return d
  18. # copied from xdist remote
  19. def unserialize_report(name, reportdict):
  20. if name == "testreport":
  21. return runner.TestReport(**reportdict)
  22. elif name == "collectreport":
  23. return runner.CollectReport(**reportdict)
  24. def pytest_addoption(parser):
  25. try:
  26. __import__('xdist.boxed')
  27. except ImportError:
  28. # dont register own option if xdist.boxed is availiable
  29. group = parser.getgroup("boxed", "boxed subprocess test execution")
  30. group.addoption(
  31. '--boxed',
  32. action="store_true", dest="boxed", default=False,
  33. help="box each test run in a separate process (unix)")
  34. @pytest.mark.tryfirst
  35. def pytest_runtest_protocol(item):
  36. if item.config.getvalue("boxed"):
  37. reports = forked_run_report(item)
  38. for rep in reports:
  39. item.ihook.pytest_runtest_logreport(report=rep)
  40. return True
  41. def forked_run_report(item):
  42. # for now, we run setup/teardown in the subprocess
  43. # XXX optionally allow sharing of setup/teardown
  44. from _pytest.runner import runtestprotocol
  45. EXITSTATUS_TESTEXIT = 4
  46. import marshal
  47. def runforked():
  48. try:
  49. reports = runtestprotocol(item, log=False)
  50. except KeyboardInterrupt:
  51. py.std.os._exit(EXITSTATUS_TESTEXIT)
  52. return marshal.dumps([serialize_report(x) for x in reports])
  53. ff = py.process.ForkedFunc(runforked)
  54. result = ff.waitfinish()
  55. if result.retval is not None:
  56. report_dumps = marshal.loads(result.retval)
  57. return [unserialize_report("testreport", x) for x in report_dumps]
  58. else:
  59. if result.exitstatus == EXITSTATUS_TESTEXIT:
  60. py.test.exit("forked test item %s raised Exit" % (item,))
  61. return [report_process_crash(item, result)]
  62. def report_process_crash(item, result):
  63. path, lineno = item._getfslineno()
  64. info = ("%s:%s: running the test CRASHED with signal %d" %
  65. (path, lineno, result.signal))
  66. from _pytest import runner
  67. call = runner.CallInfo(lambda: 0/0, "???")
  68. call.excinfo = info
  69. rep = runner.pytest_runtest_makereport(item, call)
  70. if result.out:
  71. rep.sections.append(("captured stdout", result.out))
  72. if result.err:
  73. rep.sections.append(("captured stderr", result.err))
  74. return rep