[py-svn] r35637 - in py/dist/py/test/rsession: . testing

fijal at codespeak.net fijal at codespeak.net
Tue Dec 12 18:58:22 CET 2006


Author: fijal
Date: Tue Dec 12 18:58:19 2006
New Revision: 35637

Modified:
   py/dist/py/test/rsession/box.py
   py/dist/py/test/rsession/executor.py
   py/dist/py/test/rsession/master.py
   py/dist/py/test/rsession/reporter.py
   py/dist/py/test/rsession/slave.py
   py/dist/py/test/rsession/testing/test_boxing.py
   py/dist/py/test/rsession/testing/test_executor.py
   py/dist/py/test/rsession/testing/test_reporter.py
   py/dist/py/test/rsession/testing/test_rsession.py
   py/dist/py/test/rsession/testing/test_slave.py
Log:
svn merge -r 35555:HEAD http://codespeak.net/svn/py/branch/rsession-cleanup



Modified: py/dist/py/test/rsession/box.py
==============================================================================
--- py/dist/py/test/rsession/box.py	(original)
+++ py/dist/py/test/rsession/box.py	Tue Dec 12 18:58:19 2006
@@ -21,6 +21,7 @@
     def __init__(self, fun, args = [], kwargs = {}):
         self.fun = fun
         self.args = args
+        self.info = info
         self.kwargs = kwargs
     
     def run(self):
@@ -48,7 +49,7 @@
         self.args = args
         self.kwargs = kwargs
     
-    def run(self):
+    def run(self, continuation=False):
         tempdir = py.test.ensuretemp("box%d" % self.count)
         self.count += 1
         self.tempdir = tempdir
@@ -59,7 +60,10 @@
         nice_level = py.test.remote.nice_level
         pid = os.fork()
         if pid:
-            self.parent(pid)
+            if not continuation:
+                self.parent(pid)
+            else:
+                return self.parent, pid
         else:
             try:
                 outcome = self.children(nice_level)

Modified: py/dist/py/test/rsession/executor.py
==============================================================================
--- py/dist/py/test/rsession/executor.py	(original)
+++ py/dist/py/test/rsession/executor.py	Tue Dec 12 18:58:19 2006
@@ -65,27 +65,27 @@
         else:
             return (False, False, None, False, False, b.signal, b.stdoutrepr, b.stderrrepr)
 
-# XXX old code 
-class XXXExecutor(object):
-    def __init__(self, fun, setup=lambda: None): 
-        self.fun = fun
-        self.setup = setup
+class AsyncExecutor(RunExecutor):
+    """ same as box executor, but instead it returns function to continue
+    computations (more async mode)
+    """
+    wraps = True
     
-    def _execute(self, fun):
-        try:
-            fun()
-        except:
-            excinfo = py.code.ExceptionInfo()
-            code = py.code.Code(fun)
-            excinfo.traceback = excinfo.traceback.cut(
-                    path=code.path, firstlineno=code.firstlineno)
-            return excinfo 
-
     def execute(self):
-        excinfo = self._execute(self.setup)
-        if excinfo is not None:
-            return Outcome(excinfo=excinfo, setupfailure=True)
-        excinfo = self._execute(self.fun)
-        if excinfo is not None:
-            return Outcome(excinfo=excinfo, setupfailure=False)
-        return Outcome()
+        def fun():
+            outcome = RunExecutor.execute(self)
+            return outcome.make_repr()
+        
+        b = Box(fun)
+        parent, pid = b.run(continuation=True)
+        
+        def cont():
+            parent(pid)
+            if b.retval is not None:
+                passed, setupfailure, excinfo, skipped, critical, _, _, _ = b.retval
+                return (passed, setupfailure, excinfo, skipped, critical, 0,
+                    b.stdoutrepr, b.stderrrepr)
+            else:
+                return (False, False, None, False, False, b.signal, b.stdoutrepr, b.stderrrepr)
+        
+        return cont, pid

Modified: py/dist/py/test/rsession/master.py
==============================================================================
--- py/dist/py/test/rsession/master.py	(original)
+++ py/dist/py/test/rsession/master.py	Tue Dec 12 18:58:19 2006
@@ -20,11 +20,14 @@
                         self.channel, item, repr_outcome))
 
     def send(self, item):
-        self.pending.insert(0, item)
-        itemspec = item.listnames()[1:]
-        self.channel.send(itemspec)
-        # send start report
-        self.reporter(report.SendItem(self.channel, item))
+        if item is StopIteration:
+            self.channel.send(42)
+        else:
+            self.pending.insert(0, item)
+            itemspec = item.listnames()[1:]
+            self.channel.send(itemspec)
+            # send start report
+            self.reporter(report.SendItem(self.channel, item))
 
 def dispatch_loop(masternodes, itemgenerator, shouldstop, 
                   waiter = lambda: py.std.time.sleep(0.1)):
@@ -37,6 +40,8 @@
                 if len(node.pending) < max_tasks_per_node:
                     item = itemgenerator.next()
                     if shouldstop():
