2017-02-23 10 views
0

テストでrecord_xml_property fixtureを積極的に使用していますが、残念ながらxdsitプラグインでは機能しません。私は回避策を実装しようとしました。代わりに、直接、私はslaveoutputにそれらを入れて、記者にプロパティを追加:xdistでrecord_xml_propertyが動作しない

@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) 

しかし、問題はありますそのスレーブ出力はSlaveControllerオブジェクトではまだ利用できません。pytest_runtest_logreportフックが実行されているときです。 pytest_testnodedownで利用可能で、SlaveInteractor"slavefinished"イベントで送信しますが、この時点でレポートは既に確定済みです。以前にスレーブノードからスレーブ出力を取得する方法はありますか?

答えて

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) 
関連する問題