PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/tests/greenio_test.py

https://bitbucket.org/jmalicki/eventlet
Python | 416 lines | 392 code | 8 blank | 16 comment | 7 complexity | f2f87df54d137baa30daa01e67d2c666 MD5 | raw file
Possible License(s): MIT
  1. import socket as _orig_sock
  2. from tests import LimitedTestCase, skip_with_pyevent, main
  3. from eventlet import greenio
  4. from eventlet import debug
  5. from eventlet.green import socket
  6. from eventlet.green import time
  7. from eventlet.green.socket import GreenSSLObject
  8. import errno
  9. import eventlet
  10. import os
  11. import sys
  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. self.assertRaises(socket.timeout, gs.connect, ('192.0.2.1', 80))
  33. except socket.error, e:
  34. # unreachable is also a valid outcome
  35. if e[0] != errno.EHOSTUNREACH:
  36. raise
  37. def test_close_with_makefile(self):
  38. def accept_close_early(listener):
  39. # verify that the makefile and the socket are truly independent
  40. # by closing the socket prior to using the made file
  41. try:
  42. conn, addr = listener.accept()
  43. fd = conn.makefile()
  44. conn.close()
  45. fd.write('hello\n')
  46. fd.close()
  47. # socket._fileobjects are odd: writes don't check
  48. # whether the socket is closed or not, and you get an
  49. # AttributeError during flush if it is closed
  50. fd.write('a')
  51. self.assertRaises(Exception, fd.flush)
  52. self.assertRaises(socket.error, conn.send, 'b')
  53. finally:
  54. listener.close()
  55. def accept_close_late(listener):
  56. # verify that the makefile and the socket are truly independent
  57. # by closing the made file and then sending a character
  58. try:
  59. conn, addr = listener.accept()
  60. fd = conn.makefile()
  61. fd.write('hello')
  62. fd.close()
  63. conn.send('\n')
  64. conn.close()
  65. fd.write('a')
  66. self.assertRaises(Exception, fd.flush)
  67. self.assertRaises(socket.error, conn.send, 'b')
  68. finally:
  69. listener.close()
  70. def did_it_work(server):
  71. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  72. client.connect(('127.0.0.1', server.getsockname()[1]))
  73. fd = client.makefile()
  74. client.close()
  75. assert fd.readline() == 'hello\n'
  76. assert fd.read() == ''
  77. fd.close()
  78. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  79. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  80. server.bind(('0.0.0.0', 0))
  81. server.listen(50)
  82. killer = eventlet.spawn(accept_close_early, server)
  83. did_it_work(server)
  84. killer.wait()
  85. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  86. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  87. server.bind(('0.0.0.0', 0))
  88. server.listen(50)
  89. killer = eventlet.spawn(accept_close_late, server)
  90. did_it_work(server)
  91. killer.wait()
  92. def test_del_closes_socket(self):
  93. def accept_once(listener):
  94. # delete/overwrite the original conn
  95. # object, only keeping the file object around
  96. # closing the file object should close everything
  97. try:
  98. conn, addr = listener.accept()
  99. conn = conn.makefile()
  100. conn.write('hello\n')
  101. conn.close()
  102. conn.write('a')
  103. self.assertRaises(Exception, conn.flush)
  104. finally:
  105. listener.close()
  106. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  107. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  108. server.bind(('127.0.0.1', 0))
  109. server.listen(50)
  110. killer = eventlet.spawn(accept_once, server)
  111. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  112. client.connect(('127.0.0.1', server.getsockname()[1]))
  113. fd = client.makefile()
  114. client.close()
  115. assert fd.read() == 'hello\n'
  116. assert fd.read() == ''
  117. killer.wait()
  118. def test_full_duplex(self):
  119. large_data = '*' * 10 * min_buf_size()
  120. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  121. listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  122. listener.bind(('127.0.0.1', 0))
  123. listener.listen(50)
  124. bufsized(listener)
  125. def send_large(sock):
  126. sock.sendall(large_data)
  127. def read_large(sock):
  128. result = sock.recv(len(large_data))
  129. expected = 'hello world'
  130. while len(result) < len(large_data):
  131. result += sock.recv(len(large_data))
  132. self.assertEquals(result, large_data)
  133. def server():
  134. (sock, addr) = listener.accept()
  135. sock = bufsized(sock)
  136. send_large_coro = eventlet.spawn(send_large, sock)
  137. eventlet.sleep(0)
  138. result = sock.recv(10)
  139. expected = 'hello world'
  140. while len(result) < len(expected):
  141. result += sock.recv(10)
  142. self.assertEquals(result, expected)
  143. send_large_coro.wait()
  144. server_evt = eventlet.spawn(server)
  145. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  146. client.connect(('127.0.0.1', listener.getsockname()[1]))
  147. bufsized(client)
  148. large_evt = eventlet.spawn(read_large, client)
  149. eventlet.sleep(0)
  150. client.sendall('hello world')
  151. server_evt.wait()
  152. large_evt.wait()
  153. client.close()
  154. def test_sendall(self):
  155. # test adapted from Marcus Cavanaugh's email
  156. # it may legitimately take a while, but will eventually complete
  157. self.timer.cancel()
  158. second_bytes = 10
  159. def test_sendall_impl(many_bytes):
  160. bufsize = max(many_bytes/15, 2)
  161. def sender(listener):
  162. (sock, addr) = listener.accept()
  163. sock = bufsized(sock, size=bufsize)
  164. sock.sendall('x'*many_bytes)
  165. sock.sendall('y'*second_bytes)
  166. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  167. listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  168. listener.bind(("", 0))
  169. listener.listen(50)
  170. sender_coro = eventlet.spawn(sender, listener)
  171. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  172. client.connect(('127.0.0.1', listener.getsockname()[1]))
  173. bufsized(client, size=bufsize)
  174. total = 0
  175. while total < many_bytes:
  176. data = client.recv(min(many_bytes - total, many_bytes/10))
  177. if data == '':
  178. break
  179. total += len(data)
  180. total2 = 0
  181. while total < second_bytes:
  182. data = client.recv(second_bytes)
  183. if data == '':
  184. break
  185. total2 += len(data)
  186. sender_coro.wait()
  187. client.close()
  188. for bytes in (1000, 10000, 100000, 1000000):
  189. test_sendall_impl(bytes)
  190. def test_wrap_socket(self):
  191. try:
  192. import ssl
  193. except ImportError:
  194. pass # pre-2.6
  195. else:
  196. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  197. sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  198. sock.bind(('127.0.0.1', 0))
  199. sock.listen(50)
  200. ssl_sock = ssl.wrap_socket(sock)
  201. def test_timeout_and_final_write(self):
  202. # This test verifies that a write on a socket that we've
  203. # stopped listening for doesn't result in an incorrect switch
  204. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  205. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  206. server.bind(('127.0.0.1', 0))
  207. server.listen(50)
  208. bound_port = server.getsockname()[1]
  209. def sender(evt):
  210. s2, addr = server.accept()
  211. wrap_wfile = s2.makefile()
  212. eventlet.sleep(0.02)
  213. wrap_wfile.write('hi')
  214. s2.close()
  215. evt.send('sent via event')
  216. from eventlet import event
  217. evt = event.Event()
  218. eventlet.spawn(sender, evt)
  219. eventlet.sleep(0) # lets the socket enter accept mode, which
  220. # is necessary for connect to succeed on windows
  221. try:
  222. # try and get some data off of this pipe
  223. # but bail before any is sent
  224. eventlet.Timeout(0.01)
  225. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  226. client.connect(('127.0.0.1', bound_port))
  227. wrap_rfile = client.makefile()
  228. _c = wrap_rfile.read(1)
  229. self.fail()
  230. except eventlet.TimeoutError:
  231. pass
  232. result = evt.wait()
  233. self.assertEquals(result, 'sent via event')
  234. server.close()
  235. client.close()
  236. class TestGreenIoLong(LimitedTestCase):
  237. TEST_TIMEOUT=10 # the test here might take a while depending on the OS
  238. @skip_with_pyevent
  239. def test_multiple_readers(self, clibufsize=False):
  240. recvsize = 2 * min_buf_size()
  241. sendsize = 10 * recvsize
  242. # test that we can have multiple coroutines reading
  243. # from the same fd. We make no guarantees about which one gets which
  244. # bytes, but they should both get at least some
  245. def reader(sock, results):
  246. while True:
  247. data = sock.recv(recvsize)
  248. if data == '':
  249. break
  250. results.append(data)
  251. results1 = []
  252. results2 = []
  253. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  254. listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  255. listener.bind(('127.0.0.1', 0))
  256. listener.listen(50)
  257. def server():
  258. (sock, addr) = listener.accept()
  259. sock = bufsized(sock)
  260. try:
  261. c1 = eventlet.spawn(reader, sock, results1)
  262. c2 = eventlet.spawn(reader, sock, results2)
  263. try:
  264. c1.wait()
  265. c2.wait()
  266. finally:
  267. c1.kill()
  268. c2.kill()
  269. finally:
  270. sock.close()
  271. server_coro = eventlet.spawn(server)
  272. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  273. client.connect(('127.0.0.1', listener.getsockname()[1]))
  274. if clibufsize:
  275. bufsized(client, size=sendsize)
  276. else:
  277. bufsized(client)
  278. client.sendall('*' * sendsize)
  279. client.close()
  280. server_coro.wait()
  281. listener.close()
  282. self.assert_(len(results1) > 0)
  283. self.assert_(len(results2) > 0)
  284. @skip_with_pyevent
  285. def test_multiple_readers2(self):
  286. self.test_multiple_readers(clibufsize=True)
  287. class TestGreenIoStarvation(LimitedTestCase):
  288. # fixme: this doesn't fail, because of eventlet's predetermined
  289. # ordering. two processes, one with server, one with client eventlets
  290. # might be more reliable?
  291. TEST_TIMEOUT=300 # the test here might take a while depending on the OS
  292. @skip_with_pyevent
  293. def test_server_starvation(self, sendloops=15):
  294. recvsize = 2 * min_buf_size()
  295. sendsize = 10000 * recvsize
  296. results = [[] for i in xrange(5)]
  297. listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  298. listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
  299. listener.bind(('127.0.0.1', 0))
  300. port = listener.getsockname()[1]
  301. listener.listen(50)
  302. base_time = time.time()
  303. def server(my_results):
  304. (sock, addr) = listener.accept()
  305. datasize = 0
  306. t1 = None
  307. t2 = None
  308. try:
  309. while True:
  310. data = sock.recv(recvsize)
  311. if not t1:
  312. t1 = time.time() - base_time
  313. if data == '':
  314. t2 = time.time() - base_time
  315. my_results.append(datasize)
  316. my_results.append((t1,t2))
  317. break
  318. datasize += len(data)
  319. finally:
  320. sock.close()
  321. def client():
  322. pid = os.fork()
  323. if pid:
  324. return pid
  325. client = _orig_sock.socket(socket.AF_INET, socket.SOCK_STREAM)
  326. client.connect(('127.0.0.1', port))
  327. bufsized(client, size=sendsize)
  328. for i in range(sendloops):
  329. client.sendall('*' * sendsize)
  330. client.close()
  331. os._exit(0)
  332. clients = []
  333. servers = []
  334. for r in results:
  335. servers.append(eventlet.spawn(server, r))
  336. for r in results:
  337. clients.append(client())
  338. for s in servers:
  339. s.wait()
  340. for c in clients:
  341. os.waitpid(c, 0)
  342. listener.close()
  343. # now test that all of the server receive intervals overlap, and
  344. # that there were no errors.
  345. for r in results:
  346. assert len(r) == 2, "length is %d not 2!: %s\n%s" % (len(r), r, results)
  347. assert r[0] == sendsize * sendloops
  348. assert len(r[1]) == 2
  349. assert r[1][0] is not None
  350. assert r[1][1] is not None
  351. starttimes = sorted(r[1][0] for r in results)
  352. endtimes = sorted(r[1][1] for r in results)
  353. runlengths = sorted(r[1][1] - r[1][0] for r in results)
  354. # assert that the last task started before the first task ended
  355. # (our no-starvation condition)
  356. assert starttimes[-1] < endtimes[0], "Not overlapping: starts %s ends %s" % (starttimes, endtimes)
  357. maxstartdiff = starttimes[-1] - starttimes[0]
  358. assert maxstartdiff * 2 < runlengths[0], "Largest difference in starting times more than twice the shortest running time!"
  359. assert runlengths[0] * 2 > runlengths[-1], "Longest runtime more than twice as long as shortest!"
  360. if __name__ == '__main__':
  361. main()