PageRenderTime 24ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/greenio_test.py

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