[py-svn] r51222 - in py/branch/event/py/test2: . rsession rsession/testing testing

hpk at codespeak.net hpk at codespeak.net
Sat Feb 2 21:38:03 CET 2008


Author: hpk
Date: Sat Feb  2 21:38:02 2008
New Revision: 51222

Removed:
   py/branch/event/py/test2/rsession/testing/test_master.py
Modified:
   py/branch/event/py/test2/repevent.py
   py/branch/event/py/test2/rsession/hostmanage.py
   py/branch/event/py/test2/rsession/master.py
   py/branch/event/py/test2/rsession/rsession.py
   py/branch/event/py/test2/rsession/slave.py
   py/branch/event/py/test2/rsession/testing/basetest.py
   py/branch/event/py/test2/rsession/testing/test_hostmanage.py
   py/branch/event/py/test2/rsession/testing/test_rsession.py
   py/branch/event/py/test2/rsession/testing/test_slave.py
   py/branch/event/py/test2/session.py
   py/branch/event/py/test2/testing/test_itemgen.py
   py/branch/event/py/test2/testing/test_outcome.py
   py/branch/event/py/test2/testing/test_session2.py
Log:
* intermediate checkin (2 tests failing)
* sharing more code between dist and local sessions 
* strike one layer of indirection 
* remove some obscure and complicated (mostly skipped) tests 



Modified: py/branch/event/py/test2/repevent.py
==============================================================================
--- py/branch/event/py/test2/repevent.py	(original)
+++ py/branch/event/py/test2/repevent.py	Sat Feb  2 21:38:02 2008
@@ -67,7 +67,6 @@
         self.trail = trail 
         assert outcome in ("passed", "failed", "skipped") 
         setattr(self, outcome, True) 
-        self.outcome = outcome 
         self.info = info 
 
 # ----------------------------------------------------------------------
@@ -75,11 +74,9 @@
 # ----------------------------------------------------------------------
 
 class SendItem(BaseEvent):
-    def __init__(self, channel, item):
+    def __init__(self, host, item):
         self.item = item
-        self.channel = channel
-        if channel:
-            self.host = channel.gateway.host
+        self.host = host 
 
 class HostRSyncing(BaseEvent):
     def __init__(self, host, root, remotepath, synced):
@@ -97,12 +94,15 @@
         self.host = host
         self.roots = roots
 
+class HostDown(BaseEvent):
+    def __init__(self, host):
+        self.host = host 
+
 class HostRSyncRootReady(BaseEvent):
     def __init__(self, host, root):
         self.host = host
         self.root = root
 
-
 # ----------------------------------------------------------------------
 # XXX Extra Events XXX 
 # ----------------------------------------------------------------------

Modified: py/branch/event/py/test2/rsession/hostmanage.py
==============================================================================
--- py/branch/event/py/test2/rsession/hostmanage.py	(original)
+++ py/branch/event/py/test2/rsession/hostmanage.py	Sat Feb  2 21:38:02 2008
@@ -1,7 +1,6 @@
 import py
 import sys, os
 from py.__.test2.rsession.master import MasterNode
-from py.__.test2.rsession.slave import setup_slave
 from py.__.test2 import repevent
 
 class HostInfo(object):
@@ -157,43 +156,41 @@
 
     def setup_hosts(self):
         self.init_rsync()
-        nodes = []
         for host in self.hosts:
-            if hasattr(host.gw, 'remote_exec'): # otherwise dummy for tests :/
-                ch = setup_slave(host, self.config)
-                nodes.append(MasterNode(ch, self.config.hub.notify))
-        return nodes
-
-    def teardown_hosts(self, nodes, timeout=1.0): 
-        return
-        for node in nodes: 
-            node.channel.send(None) 
-        clean = False 
-        while not clean:
-            clean = True
-            for node in nodes:
-                if node.pending:
-                    clean = False
-            # XXX magic waiting
-            py.std.time.sleep(0.1) 
-        self.teardown_gateways(nodes) 
-
-    def kill_channels(self, channels):
-        for channel in channels:
-            channel.send(42)
-
-    def teardown_gateways(self, nodes):
-        return
-        self.config.hub.notify("teardown gateways %r" %(nodes,))
-        for node in nodes: 
-            #try:
-            try:
-                node.channel.waitclose(1.0)
-            except IOError: # timeout
-                # force closing
-                node.channel.close()
-            node.channel.gateway.exit()
+            host.node = MasterNode(host, self.config)
 