+                        for _node in masternodes:
+                            _node.send(StopIteration) # magic connector
                         return
                     node.send(item)
         except StopIteration:

Modified: py/dist/py/test/rsession/reporter.py
==============================================================================
--- py/dist/py/test/rsession/reporter.py	(original)
+++ py/dist/py/test/rsession/reporter.py	Tue Dec 12 18:58:19 2006
@@ -91,6 +91,10 @@
     
     def hangs(self):
         h = []
+        if self.config.option.exitfirst:
+            # reporting hanging nodes in that case makes no sense at all
+            # but we should share some code in all reporters than
+            return
         for node in self.nodes:
             h += [(i, node.channel.gateway.sshaddress) for i in node.pending]
         if h:

Modified: py/dist/py/test/rsession/slave.py
==============================================================================
--- py/dist/py/test/rsession/slave.py	(original)
+++ py/dist/py/test/rsession/slave.py	Tue Dec 12 18:58:19 2006
@@ -3,11 +3,14 @@
 """
 
 import py
-from py.__.test.rsession.executor import RunExecutor, BoxExecutor
+from py.__.test.rsession.executor import RunExecutor, BoxExecutor, AsyncExecutor
 from py.__.test.rsession.outcome import Outcome
 
+class Info:
+    pid = None
+
 class SlaveNode(object):
-    def __init__(self, rootcollector, executor=BoxExecutor):
+    def __init__(self, rootcollector, executor=AsyncExecutor):
         self.rootcollector = rootcollector
         self.executor = executor
 
@@ -17,7 +20,13 @@
         #    ex = Executor(item.obj, setup=item.setup)
         #else:
         ex = self.executor(item)
-        return ex.execute()
+        if self.executor is AsyncExecutor:
+            cont, pid = ex.execute()
+        else:
+            # for tests only
+            return ex.execute()
+        Info.pid = pid
+        return cont()
 
     def run(self, itemspec):
         #outcome = self.execute(itemspec)
@@ -28,7 +37,7 @@
         else:
             return outcome.make_repr()
 
-def slave_main(receive, send, path): 
+def slave_main(receive, send, path, info = None):
     import os
     assert os.path.exists(path) 
     path = os.path.abspath(path) 
@@ -61,9 +70,21 @@
     
     while nextitem is not None:
         nextitem = receive()
-
+    
 def setup():
+    def callback_gen(queue):
+        from py.__.test.rsession.slave import Info
+        def callback(item):
+            if item == 42: # magic call-cleanup
+                # XXX should kill a pid here
+                if Info.pid:
+                    os.kill(Info.pid, 15)
+                sys.exit(0)
+            queue.put(item)
+        return callback
+
     import os, sys
+    from Queue import Queue
     pkgdir = channel.receive()   # path is ready 
     options = channel.receive()  # options stuff, should be dictionary
     basedir = os.path.dirname(pkgdir)
@@ -73,6 +94,8 @@
     import py
     options['we_are_remote'] = True
     from py.__.test.rsession.rsession import RemoteOptions
+    from py.__.test.rsession.slave import Info
+    Info.pid = 0
     py.test.remote = RemoteOptions(options)
     # XXX the following assumes that py lib is there, a bit
     # much of an assumtion 
@@ -81,6 +104,8 @@
     mod = __import__(pkgname)
     assert py.path.local(mod.__file__).dirpath() == py.path.local(pkgdir)
     from py.__.test.rsession.slave import slave_main
-    slave_main(channel.receive, channel.send, basedir)
+    queue = Queue()
+    channel.setcallback(callback_gen(queue))
+    slave_main(queue.get, channel.send, basedir)
     if not py.test.remote.nomagic:
         py.magic.revoke(assertion=1)

Modified: py/dist/py/test/rsession/testing/test_boxing.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_boxing.py	(original)
+++ py/dist/py/test/rsession/testing/test_boxing.py	Tue Dec 12 18:58:19 2006
@@ -2,7 +2,7 @@
 """ test boxing functionality
 """
 
-import py, sys
+import py, sys, os
 
 if sys.platform == 'win32':
     py.test.skip("rsession is unsupported on Windows.")
@@ -74,3 +74,18 @@
     assert b.exitstat == 0
     assert b.signal == 0
     assert b.retval == 2
+
+def test_box_killer():
+    class A:
+        pass
+    info = A()
+    import time
+
+    def box_fun():
+        time.sleep(300) # we don't want to last forever here
+    
+    b = RealBox(box_fun)
+    par, pid = b.run(continuation=True)
+    os.kill(pid, 15)
+    par(pid)
+    assert b.signal == 15

Modified: py/dist/py/test/rsession/testing/test_executor.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_executor.py	(original)
+++ py/dist/py/test/rsession/testing/test_executor.py	Tue Dec 12 18:58:19 2006
@@ -2,13 +2,16 @@
 import py
 import example1
 
-from py.__.test.rsession.executor import RunExecutor, BoxExecutor
+from py.__.test.rsession.executor import RunExecutor, BoxExecutor,\
+    AsyncExecutor
 from py.__.test.rsession.outcome import ReprOutcome
 from py.__.test.rsession.testing.test_slave import funcprint_spec, \
     funcprintfail_spec
 
 def setup_module(mod):
     mod.rootdir = py.path.local(py.__file__).dirpath().dirpath()
+    from py.__.test.rsession.rsession import remote_options
+    remote_options['nice_level'] = 0
     
 def XXXtest_executor_passing_function():
     ex = Executor(example1.f1)
@@ -107,3 +110,14 @@
     outcome = ReprOutcome(outcome_repr)
     assert not outcome.passed
     assert outcome.stdout == "samfing elz\n"
+
+def test_cont_executor():
+    rootcol = py.test.collect.Directory(rootdir)
+    item = rootcol.getitembynames(funcprintfail_spec)
+    ex = AsyncExecutor(item)
+    cont, pid = ex.execute()
+    assert pid
+    outcome_repr = cont()
+    outcome = ReprOutcome(outcome_repr)
+    assert not outcome.passed
+    assert outcome.stdout == "samfing elz\n"

Modified: py/dist/py/test/rsession/testing/test_reporter.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_reporter.py	(original)
+++ py/dist/py/test/rsession/testing/test_reporter.py	Tue Dec 12 18:58:19 2006
@@ -140,7 +140,7 @@
         assert self.report_received_item_outcome() == 'FsF.'
 
     def test_module(self):
-        assert self._test_module().endswith("test_slave.py[8] FsF."),\
+        assert self._test_module().endswith("test_slave.py[9] FsF."),\
             self._test_module()
     
     def test_full_module(self):

Modified: py/dist/py/test/rsession/testing/test_rsession.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_rsession.py	(original)
+++ py/dist/py/test/rsession/testing/test_rsession.py	Tue Dec 12 18:58:19 2006
@@ -302,7 +302,7 @@
                         if isinstance(x, report.ReceivedItemOutcome)]
         passevents = [x for x in testevents if x.outcome.passed]
         assert len(passevents) == 1
-
+    
 class TestDirectories(object):
     def test_simple_parse(self):
         sshhosts = ['h1', 'h2', 'h3']

Modified: py/dist/py/test/rsession/testing/test_slave.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_slave.py	(original)
+++ py/dist/py/test/rsession/testing/test_slave.py	Tue Dec 12 18:58:19 2006
@@ -40,6 +40,10 @@
 def funcoptioncustom():
     assert py.test.remote.custom == "custom"
 
+def funchang():
+    import time
+    time.sleep(1000)
+
 BASE = "py/test/rsession/testing/test_slave.py/"
 funcpass_spec = (BASE + "funcpass").split("/")
 funcfail_spec = (BASE + "funcfail").split("/")
@@ -48,6 +52,7 @@
 funcprintfail_spec = (BASE + "funcprintfail").split("/")
 funcoption_spec = (BASE + "funcoption").split("/")
 funcoptioncustom_spec = (BASE + "funcoptioncustom").split("/")
+funchang_spec = (BASE + "funchang").split("/")
 mod_spec = BASE[:-1].split("/")
 
 # ----------------------------------------------------------------------
@@ -132,7 +137,7 @@
                 from py.__.test.rsession.rsession import remote_options
                 retval = remote_options.d
             else:
-                raise NotImplementedError("mora data")
+                raise NotImplementedError("more data")
             self.count += 1
             return retval
     try:
@@ -143,6 +148,43 @@
     else:
         py.test.fail("missing exception") 
     
+def test_slave_setup_exit():
+    tmp = py.test.ensuretemp("slaveexit")
+    tmp.ensure("__init__.py")
+    from py.__.test.rsession.slave import setup
+    from Queue import Queue
+    q = Queue()
+    
+    class C:
+        res = []
+        def __init__(self):
+            from py.__.test.rsession.rsession import remote_options
+            self.q = [str(tmp),
+                remote_options.d,
+                funchang_spec,
+                42,
+                funcpass_spec]
+            self.q.reverse()
+    
+        def receive(self):
+            return self.q.pop()
+        
+        def setcallback(self, callback):
+            import thread
+            def f():
+                while 1:
+                    callback(self.q.pop())
+            f()
+            #thread.start_new_thread(f, ())
+        
+        send = res.append
+    try:
+        exec py.code.Source(setup, "setup()").compile() in {'channel':C()}
+    except SystemExit:
+        pass
+    else:
+        py.test.fail("Did not exit")
+
 def test_slave_setup_fails_on_missing_pkg():
     from py.__.test.rsession.slave import setup 
     tmp = py.test.ensuretemp("slavesetup2")
@@ -158,7 +200,7 @@
                 from py.__.test.rsession.rsession import remote_options
                 retval = remote_options.d
             else:
-                raise NotImplementedError("mora data")
+                raise NotImplementedError("more data")
             self.count += 1
             return retval
     try:


More information about the py-svn mailing list