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