Merge branch 'master' into add_remote_hook

This commit is contained in:
Bruno Oliveira
2019-02-15 09:23:32 -02:00
committed by GitHub
15 changed files with 283 additions and 48 deletions

View File

@@ -229,9 +229,10 @@ class DSession(object):
if self.terminal and not self.sched.has_pending:
self.trdist.ensure_show_status()
self.terminal.write_line("")
self.terminal.write_line(
"scheduling tests via %s" % (self.sched.__class__.__name__)
)
if self.config.option.verbose > 0:
self.terminal.write_line(
"scheduling tests via %s" % (self.sched.__class__.__name__)
)
self.sched.schedule()
def worker_logstart(self, node, nodeid, location):
@@ -344,8 +345,11 @@ class TerminalDistReporter(object):
self.rewrite(self.getstatus())
def getstatus(self):
parts = ["%s %s" % (spec.id, self._status[spec.id]) for spec in self._specs]
return " / ".join(parts)
if self.config.option.verbose >= 0:
parts = ["%s %s" % (spec.id, self._status[spec.id]) for spec in self._specs]
return " / ".join(parts)
else:
return "bringing up nodes..."
def rewrite(self, line, newline=False):
pline = line + " " * max(self._lastlen - len(line), 0)

View File

@@ -32,7 +32,7 @@ def pytest_cmdline_main(config):
if config.getoption("looponfail"):
usepdb = config.getoption("usepdb") # a core option
if usepdb:
raise pytest.UsageError("--pdb incompatible with --looponfail.")
raise pytest.UsageError("--pdb is incompatible with --looponfail.")
looponfail_main(config)
return 2 # looponfail only can get stop with ctrl-C anyway

View File

