Skip to content

Commit caa59c1

Browse files
authored
[3.6] bpo-30106: Fix test_asyncore.test_quick_connect() (#1336)
* Fix/optimize test_asyncore.test_quick_connect() (#1188) Don't use addCleanup() in test_quick_connect() because it keeps the Thread object alive and so @reap_threads fails on its timeout of 1 second. "./python -m test -v test_asyncore -m test_quick_connect" now takes 185 ms, instead of 11 seconds. Other minor changes: * Use "with sock:" to close the socket instead of try/finally: sock.close() * Use self.skipTest() in test_quick_connect() to remove one indentation level and notice user that the test is specific to AF_INET and AF_INET6 * bpo-30106: Fix tearDown() of test_asyncore (#1194) Call asyncore.close_all() with ignore_all=True in the tearDown() method of the test_asyncore base test case. It should prevent keeping alive sockets in asyncore.socket_map if close() fails with an unexpected error. Revert also an unwanted change of my previous commit: remove name parameter of Thread in test_quick_connect(). * bpo-30106: Fix test_asyncore.test_quick_connect() (#1234) test_quick_connect() runs a thread up to 50 seconds, whereas the socket is connected in 0.2 second and then the thread is expected to end in less than 3 second. On Linux, the thread ends quickly because select() seems to always return quickly. On FreeBSD, sometimes select() fails with timeout and so the thread runs much longer than expected. Fix the thread timeout to fix a race condition in the test.
1 parent c9ca57e commit caa59c1

File tree

1 file changed

+40
-40
lines changed

1 file changed

+40
-40
lines changed

Lib/test/test_asyncore.py

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ def handle_connect(self):
502502
class BaseTestAPI:
503503

504504
def tearDown(self):
505-
asyncore.close_all()
505+
asyncore.close_all(ignore_all=True)
506506

507507
def loop_waiting_for_flag(self, instance, timeout=5):
508508
timeout = float(timeout) / 100
@@ -755,50 +755,50 @@ def test_bind(self):
755755
def test_set_reuse_addr(self):
756756
if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
757757
self.skipTest("Not applicable to AF_UNIX sockets.")
758-
sock = socket.socket(self.family)
759-
try:
760-
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
761-
except OSError:
762-
unittest.skip("SO_REUSEADDR not supported on this platform")
763-
else:
764-
# if SO_REUSEADDR succeeded for sock we expect asyncore
765-
# to do the same
766-
s = asyncore.dispatcher(socket.socket(self.family))
767-
self.assertFalse(s.socket.getsockopt(socket.SOL_SOCKET,
768-
socket.SO_REUSEADDR))
769-
s.socket.close()
770-
s.create_socket(self.family)
771-
s.set_reuse_addr()
772-
self.assertTrue(s.socket.getsockopt(socket.SOL_SOCKET,
773-
socket.SO_REUSEADDR))
774-
finally:
775-
sock.close()
758+
759+
with socket.socket(self.family) as sock:
760+
try:
761+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
762+
except OSError:
763+
unittest.skip("SO_REUSEADDR not supported on this platform")
764+
else:
765+
# if SO_REUSEADDR succeeded for sock we expect asyncore
766+
# to do the same
767+
s = asyncore.dispatcher(socket.socket(self.family))
768+
self.assertFalse(s.socket.getsockopt(socket.SOL_SOCKET,
769+
socket.SO_REUSEADDR))
770+
s.socket.close()
771+
s.create_socket(self.family)
772+
s.set_reuse_addr()
773+
self.assertTrue(s.socket.getsockopt(socket.SOL_SOCKET,
774+
socket.SO_REUSEADDR))
776775

777776
@unittest.skipUnless(threading, 'Threading required for this test.')
778777
@support.reap_threads
779778
def test_quick_connect(self):
780779
# see: http://bugs.python.org/issue10340
781-
if self.family in (socket.AF_INET, getattr(socket, "AF_INET6", object())):
782-
server = BaseServer(self.family, self.addr)
783-
t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1,
784-
count=500))
785-
t.start()
786-
def cleanup():
787-
t.join(timeout=TIMEOUT)
788-
if t.is_alive():
789-
self.fail("join() timed out")
790-
self.addCleanup(cleanup)
791-
792-
s = socket.socket(self.family, socket.SOCK_STREAM)
793-
s.settimeout(.2)
794-
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
795-
struct.pack('ii', 1, 0))
796-
try:
797-
s.connect(server.address)
798-
except OSError:
799-
pass
800-
finally:
801-
s.close()
780+
if self.family not in (socket.AF_INET, getattr(socket, "AF_INET6", object())):
781+
self.skipTest("test specific to AF_INET and AF_INET6")
782+
783+
server = BaseServer(self.family, self.addr)
784+
# run the thread 500 ms: the socket should be connected in 200 ms
785+
t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1,
786+
count=5))
787+
t.start()
788+
try:
789+
with socket.socket(self.family, socket.SOCK_STREAM) as s:
790+
s.settimeout(.2)
791+
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
792+
struct.pack('ii', 1, 0))
793+
794+
try:
795+
s.connect(server.address)
796+
except OSError:
797+
pass
798+
finally:
799+
t.join(timeout=TIMEOUT)
800+
if t.is_alive():
801+
self.fail("join() timed out")
802802

803803
class TestAPI_UseIPv4Sockets(BaseTestAPI):
804804
family = socket.AF_INET

0 commit comments

Comments
 (0)