[py-svn] r36986 - in py/branch/config/py/test/rsession: . testing webdata

fijal at codespeak.net fijal at codespeak.net
Fri Jan 19 13:06:02 CET 2007


Author: fijal
Date: Fri Jan 19 13:05:58 2007
New Revision: 36986

Modified:
   py/branch/config/py/test/rsession/box.py
   py/branch/config/py/test/rsession/executor.py
   py/branch/config/py/test/rsession/master.py
   py/branch/config/py/test/rsession/slave.py
   py/branch/config/py/test/rsession/testing/test_master.py
   py/branch/config/py/test/rsession/testing/test_slave.py
   py/branch/config/py/test/rsession/testing/test_webjs.py
   py/branch/config/py/test/rsession/webdata/source.js
Log:
Improve the behaviour off cleanup and channel closing, at least on slave side.
Some cleanups, got rid of some hacks (in favor of other hacks, but posix
is a bit hackish anyway)


Modified: py/branch/config/py/test/rsession/box.py
==============================================================================
--- py/branch/config/py/test/rsession/box.py	(original)
+++ py/branch/config/py/test/rsession/box.py	Fri Jan 19 13:05:58 2007
@@ -86,8 +86,8 @@
             retvalf.close()
         os._exit(0)
     
-    def parent(self, pid):
-        pid, exitstat = os.waitpid(pid, 0)
+    def parent(self, pid, waiter=os.waitpid):
+        pid, exitstat = waiter(pid, 0)
         self.signal = exitstat & 0x7f
         self.exitstat = exitstat & 0xff00
 

Modified: py/branch/config/py/test/rsession/executor.py
==============================================================================
--- py/branch/config/py/test/rsession/executor.py	(original)
+++ py/branch/config/py/test/rsession/executor.py	Fri Jan 19 13:05:58 2007
@@ -84,8 +84,8 @@
         b = Box(fun, config=self.config)
         parent, pid = b.run(continuation=True)
         
-        def cont():
-            parent(pid)
+        def cont(waiter=os.waitpid):
+            parent(pid, waiter=waiter)
             if b.retval is not None:
                 passed, setupfailure, excinfo, skipped,\
                     critical, _, _, _ = b.retval

Modified: py/branch/config/py/test/rsession/master.py
==============================================================================
--- py/branch/config/py/test/rsession/master.py	(original)
+++ py/branch/config/py/test/rsession/master.py	Fri Jan 19 13:05:58 2007
@@ -35,7 +35,7 @@
             self.reporter(report.SendItem(self.channel, item))
 
 def itemgen(colitems, reporter, keyword, reporterror):
-    for x in colitems: 
+    for x in colitems:
         for y in x.tryiter(reporterror = lambda x: reporterror(reporter, x), keyword = keyword):
             yield y
 

Modified: py/branch/config/py/test/rsession/slave.py
==============================================================================
--- py/branch/config/py/test/rsession/slave.py	(original)
+++ py/branch/config/py/test/rsession/slave.py	Fri Jan 19 13:05:58 2007
@@ -5,16 +5,51 @@
 import py
 from py.__.test.rsession.executor import RunExecutor, BoxExecutor, AsyncExecutor
 from py.__.test.rsession.outcome import Outcome
+import thread
+import os
 
-class Info:
-    # XXX: Another nasty hack to get rid off
-    pid = None
+class PidInfo(object):
+    """ Pure container class to store information of actually running
+    pid
+    """
+    def __init__(self):
+        self.pid = 0
+        self.lock = thread.allocate_lock()
+
+    def set_pid(self, pid):
+        self.lock.acquire()
+        try:
+            self.pid = pid
+        finally:
+            self.lock.release()
+
+    def kill(self):
+        self.lock.acquire()
+        try:
+            if self.pid:
+                os.kill(self.pid, 15)
+                self.pid = 0
+        finally:
+            self.lock.release()
+
+    def waitandclear(self, pid, num):
+        """ This is an obscure hack to keep locking properly, adhere to posix semantics
+        and try to clean it as much as possible, not clean at all
+        """
+        self.lock.acquire()
+        try:
+            retval = os.waitpid(self.pid, 0)
+            self.pid = 0
+            return retval
+        finally:
+            self.lock.release()
 
 class SlaveNode(object):
