PageRenderTime 58ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/greenio_test.py

https://bitbucket.org/portante/eventlet
Python | 802 lines | 764 code | 20 blank | 18 comment | 15 complexity | 2de7759e7c1d3e33a3872766652b9658 MD5 | raw file
Possible License(s): MIT
  1. import socket as _orig_sock
  2. from tests import LimitedTestCase, skip_with_pyevent, main, skipped, s2b, skip_if, skip_on_windows
  3. from eventlet import event, greenio, debug
  4. from eventlet.hubs import get_hub
  5. from eventlet.green import socket, time
  6. from eventlet.support import get_errno
  7. import errno
  8. import eventlet
  9. import os
  10. import sys
  11. import array
  12. import tempfile, shutil
  13. def bufsized(sock, size=1):
  14. """ Resize both send and receive buffers on a socket.
  15. Useful for testing trampoline. Returns the socket.
  16. >>> import socket
  17. >>> sock = bufsized(socket.socket(socket.AF_INET, socket.SOCK_STREAM))
  18. """
  19. sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, size)
  20. sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, size)
  21. return sock
  22. def min_buf_size():
  23. """Return the minimum buffer size that the platform supports."""
  24. test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  25. test_sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1)
  26. return test_sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
  27. def using_epoll_hub(_f):
  28. try:
  29. return 'epolls' in type(get_hub()).__module__
  30. except Exception:
  31. return False
  32. class TestGreenSocket(LimitedTestCase):
  33. def assertWriteToClosedFileRaises(self, fd):
  34. if sys.version_info[0] < 3:
  35. # 2.x socket._fileobjects are odd: writes don't check
  36. # whether the socket is closed or not, and you get an
  37. # AttributeError during flush if it is closed
  38. fd.write('a')
  39. self.assertRaises(Exception, fd.flush)
  40. else:
  41. # 3.x io write to closed file-like pbject raises ValueError
  42. self.assertRaises(ValueError, fd.write, 'a')
  43. def test_connect_timeout(self):
  44. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  45. s.settimeout(0.1)
  46. gs = greenio.GreenSocket(s)
  47. try:
  48. gs.connect(('192.0.2.1', 80))
  49. self.fail("socket.timeout not raised")
  50. except socket.timeout, e:
  51. self.assert_(hasattr(e, 'args'))
  52. self.assertEqual(e.args[0], 'timed out')
  53. except socket.error, e:
  54. # unreachable is also a valid outcome
  55. if not get_errno(e) in (errno.EHOSTUNREACH, errno.ENETUNREACH):
  56. raise
  57. def test_accept_timeout(self):
  58. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  59. s.bind(('', 0))
  60. s.listen(50)
  61. s.settimeout(0.1)
  62. gs = greenio.GreenSocket(s)
  63. try:
  64. gs.accept()
  65. self.fail("socket.timeout not raised")
  66. except socket.timeout, e:
  67. self.assert_(hasattr(e, 'args'))
  68. self.assertEqual(e.args[0], 'timed out')
  69. def test_connect_ex_timeout(self):
  70. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  71. s.settimeout(0.1)
  72. gs = greenio.GreenSocket(s)
  73. e = gs.connect_ex(('192.0.2.1', 80))
  74. if not e in (errno.EHOSTUNREACH, errno.ENETUNREACH):
  75. self.assertEquals(e, errno.EAGAIN)
  76. def test_recv_timeout(self):
  77. listener = greenio.GreenSocket(socket.socket())
  78. listener.bind(('', 0))
  79. listener.listen(50)
  80. evt = event.Event()
  81. def server():
  82. # accept the connection in another greenlet
  83. sock, addr = listener.accept()
  84. evt.wait()
  85. gt = eventlet.spawn(server)
  86. addr = listener.getsockname()
  87. client = greenio.GreenSocket(socket.socket())
  88. client.settimeout(0.1)
  89. client.connect(addr)
  90. try:
  91. client.recv(8192)
  92. self.fail("socket.timeout not raised")
  93. except socket.timeout, e:
  94. self.assert_(hasattr(e, 'args'))
  95. self.assertEqual(e.args[0], 'timed out')
  96. evt.send()
  97. gt.wait()
  98. def test_recvfrom_timeout(self):
  99. gs = greenio.GreenSocket(
  100. socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
  101. gs.settimeout(.1)
  102. gs.bind(('', 0))
  103. try:
  104. gs.recvfrom(8192)
  105. self.fail("socket.timeout not raised")
  106. except socket.timeout, e:
  107. self.assert_(hasattr(e, 'args'))
  108. self.assertEqual(e.args[0], 'timed out')
  109. def test_recvfrom_into_timeout(self):
  110. buf = buffer(array.array('B'))
  111. gs = greenio.GreenSocket(
  112. socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
  113. gs.settimeout(.1)
  114. gs.bind(('', 0))
  115. try:
  116. gs.recvfrom_into(buf)
  117. self.fail("socket.timeout not raised")
  118. except socket.timeout, e:
  119. self.assert_(hasattr(e, 'args'))
  120. self.assertEqual(e.args[0], 'timed out')
  121. def test_recv_into_timeout(self):
  122. buf = buffer(array.array('B'))
  123. listener = greenio.GreenSocket(socket.socket())
  124. listener.bind(('', 0))
  125. listener.listen(50)
  126. evt = event.Event()
  127. def server():
  128. # accept the connection in another greenlet
  129. sock, addr = listener.accept()
  130. evt.wait()
  131. gt = eventlet.spawn(server)
  132. addr = listener.getsockname()
  133. client = greenio.GreenSocket(socket.socket())
  134. client.settimeout(0.1)
  135. client.connect(addr)
  136. try:
  137. client.recv_into(buf)
  138. self.fail("socket.timeout not raised")
  139. except socket.timeout, e:
  140. self.assert_(hasattr(e, 'args'))
  141. self.assertEqual(e.args[0], 'timed out')
  142. evt.send()
  143. gt.wait()
  144. def test_send_timeout(self):
  145. listener = bufsized(eventlet.listen(('', 0)))
  146. evt = event.Event()
  147. def server():
  148. # accept the connection in another greenlet
  149. sock, addr = listener.accept()
  150. sock = bufsized(sock)
  151. evt.wait()
  152. gt = eventlet.spawn(server)
  153. addr = listener.getsockname()
  154. client = bufsized(greenio.GreenSocket(socket.socket()))
  155. client.connect(addr)
  156. try:
  157. client.settimeout(0.00001)
  158. msg = s2b("A") * 100000 # large enough number to overwhelm most buffers
  159. total_sent = 0
  160. # want to exceed the size of the OS buffer so it'll block in a
  161. # single send
  162. for x in range(10):
  163. total_sent += client.send(msg)
  164. self.fail("socket.timeout not raised")
  165. except socket.timeout, e:
  166. self.assert_(hasattr(e, 'args'))
  167. self.assertEqual(e.args[0], 'timed out')
  168. evt.send()
  169. gt.wait()
  170. def test_sendall_timeout(self):
  171. listener = greenio.GreenSocket(socket.socket())
  172. listener.bind(('', 0))
  173. listener.listen(50)
  174. evt = event.Event()
  175. def server():
  176. # accept the connection in another greenlet
  177. sock, addr = listener.accept()
  178. evt.wait()
  179. gt = eventlet.spawn(server)
  180. addr = listener.getsockname()
  181. client = greenio.GreenSocket(socket.socket())
  182. client.settimeout(0.1)
  183. client.connect(addr)
  184. try:
  185. msg = s2b("A") * (8 << 20)
  186. # want to exceed the size of the OS buffer so it'll block
  187. client.sendall(msg)
  188. self.fail("socket.timeout not raised")
  189. except socket.timeout, e:
  190. self.assert_(hasattr(e, 'args'))
  191. self.assertEqual(e.args[0], 'timed out')
  192. evt.send()
  193. gt.wait()
  194. def test_close_with_makefile(self):
  195. def accept_close_early(listener):
  196. # verify that the makefile and the socket are truly independent
  197. # by closing the socket prior to using the made file
  198. try:
  199. conn, addr = listener.accept()
  200. fd = conn.makefile('w')
  201. conn.close()
  202. fd.write('hello\n')
  203. fd.close()
  204. self.assertWriteToClosedFileRaises(fd)
  205. self.assertRaises(socket.error, conn.send, s2b('b'))
  206. finally:
  207. listener.close()
  208. def accept_close_late(listener):
  209. # verify that the makefile and the socket are truly independent
  210. # by closing the made file and then sending a character
  211. try:
  212. conn, addr = listener.accept()
  213. fd = conn.makefile('w')
  214. fd.write('hello')
  215. fd.close()
  216. conn.send(s2b('\n'))
  217. conn.close()
  218. self.assertWriteToClosedFileRaises(fd)
  219. self.assertRaises(socket.error, conn.send, s2b('b'))
  220. finally:
  221. listener.close()
  222. def did_it_work(server):
  223. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  224. client.connect(('127.0.0.1', server.getsockname()[1]))
  225. fd = client.makefile()
  226. client.close()
  227. assert fd.readline() == 'hello\n'
  228. assert fd.read() == ''
  229. fd.close()
  230. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  231. server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  232. server.bind(('0.0.0.0', 0))
  233. server.listen(50)
  234. killer = eventlet.spawn(accept_close_early, server)
  235. did_it_work(server)
  236. killer.wait()
  237. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  238. server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  239. server.bind(('0.0.0.0', 0))
  240. server.listen(50)
  241. killer = eventlet.spawn(accept_close_late, server)
  242. did_it_work(server)
  243. killer.wait()
  244. def test_del_closes_socket(self):
  245. def accept_once(listener):
  246. # delete/overwrite the original conn
  247. # object, only keeping the file object around
  248. # closing the file object should close everything
  249. try:
  250. conn, addr = listener.accept()
  251. conn = conn.makefile('w')
  252. conn.write('hello\n')
  253. conn.close()
  254. self.assertWriteToClosedFileRaises(conn)
  255. finally:
  256. listener.close()
  257. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  258. server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  259. server.bind(('127.0.0.1', 0))
  260. server.listen(50)
  261. killer = eventlet.spawn(accept_once, server)
  262. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  263. client.connect(('127.0.0.1', server.getsockname()[1]))
  264. fd = client.makefile()
  265. client.close()
  266. assert fd.read() == 'hello\n'
  267. assert fd.read() == ''
  268. killer.wait()
  269. def test_full_duplex(self):
  270. large_data = s2b('*') * 10 * min_buf_size()
  271. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  272. listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  273. listener.bind(('127.0.0.1', 0))
  274. listener.listen(50)
  275. bufsized(listener)
  276. def send_large(sock):
  277. sock.sendall(large_data)
  278. def read_large(sock):
  279. result = sock.recv(len(large_data))
  280. while len(result) < len(large_data):
  281. result += sock.recv(len(large_data))
  282. self.assertEquals(result, large_data)
  283. def server():
  284. (sock, addr) = listener.accept()
  285. sock = bufsized(sock)
  286. send_large_coro = eventlet.spawn(send_large, sock)
  287. eventlet.sleep(0)
  288. result = sock.recv(10)
  289. expected = s2b('hello world')
  290. while len(result) < len(expected):
  291. result += sock.recv(10)
  292. self.assertEquals(result, expected)
  293. send_large_coro.wait()
  294. server_evt = eventlet.spawn(server)
  295. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  296. client.connect(('127.0.0.1', listener.getsockname()[1]))
  297. bufsized(client)
  298. large_evt = eventlet.spawn(read_large, client)
  299. eventlet.sleep(0)
  300. client.sendall(s2b('hello world'))
  301. server_evt.wait()
  302. large_evt.wait()
  303. client.close()
  304. def test_sendall(self):
  305. # test adapted from Marcus Cavanaugh's email
  306. # it may legitimately take a while, but will eventually complete
  307. self.timer.cancel()
  308. second_bytes = 10
  309. def test_sendall_impl(many_bytes):
  310. bufsize = max(many_bytes // 15, 2)
  311. def sender(listener):
  312. (sock, addr) = listener.accept()
  313. sock = bufsized(sock, size=bufsize)
  314. sock.sendall(s2b('x') * many_bytes)
  315. sock.sendall(s2b('y') * second_bytes)
  316. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  317. listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  318. listener.bind(("", 0))
  319. listener.listen(50)
  320. sender_coro = eventlet.spawn(sender, listener)
  321. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  322. client.connect(('127.0.0.1', listener.getsockname()[1]))
  323. bufsized(client, size=bufsize)
  324. total = 0
  325. while total < many_bytes:
  326. data = client.recv(min(many_bytes - total, many_bytes // 10))
  327. if not data:
  328. break
  329. total += len(data)
  330. total2 = 0
  331. while total < second_bytes:
  332. data = client.recv(second_bytes)
  333. if not data:
  334. break
  335. total2 += len(data)
  336. sender_coro.wait()
  337. client.close()
  338. for how_many in (1000, 10000, 100000, 1000000):
  339. test_sendall_impl(how_many)
  340. def test_wrap_socket(self):
  341. try:
  342. import ssl
  343. except ImportError:
  344. pass # pre-2.6
  345. else:
  346. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  347. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  348. sock.bind(('127.0.0.1', 0))
  349. sock.listen(50)
  350. ssl.wrap_socket(sock)
  351. def test_timeout_and_final_write(self):
  352. # This test verifies that a write on a socket that we've
  353. # stopped listening for doesn't result in an incorrect switch
  354. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  355. server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  356. server.bind(('127.0.0.1', 0))
  357. server.listen(50)
  358. bound_port = server.getsockname()[1]
  359. def sender(evt):
  360. s2, addr = server.accept()
  361. wrap_wfile = s2.makefile('w')
  362. eventlet.sleep(0.02)
  363. wrap_wfile.write('hi')
  364. s2.close()
  365. evt.send('sent via event')
  366. evt = event.Event()
  367. eventlet.spawn(sender, evt)
  368. eventlet.sleep(0) # lets the socket enter accept mode, which
  369. # is necessary for connect to succeed on windows
  370. try:
  371. # try and get some data off of this pipe
  372. # but bail before any is sent
  373. eventlet.Timeout(0.01)
  374. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  375. client.connect(('127.0.0.1', bound_port))
  376. wrap_rfile = client.makefile()
  377. wrap_rfile.read(1)
  378. self.fail()
  379. except eventlet.TimeoutError:
  380. pass
  381. result = evt.wait()
  382. self.assertEquals(result, 'sent via event')
  383. server.close()
  384. client.close()
  385. @skip_with_pyevent
  386. def test_raised_multiple_readers(self):
  387. debug.hub_prevent_multiple_readers(True)
  388. def handle(sock, addr):
  389. sock.recv(1)
  390. sock.sendall("a")
  391. raise eventlet.StopServe()
  392. listener = eventlet.listen(('127.0.0.1', 0))
  393. eventlet.spawn(eventlet.serve, listener, handle)
  394. def reader(s):
  395. s.recv(1)
  396. s = eventlet.connect(('127.0.0.1', listener.getsockname()[1]))
  397. a = eventlet.spawn(reader, s)
  398. eventlet.sleep(0)
  399. self.assertRaises(RuntimeError, s.recv, 1)
  400. s.sendall('b')
  401. a.wait()
  402. @skip_with_pyevent
  403. @skip_if(using_epoll_hub)
  404. def test_closure(self):
  405. def spam_to_me(address):
  406. sock = eventlet.connect(address)
  407. while True:
  408. try:
  409. sock.sendall('hello world')
  410. except socket.error, e:
  411. if get_errno(e) == errno.EPIPE:
  412. return
  413. raise
  414. server = eventlet.listen(('127.0.0.1', 0))
  415. sender = eventlet.spawn(spam_to_me, server.getsockname())
  416. client, address = server.accept()
  417. server.close()
  418. def reader():
  419. try:
  420. while True:
  421. data = client.recv(1024)
  422. self.assert_(data)
  423. except socket.error, e:
  424. # we get an EBADF because client is closed in the same process
  425. # (but a different greenthread)
  426. if get_errno(e) != errno.EBADF:
  427. raise
  428. def closer():
  429. client.close()
  430. reader = eventlet.spawn(reader)
  431. eventlet.spawn_n(closer)
  432. reader.wait()
  433. sender.wait()
  434. def test_invalid_connection(self):
  435. # find an unused port by creating a socket then closing it
  436. port = eventlet.listen(('127.0.0.1', 0)).getsockname()[1]
  437. self.assertRaises(socket.error, eventlet.connect, ('127.0.0.1', port))
  438. class TestGreenPipe(LimitedTestCase):
  439. @skip_on_windows
  440. def setUp(self):
  441. super(self.__class__, self).setUp()
  442. self.tempdir = tempfile.mkdtemp('_green_pipe_test')
  443. def tearDown(self):
  444. shutil.rmtree(self.tempdir)
  445. super(self.__class__, self).tearDown()
  446. def test_pipe(self):
  447. r, w = os.pipe()
  448. rf = greenio.GreenPipe(r, 'r')
  449. wf = greenio.GreenPipe(w, 'w', 0)
  450. def sender(f, content):
  451. for ch in content:
  452. eventlet.sleep(0.0001)
  453. f.write(ch)
  454. f.close()
  455. one_line = "12345\n"
  456. eventlet.spawn(sender, wf, one_line * 5)
  457. for i in xrange(5):
  458. line = rf.readline()
  459. eventlet.sleep(0.01)
  460. self.assertEquals(line, one_line)
  461. self.assertEquals(rf.readline(), '')
  462. def test_pipe_read(self):
  463. # ensure that 'readline' works properly on GreenPipes when data is not
  464. # immediately available (fd is nonblocking, was raising EAGAIN)
  465. # also ensures that readline() terminates on '\n' and '\r\n'
  466. r, w = os.pipe()
  467. r = greenio.GreenPipe(r)
  468. w = greenio.GreenPipe(w, 'w')
  469. def writer():
  470. eventlet.sleep(.1)
  471. w.write('line\n')
  472. w.flush()
  473. w.write('line\r\n')
  474. w.flush()
  475. gt = eventlet.spawn(writer)
  476. eventlet.sleep(0)
  477. line = r.readline()
  478. self.assertEquals(line, 'line\n')
  479. line = r.readline()
  480. self.assertEquals(line, 'line\r\n')
  481. gt.wait()
  482. def test_pipe_writes_large_messages(self):
  483. r, w = os.pipe()
  484. r = greenio.GreenPipe(r)
  485. w = greenio.GreenPipe(w, 'w')
  486. large_message = "".join([1024 * chr(i) for i in xrange(65)])
  487. def writer():
  488. w.write(large_message)
  489. w.close()
  490. gt = eventlet.spawn(writer)
  491. for i in xrange(65):
  492. buf = r.read(1024)
  493. expected = 1024 * chr(i)
  494. self.assertEquals(buf, expected,
  495. "expected=%r..%r, found=%r..%r iter=%d"
  496. % (expected[:4], expected[-4:], buf[:4], buf[-4:], i))
  497. gt.wait()
  498. def test_seek_on_buffered_pipe(self):
  499. f = greenio.GreenPipe(self.tempdir + "/TestFile", 'w+', 1024)
  500. self.assertEquals(f.tell(), 0)
  501. f.seek(0, 2)
  502. self.assertEquals(f.tell(), 0)
  503. f.write('1234567890')
  504. f.seek(0, 2)
  505. self.assertEquals(f.tell(), 10)
  506. f.seek(0)
  507. value = f.read(1)
  508. self.assertEqual(value, '1')
  509. self.assertEquals(f.tell(), 1)
  510. value = f.read(1)
  511. self.assertEqual(value, '2')
  512. self.assertEquals(f.tell(), 2)
  513. f.seek(0, 1)
  514. self.assertEqual(f.readline(), '34567890')
  515. f.seek(-5, 1)
  516. self.assertEqual(f.readline(), '67890')
  517. f.seek(0)
  518. self.assertEqual(f.readline(), '1234567890')
  519. f.seek(0, 2)
  520. self.assertEqual(f.readline(), '')
  521. def test_truncate(self):
  522. f = greenio.GreenPipe(self.tempdir + "/TestFile", 'w+', 1024)
  523. f.write('1234567890')
  524. f.truncate(9)
  525. self.assertEquals(f.tell(), 9)
  526. class TestGreenIoLong(LimitedTestCase):
  527. TEST_TIMEOUT = 10 # the test here might take a while depending on the OS
  528. @skip_with_pyevent
  529. def test_multiple_readers(self, clibufsize=False):
  530. debug.hub_prevent_multiple_readers(False)
  531. recvsize = 2 * min_buf_size()
  532. sendsize = 10 * recvsize
  533. # test that we can have multiple coroutines reading
  534. # from the same fd. We make no guarantees about which one gets which
  535. # bytes, but they should both get at least some
  536. def reader(sock, results):
  537. while True:
  538. data = sock.recv(recvsize)
  539. if not data:
  540. break
  541. results.append(data)
  542. results1 = []
  543. results2 = []
  544. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  545. listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  546. listener.bind(('127.0.0.1', 0))
  547. listener.listen(50)
  548. def server():
  549. (sock, addr) = listener.accept()
  550. sock = bufsized(sock)
  551. try:
  552. c1 = eventlet.spawn(reader, sock, results1)
  553. c2 = eventlet.spawn(reader, sock, results2)
  554. try:
  555. c1.wait()
  556. c2.wait()
  557. finally:
  558. c1.kill()
  559. c2.kill()
  560. finally:
  561. sock.close()
  562. server_coro = eventlet.spawn(server)
  563. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  564. client.connect(('127.0.0.1', listener.getsockname()[1]))
  565. if clibufsize:
  566. bufsized(client, size=sendsize)
  567. else:
  568. bufsized(client)
  569. client.sendall(s2b('*') * sendsize)
  570. client.close()
  571. server_coro.wait()
  572. listener.close()
  573. self.assert_(len(results1) > 0)
  574. self.assert_(len(results2) > 0)
  575. debug.hub_prevent_multiple_readers()
  576. @skipped # by rdw because it fails but it's not clear how to make it pass
  577. @skip_with_pyevent
  578. def test_multiple_readers2(self):
  579. self.test_multiple_readers(clibufsize=True)
  580. class TestGreenIoStarvation(LimitedTestCase):
  581. # fixme: this doesn't succeed, because of eventlet's predetermined
  582. # ordering. two processes, one with server, one with client eventlets
  583. # might be more reliable?
  584. TEST_TIMEOUT = 300 # the test here might take a while depending on the OS
  585. @skipped # by rdw, because it fails but it's not clear how to make it pass
  586. @skip_with_pyevent
  587. def test_server_starvation(self, sendloops=15):
  588. recvsize = 2 * min_buf_size()
  589. sendsize = 10000 * recvsize
  590. results = [[] for i in xrange(5)]
  591. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  592. listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  593. listener.bind(('127.0.0.1', 0))
  594. port = listener.getsockname()[1]
  595. listener.listen(50)
  596. base_time = time.time()
  597. def server(my_results):
  598. sock, addr = listener.accept()
  599. datasize = 0
  600. t1 = None
  601. t2 = None
  602. try:
  603. while True:
  604. data = sock.recv(recvsize)
  605. if not t1:
  606. t1 = time.time() - base_time
  607. if not data:
  608. t2 = time.time() - base_time
  609. my_results.append(datasize)
  610. my_results.append((t1, t2))
  611. break
  612. datasize += len(data)
  613. finally:
  614. sock.close()
  615. def client():
  616. pid = os.fork()
  617. if pid:
  618. return pid
  619. client = _orig_sock.socket(socket.AF_INET, socket.SOCK_STREAM)
  620. client.connect(('127.0.0.1', port))
  621. bufsized(client, size=sendsize)
  622. for i in range(sendloops):
  623. client.sendall(s2b('*') * sendsize)
  624. client.close()
  625. os._exit(0)
  626. clients = []
  627. servers = []
  628. for r in results:
  629. servers.append(eventlet.spawn(server, r))
  630. for r in results:
  631. clients.append(client())
  632. for s in servers:
  633. s.wait()
  634. for c in clients:
  635. os.waitpid(c, 0)
  636. listener.close()
  637. # now test that all of the server receive intervals overlap, and
  638. # that there were no errors.
  639. for r in results:
  640. assert len(r) == 2, "length is %d not 2!: %s\n%s" % (len(r), r, results)
  641. assert r[0] == sendsize * sendloops
  642. assert len(r[1]) == 2
  643. assert r[1][0] is not None
  644. assert r[1][1] is not None
  645. starttimes = sorted(r[1][0] for r in results)
  646. endtimes = sorted(r[1][1] for r in results)
  647. runlengths = sorted(r[1][1] - r[1][0] for r in results)
  648. # assert that the last task started before the first task ended
  649. # (our no-starvation condition)
  650. assert starttimes[-1] < endtimes[0], "Not overlapping: starts %s ends %s" % (starttimes, endtimes)
  651. maxstartdiff = starttimes[-1] - starttimes[0]
  652. assert maxstartdiff * 2 < runlengths[0], "Largest difference in starting times more than twice the shortest running time!"
  653. assert runlengths[0] * 2 > runlengths[-1], "Longest runtime more than twice as long as shortest!"
  654. if __name__ == '__main__':
  655. main()