PageRenderTime 44ms CodeModel.GetById 2ms app.highlight 36ms RepoModel.GetById 2ms app.codeStats 0ms

/tests/greenio_test.py

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