record_xml_property не работает с xdist
Я активно использую фиксацию record_xml_property в своих тестах, но, к сожалению, она просто не работает с плагином xdsit. Я пытался реализовать обходной путь. Вместо того, чтобы напрямую добавлять свойства в репортер, я помещаю их в slaveoutput:
@pytest.fixture
def record_xml_property(request):
xml = getattr(request.config, "_xml", None)
if xml is not None:
node_reporter = xml.node_reporter(request.node.nodeid)
return node_reporter.add_property
else:
def add_property_xdist(name, value):
request.node.config.slaveoutput.update({'properties': {name: value}})
return add_property_xdist
И после этого я хотел добавить эти свойства в отчет в pytest_runtest_logreport
крюк:
@pytest.hookimpl(tryfirst=True)
def pytest_runtest_logreport(report):
if report.when != 'teardown':
return
node = getattr(report, 'node', None)
if not node:
return
xml = getattr(node.config, '_xml', None)
if not xml:
return
node_reporter = xml.node_reporter(report)
slaveoutput = getattr(node, 'slaveoutput', None)
if not slaveoutput:
return
node_properties = slaveoutput.get('properties', {})
for key, value in node_properties.items():
node_reporter.add_property(key, value)
Но проблема в том, что slaveoutput обычно не доступен в SlaveController
возражать еще когда pytest_runtest_logreport
крюк выполнен. Это доступно в pytest_testnodedown
, SlaveInteractor
отправляет это с "slavefinished"
событие, но на данный момент отчеты уже доработаны. Есть ли способ получить slaveoutput от подчиненного узла ранее?
1 ответ
Наконец я решил не использовать slaveoutput
, Я думал о каком-то решении, которое предполагает использование общих директорий, но в итоге я решил использовать канал execnet между главным и подчиненным узлами. К сожалению, кажется, что дизайн xdist не позволяет легко расширять связь между главным и подчиненным узлами. Я должен был сделать некоторые исправления обезьяны, дублирование кода и некоторые другие неприятные вещи, которые мне не нравятся. Но, по крайней мере, это работает. Вот мое решение:
@pytest.fixture
def record_xml_property(request):
"""
Overrides original record_xml_property fixture from junitxml plugin
"""
xml = getattr(request.config, "_xml", None)
if xml is not None:
node_reporter = xml.node_reporter(request.node.nodeid)
return node_reporter.add_property
else:
pluginmanager = request.node.config.pluginmanager
plugins = pluginmanager.get_plugins()
slave_interactor = None
for plugin in plugins:
if plugin.__class__.__name__ == 'SlaveInteractor':
slave_interactor = plugin
if slave_interactor:
# if test is running in slave node
def add_property_xdist(name, value):
slave_interactor.sendevent("record_xml_property", property=(name, value), nodeid=request.node.nodeid)
return add_property_xdist
def add_property_noop(name, value):
pass
return add_property_noop
def pytest_configure_node(node):
xml = getattr(node.config, '_xml', None)
if xml:
# monkeypatching SlaveController right after it is created
# process_from_remote is a callback function which is executed on channel event
original_process_from_remote = node.process_from_remote
def process_from_remote(self, eventcall):
try:
if eventcall != self.ENDMARK:
eventname, kwargs = eventcall
# In case of record_xml_property event, process it here. Otherwise process it in original
# process_from_remote function
if eventname == "record_xml_property":
self.log("recording xml property %s(%s)" % (eventname, kwargs))
# Report is not yet exists. I should use fake one to get proper reporter
class Fakereport:
def __init__(self, node, nodeid):
self.node = node
self.nodeid = nodeid
node_reporter = xml.node_reporter(Fakereport(self, kwargs['nodeid']))
name, value = kwargs['property']
node_reporter.add_property(name, value)
return
except KeyboardInterrupt:
# should not land in receiver-thread
raise
except:
# the same except as in original process_from_remote method
excinfo = py.code.ExceptionInfo()
py.builtin.print_("!" * 20, excinfo)
self.config.pluginmanager.notify_exception(excinfo)
return original_process_from_remote(eventcall)
node.process_from_remote = types.MethodType(process_from_remote, node)