-    def __init__(self, rootcollector, config, executor=AsyncExecutor):
+    def __init__(self, rootcollector, config, pidinfo, executor=AsyncExecutor):
         self.rootcollector = rootcollector
         self.config = config
         self.executor = executor
+        self.pidinfo = pidinfo
 
     def execute(self, itemspec):
         item = self.rootcollector.getitembynames(itemspec)
@@ -24,11 +59,11 @@
         ex = self.executor(item, config=self.config)
         if self.executor is AsyncExecutor:
             cont, pid = ex.execute()
+            self.pidinfo.set_pid(pid)
         else:
             # for tests only
             return ex.execute()
-        Info.pid = pid
-        return cont()
+        return cont(self.pidinfo.waitandclear)
 
     def run(self, itemspec):
         #outcome = self.execute(itemspec)
@@ -39,7 +74,7 @@
         else:
             return outcome.make_repr(self.config.option.tbstyle)
 
-def slave_main(receive, send, path, config, info = None):
+def slave_main(receive, send, path, config, pidinfo):
     import os
     assert os.path.exists(path) 
     path = os.path.abspath(path) 
@@ -49,7 +84,7 @@
         if node is not None:
             return node
         col = py.test.collect.Directory(str(py.path.local(path).join(item[0])))
-        node = nodes[item[0]] = SlaveNode(col, config)
+        node = nodes[item[0]] = SlaveNode(col, config, pidinfo)
         return node
     while 1:
         nextitem = receive()
@@ -72,15 +107,14 @@
     
     while nextitem is not None:
         nextitem = receive()
-    
+
 def setup():
-    def callback_gen(queue):
-        from py.__.test.rsession.slave import Info
+    def callback_gen(channel, queue, info):
         def callback(item):
             if item == 42: # magic call-cleanup
                 # XXX should kill a pid here
-                if Info.pid:
-                    os.kill(Info.pid, 15)
+                info.kill()
+                channel.close()
                 sys.exit(0)
             queue.put(item)
         return callback
@@ -100,15 +134,15 @@
         config.conftest.setinitial([basedir])
         #config.conftest.lget('adddefaultoptions')()
     config.merge_repr(config_repr)
-    from py.__.test.rsession.slave import Info
-    Info.pid = 0
     if not config.option.nomagic:
         py.magic.invoke(assertion=1)
     mod = __import__(pkgname)
     assert py.path.local(mod.__file__).dirpath() == py.path.local(pkgdir)
-    from py.__.test.rsession.slave import slave_main
+    from py.__.test.rsession.slave import slave_main, PidInfo
     queue = py.std.Queue.Queue()
-    channel.setcallback(callback_gen(queue))
-    slave_main(queue.get, channel.send, basedir, config)
+    pidinfo = PidInfo()
+    channel.setcallback(callback_gen(channel, queue, pidinfo))
+    slave_main(queue.get, channel.send, basedir, config, pidinfo)
     if not config.option.nomagic:
         py.magic.revoke(assertion=1)
+    channel.close()

Modified: py/branch/config/py/test/rsession/testing/test_master.py
==============================================================================
--- py/branch/config/py/test/rsession/testing/test_master.py	(original)
+++ py/branch/config/py/test/rsession/testing/test_master.py	Fri Jan 19 13:05:58 2007
@@ -11,7 +11,7 @@
 
 from py.__.test.rsession.master import dispatch_loop, setup_slave, MasterNode, randomgen
 from py.__.test.rsession.outcome import ReprOutcome, Outcome 
-from py.__.test.rsession.testing.test_slave import funcpass_spec, funcfail_spec
+from py.__.test.rsession.testing.test_slave import funcpass_spec, funcfail_spec, funchang_spec
 from py.__.test.rsession import report
 from py.__.test.rsession.hostmanage import HostInfo
 
@@ -94,7 +94,7 @@
     channel.send(funcpass_spec)
     output = ReprOutcome(channel.receive())
     assert output.passed
-    channel.send(None)
+    channel.send(42)
     channel.waitclose(10)
     gw.exit()
 
@@ -126,6 +126,34 @@
     shouldstop = lambda : False
     dispatch_loop(master_nodes, itemgenerator, shouldstop)
 
