PageRenderTime 64ms CodeModel.GetById 1ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 1ms

/tests/greenio_test.py

https://bitbucket.org/portante/eventlet
Python | 802 lines | 764 code | 20 blank | 18 comment | 10 complexity | 2de7759e7c1d3e33a3872766652b9658 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
532class TestGreenPipe(LimitedTestCase):
533    @skip_on_windows
534    def setUp(self):
535        super(self.__class__, self).setUp()
536        self.tempdir = tempfile.mkdtemp('_green_pipe_test')
537
538    def tearDown(self):
539        shutil.rmtree(self.tempdir)
540        super(self.__class__, self).tearDown()
541
542    def test_pipe(self):
543        r, w = os.pipe()
544        rf = greenio.GreenPipe(r, 'r')
545        wf = greenio.GreenPipe(w, 'w', 0)
546
547        def sender(f, content):
548            for ch in content:
549                eventlet.sleep(0.0001)
550                f.write(ch)
551            f.close()
552
553        one_line = "12345\n"
554        eventlet.spawn(sender, wf, one_line * 5)
555        for i in xrange(5):
556            line = rf.readline()
557            eventlet.sleep(0.01)
558            self.assertEquals(line, one_line)
559        self.assertEquals(rf.readline(), '')
560
561    def test_pipe_read(self):
562        # ensure that 'readline' works properly on GreenPipes when data is not
563        # immediately available (fd is nonblocking, was raising EAGAIN)
564        # also ensures that readline() terminates on '\n' and '\r\n'
565        r, w = os.pipe()
566
567        r = greenio.GreenPipe(r)
568        w = greenio.GreenPipe(w, 'w')
569
570        def writer():
571            eventlet.sleep(.1)
572
573            w.write('line\n')
574            w.flush()
575
576            w.write('line\r\n')
577            w.flush()
578
579        gt = eventlet.spawn(writer)
580
581        eventlet.sleep(0)
582
583        line = r.readline()
584        self.assertEquals(line, 'line\n')
585
586        line = r.readline()
587        self.assertEquals(line, 'line\r\n')
588
589        gt.wait()
590
591    def test_pipe_writes_large_messages(self):
592        r, w = os.pipe()
593
594        r = greenio.GreenPipe(r)
595        w = greenio.GreenPipe(w, 'w')
596
597        large_message = "".join([1024 * chr(i) for i in xrange(65)])
598
599        def writer():
600            w.write(large_message)
601            w.close()
602
603        gt = eventlet.spawn(writer)
604
605        for i in xrange(65):
606            buf = r.read(1024)
607            expected = 1024 * chr(i)
608            self.assertEquals(buf, expected,
609                "expected=%r..%r, found=%r..%r iter=%d"
610                % (expected[:4], expected[-4:], buf[:4], buf[-4:], i))
611        gt.wait()
612
613    def test_seek_on_buffered_pipe(self):
614        f = greenio.GreenPipe(self.tempdir + "/TestFile", 'w+', 1024)
615        self.assertEquals(f.tell(), 0)
616        f.seek(0, 2)
617        self.assertEquals(f.tell(), 0)
618        f.write('1234567890')
619        f.seek(0, 2)
620        self.assertEquals(f.tell(), 10)
621        f.seek(0)
622        value = f.read(1)
623        self.assertEqual(value, '1')
624        self.assertEquals(f.tell(), 1)
625        value = f.read(1)
626        self.assertEqual(value, '2')
627        self.assertEquals(f.tell(), 2)
628        f.seek(0, 1)
629        self.assertEqual(f.readline(), '34567890')
630        f.seek(-5, 1)
631        self.assertEqual(f.readline(), '67890')
632        f.seek(0)
633        self.assertEqual(f.readline(), '1234567890')
634        f.seek(0, 2)
635        self.assertEqual(f.readline(), '')
636
637    def test_truncate(self):
638        f = greenio.GreenPipe(self.tempdir + "/TestFile", 'w+', 1024)
639        f.write('1234567890')
640        f.truncate(9)
641        self.assertEquals(f.tell(), 9)
642
643
644class TestGreenIoLong(LimitedTestCase):
645    TEST_TIMEOUT = 10  # the test here might take a while depending on the OS
646
647    @skip_with_pyevent
648    def test_multiple_readers(self, clibufsize=False):
649        debug.hub_prevent_multiple_readers(False)
650        recvsize = 2 * min_buf_size()
651        sendsize = 10 * recvsize
652
653        # test that we can have multiple coroutines reading
654        # from the same fd.  We make no guarantees about which one gets which
655        # bytes, but they should both get at least some
656        def reader(sock, results):
657            while True:
658                data = sock.recv(recvsize)
659                if not data:
660                    break
661                results.append(data)
662
663        results1 = []
664        results2 = []
665        listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
666        listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
667        listener.bind(('127.0.0.1', 0))
668        listener.listen(50)
669
670        def server():
671            (sock, addr) = listener.accept()
672            sock = bufsized(sock)
673            try:
674                c1 = eventlet.spawn(reader, sock, results1)
675                c2 = eventlet.spawn(reader, sock, results2)
676                try:
677                    c1.wait()
678                    c2.wait()
679                finally:
680                    c1.kill()
681                    c2.kill()
682            finally:
683                sock.close()
684
685        server_coro = eventlet.spawn(server)
686        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
687        client.connect(('127.0.0.1', listener.getsockname()[1]))
688        if clibufsize:
689            bufsized(client, size=sendsize)
690        else:
691            bufsized(client)
692        client.sendall(s2b('*') * sendsize)
693        client.close()
694        server_coro.wait()
695        listener.close()
696        self.assert_(len(results1) > 0)
697        self.assert_(len(results2) > 0)
698        debug.hub_prevent_multiple_readers()
699
700    @skipped  # by rdw because it fails but it's not clear how to make it pass
701    @skip_with_pyevent
702    def test_multiple_readers2(self):
703        self.test_multiple_readers(clibufsize=True)
704
705
706class TestGreenIoStarvation(LimitedTestCase):
707    # fixme: this doesn't succeed, because of eventlet's predetermined
708    # ordering.  two processes, one with server, one with client eventlets
709    # might be more reliable?
710
711    TEST_TIMEOUT = 300  # the test here might take a while depending on the OS
712
713    @skipped  # by rdw, because it fails but it's not clear how to make it pass
714    @skip_with_pyevent
715    def test_server_starvation(self, sendloops=15):
716        recvsize = 2 * min_buf_size()
717        sendsize = 10000 * recvsize
718
719        results = [[] for i in xrange(5)]
720
721        listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
722        listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
723        listener.bind(('127.0.0.1', 0))
724        port = listener.getsockname()[1]
725        listener.listen(50)
726
727        base_time = time.time()
728
729        def server(my_results):
730            sock, addr = listener.accept()
731
732            datasize = 0
733
734            t1 = None
735            t2 = None
736            try:
737                while True:
738                    data = sock.recv(recvsize)
739                    if not t1:
740                        t1 = time.time() - base_time
741                    if not data:
742                        t2 = time.time() - base_time
743                        my_results.append(datasize)
744                        my_results.append((t1, t2))
745                        break
746                    datasize += len(data)
747            finally:
748                sock.close()
749
750        def client():
751            pid = os.fork()
752            if pid:
753                return pid
754
755            client = _orig_sock.socket(socket.AF_INET, socket.SOCK_STREAM)
756            client.connect(('127.0.0.1', port))
757
758            bufsized(client, size=sendsize)
759
760            for i in range(sendloops):
761                client.sendall(s2b('*') * sendsize)
762            client.close()
763            os._exit(0)
764
765        clients = []
766        servers = []
767        for r in results:
768            servers.append(eventlet.spawn(server, r))
769        for r in results:
770            clients.append(client())
771
772        for s in servers:
773            s.wait()
774        for c in clients:
775            os.waitpid(c, 0)
776
777        listener.close()
778
779        # now test that all of the server receive intervals overlap, and
780        # that there were no errors.
781        for r in results:
782            assert len(r) == 2, "length is %d not 2!: %s\n%s" % (len(r), r, results)
783            assert r[0] == sendsize * sendloops
784            assert len(r[1]) == 2
785            assert r[1][0] is not None
786            assert r[1][1] is not None
787
788        starttimes = sorted(r[1][0] for r in results)
789        endtimes = sorted(r[1][1] for r in results)
790        runlengths = sorted(r[1][1] - r[1][0] for r in results)
791
792        # assert that the last task started before the first task ended
793        # (our no-starvation condition)
794        assert starttimes[-1] < endtimes[0], "Not overlapping: starts %s ends %s" % (starttimes, endtimes)
795
796        maxstartdiff = starttimes[-1] - starttimes[0]
797
798        assert maxstartdiff * 2 < runlengths[0], "Largest difference in starting times more than twice the shortest running time!"
799        assert runlengths[0] * 2 > runlengths[-1], "Longest runtime more than twice as long as shortest!"
800
801if __name__ == '__main__':
802    main()