@@ -27,10 +27,14 @@ def auto_detect_cpus():
return n if n else 1
class AutoInt(int):
"""Mark value as auto-detected."""
def parse_numprocesses(s):
if s == "auto":
return auto_detect_cpus()
else:
return AutoInt(auto_detect_cpus())
elif s is not None:
return int(s)
@@ -45,7 +49,7 @@ def pytest_addoption(parser):
type=parse_numprocesses,
help="shortcut for '--dist=load --tx=NUM*popen', "
"you can use 'auto' here for auto detection CPUs number on "
"host system",
"host system and it will be 0 when used with --pdb",
)
group.addoption(
"--maxprocesses",
@@ -126,12 +130,12 @@ def pytest_addoption(parser):
)
parser.addini(
"rsyncdirs",
"list of (relative) paths to be rsynced for" " remote distributed testing.",
"list of (relative) paths to be rsynced for remote distributed testing.",
type="pathlist",
)
parser.addini(
"rsyncignore",
"list of (relative) glob-style paths to be ignored " "for rsyncing.",
"list of (relative) glob-style paths to be ignored for rsyncing.",
type="pathlist",
)
parser.addini(
@@ -177,6 +181,10 @@ def pytest_configure(config):
@pytest.mark.tryfirst
def pytest_cmdline_main(config):
usepdb = config.getoption("usepdb") # a core option
if isinstance(config.option.numprocesses, AutoInt):
config.option.numprocesses = 0 if usepdb else int(config.option.numprocesses)
if config.option.numprocesses:
if config.option.dist == "no":
config.option.dist = "load"
@@ -188,11 +196,10 @@ def pytest_cmdline_main(config):
config.option.dist = "load"
val = config.getvalue
if not val("collectonly"):
usepdb = config.getoption("usepdb") # a core option
if val("dist") != "no":
if usepdb:
raise pytest.UsageError(
"--pdb is incompatible with distributing tests; try using -n0."
"--pdb is incompatible with distributing tests; try using -n0 or -nauto."
) # noqa: E501

View File

@@ -116,14 +116,19 @@ class WorkerInteractor(object):
data = serialize_report(report)
self.sendevent("collectreport", data=data)
def pytest_logwarning(self, message, code, nodeid, fslocation):
self.sendevent(
"logwarning",
message=message,
code=code,
nodeid=nodeid,
fslocation=str(fslocation),
)
# the pytest_logwarning hook was deprecated since pytest 4.0
if hasattr(
_pytest.hookspec, "pytest_logwarning"
) and not _pytest.hookspec.pytest_logwarning.pytest_spec.get("warn_on_impl"):
def pytest_logwarning(self, message, code, nodeid, fslocation):
self.sendevent(
"logwarning",
message=message,
code=code,
nodeid=nodeid,
fslocation=str(fslocation),
)
# the pytest_warning_captured hook was introduced in pytest 3.8
if hasattr(_pytest.hookspec, "pytest_warning_captured"):
@@ -216,7 +221,15 @@ def serialize_warning_message(warning_message):
for attr_name in warning_message._WARNING_DETAILS:
if attr_name in ("message", "category"):
continue
result[attr_name] = getattr(warning_message, attr_name)
attr = getattr(warning_message, attr_name)
# Check if we can serialize the warning detail, marking `None` otherwise
# Note that we need to define the attr (even as `None`) to allow deserializing
try:
dumps(attr)
except DumpError:
result[attr_name] = repr(attr)
else:
result[attr_name] = attr
return result
@@ -249,18 +262,23 @@ def remote_initconfig(option_dict, args):
if __name__ == "__channelexec__":
import py
channel = channel # noqa
workerinput, args, option_dict = channel.receive()
importpath = os.getcwd()
sys.path.insert(0, importpath) # XXX only for remote situations
os.environ["PYTHONPATH"] = (
importpath + os.pathsep + os.environ.get("PYTHONPATH", "")
)
workerinput, args, option_dict, change_sys_path = channel.receive()
if change_sys_path:
importpath = os.getcwd()
sys.path.insert(0, importpath)
os.environ["PYTHONPATH"] = (
importpath + os.pathsep + os.environ.get("PYTHONPATH", "")
)
os.environ["PYTEST_XDIST_WORKER"] = workerinput["workerid"]
os.environ["PYTEST_XDIST_WORKER_COUNT"] = str(workerinput["workercount"])
# os.environ['PYTHONPATH'] = importpath
config = remote_initconfig(option_dict, args)
config._parser.prog = os.path.basename(workerinput["mainargv"][0])
config.workerinput = workerinput
config.workeroutput = {}
# TODO: deprecated name, backward compatibility only. Remove it in future

View File

@@ -187,7 +187,7 @@ class LoadScopeScheduling(object):
break
else:
raise RuntimeError(
"Unable to identify crashitem on a workload with " "pending items"
"Unable to identify crashitem on a workload with pending items"
)
# Made uncompleted work unit available again

View File

@@ -2,6 +2,7 @@ from __future__ import print_function
import fnmatch
import os
import re
import sys
import threading
import py
@@ -219,6 +220,7 @@ class WorkerController(object):
"workercount": len(nodemanager.specs),
"slaveid": gateway.id,
"slavecount": len(nodemanager.specs),
"mainargv": sys.argv,
}
# TODO: deprecated name, backward compatibility only. Remove it in future
self.slaveinput = self.workerinput
@@ -248,9 +250,13 @@ class WorkerController(object):
basetemp = self.config._tmpdirhandler.getbasetemp()
option_dict["basetemp"] = str(basetemp.join(name))
self.config.hook.pytest_configure_node(node=self)
remote_module = self.config.hook.pytest_xdist_getremotemodule()
self.channel = self.gateway.remote_exec(remote_module)
self.channel.send((self.workerinput, args, option_dict))
self.channel = self.gateway.remote_exec(remote_module)
# change sys.path only for remote workers
change_sys_path = not self.gateway.spec.popen
self.channel.send((self.workerinput, args, option_dict, change_sys_path))
if self.putevent:
self.channel.setcallback(self.process_from_remote, endmarker=self.ENDMARK)
@@ -275,7 +281,7 @@ class WorkerController(object):
if not self._down:
try:
self.sendcommand("shutdown")
except IOError:
except (IOError, OSError):
pass
self._shutdown_sent = True
@@ -352,7 +358,11 @@ class WorkerController(object):
except: # noqa
from _pytest._code import ExceptionInfo
excinfo = ExceptionInfo()
# ExceptionInfo API changed in pytest 4.1
if hasattr(ExceptionInfo, "from_current"):
excinfo = ExceptionInfo.from_current()
else:
excinfo = ExceptionInfo()
print("!" * 20, excinfo)
self.config.notify_exception(excinfo)
self.shutdown()