/tests/greenio_test.py
Python | 825 lines | 787 code | 20 blank | 18 comment | 10 complexity | a70ea525121fddab3f33fdae3a7bf907 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 14 15 16def bufsized(sock, size=1): 17 """ Resize both send and receive buffers on a socket. 18 Useful for testing trampoline. Returns the socket. 19 20 >>> import socket 21 >>> sock = bufsized(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) 22 """ 23 sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, size) 24 sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, size) 25 return sock 26 27 28def min_buf_size(): 29 """Return the minimum buffer size that the platform supports.""" 30 test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 31 test_sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1) 32 return test_sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) 33 34 35def using_epoll_hub(_f): 36 try: 37 return 'epolls' in type(get_hub()).__module__ 38 except Exception: 39 return False 40 41 42class TestGreenSocket(LimitedTestCase): 43 def assertWriteToClosedFileRaises(self, fd): 44 if sys.version_info[0] < 3: 45 # 2.x socket._fileobjects are odd: writes don't check 46 # whether the socket is closed or not, and you get an 47 # AttributeError during flush if it is closed 48 fd.write('a') 49 self.assertRaises(Exception, fd.flush) 50 else: 51 # 3.x io write to closed file-like pbject raises ValueError 52 self.assertRaises(ValueError, fd.write, 'a') 53 54 def test_connect_timeout(self): 55 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 56 s.settimeout(0.1) 57 gs = greenio.GreenSocket(s) 58 try: 59 gs.connect(('192.0.2.1', 80)) 60 self.fail("socket.timeout not raised") 61 except socket.timeout, e: 62 self.assert_(hasattr(e, 'args')) 63 self.assertEqual(e.args[0], 'timed out') 64 except socket.error, e: 65 # unreachable is also a valid outcome 66 if not get_errno(e) in (errno.EHOSTUNREACH, errno.ENETUNREACH): 67 raise 68 69 def test_accept_timeout(self): 70 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 71 s.bind(('', 0)) 72 s.listen(50) 73 74 s.settimeout(0.1) 75 gs = greenio.GreenSocket(s) 76 try: 77 gs.accept() 78 self.fail("socket.timeout not raised") 79 except socket.timeout, e: 80 self.assert_(hasattr(e, 'args')) 81 self.assertEqual(e.args[0], 'timed out') 82 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 not e in (errno.EHOSTUNREACH, errno.ENETUNREACH): 89 self.assertEquals(e, errno.EAGAIN) 90 91 def test_recv_timeout(self): 92 listener = greenio.GreenSocket(socket.socket()) 93 listener.bind(('', 0)) 94 listener.listen(50) 95 96 evt = event.Event() 97 98 def server(): 99 # accept the connection in another greenlet 100 sock, addr = listener.accept() 101 evt.wait() 102 103 gt = eventlet.spawn(server) 104 105 addr = listener.getsockname() 106 107 client = greenio.GreenSocket(socket.socket()) 108 client.settimeout(0.1) 109 110 client.connect(addr) 111 112 try: 113 client.recv(8192) 114 self.fail("socket.timeout not raised") 115 except socket.timeout, e: 116 self.assert_(hasattr(e, 'args')) 117 self.assertEqual(e.args[0], 'timed out') 118 119 evt.send() 120 gt.wait() 121 122 def test_recvfrom_timeout(self): 123 gs = greenio.GreenSocket( 124 socket.socket(socket.AF_INET, socket.SOCK_DGRAM)) 125 gs.settimeout(.1) 126 gs.bind(('', 0)) 127 128 try: 129 gs.recvfrom(8192) 130 self.fail("socket.timeout not raised") 131 except socket.timeout, e: 132 self.assert_(hasattr(e, 'args')) 133 self.assertEqual(e.args[0], 'timed out') 134 135 def test_recvfrom_into_timeout(self): 136 buf = buffer(array.array('B')) 137 138 gs = greenio.GreenSocket( 139 socket.socket(socket.AF_INET, socket.SOCK_DGRAM)) 140 gs.settimeout(.1) 141 gs.bind(('', 0)) 142 143 try: 144 gs.recvfrom_into(buf) 145 self.fail("socket.timeout not raised") 146 except socket.timeout, e: 147 self.assert_(hasattr(e, 'args')) 148 self.assertEqual(e.args[0], 'timed out') 149 150 def test_recv_into_timeout(self): 151 buf = buffer(array.array('B')) 152 153 listener = greenio.GreenSocket(socket.socket()) 154 listener.bind(('', 0)) 155 listener.listen(50) 156 157 evt = event.Event() 158 159 def server(): 160 # accept the connection in another greenlet 161 sock, addr = listener.accept() 162 evt.wait() 163 164 gt = eventlet.spawn(server) 165 166 addr = listener.getsockname() 167 168 client = greenio.GreenSocket(socket.socket()) 169 client.settimeout(0.1) 170 171 client.connect(addr) 172 173 try: 174 client.recv_into(buf) 175 self.fail("socket.timeout not raised") 176 except socket.timeout, e: 177 self.assert_(hasattr(e, 'args')) 178 self.assertEqual(e.args[0], 'timed out') 179 180 evt.send() 181 gt.wait() 182 183 def test_send_timeout(self): 184 listener = bufsized(eventlet.listen(('', 0))) 185 186 evt = event.Event() 187 188 def server(): 189 # accept the connection in another greenlet 190 sock, addr = listener.accept() 191 sock = bufsized(sock) 192 evt.wait() 193 194 gt = eventlet.spawn(server) 195 196 addr = listener.getsockname() 197 198 client = bufsized(greenio.GreenSocket(socket.socket())) 199 client.connect(addr) 200 try: 201 client.settimeout(0.00001) 202 msg = s2b("A") * 100000 # large enough number to overwhelm most buffers 203 204 total_sent = 0 205 # want to exceed the size of the OS buffer so it'll block in a 206 # single send 207 for x in range(10): 208 total_sent += client.send(msg) 209 self.fail("socket.timeout not raised") 210 except socket.timeout, e: 211 self.assert_(hasattr(e, 'args')) 212 self.assertEqual(e.args[0], 'timed out') 213 214 evt.send() 215 gt.wait() 216 217 def test_sendall_timeout(self): 218 listener = greenio.GreenSocket(socket.socket()) 219 listener.bind(('', 0)) 220 listener.listen(50) 221 222 evt = event.Event() 223 224 def server(): 225 # accept the connection in another greenlet 226 sock, addr = listener.accept() 227 evt.wait() 228 229 gt = eventlet.spawn(server) 230 231 addr = listener.getsockname() 232 233 client = greenio.GreenSocket(socket.socket()) 234 client.settimeout(0.1) 235 client.connect(addr) 236 237 try: 238 msg = s2b("A") * (8 << 20) 239 240 # want to exceed the size of the OS buffer so it'll block 241 client.sendall(msg) 242 self.fail("socket.timeout not raised") 243 except socket.timeout, e: 244 self.assert_(hasattr(e, 'args')) 245 self.assertEqual(e.args[0], 'timed out') 246 247 evt.send() 248 gt.wait() 249 250 def test_close_with_makefile(self): 251 def accept_close_early(listener): 252 # verify that the makefile and the socket are truly independent 253 # by closing the socket prior to using the made file 254 try: 255 conn, addr = listener.accept() 256 fd = conn.makefile('w') 257 conn.close() 258 fd.write('hello\n') 259 fd.close() 260 self.assertWriteToClosedFileRaises(fd) 261 self.assertRaises(socket.error, conn.send, s2b('b')) 262 finally: 263 listener.close() 264 265 def accept_close_late(listener): 266 # verify that the makefile and the socket are truly independent 267 # by closing the made file and then sending a character 268 try: 269 conn, addr = listener.accept() 270 fd = conn.makefile('w') 271 fd.write('hello') 272 fd.close() 273 conn.send(s2b('\n')) 274 conn.close() 275 self.assertWriteToClosedFileRaises(fd) 276 self.assertRaises(socket.error, conn.send, s2b('b')) 277 finally: 278 listener.close() 279 280 def did_it_work(server): 281 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 282 client.connect(('127.0.0.1', server.getsockname()[1])) 283 fd = client.makefile() 284 client.close() 285 assert fd.readline() == 'hello\n' 286 assert fd.read() == '' 287 fd.close() 288 289 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 290 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 291 server.bind(('0.0.0.0', 0)) 292 server.listen(50) 293 killer = eventlet.spawn(accept_close_early, server) 294 did_it_work(server) 295 killer.wait() 296 297 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 298 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 299 server.bind(('0.0.0.0', 0)) 300 server.listen(50) 301 killer = eventlet.spawn(accept_close_late, server) 302 did_it_work(server) 303 killer.wait() 304 305 def test_del_closes_socket(self): 306 def accept_once(listener): 307 # delete/overwrite the original conn 308 # object, only keeping the file object around 309 # closing the file object should close everything 310 try: 311 conn, addr = listener.accept() 312 conn = conn.makefile('w') 313 conn.write('hello\n') 314 conn.close() 315 self.assertWriteToClosedFileRaises(conn) 316 finally: 317 listener.close() 318 319 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 320 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 321 server.bind(('127.0.0.1', 0)) 322 server.listen(50) 323 killer = eventlet.spawn(accept_once, server) 324 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 325 client.connect(('127.0.0.1', server.getsockname()[1])) 326 fd = client.makefile() 327 client.close() 328 assert fd.read() == 'hello\n' 329 assert fd.read() == '' 330 331 killer.wait() 332 333 def test_full_duplex(self): 334 large_data = s2b('*') * 10 * min_buf_size() 335 listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 336 listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 337 listener.bind(('127.0.0.1', 0)) 338 listener.listen(50) 339 bufsized(listener) 340 341 def send_large(sock): 342 sock.sendall(large_data) 343 344 def read_large(sock): 345 result = sock.recv(len(large_data)) 346 while len(result) < len(large_data): 347 result += sock.recv(len(large_data)) 348 self.assertEquals(result, large_data) 349 350 def server(): 351 (sock, addr) = listener.accept() 352 sock = bufsized(sock) 353 send_large_coro = eventlet.spawn(send_large, sock) 354 eventlet.sleep(0) 355 result = sock.recv(10) 356 expected = s2b('hello world') 357 while len(result) < len(expected): 358 result += sock.recv(10) 359 self.assertEquals(result, expected) 360 send_large_coro.wait() 361 362 server_evt = eventlet.spawn(server) 363 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 364 client.connect(('127.0.0.1', listener.getsockname()[1])) 365 bufsized(client) 366 large_evt = eventlet.spawn(read_large, client) 367 eventlet.sleep(0) 368 client.sendall(s2b('hello world')) 369 server_evt.wait() 370 large_evt.wait() 371 client.close() 372 373 def test_sendall(self): 374 # test adapted from Marcus Cavanaugh's email 375 # it may legitimately take a while, but will eventually complete 376 self.timer.cancel() 377 second_bytes = 10 378 379 def test_sendall_impl(many_bytes): 380 bufsize = max(many_bytes // 15, 2) 381 382 def sender(listener): 383 (sock, addr) = listener.accept() 384 sock = bufsized(sock, size=bufsize) 385 sock.sendall(s2b('x') * many_bytes) 386 sock.sendall(s2b('y') * second_bytes) 387 388 listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 389 listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 390 listener.bind(("", 0)) 391 listener.listen(50) 392 sender_coro = eventlet.spawn(sender, listener) 393 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 394 client.connect(('127.0.0.1', listener.getsockname()[1])) 395 bufsized(client, size=bufsize) 396 total = 0 397 while total < many_bytes: 398 data = client.recv(min(many_bytes - total, many_bytes // 10)) 399 if not data: 400 break 401 total += len(data) 402 403 total2 = 0 404 while total < second_bytes: 405 data = client.recv(second_bytes) 406 if not data: 407 break 408 total2 += len(data) 409 410 sender_coro.wait() 411 client.close() 412 413 for how_many in (1000, 10000, 100000, 1000000): 414 test_sendall_impl(how_many) 415 416 def test_wrap_socket(self): 417 try: 418 import ssl 419 except ImportError: 420 pass # pre-2.6 421 else: 422 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 423 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 424 sock.bind(('127.0.0.1', 0)) 425 sock.listen(50) 426 ssl.wrap_socket(sock) 427 428 def test_timeout_and_final_write(self): 429 # This test verifies that a write on a socket that we've 430 # stopped listening for doesn't result in an incorrect switch 431 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 432 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 433 server.bind(('127.0.0.1', 0)) 434 server.listen(50) 435 bound_port = server.getsockname()[1] 436 437 def sender(evt): 438 s2, addr = server.accept() 439 wrap_wfile = s2.makefile('w') 440 441 eventlet.sleep(0.02) 442 wrap_wfile.write('hi') 443 s2.close() 444 evt.send('sent via event') 445 446 evt = event.Event() 447 eventlet.spawn(sender, evt) 448 eventlet.sleep(0) # lets the socket enter accept mode, which 449 # is necessary for connect to succeed on windows 450 try: 451 # try and get some data off of this pipe 452 # but bail before any is sent 453 eventlet.Timeout(0.01) 454 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 455 client.connect(('127.0.0.1', bound_port)) 456 wrap_rfile = client.makefile() 457 wrap_rfile.read(1) 458 self.fail() 459 except eventlet.TimeoutError: 460 pass 461 462 result = evt.wait() 463 self.assertEquals(result, 'sent via event') 464 server.close() 465 client.close() 466 467 @skip_with_pyevent 468 def test_raised_multiple_readers(self): 469 debug.hub_prevent_multiple_readers(True) 470 471 def handle(sock, addr): 472 sock.recv(1) 473 sock.sendall("a") 474 raise eventlet.StopServe() 475 476 listener = eventlet.listen(('127.0.0.1', 0)) 477 eventlet.spawn(eventlet.serve, listener, handle) 478 479 def reader(s): 480 s.recv(1) 481 482 s = eventlet.connect(('127.0.0.1', listener.getsockname()[1])) 483 a = eventlet.spawn(reader, s) 484 eventlet.sleep(0) 485 self.assertRaises(RuntimeError, s.recv, 1) 486 s.sendall('b') 487 a.wait() 488 489 @skip_with_pyevent 490 @skip_if(using_epoll_hub) 491 def test_closure(self): 492 def spam_to_me(address): 493 sock = eventlet.connect(address) 494 while True: 495 try: 496 sock.sendall('hello world') 497 except socket.error, e: 498 if get_errno(e) == errno.EPIPE: 499 return 500 raise 501 502 server = eventlet.listen(('127.0.0.1', 0)) 503 sender = eventlet.spawn(spam_to_me, server.getsockname()) 504 client, address = server.accept() 505 server.close() 506 507 def reader(): 508 try: 509 while True: 510 data = client.recv(1024) 511 self.assert_(data) 512 except socket.error, e: 513 # we get an EBADF because client is closed in the same process 514 # (but a different greenthread) 515 if get_errno(e) != errno.EBADF: 516 raise 517 518 def closer(): 519 client.close() 520 521 reader = eventlet.spawn(reader) 522 eventlet.spawn_n(closer) 523 reader.wait() 524 sender.wait() 525 526 def test_invalid_connection(self): 527 # find an unused port by creating a socket then closing it 528 port = eventlet.listen(('127.0.0.1', 0)).getsockname()[1] 529 self.assertRaises(socket.error, eventlet.connect, ('127.0.0.1', port)) 530 531 def test_zero_timeout_and_back(self): 532 listen = eventlet.listen(('', 0)) 533 # Keep reference to server side of socket 534 server = eventlet.spawn(listen.accept) 535 client = eventlet.connect(listen.getsockname()) 536 537 client.settimeout(0.05) 538 # Now must raise socket.timeout 539 self.assertRaises(socket.timeout, client.recv, 1) 540 541 client.settimeout(0) 542 # Now must raise socket.error with EAGAIN 543 try: 544 client.recv(1) 545 assert False 546 except socket.error, e: 547 assert get_errno(e) == errno.EAGAIN 548 549 client.settimeout(0.05) 550 # Now socket.timeout again 551 self.assertRaises(socket.timeout, client.recv, 1) 552 server.wait() 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 824if __name__ == '__main__': 825 main()