+    def teardown_hosts(self, timeout=1.0): 
+        # XXX teardown nodes and hosts 
+        queue = py.std.Queue.Queue()
+        def hostdown(event):
+            if isinstance(event, repevent.HostDown):
+                queue.put(event) 
+        self.config.hub.append(hostdown)
+
+        pending_hosts = []
+        for host in self.hosts: 
+            if not host.node.channel.isclosed():
+                host.node.channel.send(None)
+                pending_hosts.append(host) 
+
+        while pending_hosts: 
+            event = queue.get(timeout=timeout)
+            if event.host not in pending_hosts: 
+                print "got random HostDown of", event.host 
+            else:
+                pending_hosts.remove(event.host) 
+
+    def trysendtest(self, item):
+        for host in self.hosts:
+            node = getattr(host, 'node', None) 
+            if node and len(node.pending) < 15: # XXX
+                node.send(item)
+                return True
+       
+
+#
+# helpers 
+#
 def gethomedir():
     import os
     homedir = os.environ.get('HOME', '')

Modified: py/branch/event/py/test2/rsession/master.py
==============================================================================
--- py/branch/event/py/test2/rsession/master.py	(original)
+++ py/branch/event/py/test2/rsession/master.py	Sat Feb  2 21:38:02 2008
@@ -6,17 +6,19 @@
 from py.__.test2 import repevent
 
 class MasterNode(object):
-    def __init__(self, channel, notify): 
-        self.notify = notify 
-        self.channel = channel
+    def __init__(self, host, config):
+        self.host = host 
+        self.config = config 
+        self.notify = config.hub.notify 
+        self.channel = setup_slave(host, config)  
+        self.channel.setcallback(self._callback)
         self.pending = []
-        channel.setcallback(self._callback)
        
-    def _callback(self, outcome):
+    def _callback(self, outcomestring):
+        if outcomestring is None:
+            self.notify(repevent.HostDown(self.host))
+            return 
         item = self.pending.pop()
-        self.receive_result(outcome, item)
-
-    def receive_result(self, outcomestring, item):
         repr_outcome = ReprOutcome(outcomestring)
         # send finish report
         # XXX the following should be done by outcome serializing 
@@ -30,14 +32,12 @@
 
     def send(self, item):
         try:
-            if item is StopIteration:
-                self.channel.send(42)
+            if item is None: 
+                self.channel.send(None) 
             else:
-                self.pending.insert(0, item)
-            #itemspec = item.listnames()[1:]
                 self.channel.send(item._get_collector_trail())
-                # send start report
-                self.notify(repevent.SendItem(self.channel, item))
+                self.pending.insert(0, item)
+                self.notify(repevent.SendItem(self.host, item))
         except IOError:
             print "Sending error, channel IOError"
             print self.channel._getremoteerror()
@@ -45,23 +45,19 @@
             #      of hanging nodes and such
             raise
 
-def dispatch_loop(masternodes, itemgenerator, #shouldstop, 
-                  waiter = lambda: py.std.time.sleep(0.1),
-                  max_tasks_per_node=15):
-    all_tests = {}
-    while 1:
-        try:
-            for node in masternodes:
-                if len(node.pending) < max_tasks_per_node:
-                    item = itemgenerator.next()
-                    all_tests[item] = True
-                    #if shouldstop():
-                    #    for _node in masternodes:
-                    #        _node.send(StopIteration) # magic connector
-                    #    return None
-                    node.send(item)
-        except StopIteration:
-            break
-        waiter()
-    return all_tests
+# setting up slave code 
+from slave import setup 
+defaultconftestnames = ['dist_nicelevel']
+def setup_slave(host, config): 
+    channel = host.gw.remote_exec(str(py.code.Source(setup, "setup()")))
+    configrepr = config._makerepr(defaultconftestnames)
+    #print "sending configrepr", configrepr
+    topdir = host.gw_remotepath 
+    if topdir is None:
+        assert host.inplacelocal
+        topdir = config.topdir
+    channel.send(str(topdir))
+    channel.send(configrepr) 
+    return channel
+
 