+def test_slave_running_interrupted():
+    #def simple_report(event):
+    #    if not isinstance(event, report.ReceivedItemOutcome):
+    #        return
+    #    item = event.item
+    #    if item.code.name == 'funcpass':
+    #        assert event.outcome.passed
+    #    else:
+    #        assert not event.outcome.passed
+    reports = []
+    
+    def open_gw():
+        gw = py.execnet.PopenGateway()
+        gw.host = HostInfo("localhost")
+        gw.host.gw = gw
+        config = py.test.config._reparse([])
+        channel = setup_slave(gw, pkgdir, config)
+        mn = MasterNode(channel, reports.append, {})
+        return mn, gw, channel
+
+    mn, gw, channel = open_gw()
+    rootcol = py.test.collect.Directory(pkgdir.dirpath())
+    funchang_item = rootcol.getitembynames(funchang_spec)
+    mn.send(funchang_item)
+    mn.send(StopIteration)
+    # XXX: We have to wait here a bit to make sure that it really did happen
+    channel.waitclose(2)
+
 def test_randomgen():
     d = {}
     gen = randomgen({1:True, 2:True, 3:True}, d)

Modified: py/branch/config/py/test/rsession/testing/test_slave.py
==============================================================================
--- py/branch/config/py/test/rsession/testing/test_slave.py	(original)
+++ py/branch/config/py/test/rsession/testing/test_slave.py	Fri Jan 19 13:05:58 2007
@@ -1,6 +1,6 @@
 
 """ Testing the slave side node code (in a local way). """
-from py.__.test.rsession.slave import SlaveNode, slave_main, setup
+from py.__.test.rsession.slave import SlaveNode, slave_main, setup, PidInfo
 from py.__.test.rsession.outcome import ReprOutcome
 import py, sys
 
@@ -55,7 +55,8 @@
 def gettestnode():
     rootcol = py.test.collect.Directory(rootdir)
     config = py.test.config._reparse([rootdir])
-    node = SlaveNode(rootcol, config, executor=RunExecutor) 
+    pidinfo = PidInfo()
+    node = SlaveNode(rootcol, config, pidinfo, executor=RunExecutor) 
     return node
 
 def test_slave_run_passing():
@@ -109,7 +110,8 @@
          funcfail_spec
         ]
     config = py.test.config._reparse([])
-    slave_main(q.pop, res.append, str(rootdir), config)
+    pidinfo = PidInfo()
+    slave_main(q.pop, res.append, str(rootdir), config, pidinfo)
     assert len(res) == 2
     res_repr = [ReprOutcome(r) for r in res]
     assert not res_repr[0].passed and res_repr[1].passed
@@ -134,6 +136,10 @@
                 raise NotImplementedError("more data")
             self.count += 1
             return retval
+
+        def close(self):
+            pass
+        
     try:
         exec py.code.Source(setup, "setup()").compile() in {
             'channel': C()}
@@ -168,6 +174,9 @@
                     callback(self.q.pop())
             f()
             #thread.start_new_thread(f, ())
+
+        def close(self):
+            pass
         
         send = res.append
     try:

Modified: py/branch/config/py/test/rsession/testing/test_webjs.py
==============================================================================
--- py/branch/config/py/test/rsession/testing/test_webjs.py	(original)
+++ py/branch/config/py/test/rsession/testing/test_webjs.py	Fri Jan 19 13:05:58 2007
@@ -7,8 +7,6 @@
 from pypy.translator.js.tester import schedule_callbacks
 here = py.magic.autopath().dirpath()
 
-py.test.skip("will fix later, multiple issues")
-
 def setup_module(mod):
     # load HTML into window object
     html = here.join('../webdata/index.html').read()
@@ -18,9 +16,7 @@
     dom.window = dom.Window(html)
     dom.document = dom.window.document
     config = py.test.config._reparse([])
-    from py.__.test.rsession.rsession import session_options
-    session_options.bind_config(config)
-    session_options.import_pypy = True
+    config._overwrite('_dist_import_pypy', True)
     from py.__.test.rsession import webjs
     from py.__.test.rsession.web import exported_methods
     mod.webjs = webjs

Modified: py/branch/config/py/test/rsession/webdata/source.js
==============================================================================
Binary files. No diff available.



More information about the pytest-commit mailing list