[Checkins] SVN: zc.ngi/trunk/src/zc/ngi/ Fixed some bugs in connector error handling.

Jim Fulton jim at zope.com
Fri Sep 8 15:01:50 EDT 2006


Log message for revision 70076:
  Fixed some bugs in connector error handling.
  

Changed:
  U   zc.ngi/trunk/src/zc/ngi/async.py
  U   zc.ngi/trunk/src/zc/ngi/testing.py
  U   zc.ngi/trunk/src/zc/ngi/tests.py

-=-
Modified: zc.ngi/trunk/src/zc/ngi/async.py
===================================================================
--- zc.ngi/trunk/src/zc/ngi/async.py	2006-09-08 19:01:47 UTC (rev 70075)
+++ zc.ngi/trunk/src/zc/ngi/async.py	2006-09-08 19:01:49 UTC (rev 70076)
@@ -169,7 +169,7 @@
             self.__handler_lock.release()
 
     def handle_expt(self):
-        self.handle_close('expt')
+        self.handle_close('socket error')
         
 
 class connector(dispatcher):
@@ -216,7 +216,7 @@
     def writable(self):
         return True
 
-    def handle_close(reason):
+    def handle_close(self, reason=None):
         if __debug__:
             self.logger.debug('connector close %r', reason)
         self.__handler.failed_connect(reason)
@@ -240,6 +240,15 @@
             _Connection(self.socket, self.addr, self.logger))
         return
 
+    def handle_error(self):
+        reason = sys.exc_info()[1]
+        self.logger.exception('connect error')
+        self.__handler.failed_connect(reason)
+        self.close()
+
+    def handle_expt(self):
+        self.handle_close('connection failed')
+
 class listener(asyncore.dispatcher):
 
     logger = logging.getLogger('zc.ngi.async.server')

Modified: zc.ngi/trunk/src/zc/ngi/testing.py
===================================================================
--- zc.ngi/trunk/src/zc/ngi/testing.py	2006-09-08 19:01:47 UTC (rev 70075)
+++ zc.ngi/trunk/src/zc/ngi/testing.py	2006-09-08 19:01:49 UTC (rev 70076)
@@ -147,3 +147,25 @@
         else:
             handler.connected(Connection(None, self.handler))
 
+# XXX This should move to zope.testing
+import random, socket
+def get_port():
+    """Return a port that is not in use.
+
+    Checks if a port is in use by trying to connect to it.  Assumes it
+    is not in use if connect raises an exception.
+
+    Raises RuntimeError after 10 tries.
+    """
+    for i in range(10):
+        port = random.randrange(20000, 30000)
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        try:
+            try:
+                s.connect(('localhost', port))
+            except socket.error:
+                # Perhaps we should check value of error too.
+                return port
+        finally:
+            s.close()
+    raise RuntimeError("Can't find port")

Modified: zc.ngi/trunk/src/zc/ngi/tests.py
===================================================================
--- zc.ngi/trunk/src/zc/ngi/tests.py	2006-09-08 19:01:47 UTC (rev 70075)
+++ zc.ngi/trunk/src/zc/ngi/tests.py	2006-09-08 19:01:49 UTC (rev 70076)
@@ -17,15 +17,49 @@
 """
 import unittest
 from zope.testing import doctest
+import zc.ngi.testing
 import zc.ngi.async # start async thread before tests run
 
+def test_async_cannot_connect():
+    """Let's make sure that the connector handles connection failures correctly
+
+    >>> import threading
+    >>> lock = threading.Lock()
+    >>> _ = lock.acquire()
+
+    We define a simple handler that just notifies of failed connectioons.
+
+    >>> class Handler:
+    ...     def failed_connect(connection, reason):
+    ...         print 'failed', reason
+    ...         lock.release()
+
+    >>> def connect(addr):
+    ...     zc.ngi.async.connector(addr, Handler())
+    ...     lock.acquire()
+
+    We find an unused port (so when we connect to it, the connection
+    will fail).
+
+    >>> port = zc.ngi.testing.get_port()
+
+    Now let's try to connect
+
+    >>> connect(('localhost', port))
+    failed connection failed
+    
+    """
+
 def test_suite():
-    return doctest.DocFileSuite(
-        'README.txt',
-        'message.txt',
-        'async.txt',
-        'adapters.txt',
-        )
+    return unittest.TestSuite([
+        doctest.DocFileSuite(
+            'README.txt',
+            'message.txt',
+            'async.txt',
+            'adapters.txt',
+            ),
+        doctest.DocTestSuite(),
+        ])
 
 if __name__ == '__main__':
     unittest.main(defaultTest='test_suite')



More information about the Checkins mailing list