PageRenderTime 59ms CodeModel.GetById 2ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/greenio_test.py

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