[svn r63040] try harder to record and auto-exit gateways after test runs
--HG-- branch : trunk
This commit is contained in:
		
							parent
							
								
									ee52739b17
								
							
						
					
					
						commit
						941d06e509
					
				|  | @ -330,6 +330,7 @@ class Gateway(object): | |||
|         self._cleanup.unregister(self) | ||||
|         self._stopexec() | ||||
|         self._stopsend() | ||||
|         py._com.pyplugins.notify("gateway_exit", self) | ||||
| 
 | ||||
|     def _stopsend(self): | ||||
|         self._send(None) | ||||
|  |  | |||
|  | @ -41,6 +41,7 @@ class InstallableGateway(gateway.Gateway): | |||
|         super(InstallableGateway, self).__init__(io=io, _startcount=1)  | ||||
|         # XXX we dissallow execution form the other side | ||||
|         self._initreceive(requestqueue=False)  | ||||
|         py._com.pyplugins.notify("gateway_init", self) | ||||
| 
 | ||||
|     def _remote_bootstrap_gateway(self, io, extra=''): | ||||
|         """ return Gateway with a asynchronously remotely | ||||
|  |  | |||
|  | @ -0,0 +1,11 @@ | |||
| import py | ||||
| pytest_plugins = "pytester" | ||||
| 
 | ||||
| class TestExecnetEvents: | ||||
|     def test_popengateway(self, eventrecorder): | ||||
|         gw = py.execnet.PopenGateway() | ||||
|         event = eventrecorder.popevent("gateway_init") | ||||
|         assert event.args[0] == gw  | ||||
|         gw.exit() | ||||
|         event = eventrecorder.popevent("gateway_exit") | ||||
|         assert event.args[0] == gw  | ||||
|  | @ -571,6 +571,9 @@ class TestSocketGateway(SocketGatewaySetup, BasicRemoteExecution): | |||
| class TestSshGateway(BasicRemoteExecution): | ||||
|     def setup_class(cls):  | ||||
|         sshhost = py.test.config.getvalueorskip("sshhost") | ||||
|         if sshhost.find(":") != -1: | ||||
|             sshhost = sshhost.split(":")[0] | ||||
|         cls.sshhost = sshhost | ||||
|         cls.gw = py.execnet.SshGateway(sshhost) | ||||
| 
 | ||||
|     def test_sshconfig_functional(self): | ||||
|  | @ -578,7 +581,7 @@ class TestSshGateway(BasicRemoteExecution): | |||
|         ssh_config = tmpdir.join("ssh_config")  | ||||
|         ssh_config.write( | ||||
|             "Host alias123\n" | ||||
|             "   HostName %s\n" % (py.test.config.option.sshhost,)) | ||||
|             "   HostName %s\n" % self.sshhost) | ||||
|         gw = py.execnet.SshGateway("alias123", ssh_config=ssh_config) | ||||
|         assert gw._cmd.find("-F") != -1 | ||||
|         assert gw._cmd.find(str(ssh_config)) != -1 | ||||
|  | @ -586,7 +589,7 @@ class TestSshGateway(BasicRemoteExecution): | |||
|         gw.exit() | ||||
| 
 | ||||
|     def test_sshaddress(self): | ||||
|         assert self.gw.remoteaddress == py.test.config.option.sshhost | ||||
|         assert self.gw.remoteaddress == self.sshhost | ||||
| 
 | ||||
|     @py.test.mark.xfail("XXX ssh-gateway error handling") | ||||
|     def test_connexion_failes_on_non_existing_hosts(self): | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ Instance = py.test.collect.Instance | |||
| conf_iocapture = "fd" # overridable from conftest.py  | ||||
| 
 | ||||
| # XXX resultlog should go, pypy's nightrun depends on it | ||||
| pytest_plugins = "default terminal xfail tmpdir resultlog monkeypatch".split() | ||||
| pytest_plugins = "default terminal xfail tmpdir execnetcleanup resultlog monkeypatch".split() | ||||
| 
 | ||||
| # =================================================== | ||||
| # Distributed testing specific options  | ||||
|  |  | |||
|  | @ -0,0 +1,53 @@ | |||
| import py | ||||
| 
 | ||||
| class ExecnetcleanupPlugin: | ||||
|     _gateways = None | ||||
|     _debug = None | ||||
| 
 | ||||
|     def pytest_configure(self, config): | ||||
|         self._debug = config.option.debug | ||||
| 
 | ||||
|     def trace(self, msg, *args): | ||||
|         if self._debug: | ||||
|             print "[execnetcleanup %0x] %s %s" %(id(self), msg, args) | ||||
|          | ||||
|     def pyevent_gateway_init(self, gateway): | ||||
|         self.trace("init", gateway) | ||||
|         if self._gateways is not None: | ||||
|             self._gateways.append(gateway) | ||||
|          | ||||
|     def pyevent_gateway_exit(self, gateway): | ||||
|         self.trace("exit", gateway) | ||||
|         if self._gateways is not None: | ||||
|             self._gateways.remove(gateway) | ||||
| 
 | ||||
|     def pyevent_testrunstart(self, event): | ||||
|         self.trace("testrunstart", event) | ||||
|         self._gateways = [] | ||||
| 
 | ||||
|     def pyevent_testrunfinish(self, event): | ||||
|         self.trace("testrunfinish", event) | ||||
|         l = [] | ||||
|         for gw in self._gateways: | ||||
|             gw.exit() | ||||
|             l.append(gw) | ||||
|         for gw in l: | ||||
|             gw.join() | ||||
|     | ||||
| def test_generic(plugintester): | ||||
|     plugintester.apicheck(ExecnetcleanupPlugin) | ||||
| 
 | ||||
| @py.test.mark.xfail("clarify plugin registration/unregistration") | ||||
| def test_execnetplugin(testdir): | ||||
|     p = ExecnetcleanupPlugin() | ||||
|     testdir.plugins.append(p) | ||||
|     testdir.inline_runsource(""" | ||||
|         import py | ||||
|         import sys | ||||
|         def test_hello(): | ||||
|             sys._gw = py.execnet.PopenGateway() | ||||
|     """, "-s", "--debug") | ||||
|     assert not p._gateways  | ||||
|     assert py.std.sys._gw | ||||
|     py.test.raises(KeyError, "py.std.sys._gw.exit()") # already closed  | ||||
|      | ||||
|  | @ -155,8 +155,14 @@ class PytestPluginHooks: | |||
|     def pyevent(self, eventname, *args, **kwargs): | ||||
|         """ called for each testing event. """ | ||||
| 
 | ||||
|     def pyevent_gateway_init(self, gateway): | ||||
|         """ called a gateway has been initialized. """ | ||||
| 
 | ||||
|     def pyevent_gateway_exit(self, gateway): | ||||
|         """ called when gateway is being exited. """ | ||||
| 
 | ||||
|     def pyevent_trace(self, category, msg): | ||||
|         """ called for tracing events events. """ | ||||
|         """ called for tracing events. """ | ||||
| 
 | ||||
|     def pyevent_internalerror(self, event): | ||||
|         """ called for internal errors. """ | ||||
|  |  | |||
|  | @ -21,6 +21,11 @@ class PytesterPlugin: | |||
|     def pytest_pyfuncarg_EventRecorder(self, pyfuncitem): | ||||
|         return EventRecorder | ||||
| 
 | ||||
|     def pytest_pyfuncarg_eventrecorder(self, pyfuncitem): | ||||
|         evrec = EventRecorder(py._com.pyplugins) | ||||
|         pyfuncitem.addfinalizer(lambda: evrec.pyplugins.unregister(evrec)) | ||||
|         return evrec | ||||
| 
 | ||||
| def test_generic(plugintester): | ||||
|     plugintester.apicheck(PytesterPlugin) | ||||
| 
 | ||||
|  | @ -245,6 +250,8 @@ class Event: | |||
|         self.name = name | ||||
|         self.args = args | ||||
|         self.kwargs = kwargs | ||||
|     def __repr__(self): | ||||
|         return "<Event %r %r>" %(self.name, self.args) | ||||
| 
 | ||||
| class EventRecorder(object): | ||||
|     def __init__(self, pyplugins, debug=False): # True): | ||||
|  | @ -260,6 +267,13 @@ class EventRecorder(object): | |||
|             print "[event: %s]: %s **%s" %(name, ", ".join(map(str, args)), kwargs,) | ||||
|         self.events.append(Event(name, args, kwargs)) | ||||
| 
 | ||||
|     def popevent(self, name): | ||||
|         for i, event in py.builtin.enumerate(self.events): | ||||
|             if event.name == name: | ||||
|                 del self.events[i] | ||||
|                 return event | ||||
|         raise KeyError("popevent: %r not found in %r"  %(name, self.events)) | ||||
| 
 | ||||
|     def get(self, cls): | ||||
|         l = [] | ||||
|         for event in self.events: | ||||
|  |  | |||
|  | @ -95,6 +95,7 @@ class PytestPlugins(object): | |||
|         config = self._config  | ||||
|         del self._config  | ||||
|         self.pyplugins.call_each("pytest_unconfigure", config=config) | ||||
|         config.bus.unregister(self) | ||||
| 
 | ||||
| #  | ||||
| #  XXX old code to automatically load classes | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue