[Checkins] SVN: zc.async/trunk/src/zc/async/ Merge in testing fixes from branches/patrick-twisted

Patrick Strawderman patrick at zope.com
Fri Jan 15 17:59:20 EST 2010


Log message for revision 108169:
  Merge in testing fixes from branches/patrick-twisted

Changed:
  U   zc.async/trunk/src/zc/async/CHANGES.txt
  U   zc.async/trunk/src/zc/async/QUICKSTART_1_VIRTUALENV.txt
  U   zc.async/trunk/src/zc/async/ftesting.py
  U   zc.async/trunk/src/zc/async/monitor.txt
  U   zc.async/trunk/src/zc/async/parallel_serial.txt
  U   zc.async/trunk/src/zc/async/subscribers.py
  U   zc.async/trunk/src/zc/async/testing.py
  U   zc.async/trunk/src/zc/async/tests.py
  U   zc.async/trunk/src/zc/async/twisted.txt

-=-
Modified: zc.async/trunk/src/zc/async/CHANGES.txt
===================================================================
--- zc.async/trunk/src/zc/async/CHANGES.txt	2010-01-15 22:55:49 UTC (rev 108168)
+++ zc.async/trunk/src/zc/async/CHANGES.txt	2010-01-15 22:59:20 UTC (rev 108169)
@@ -8,6 +8,14 @@
 - Rearrange ftesting.setUp to avoid provoking a DemoStorage bug
   present in ZODB <= 3.9.3.
 
