PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/greenio_test.py

https://bitbucket.org/chrisatlee/eventlet
Python | 581 lines | 552 code | 12 blank | 17 comment | 11 complexity | 0f9f0a3f6cc380daa11475a670b353cc MD5 | raw file
Possible License(s): MIT
  1. from tests import LimitedTestCase, skip_with_pyevent, main
  2. from eventlet import event
  3. from eventlet import greenio
  4. from eventlet import debug
  5. from eventlet.green import socket
  6. from eventlet.green.socket import GreenSSLObject
  7. import errno
  8. import eventlet
  9. import os
  10. import sys
  11. import array
  12. def bufsized(sock, size=1):
  13. """ Resize both send and receive buffers on a socket.
  14. Useful for testing trampoline. Returns the socket.
  15. >>> import socket
  16. >>> sock = bufsized(socket.socket(socket.AF_INET, socket.SOCK_STREAM))
  17. """
  18. sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, size)
  19. sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, size)
  20. return sock
  21. def min_buf_size():
  22. """Return the minimum buffer size that the platform supports."""
  23. test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  24. test_sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1)
  25. return test_sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
  26. class TestGreenIo(LimitedTestCase):
  27. def test_connect_timeout(self):
  28. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  29. s.settimeout(0.1)
  30. gs = greenio.GreenSocket(s)
  31. try:
  32. gs.connect(('192.0.2.1', 80))
  33. self.fail("socket.timeout not raised")
  34. except socket.timeout, e:
  35. self.assert_(hasattr(e, 'args'))
  36. self.assertEqual(e.args[0], 'timed out')
  37. except socket.error, e:
  38. # unreachable is also a valid outcome
  39. if not e[0] in (errno.EHOSTUNREACH, errno.ENETUNREACH):
  40. raise
  41. def test_accept_timeout(self):
  42. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  43. s.bind(('', 0))
  44. s.listen(50)
  45. s.settimeout(0.1)
  46. gs = greenio.GreenSocket(s)
  47. try:
  48. gs.accept()
  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. def test_connect_ex_timeout(self):
  54. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  55. s.settimeout(0.1)
  56. gs = greenio.GreenSocket(s)
  57. e = gs.connect_ex(('192.0.2.1', 80))
  58. if not e in (errno.EHOSTUNREACH, errno.ENETUNREACH):
  59. self.assertEquals(e, errno.EAGAIN)
  60. def test_recv_timeout(self):
  61. listener = greenio.GreenSocket(socket.socket())
  62. listener.bind(('', 0))
  63. listener.listen(50)
  64. evt = event.Event()
  65. def server():
  66. # accept the connection in another greenlet
  67. sock, addr = listener.accept()
  68. evt.wait()
  69. gt = eventlet.spawn(server)
  70. addr = listener.getsockname()
  71. client = greenio.GreenSocket(socket.socket())
  72. client.settimeout(0.1)
  73. client.connect(addr)
  74. try:
  75. r = client.recv(8192)
  76. self.fail("socket.timeout not raised")
  77. except socket.timeout, e:
  78. self.assert_(hasattr(e, 'args'))
  79. self.assertEqual(e.args[0], 'timed out')
  80. evt.send()
  81. gt.wait()
  82. def test_recvfrom_timeout(self):
  83. gs = greenio.GreenSocket(
  84. socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
  85. gs.settimeout(.1)
  86. gs.bind(('', 0))
  87. try:
  88. gs.recvfrom(8192)
  89. self.fail("socket.timeout not raised")
  90. except socket.timeout, e:
  91. self.assert_(hasattr(e, 'args'))
  92. self.assertEqual(e.args[0], 'timed out')
  93. def test_recvfrom_into_timeout(self):
  94. buf = buffer(array.array('B'))
  95. gs = greenio.GreenSocket(
  96. socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
  97. gs.settimeout(.1)
  98. gs.bind(('', 0))
  99. try:
  100. gs.recvfrom_into(buf)
  101. self.fail("socket.timeout not raised")
  102. except socket.timeout, e:
  103. self.assert_(hasattr(e, 'args'))
  104. self.assertEqual(e.args[0], 'timed out')
  105. def test_recv_into_timeout(self):
  106. buf = buffer(array.array('B'))
  107. listener = greenio.GreenSocket(socket.socket())
  108. listener.bind(('', 0))
  109. listener.listen(50)
  110. evt = event.Event()
  111. def server():
  112. # accept the connection in another greenlet
  113. sock, addr = listener.accept()
  114. evt.wait()
  115. gt = eventlet.spawn(server)
  116. addr = listener.getsockname()
  117. client = greenio.GreenSocket(socket.socket())
  118. client.settimeout(0.1)
  119. client.connect(addr)
  120. try:
  121. r = client.recv_into(buf)
  122. self.fail("socket.timeout not raised")
  123. except socket.timeout, e:
  124. self.assert_(hasattr(e, 'args'))
  125. self.assertEqual(e.args[0], 'timed out')
  126. evt.send()
  127. gt.wait()
  128. def test_send_timeout(self):
  129. listener = bufsized(eventlet.listen(('', 0)))
  130. evt = event.Event()
  131. def server():
  132. # accept the connection in another greenlet
  133. sock, addr = listener.accept()
  134. sock = bufsized(sock)
  135. evt.wait()
  136. gt = eventlet.spawn(server)
  137. addr = listener.getsockname()
  138. client = bufsized(greenio.GreenSocket(socket.socket()))
  139. client.connect(addr)
  140. try:
  141. client.settimeout(0.00001)
  142. msg = "A"*(100000) # large enough number to overwhelm most buffers
  143. total_sent = 0
  144. # want to exceed the size of the OS buffer so it'll block in a
  145. # single send
  146. for x in range(10):
  147. total_sent += client.send(msg)
  148. self.fail("socket.timeout not raised")
  149. except socket.timeout, e:
  150. self.assert_(hasattr(e, 'args'))
  151. self.assertEqual(e.args[0], 'timed out')
  152. evt.send()
  153. gt.wait()
  154. def test_sendall_timeout(self):
  155. listener = greenio.GreenSocket(socket.socket())
  156. listener.bind(('', 0))
  157. listener.listen(50)
  158. evt = event.Event()
  159. def server():
  160. # accept the connection in another greenlet
  161. sock, addr = listener.accept()
  162. evt.wait()
  163. gt = eventlet.spawn(server)
  164. addr = listener.getsockname()
  165. client = greenio.GreenSocket(socket.socket())
  166. client.settimeout(0.1)
  167. client.connect(addr)
  168. try:
  169. msg = "A"*(8*1024*1024)
  170. # want to exceed the size of the OS buffer so it'll block
  171. client.sendall(msg)
  172. self.fail("socket.timeout not raised")
  173. except socket.timeout, e:
  174. self.assert_(hasattr(e, 'args'))
  175. self.assertEqual(e.args[0], 'timed out')
  176. evt.send()
  177. gt.wait()
  178. def test_close_with_makefile(self):
  179. def accept_close_early(listener):
  180. # verify that the makefile and the socket are truly independent
  181. # by closing the socket prior to using the made file
  182. try:
  183. conn, addr = listener.accept()
  184. fd = conn.makefile()
  185. conn.close()
  186. fd.write('hello\n')
  187. fd.close()
  188. # socket._fileobjects are odd: writes don't check
  189. # whether the socket is closed or not, and you get an
  190. # AttributeError during flush if it is closed
  191. fd.write('a')
  192. self.assertRaises(Exception, fd.flush)
  193. self.assertRaises(socket.error, conn.send, 'b')
  194. finally:
  195. listener.close()
  196. def accept_close_late(listener):
  197. # verify that the makefile and the socket are truly independent
  198. # by closing the made file and then sending a character
  199. try:
  200. conn, addr = listener.accept()
  201. fd = conn.makefile()
  202. fd.write('hello')
  203. fd.close()
  204. conn.send('\n')
  205. conn.close()
  206. fd.write('a')
  207. self.assertRaises(Exception, fd.flush)
  208. self.assertRaises(socket.error, conn.send, 'b')
  209. finally:
  210. listener.close()
  211. def did_it_work(server):
  212. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  213. client.connect(('127.0.0.1', server.getsockname()[1]))
  214. fd = client.makefile()
  215. client.close()
  216. assert fd.readline() == 'hello\n'
  217. assert fd.read() == ''
  218. fd.close()
  219. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  220. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  221. server.bind(('0.0.0.0', 0))
  222. server.listen(50)
  223. killer = eventlet.spawn(accept_close_early, server)
  224. did_it_work(server)
  225. killer.wait()
  226. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  227. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  228. server.bind(('0.0.0.0', 0))
  229. server.listen(50)
  230. killer = eventlet.spawn(accept_close_late, server)
  231. did_it_work(server)
  232. killer.wait()
  233. def test_del_closes_socket(self):
  234. def accept_once(listener):
  235. # delete/overwrite the original conn
  236. # object, only keeping the file object around
  237. # closing the file object should close everything
  238. try:
  239. conn, addr = listener.accept()
  240. conn = conn.makefile()
  241. conn.write('hello\n')
  242. conn.close()
  243. conn.write('a')
  244. self.assertRaises(Exception, conn.flush)
  245. finally:
  246. listener.close()
  247. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  248. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  249. server.bind(('127.0.0.1', 0))
  250. server.listen(50)
  251. killer = eventlet.spawn(accept_once, server)
  252. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  253. client.connect(('127.0.0.1', server.getsockname()[1]))
  254. fd = client.makefile()
  255. client.close()
  256. assert fd.read() == 'hello\n'
  257. assert fd.read() == ''
  258. killer.wait()
  259. def test_full_duplex(self):
  260. large_data = '*' * 10 * min_buf_size()
  261. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  262. listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  263. listener.bind(('127.0.0.1', 0))
  264. listener.listen(50)
  265. bufsized(listener)
  266. def send_large(sock):
  267. sock.sendall(large_data)
  268. def read_large(sock):
  269. result = sock.recv(len(large_data))
  270. expected = 'hello world'
  271. while len(result) < len(large_data):
  272. result += sock.recv(len(large_data))
  273. self.assertEquals(result, large_data)
  274. def server():
  275. (sock, addr) = listener.accept()
  276. sock = bufsized(sock)
  277. send_large_coro = eventlet.spawn(send_large, sock)
  278. eventlet.sleep(0)
  279. result = sock.recv(10)
  280. expected = 'hello world'
  281. while len(result) < len(expected):
  282. result += sock.recv(10)
  283. self.assertEquals(result, expected)
  284. send_large_coro.wait()
  285. server_evt = eventlet.spawn(server)
  286. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  287. client.connect(('127.0.0.1', listener.getsockname()[1]))
  288. bufsized(client)
  289. large_evt = eventlet.spawn(read_large, client)
  290. eventlet.sleep(0)
  291. client.sendall('hello world')
  292. server_evt.wait()
  293. large_evt.wait()
  294. client.close()
  295. def test_sendall(self):
  296. # test adapted from Marcus Cavanaugh's email
  297. # it may legitimately take a while, but will eventually complete
  298. self.timer.cancel()
  299. second_bytes = 10
  300. def test_sendall_impl(many_bytes):
  301. bufsize = max(many_bytes/15, 2)
  302. def sender(listener):
  303. (sock, addr) = listener.accept()
  304. sock = bufsized(sock, size=bufsize)
  305. sock.sendall('x'*many_bytes)
  306. sock.sendall('y'*second_bytes)
  307. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  308. listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  309. listener.bind(("", 0))
  310. listener.listen(50)
  311. sender_coro = eventlet.spawn(sender, listener)
  312. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  313. client.connect(('127.0.0.1', listener.getsockname()[1]))
  314. bufsized(client, size=bufsize)
  315. total = 0
  316. while total < many_bytes:
  317. data = client.recv(min(many_bytes - total, many_bytes/10))
  318. if data == '':
  319. break
  320. total += len(data)
  321. total2 = 0
  322. while total < second_bytes:
  323. data = client.recv(second_bytes)
  324. if data == '':
  325. break
  326. total2 += len(data)
  327. sender_coro.wait()
  328. client.close()
  329. for bytes in (1000, 10000, 100000, 1000000):
  330. test_sendall_impl(bytes)
  331. def test_wrap_socket(self):
  332. try:
  333. import ssl
  334. except ImportError:
  335. pass # pre-2.6
  336. else:
  337. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  338. sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  339. sock.bind(('127.0.0.1', 0))
  340. sock.listen(50)
  341. ssl_sock = ssl.wrap_socket(sock)
  342. def test_timeout_and_final_write(self):
  343. # This test verifies that a write on a socket that we've
  344. # stopped listening for doesn't result in an incorrect switch
  345. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  346. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  347. server.bind(('127.0.0.1', 0))
  348. server.listen(50)
  349. bound_port = server.getsockname()[1]
  350. def sender(evt):
  351. s2, addr = server.accept()
  352. wrap_wfile = s2.makefile()
  353. eventlet.sleep(0.02)
  354. wrap_wfile.write('hi')
  355. s2.close()
  356. evt.send('sent via event')
  357. from eventlet import event
  358. evt = event.Event()
  359. eventlet.spawn(sender, evt)
  360. eventlet.sleep(0) # lets the socket enter accept mode, which
  361. # is necessary for connect to succeed on windows
  362. try:
  363. # try and get some data off of this pipe
  364. # but bail before any is sent
  365. eventlet.Timeout(0.01)
  366. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  367. client.connect(('127.0.0.1', bound_port))
  368. wrap_rfile = client.makefile()
  369. _c = wrap_rfile.read(1)
  370. self.fail()
  371. except eventlet.TimeoutError:
  372. pass
  373. result = evt.wait()
  374. self.assertEquals(result, 'sent via event')
  375. server.close()
  376. client.close()
  377. def test_pipe_read(self):
  378. # ensure that 'readline' works properly on GreenPipes when data is not
  379. # immediately available (fd is nonblocking, was raising EAGAIN)
  380. # also ensures that readline() terminates on '\n' and '\r\n'
  381. r, w = os.pipe()
  382. r = os.fdopen(r)
  383. w = os.fdopen(w, 'w')
  384. r = greenio.GreenPipe(r)
  385. w = greenio.GreenPipe(w)
  386. def writer():
  387. eventlet.sleep(.1)
  388. w.write('line\n')
  389. w.flush()
  390. w.write('line\r\n')
  391. w.flush()
  392. gt = eventlet.spawn(writer)
  393. eventlet.sleep(0)
  394. line = r.readline()
  395. self.assertEquals(line, 'line\n')
  396. line = r.readline()
  397. self.assertEquals(line, 'line\r\n')
  398. gt.wait()
  399. class TestGreenIoLong(LimitedTestCase):
  400. TEST_TIMEOUT=10 # the test here might take a while depending on the OS
  401. @skip_with_pyevent
  402. def test_multiple_readers(self):
  403. recvsize = 2 * min_buf_size()
  404. sendsize = 10 * recvsize
  405. # test that we can have multiple coroutines reading
  406. # from the same fd. We make no guarantees about which one gets which
  407. # bytes, but they should both get at least some
  408. def reader(sock, results):
  409. while True:
  410. data = sock.recv(recvsize)
  411. if data == '':
  412. break
  413. results.append(data)
  414. results1 = []
  415. results2 = []
  416. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  417. listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  418. listener.bind(('127.0.0.1', 0))
  419. listener.listen(50)
  420. def server():
  421. (sock, addr) = listener.accept()
  422. sock = bufsized(sock)
  423. try:
  424. c1 = eventlet.spawn(reader, sock, results1)
  425. c2 = eventlet.spawn(reader, sock, results2)
  426. c1.wait()
  427. c2.wait()
  428. finally:
  429. c1.kill()
  430. c2.kill()
  431. sock.close()
  432. server_coro = eventlet.spawn(server)
  433. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  434. client.connect(('127.0.0.1', listener.getsockname()[1]))
  435. bufsized(client)
  436. client.sendall('*' * sendsize)
  437. client.close()
  438. server_coro.wait()
  439. listener.close()
  440. self.assert_(len(results1) > 0)
  441. self.assert_(len(results2) > 0)
  442. class TestServe(LimitedTestCase):
  443. def setUp(self):
  444. super(TestServe, self).setUp()
  445. from eventlet import debug
  446. debug.hub_exceptions(False)
  447. def tearDown(self):
  448. super(TestServe, self).tearDown()
  449. from eventlet import debug
  450. debug.hub_exceptions(True)
  451. def test_exiting_server(self):
  452. # tests that the server closes the client sock on handle() exit
  453. def closer(sock,addr):
  454. pass
  455. l = eventlet.listen(('localhost', 0))
  456. gt = eventlet.spawn(greenio.serve, l, closer)
  457. client = eventlet.connect(('localhost', l.getsockname()[1]))
  458. client.sendall('a')
  459. self.assertEqual('', client.recv(100))
  460. gt.kill()
  461. def test_excepting_server(self):
  462. # tests that the server closes the client sock on handle() exception
  463. def crasher(sock,addr):
  464. x = sock.recv(1024)
  465. 0/0
  466. l = eventlet.listen(('localhost', 0))
  467. gt = eventlet.spawn(greenio.serve, l, crasher)
  468. client = eventlet.connect(('localhost', l.getsockname()[1]))
  469. client.sendall('a')
  470. self.assertRaises(ZeroDivisionError, gt.wait)
  471. self.assertEqual('', client.recv(100))
  472. def test_excepting_server_already_closed(self):
  473. # tests that the server closes the client sock on handle() exception
  474. def crasher(sock,addr):
  475. x = sock.recv(1024)
  476. sock.close()
  477. 0/0
  478. l = eventlet.listen(('localhost', 0))
  479. gt = eventlet.spawn(greenio.serve, l, crasher)
  480. client = eventlet.connect(('localhost', l.getsockname()[1]))
  481. client.sendall('a')
  482. self.assertRaises(ZeroDivisionError, gt.wait)
  483. self.assertEqual('', client.recv(100))
  484. if __name__ == '__main__':
  485. main()