Modified: py/branch/event/py/test2/rsession/rsession.py
==============================================================================
--- py/branch/event/py/test2/rsession/rsession.py	(original)
+++ py/branch/event/py/test2/rsession/rsession.py	Sat Feb  2 21:38:02 2008
@@ -1,27 +1,22 @@
-
-""" Remote session base class
+""" 
+    Remote Session Base Class 
 """
 
 import os
 import py
-import sys
-import re
-import time
 
-from py.__.test2 import repevent
-from py.__.test2.rsession.master import dispatch_loop
+from py.__.test2.session import Session 
 from py.__.test2.rsession.hostmanage import HostManager
-from py.__.test2.session import AbstractSession, itemgen
     
-class RSession(AbstractSession):
-    """ Remote version of session
+class RSession(Session): 
+    """ Distributing tests to remote places. 
     """
     def fixoptions(self):
         super(RSession, self).fixoptions()
         option = self.config.option 
         if option.nocapture:
             print "Cannot use nocapture with distributed testing"
-            sys.exit(1)
+            py.std.sys.exit(1)
         config = self.config
         try:
             config.getvalue('dist_hosts')
@@ -37,37 +32,20 @@
             print "see also: http://codespeak.net/py/current/doc/test.html#automated-distributed-testing"
             raise SystemExit
 
-    def main(self):
-        """ main loop for running tests. """
-        hm = HostManager(self.config)
-        hub = self.config.hub
-        hub.notify(repevent.SessionStart(self))
-        try:
-            nodes = hm.setup_hosts()
-            try:
-                self.dispatch_tests(nodes)
-            except (KeyboardInterrupt, SystemExit):
-                print >>sys.stderr, "C-c pressed waiting for gateways to teardown..."
-                channels = [node.channel for node in nodes]
-                hm.kill_channels(channels)
-                hm.teardown_gateways(channels)
-                print >>sys.stderr, "... Done"
-                raise
-
-            print "tearing down nodes"
-            hm.teardown_hosts(nodes)
-            hub.notify(repevent.SessionFinish(self))
-        except (KeyboardInterrupt, SystemExit):
-            hub.notify(repevent.InterruptedExecution())
-            raise
-        except:
-            hub.notify(repevent.CrashedExecution())
-            raise
-
-    def dispatch_tests(self, nodes):
-        colitems = self.config.getcolitems()
-        keyword = self.config.option.keyword
-        itemgenerator = itemgen(self, colitems, keyword)
-        max_tasks_per_node = self.config.getvalue("dist_taskspernode")
-        all_tests = dispatch_loop(nodes, itemgenerator, 
-                                  max_tasks_per_node=max_tasks_per_node)
+    def setup(self):
+        super(RSession, self).setup()
+        self.hm = hm = HostManager(self.config)
+        self.hm.setup_hosts()
+
+    def teardown(self):
+        super(RSession, self).teardown()
+        self.hm.teardown_hosts()
+
+    def runtest(self, item):
+        # dispatch tests to host manager 
+        sent = self.hm.trysendtest(item)
+        if not sent and not self.shouldstop:
+            self.sleepabit()
+
+    def sleepabit(self):
+        py.std.time.sleep(0.1)

Modified: py/branch/event/py/test2/rsession/slave.py
==============================================================================
--- py/branch/event/py/test2/rsession/slave.py	(original)
+++ py/branch/event/py/test2/rsession/slave.py	Sat Feb  2 21:38:02 2008
@@ -44,6 +44,7 @@
     while 1:
         nextitem = receive()
         if nextitem is None:
+            send(None)
             break
         try:
             node = getnode(nextitem)
@@ -54,28 +55,13 @@
             excinfo = py.code.ExceptionInfo()
             send(SerializableOutcome(excinfo=excinfo, is_critical=True).make_repr())
         else:
+            send(res) 
             if not res[0] and not res[3] and config.option.exitfirst:
-                # we're finished, but need to eat what we can
-                send(res)
                 break
-            send(res)
-    
+    # we're finished, but we should eat what we can 
     while nextitem is not None:
         nextitem = receive()
 
-defaultconftestnames = ['dist_nicelevel']
-def setup_slave(host, config): 
-    channel = host.gw.remote_exec(str(py.code.Source(setup, "setup()")))
-    configrepr = config._makerepr(defaultconftestnames)
-    #print "sending configrepr", configrepr
-    topdir = host.gw_remotepath 
-    if topdir is None:
-        assert host.inplacelocal
-        topdir = config.topdir
-    channel.send(str(topdir))
-    channel.send(configrepr) 
-    return channel
-
 def setup():
     # our current dir is the topdir
     import os, sys

Modified: py/branch/event/py/test2/rsession/testing/basetest.py
==============================================================================
--- py/branch/event/py/test2/rsession/testing/basetest.py	(original)
+++ py/branch/event/py/test2/rsession/testing/basetest.py	Sat Feb  2 21:38:02 2008
@@ -7,13 +7,13 @@
 def func_source():
     import py
     import time
-    def funcpass(): 
+    def funcpassed(): 
         pass
 
-    def funcfail():
+    def funcfailed():
         raise AssertionError("hello world")
 
-    def funcskip():
+    def funcskipped():
         py.test2.skip("skipped")
 
     def funcprint():

Modified: py/branch/event/py/test2/rsession/testing/test_hostmanage.py
==============================================================================
--- py/branch/event/py/test2/rsession/testing/test_hostmanage.py	(original)
+++ py/branch/event/py/test2/rsession/testing/test_hostmanage.py	Sat Feb  2 21:38:02 2008
@@ -268,6 +268,7 @@
         print events
         assert 0
 
+
 def test_getpath_relto_home():
     x = getpath_relto_home("hello")
     assert x == py.path.local._gethomedir().join("hello")