+- Resolved the following testing issues: signal handlers weren't cleaned
+  up properly in some tests, Twisted was leaking file descriptors during
+  ftesting tearDown (http://twistedmatrix.com/trac/ticket/3063), and
+  the twisted.txt regression test was not repeatable due to
+  Twisted's recalcitrance when it comes to stopping and subsequently
+  starting a reactor instance.
+
+
 1.5.3 (2009-11-15)
 ==================
 

Modified: zc.async/trunk/src/zc/async/QUICKSTART_1_VIRTUALENV.txt
===================================================================
--- zc.async/trunk/src/zc/async/QUICKSTART_1_VIRTUALENV.txt	2010-01-15 22:55:49 UTC (rev 108168)
+++ zc.async/trunk/src/zc/async/QUICKSTART_1_VIRTUALENV.txt	2010-01-15 22:59:20 UTC (rev 108169)
@@ -1022,3 +1022,4 @@
     >>> reactor = dispatcher.reactor
     >>> reactor.callFromThread(reactor.stop)
     >>> dispatcher.thread.join(3)
+    >>> zc.async.subscribers.restore_signal_handlers(dispatcher)

Modified: zc.async/trunk/src/zc/async/ftesting.py
===================================================================
--- zc.async/trunk/src/zc/async/ftesting.py	2010-01-15 22:55:49 UTC (rev 108168)
+++ zc.async/trunk/src/zc/async/ftesting.py	2010-01-15 22:59:20 UTC (rev 108169)
@@ -59,13 +59,8 @@
     zc.async.testing.tear_down_dispatcher(dispatcher)
     zc.async.dispatcher.clear()
     # Restore previous signal handlers
-    key = id(dispatcher)
-    sighandlers = zc.async.subscribers.signal_handlers.get(key)
-    if sighandlers:
-        for _signal, handlers in sighandlers.items():
-            prev, cur = handlers
-            # The previous signal handler is only restored if the currently
-            # registered handler is the one we originally installed.
-            if signal.getsignal(_signal) is cur:
-                signal.signal(_signal, prev)
-        del zc.async.subscribers.signal_handlers[key]
+    zc.async.subscribers.restore_signal_handlers(dispatcher)
+    # Avoid leaking file descriptors
+    # (see http://twistedmatrix.com/trac/ticket/3063).
+    dispatcher.reactor.removeReader(dispatcher.reactor.waker)
+    dispatcher.reactor.waker.connectionLost(None)

Modified: zc.async/trunk/src/zc/async/monitor.txt
===================================================================
--- zc.async/trunk/src/zc/async/monitor.txt	2010-01-15 22:55:49 UTC (rev 108168)
+++ zc.async/trunk/src/zc/async/monitor.txt	2010-01-15 22:59:20 UTC (rev 108169)
@@ -676,8 +676,6 @@
     -> CLOSE
 
     >>> reactor.stop()
-    >>> import time
-    >>> time.sleep(1)
 
 .. [#setUp] See the discussion in other documentation to explain this code.
 

Modified: zc.async/trunk/src/zc/async/parallel_serial.txt
===================================================================
--- zc.async/trunk/src/zc/async/parallel_serial.txt	2010-01-15 22:55:49 UTC (rev 108168)
+++ zc.async/trunk/src/zc/async/parallel_serial.txt	2010-01-15 22:59:20 UTC (rev 108169)
@@ -70,7 +70,7 @@
     ...         lock.release()
     ...     for thread in threads:
     ...         thread.join(3)
-    ...
+    ...     zc.async.subscribers.restore_signal_handlers(dispatcher)
 
 First we'll test ``serial``.  We stop the worker once while it is working on
 one of the serialized jobs, and once while it is working on the postprocess.

Modified: zc.async/trunk/src/zc/async/subscribers.py
===================================================================
--- zc.async/trunk/src/zc/async/subscribers.py	2010-01-15 22:55:49 UTC (rev 108168)
+++ zc.async/trunk/src/zc/async/subscribers.py	2010-01-15 22:59:20 UTC (rev 108169)
@@ -78,6 +78,19 @@
 multidb_queue_installer = QueueInstaller(db_name='async')
 signal_handlers = {} # id(dispatcher) -> signal -> (prev handler, curr handler)
 
+def restore_signal_handlers(dispatcher):
+    key = id(dispatcher)
+    sighandlers = signal_handlers.get(key)
+    if sighandlers:
+        for _signal, handlers in sighandlers.items():
+            prev, cur = handlers
+            # The previous signal handler is only restored if the currently
+            # registered handler is the one we originally installed.
+            if signal.getsignal(_signal) is cur:
+                signal.signal(_signal, prev)
+        del signal_handlers[key]
+
+
 class ThreadedDispatcherInstaller(object):
     def __init__(self,
                  poll_interval=5,

Modified: zc.async/trunk/src/zc/async/testing.py
===================================================================
--- zc.async/trunk/src/zc/async/testing.py	2010-01-15 22:55:49 UTC (rev 108168)
+++ zc.async/trunk/src/zc/async/testing.py	2010-01-15 22:59:20 UTC (rev 108169)
@@ -299,6 +299,7 @@
                 jobid = '[job unknown]'
             problems.append(
                 'Job in pool %r failed to stop: %s' % (pool.name, jobid))
+    zc.async.subscribers.restore_signal_handlers(dispatcher)
     if problems:
         problems = '\n' + '\n'.join(problems)
         raise TearDownDispatcherError(problems)

Modified: zc.async/trunk/src/zc/async/tests.py
===================================================================
--- zc.async/trunk/src/zc/async/tests.py	2010-01-15 22:55:49 UTC (rev 108168)
+++ zc.async/trunk/src/zc/async/tests.py	2010-01-15 22:59:20 UTC (rev 108169)
@@ -14,19 +14,23 @@
 import os
 import unittest
 import re
+import signal
 
+import transaction
+
 from zope.testing import doctest, module, loggingsupport, renormalizing
 import zope.component
 import zope.component.testing
 import zope.component.eventtesting
+import zc.async.dispatcher
+import zc.async.instanceuuid
 import zc.async.interfaces
+import zc.async.subscribers
 import zc.async.testing
 
 def uuidSetUp(test):
-    import zc.async.interfaces
     os.environ['ZC_ASYNC_UUID'] = os.path.join(os.path.dirname(
         zc.async.interfaces.__file__), 'uuid.txt')
-    import zc.async.instanceuuid
     uuid = zc.async.instanceuuid.getUUID()
     if uuid != zc.async.instanceuuid.UUID: # test run changed it...
         zc.async.instanceuuid.UUID = uuid
@@ -45,15 +49,13 @@
         'zc.async.trace')
 
 def modTearDown(test):
-    import transaction
+    assert len(zc.async.subscribers.signal_handlers) == 0
     transaction.abort()
-    import zc.async.dispatcher
     zc.async.dispatcher.clear()
     uuidTearDown(test)
     zc.async.testing.tearDownDatetime()
     module.tearDown(test)
     zope.component.testing.tearDown(test)
-    import signal
     signal.signal(signal.SIGINT, signal.default_int_handler)
     if 'storage' in test.globs:
         test.globs['db'].close()

Modified: zc.async/trunk/src/zc/async/twisted.txt
===================================================================
--- zc.async/trunk/src/zc/async/twisted.txt	2010-01-15 22:55:49 UTC (rev 108168)
+++ zc.async/trunk/src/zc/async/twisted.txt	2010-01-15 22:59:20 UTC (rev 108169)
@@ -41,3 +41,17 @@
     >>> import zc.async.testing
     >>> zc.async.testing.wait_for_result(j)
     42
+
+Clean Up
+========
+
+We do the following to avoid leaking file descriptors
+(see http://twistedmatrix.com/trac/ticket/3063).
+
+    >>> twisted.internet.reactor.removeReader(twisted.internet.reactor.waker)
+    >>> twisted.internet.reactor.waker.connectionLost(None)
+
+And we instantiate a new reactor because the Twisted reactors don't
+run correctly after being stopped.
+
+    >>> twisted.internet.reactor = twisted.internet.reactor.__class__()



More information about the checkins mailing list