Skip to content

Commit ebd5d6d

Browse files
authored
bpo-35347: Fix test_socket.NonBlockingTCPTests (GH-10791)
testAccept() and testRecv() of test_socket.NonBlockingTCPTests have a race condition: time.sleep() is used as a weak synchronization primitive and the tests fail randomly on slow buildbots. Use a reliable threading.Event to fix these tests. Other changes: * Replace send() with sendall() * Expect specific BlockingIOError rather than generic OSError * Add a timeout to select() in testAccept() and testRecv() * Use addCleanup() to close sockets * Use assertRaises()
1 parent 55e4980 commit ebd5d6d

File tree

1 file changed

+39
-25
lines changed

1 file changed

+39
-25
lines changed

Lib/test/test_socket.py

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
HOST = support.HOST
3737
MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') ## test unicode string and carriage return
38+
MAIN_TIMEOUT = 60.0
3839

3940
VSOCKPORT = 1234
4041

@@ -4214,6 +4215,7 @@ def _testSend(self):
42144215
class NonBlockingTCPTests(ThreadedTCPSocketTest):
42154216

42164217
def __init__(self, methodName='runTest'):
4218+
self.event = threading.Event()
42174219
ThreadedTCPSocketTest.__init__(self, methodName=methodName)
42184220

42194221
def testSetBlocking(self):
@@ -4326,22 +4328,27 @@ def _testInheritFlags(self):
43264328
def testAccept(self):
43274329
# Testing non-blocking accept
43284330
self.serv.setblocking(0)
4329-
try:
4330-
conn, addr = self.serv.accept()
4331-
except OSError:
4332-
pass
4333-
else:
4334-
self.fail("Error trying to do non-blocking accept.")
4335-
read, write, err = select.select([self.serv], [], [])
4336-
if self.serv in read:
4331+
4332+
# connect() didn't start: non-blocking accept() fails
4333+
with self.assertRaises(BlockingIOError):
43374334
conn, addr = self.serv.accept()
4338-
self.assertIsNone(conn.gettimeout())
4339-
conn.close()
4340-
else:
4335+
4336+
self.event.set()
4337+
4338+
read, write, err = select.select([self.serv], [], [], MAIN_TIMEOUT)
4339+
if self.serv not in read:
43414340
self.fail("Error trying to do accept after select.")
43424341

4342+
# connect() completed: non-blocking accept() doesn't block
4343+
conn, addr = self.serv.accept()
4344+
self.addCleanup(conn.close)
4345+
self.assertIsNone(conn.gettimeout())
4346+
43434347
def _testAccept(self):
4344-
time.sleep(0.1)
4348+
# don't connect before event is set to check
4349+
# that non-blocking accept() raises BlockingIOError
4350+
self.event.wait()
4351+
43454352
self.cli.connect((HOST, self.port))
43464353

43474354
def testConnect(self):
@@ -4356,25 +4363,32 @@ def _testConnect(self):
43564363
def testRecv(self):
43574364
# Testing non-blocking recv
43584365
conn, addr = self.serv.accept()
4366+
self.addCleanup(conn.close)
43594367
conn.setblocking(0)
4360-
try:
4361-
msg = conn.recv(len(MSG))
4362-
except OSError:
4363-
pass
4364-
else:
4365-
self.fail("Error trying to do non-blocking recv.")
4366-
read, write, err = select.select([conn], [], [])
4367-
if conn in read:
4368+
4369+
# the server didn't send data yet: non-blocking recv() fails
4370+
with self.assertRaises(BlockingIOError):
43684371
msg = conn.recv(len(MSG))
4369-
conn.close()
4370-
self.assertEqual(msg, MSG)
4371-
else:
4372+
4373+
self.event.set()
4374+
4375+
read, write, err = select.select([conn], [], [], MAIN_TIMEOUT)
4376+
if conn not in read:
43724377
self.fail("Error during select call to non-blocking socket.")
43734378

4379+
# the server sent data yet: non-blocking recv() doesn't block
4380+
msg = conn.recv(len(MSG))
4381+
self.assertEqual(msg, MSG)
4382+
43744383
def _testRecv(self):
43754384
self.cli.connect((HOST, self.port))
4376-
time.sleep(0.1)
4377-
self.cli.send(MSG)
4385+
4386+
# don't send anything before event is set to check
4387+
# that non-blocking recv() raises BlockingIOError
4388+
self.event.wait()
4389+
4390+
# send data: recv() will no longer block
4391+
self.cli.sendall(MSG)
43784392

43794393

43804394
class FileObjectClassTestCase(SocketConnectedTest):

0 commit comments

Comments
 (0)