Deleted: /py/branch/event/py/test2/rsession/testing/test_master.py
==============================================================================
--- /py/branch/event/py/test2/rsession/testing/test_master.py	Sat Feb  2 21:38:02 2008
+++ (empty file)
@@ -1,198 +0,0 @@
-""" master code and test dispatching for 
-    making 1-n master -> slave connection
-    and test it locally. 
-"""
-
-import time, threading
-import py, sys
-
-if sys.platform == 'win32':
-    py.test.skip("rsession is unsupported on Windows.")
-
-from py.__.test2.rsession.master import dispatch_loop, MasterNode
-from py.__.test2.rsession.slave import setup_slave 
-from py.__.test2.outcome import ReprOutcome, SerializableOutcome 
-from py.__.test2 import repevent
-from py.__.test2.rsession.hostmanage import HostInfo
-
-def setup_module(mod):
-    # bind an empty config
-    mod.tmpdir = tmpdir = py.test2.ensuretemp(mod.__name__)
-    # to avoid rsyncing
-    config = py.test2.config._reparse([tmpdir])
-    config.option.dist_taskspernode = 10 
-    mod.rootcol = config._getcollector(tmpdir)
-
-class DummyGateway(object):
-    def __init__(self):
-        self.host = HostInfo("localhost")
-
-class DummyChannel(object):
-    def __init__(self):
-        self.sent = []
-        self.gateway = DummyGateway()
-
-    def setcallback(self, func):
-        self.callback = func 
-
-    def send(self, item):
-        assert py.std.marshal.dumps(item)
-        self.sent.append(item)
-
-class NonWorkingChannel(object):
-    def setcallback(self, func):
-        pass
-
-    def send(self, item):
-        raise IOError
-
-    def _getremoteerror(self):
-        return "blah"
-
-class Item(py.test2.collect.Item):
-    def _get_collector_trail(self):
-        return (self.name,)
-
-def test_masternode():
-    try:
-        raise ValueError()
-    except ValueError:
-        excinfo = py.code.ExceptionInfo()
-    
-    ch = DummyChannel()
-    reportlist = []
-    mnode = MasterNode(ch, reportlist.append)
-    mnode.send(Item("ok"))
-    mnode.send(Item("notok"))
-    ch.callback(SerializableOutcome().make_repr())
-    ch.callback(SerializableOutcome(excinfo=excinfo).make_repr())
-    assert len(reportlist) == 4
-    received = [i for i in reportlist 
-        if isinstance(i, repevent.ItemTestReport)]
-    py.test.skip("XXX fix master tests") 
-    assert received[0].outcome.passed 
-    assert not received[1].outcome.passed 
-
-def test_masternode_nonworking_channel():
-    ch = NonWorkingChannel()
-    reportlist = []
-    mnode = MasterNode(ch, reportlist.append)
-    cap = py.io.StdCaptureFD()
-    py.test2.raises(IOError, 'mnode.send(Item("ok"))')
-    out, err = cap.reset()
-    assert out.find("blah") != -1
-
-def test_sending_two_noes():
-    # XXX fijal: this test previously tested that the second
-    #     item result would not get send. why? did i miss
-    #     something? 
-    #     
-    ch = DummyChannel()
-    reportlist = []
-    mnode = MasterNode(ch, reportlist.append)
-    mnode.send(Item("ok"))
-    mnode.send(Item("ok"))
-    ch.callback(SerializableOutcome().make_repr())
-    ch.callback(SerializableOutcome().make_repr())
-    assert len(reportlist) == 4
-
-def test_outcome_repr():
-    out = ReprOutcome(SerializableOutcome(skipped="xxx").make_repr())
-    s = repr(out)
-    assert s.lower().find("skip") != -1
-
-class DummyMasterNode(object):
-    def __init__(self):
-        self.pending = []
-    
-    def send(self, data):
-        self.pending.append(data)
-
-def test_dispatch_loop():
-    masternodes = [DummyMasterNode(), DummyMasterNode()]
-    itemgenerator = iter(range(100))
-    shouldstop = lambda : False
-    def waiter():
-        for node in masternodes:
-            node.pending.pop()
-    dispatch_loop(masternodes, itemgenerator, waiter=waiter)
-
-class TestSlave:
-    def setup_class(cls):
-        cls.tmpdir = tmpdir = py.test2.ensuretemp(cls.__name__)
-        cls.pkgpath = pkgpath = tmpdir.join("slavetestpkg")
-        pkgpath.ensure("__init__.py")
-        pkgpath.join("test_something.py").write(py.code.Source("""
-            def funcpass(): 
-                pass
-
-            def funcfail():
-                raise AssertionError("hello world")
-        """))
-        cls.config = py.test2.config._reparse([tmpdir])
-        assert cls.config.topdir == tmpdir
-        cls.rootcol = cls.config._getcollector(tmpdir)
-
-    def _gettrail(self, *names):
-        item = self.rootcol._getitembynames(names)
-        return self.config.get_collector_trail(item) 
-        
-    def test_slave_running(self):
-        py.test.skip("XXX test broken, needs refactoring")
-        def simple_report(event):
-            if not isinstance(event, repevent.ItemFinish):
-                return
-            item = event.item
-            if item.code.name == 'funcpass':
-                assert event.outcome.passed
-            else:
-                assert not event.outcome.passed
-        
-        def open_gw():
-            gw = py.execnet.PopenGateway()
-            host = HostInfo("localhost")
-            host.gw_remotepath = ''
-            host.gw = gw
-            #gw.host.gw = gw
-            config = py.test2.config._reparse([tmpdir])
-            channel = setup_slave(host, config)
-            mn = MasterNode(channel, simple_report)
-            return mn
-        
-        master_nodes = [open_gw(), open_gw(), open_gw()]
-        funcpass_item = self.xxx
-        funcfail_item = rootcol._getitembynames(funcfail_spec)
-        itemgenerator = iter([funcfail_item] + 
-                             [funcpass_item] * 5 + [funcfail_item] * 5)
-        shouldstop = lambda : False
-        dispatch_loop(master_nodes, itemgenerator, shouldstop)
-
-def test_slave_running_interrupted():
-    py.test.skip("XXX test broken, needs refactoring")
-    #def simple_report(event):
-    #    if not isinstance(event, repevent.ItemFinish):
-    #        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.test2.config._reparse([tmpdir])
-        channel = setup_slave(gw.host, config)
-        mn = MasterNode(channel, reports.append, {})
-        return mn, gw, channel
-
-    mn, gw, channel = open_gw()
-    rootcol = py.test2.collect.Directory(pkgdir)
-    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)
-

