/tests/greenio_test.py
Python | 312 lines | 288 code | 8 blank | 16 comment | 1 complexity | 19ce0c8d3de519e2a3986fffcafa2210 MD5 | raw file
1from tests import LimitedTestCase, skip_with_pyevent, main 2from eventlet import greenio 3from eventlet import debug 4from eventlet.green import socket 5from eventlet.green.socket import GreenSSLObject 6import errno 7 8import eventlet 9import os 10import sys 11 12def bufsized(sock, size=1): 13 """ Resize both send and receive buffers on a socket. 14 Useful for testing trampoline. Returns the socket. 15 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 23def min_buf_size(): 24 """Return the minimum buffer size that the platform supports.""" 25 test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 26 test_sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1) 27 return test_sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) 28 29class TestGreenIo(LimitedTestCase): 30 def test_connect_timeout(self): 31 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 32 s.settimeout(0.1) 33 gs = greenio.GreenSocket(s) 34 try: 35 self.assertRaises(socket.timeout, gs.connect, ('192.0.2.1', 80)) 36 except socket.error, e: 37 # unreachable is also a valid outcome 38 if e[0] != errno.EHOSTUNREACH: 39 raise 40 41 def test_close_with_makefile(self): 42 def accept_close_early(listener): 43 # verify that the makefile and the socket are truly independent 44 # by closing the socket prior to using the made file 45 try: 46 conn, addr = listener.accept() 47 fd = conn.makefile() 48 conn.close() 49 fd.write('hello\n') 50 fd.close() 51 # socket._fileobjects are odd: writes don't check 52 # whether the socket is closed or not, and you get an 53 # AttributeError during flush if it is closed 54 fd.write('a') 55 self.assertRaises(Exception, fd.flush) 56 self.assertRaises(socket.error, conn.send, 'b') 57 finally: 58 listener.close() 59 60 def accept_close_late(listener): 61 # verify that the makefile and the socket are truly independent 62 # by closing the made file and then sending a character 63 try: 64 conn, addr = listener.accept() 65 fd = conn.makefile() 66 fd.write('hello') 67 fd.close() 68 conn.send('\n') 69 conn.close() 70 fd.write('a') 71 self.assertRaises(Exception, fd.flush) 72 self.assertRaises(socket.error, conn.send, 'b') 73 finally: 74 listener.close() 75 76 def did_it_work(server): 77 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 78 client.connect(('127.0.0.1', server.getsockname()[1])) 79 fd = client.makefile() 80 client.close() 81 assert fd.readline() == 'hello\n' 82 assert fd.read() == '' 83 fd.close() 84 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_early, server) 90 did_it_work(server) 91 killer.wait() 92 93 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 94 server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) 95 server.bind(('0.0.0.0', 0)) 96 server.listen(50) 97 killer = eventlet.spawn(accept_close_late, server) 98 did_it_work(server) 99 killer.wait() 100 101 def test_del_closes_socket(self): 102 def accept_once(listener): 103 # delete/overwrite the original conn 104 # object, only keeping the file object around 105 # closing the file object should close everything 106 try: 107 conn, addr = listener.accept() 108 conn = conn.makefile() 109 conn.write('hello\n') 110 conn.close() 111 conn.write('a') 112 self.assertRaises(Exception, conn.flush) 113 finally: 114 listener.close() 115 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 116 server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) 117 server.bind(('127.0.0.1', 0)) 118 server.listen(50) 119 killer = eventlet.spawn(accept_once, server) 120 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 121 client.connect(('127.0.0.1', server.getsockname()[1])) 122 fd = client.makefile() 123 client.close() 124 assert fd.read() == 'hello\n' 125 assert fd.read() == '' 126 127 killer.wait() 128 129 def test_full_duplex(self): 130 large_data = '*' * 10 * min_buf_size() 131 listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 132 listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) 133 listener.bind(('127.0.0.1', 0)) 134 listener.listen(50) 135 bufsized(listener) 136 137 def send_large(sock): 138 sock.sendall(large_data) 139 140 def read_large(sock): 141 result = sock.recv(len(large_data)) 142 expected = 'hello world' 143 while len(result) < len(large_data): 144 result += sock.recv(len(large_data)) 145 self.assertEquals(result, large_data) 146 147 def server(): 148 (sock, addr) = listener.accept() 149 sock = bufsized(sock) 150 send_large_coro = eventlet.spawn(send_large, sock) 151 eventlet.sleep(0) 152 result = sock.recv(10) 153 expected = 'hello world' 154 while len(result) < len(expected): 155 result += sock.recv(10) 156 self.assertEquals(result, expected) 157 send_large_coro.wait() 158 159 server_evt = eventlet.spawn(server) 160 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 161 client.connect(('127.0.0.1', listener.getsockname()[1])) 162 bufsized(client) 163 large_evt = eventlet.spawn(read_large, client) 164 eventlet.sleep(0) 165 client.sendall('hello world') 166 server_evt.wait() 167 large_evt.wait() 168 client.close() 169 170 def test_sendall(self): 171 # test adapted from Marcus Cavanaugh's email 172 # it may legitimately take a while, but will eventually complete 173 self.timer.cancel() 174 second_bytes = 10 175 def test_sendall_impl(many_bytes): 176 bufsize = max(many_bytes/15, 2) 177 def sender(listener): 178 (sock, addr) = listener.accept() 179 sock = bufsized(sock, size=bufsize) 180 sock.sendall('x'*many_bytes) 181 sock.sendall('y'*second_bytes) 182 183 listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 184 listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) 185 listener.bind(("", 0)) 186 listener.listen(50) 187 sender_coro = eventlet.spawn(sender, listener) 188 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 189 client.connect(('127.0.0.1', listener.getsockname()[1])) 190 bufsized(client, size=bufsize) 191 total = 0 192 while total < many_bytes: 193 data = client.recv(min(many_bytes - total, many_bytes/10)) 194 if data == '': 195 break 196 total += len(data) 197 198 total2 = 0 199 while total < second_bytes: 200 data = client.recv(second_bytes) 201 if data == '': 202 break 203 total2 += len(data) 204 205 sender_coro.wait() 206 client.close() 207 208 for bytes in (1000, 10000, 100000, 1000000): 209 test_sendall_impl(bytes) 210 211 def test_wrap_socket(self): 212 try: 213 import ssl 214 except ImportError: 215 pass # pre-2.6 216 else: 217 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 218 sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) 219 sock.bind(('127.0.0.1', 0)) 220 sock.listen(50) 221 ssl_sock = ssl.wrap_socket(sock) 222 223 def test_timeout_and_final_write(self): 224 # This test verifies that a write on a socket that we've 225 # stopped listening for doesn't result in an incorrect switch 226 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 227 server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) 228 server.bind(('127.0.0.1', 0)) 229 server.listen(50) 230 bound_port = server.getsockname()[1] 231 232 def sender(evt): 233 s2, addr = server.accept() 234 wrap_wfile = s2.makefile() 235 236 eventlet.sleep(0.02) 237 wrap_wfile.write('hi') 238 s2.close() 239 evt.send('sent via event') 240 241 from eventlet import event 242 evt = event.Event() 243 eventlet.spawn(sender, evt) 244 eventlet.sleep(0) # lets the socket enter accept mode, which 245 # is necessary for connect to succeed on windows 246 try: 247 # try and get some data off of this pipe 248 # but bail before any is sent 249 eventlet.exc_after(0.01, eventlet.TimeoutError) 250 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 251 client.connect(('127.0.0.1', bound_port)) 252 wrap_rfile = client.makefile() 253 _c = wrap_rfile.read(1) 254 self.fail() 255 except eventlet.TimeoutError: 256 pass 257 258 result = evt.wait() 259 self.assertEquals(result, 'sent via event') 260 server.close() 261 client.close() 262 263 264class TestGreenIoLong(LimitedTestCase): 265 TEST_TIMEOUT=10 # the test here might take a while depending on the OS 266 @skip_with_pyevent 267 def test_multiple_readers(self): 268 recvsize = 2 * min_buf_size() 269 sendsize = 10 * recvsize 270 # test that we can have multiple coroutines reading 271 # from the same fd. We make no guarantees about which one gets which 272 # bytes, but they should both get at least some 273 def reader(sock, results): 274 while True: 275 data = sock.recv(recvsize) 276 if data == '': 277 break 278 results.append(data) 279 280 results1 = [] 281 results2 = [] 282 listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 283 listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) 284 listener.bind(('127.0.0.1', 0)) 285 listener.listen(50) 286 def server(): 287 (sock, addr) = listener.accept() 288 sock = bufsized(sock) 289 try: 290 c1 = eventlet.spawn(reader, sock, results1) 291 c2 = eventlet.spawn(reader, sock, results2) 292 c1.wait() 293 c2.wait() 294 finally: 295 c1.kill() 296 c2.kill() 297 sock.close() 298 299 server_coro = eventlet.spawn(server) 300 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 301 client.connect(('127.0.0.1', listener.getsockname()[1])) 302 bufsized(client) 303 client.sendall('*' * sendsize) 304 client.close() 305 server_coro.wait() 306 listener.close() 307 self.assert_(len(results1) > 0) 308 self.assert_(len(results2) > 0) 309 310 311if __name__ == '__main__': 312 main()