Index: asyncore.py =================================================================== --- asyncore.py (revision 74147) +++ asyncore.py (working copy) @@ -416,8 +416,11 @@ self.handle_read() def handle_connect_event(self): + # Since we don't know if we are connected yet here, set the connected + # state only after the connect event. This prevent unwanted failure + # when trying to send to unconnected socket. + self.handle_connect() self.connected = True - self.handle_connect() def handle_write_event(self): if self.accepting: Index: test/test_asyncore.py =================================================================== --- test/test_asyncore.py (revision 74147) +++ test/test_asyncore.py (working copy) @@ -1,8 +1,10 @@ import asyncore +import asynchat import unittest import select import os import socket +import errno import threading import sys import time @@ -302,7 +304,57 @@ self.assertEquals(lines, expected) +class testing_channel(asynchat.async_chat): + def __init__(self, *a, **kw): + asynchat.async_chat.__init__(self, *a, **kw) + self.exceptions = [] + self.close_count = 0 + def collect_incoming_data(self, data): + pass + + def found_terminator(self): + pass + + def handle_connect(self): + self.push("connected") + + def handle_error(self): + self.exceptions.append(sys.exc_info()[1]) + self.handle_close() + + def handle_close(self): + self.close_count += 1 + self.close() + + +class ConnectionRefusedTests(unittest.TestCase): + + def setUp(self): + s = socket.socket() + self.channel = testing_channel(s) + + # Assumes that noone is listeing here + self.channel.connect(('localhost', 65535)) + + # give time for socket to connect + time.sleep(0.1) + + asyncore.poll() + + def tearDown(self): + asyncore.close_all() + + def test_single_exception(self): + self.assertEqual(len(self.channel.exceptions), 1) + + def test_connection_refused(self): + self.assertEqual(self.channel.exceptions[0].args[0], errno.ECONNREFUSED) + + def test_close_once(self): + self.assertEqual(self.channel.close_count, 1) + + class dispatcherwithsend_noread(asyncore.dispatcher_with_send): def readable(self): return False @@ -393,8 +445,8 @@ def test_main(): - tests = [HelperFunctionTests, DispatcherTests, DispatcherWithSendTests, - DispatcherWithSendTests_UsePoll] + tests = [HelperFunctionTests, DispatcherTests, ConnectionRefusedTests, + DispatcherWithSendTests, DispatcherWithSendTests_UsePoll] if hasattr(asyncore, 'file_wrapper'): tests.append(FileWrapperTest)