Modified: py/branch/event/py/test2/rsession/testing/test_rsession.py
==============================================================================
--- py/branch/event/py/test2/rsession/testing/test_rsession.py	(original)
+++ py/branch/event/py/test2/rsession/testing/test_rsession.py	Sat Feb  2 21:38:02 2008
@@ -37,9 +37,6 @@
         """))
         config = py.test2.config._reparse([self.source.join("sub"), '-x'])
         rsession = RSession(config)
-        def f(ev):
-            print ev
-        config.hub.append(f)
         allevents = getevents_runmain(rsession)
         testevents = [x for x in allevents 
                         if isinstance(x, repevent.ItemTestReport)]
@@ -92,29 +89,31 @@
         queue = py.std.Queue.Queue()
         self.config.hub.append(queue.put) 
         hm = HostManager(self.config, hosts=hosts)
-        nodes = hm.setup_hosts()
+        hm.setup_hosts()
         
         # actually run some tests
-        for node in nodes:
-            node.send(self.getexample("pass"))
-            node.send(self.getexample("fail")) 
-            node.send(self.getexample("skip"))
+        for host in hm.hosts: 
+            node = host.node
+            node.send(self.getexample("passed"))
+            node.send(self.getexample("failed")) 
+            node.send(self.getexample("skipped"))
             node.send(self.getexample("print"))
 
+        num_hosts = len(hm.hosts) 
         events = []
-        while len(events) < 4 * len(nodes): 
+        while len(events) < 4 * num_hosts:
             item = queue.get(timeout=0.5) 
             if isinstance(item, repevent.ItemTestReport):
                 events.append(item) 
         print "got all events", events
-        hm.teardown_hosts(nodes) 
+        hm.teardown_hosts() 
         passed = [ev for ev in events 
                         if ev.passed]
         skipped = [ev for ev in events 
                         if ev.skipped]
-        assert len(passed) == 2 * len(nodes)
-        assert len(skipped) == len(nodes)
-        assert len(events) == 4 * len(nodes)
+        assert len(passed) == 2 * num_hosts 
+        assert len(skipped) == num_hosts 
+        assert len(events) == 4 * num_hosts 
         # one of passed for each node has non-empty stdout
         #passed_stdout = [i for i in passed if i.outcome.stdout.find('samfing') != -1]
         #assert len(passed_stdout) == len(nodes), passed

Modified: py/branch/event/py/test2/rsession/testing/test_slave.py
==============================================================================
--- py/branch/event/py/test2/rsession/testing/test_slave.py	(original)
+++ py/branch/event/py/test2/rsession/testing/test_slave.py	Sat Feb  2 21:38:02 2008
@@ -22,7 +22,7 @@
 
     def test_slave_run_passing(self):
         node = self.gettestnode()
-        item = self.getexample("pass")
+        item = self.getexample("passed")
         outcome = node.execute(item._get_collector_trail())
         assert outcome.passed 
         assert not outcome.setupfailure 
@@ -34,12 +34,12 @@
 
     def test_slave_run_failing(self):
         node = self.gettestnode()
-        item = self.getexample("fail") 
+        item = self.getexample("failed") 
         outcome = node.execute(item._get_collector_trail())
         assert not outcome.passed 
         assert not outcome.setupfailure 
         assert len(outcome.excinfo.traceback) == 1
-        assert outcome.excinfo.traceback[-1].frame.code.name == 'funcfail'
+        assert outcome.excinfo.traceback[-1].frame.code.name == 'funcfailed'
 
         ser = outcome.make_repr()
         reproutcome = ReprOutcome(ser) 
@@ -49,7 +49,7 @@
     
     def test_slave_run_skipping(self):
         node = self.gettestnode()
-        item = self.getexample("skip")
+        item = self.getexample("skipped")
         outcome = node.execute(item._get_collector_trail())
         assert not outcome.passed
         assert outcome.skipped
@@ -61,7 +61,7 @@
 
     def test_slave_run_failing_wrapped(self):
         node = self.gettestnode()
-        item = self.getexample("fail") 
+        item = self.getexample("failed") 
         repr_outcome = node.run(item._get_collector_trail()) 
         outcome = ReprOutcome(repr_outcome)  
         assert not outcome.passed 

Modified: py/branch/event/py/test2/session.py
==============================================================================
--- py/branch/event/py/test2/session.py	(original)
+++ py/branch/event/py/test2/session.py	Sat Feb  2 21:38:02 2008
@@ -12,38 +12,13 @@
 
 GeneratorExit = py.builtin.GeneratorExit 
 
-def itemgen(session, colitems, keywordexpr=None):
-    hub = session.config.hub
-    stopitems = py.test2.collect.Item # XXX should be generator here as well
-    while colitems: 
-        next = colitems.pop(0)
-        if isinstance(next, stopitems):
-            if next._skipbykeyword(keywordexpr):
-                hub.notify(repevent.DeselectedTest(next, keywordexpr))
-                if session.config.option.keyword_oneshot:
-                    keywordexpr = None
-            else:
-                yield next 
-        else:
-            hub.notify(repevent.CollectionStart(next))
-            try:
-                cols = [next.join(x) for x in next.run()]
-                for x in itemgen(session, cols, keywordexpr):
-                    yield x
-            except (KeyboardInterrupt, SystemExit, GeneratorExit):
-                raise
-            except:
-                excinfo = py.code.ExceptionInfo()
-                hub.notify(repevent.CollectionFinish(next, excinfo))
-            else:
-                hub.notify(repevent.CollectionFinish(next))
-
-class AbstractSession(object): 
-    """ An abstract session executes collectors/items through a runner. 
-    """
+class Session(object): 
+    """ 
+        Session drives the collection and running of tests
+        and generates test events for reporters. 
+    """ 
     def __init__(self, config):
         self.config = config
-        self._keyword = config.option.keyword
 
     def fixoptions(self):
         """ check, fix and determine conflicting options. """
@@ -60,64 +35,87 @@
             raise ValueError, "--looponfailing together with --dist not supported."
         if option.executable and option.usepdb:
             raise ValueError, "--exec together with --pdb not supported."
-
         if option.keyword_oneshot and not option.keyword:
             raise ValueError, "--keyword-oneshot makes sense only when --keyword is supplied"
 
-class Session(AbstractSession):
-    """
-        A Session gets test Items from Collectors, executes the
-        Items and sends the Outcome to the Reporter.
-    """
-    def shouldclose(self): 
-        return False
+    def collect(self): 
+        colitems = self.config.getcolitems()
+        keyword = self.config.option.keyword
+        for x in self.genitems(colitems, keyword):
+            yield x
 
-    def header(self, colitems):
+    def genitems(self, colitems, keywordexpr=None):
+        hub = self.config.hub
+        stopitems = py.test2.collect.Item 
+        while colitems: 
+            next = colitems.pop(0)
+            if isinstance(next, stopitems):
+                if next._skipbykeyword(keywordexpr):
+                    hub.notify(repevent.DeselectedTest(next, keywordexpr))
+                    if self.config.option.keyword_oneshot:
+                        keywordexpr = None
+                else:
+                    yield next 
+            else:
+                hub.notify(repevent.CollectionStart(next))
+                excinfo = None
+                try:
+                    cols = [next.join(x) for x in next.run()]
+                    for x in self.genitems(cols, keywordexpr):
+                        yield x
+                except (KeyboardInterrupt, SystemExit, GeneratorExit):
+                    raise
+                except:
+                    excinfo = py.code.ExceptionInfo()
+                hub.notify(repevent.CollectionFinish(next, excinfo))
+
+    def setup(self):
         """ setup any neccessary resources ahead of the test run. """
-        self.config.hub.notify(repevent.SessionStart(self))
         if not self.config.option.nomagic:
             py.magic.invoke(assertion=1)
+        self._failurelist = self._initfailurelist()
 
-    def footer(self, colitems):
+    def teardown(self):
         """ teardown any resources after a test run. """ 
         py.test2.collect.Function._state.teardown_all()
         if not self.config.option.nomagic:
             py.magic.revoke(assertion=1)
-        self.config.hub.notify(repevent.SessionFinish(self))
-    
+        return self._failurelist 
+
+    def _initfailurelist(self):
+        failurelist = []
+        def processfailures(event):
+            if isinstance(event, repevent.ItemFinish) and event.failed: 
+                failurelist.append(event) 
+                if self.config.option.exitfirst: 
+                    self.shouldstop = True 
+        self.config.hub.append(processfailures) 
+        return failurelist 
+
     def main(self):
         """ main loop for running tests. """
-        config = self.config
-        colitems = self.config.getcolitems()
-        self.header(colitems)
-        keyword = self.config.option.keyword
-        itemgenerator = itemgen(self, colitems, keyword)
-        failures = []
+        self.shouldstop = False 
+        self.setup()
+        self.config.hub.notify(repevent.SessionStart(self))
         try:
-            while 1:
-                try:
-                    item = itemgenerator.next()
-                    if not self.config.option.collectonly: 
-                        outcome = self.run(item)
-                        self.config.hub.notify(repevent.ItemFinish(item, outcome.excinfo))
-                        if outcome is not None: 
-                            if not outcome.passed and not outcome.skipped: 
-                                failures.append((item, outcome))
-                                if self.config.option.exitfirst: 
-                                    raise StopIteration()
-                except StopIteration:
-                    break
+            for item in self.collect(): 
+                if self.shouldstop: 
+                    break 
+                if not self.config.option.collectonly: 
+                    self.runtest(item)
         finally:
-            self.footer(colitems)
+            failures = self.teardown()
+        self.config.hub.notify(repevent.SessionFinish(self))
         return failures 
 
-    def run(self, item):
+    def runtest(self, item):
         if not self.config.option.boxed:
             executor = RunExecutor(item, config=self.config)
-            return ReprOutcome(executor.execute().make_repr())
+            outcome = ReprOutcome(executor.execute().make_repr())
         else:
             executor = BoxExecutor(item, config=self.config)
-            return ReprOutcome(executor.execute())
+            outcome = ReprOutcome(executor.execute())
+        self.config.hub.notify(repevent.ItemFinish(item, outcome.excinfo))
 
 class Exit(Exception):
     """ for immediate program exits without tracebacks and reporter/summary. """

Modified: py/branch/event/py/test2/testing/test_itemgen.py
==============================================================================
--- py/branch/event/py/test2/testing/test_itemgen.py	(original)
+++ py/branch/event/py/test2/testing/test_itemgen.py	Sat Feb  2 21:38:02 2008
@@ -1,6 +1,5 @@
 
 import py
-from py.__.test2.session import itemgen
 from py.__.test2 import repevent
 
 class TestItemgen:

Modified: py/branch/event/py/test2/testing/test_outcome.py
==============================================================================
--- py/branch/event/py/test2/testing/test_outcome.py	(original)
+++ py/branch/event/py/test2/testing/test_outcome.py	Sat Feb  2 21:38:02 2008
@@ -62,3 +62,9 @@
 
 #def test_f3():
 #    f3()
+
+def test_outcome_repr():
+    out = ReprOutcome(SerializableOutcome(skipped="xxx").make_repr())
+    s = repr(out)
+    assert s.lower().find("skip") != -1
+

Modified: py/branch/event/py/test2/testing/test_session2.py
==============================================================================
--- py/branch/event/py/test2/testing/test_session2.py	(original)
+++ py/branch/event/py/test2/testing/test_session2.py	Sat Feb  2 21:38:02 2008
@@ -11,12 +11,15 @@
 def getevents_runmain(session):
     hub = session.config.hub 
     allevents = []
-    hub.append(allevents.append) 
+    def appendevent(event):
+        allevents.append(event)
+        print event 
+    hub.append(appendevent) 
     try:
         session.main()
         return allevents 
     finally:
-        hub.remove(allevents.append) 
+        hub.remove(appendevent) 
 
 
 def setup_module(mod):



More information about the pytest-commit mailing list