PageRenderTime 34ms CodeModel.GetById 9ms app.highlight 21ms RepoModel.GetById 2ms app.codeStats 0ms

/tests/greenio_test.py

https://bitbucket.org/which_linden/eventlet-libevent
Python | 312 lines | 288 code | 8 blank | 16 comment | 1 complexity | 19ce0c8d3de519e2a3986fffcafa2210 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
 11
 12def bufsized(sock, size=1):
 13    """ Resize both send and receive buffers on a socket.
 14    Useful for testing trampoline.  Returns the socket.
 15    
 16    >>> import socket
 17    >>> sock = bufsized(socket.socket(socket.AF_INET, socket.SOCK_STREAM))
 18    """
 19    sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, size)
 20    sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, size)
 21    return sock
 22
 23def min_buf_size():
 24    """Return the minimum buffer size that the platform supports."""
 25    test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 26    test_sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1)
 27    return test_sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
 28
 29class TestGreenIo(LimitedTestCase):
 30    def test_connect_timeout(self):
 31        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 32        s.settimeout(0.1)
 33        gs = greenio.GreenSocket(s)
 34        try:
 35            self.assertRaises(socket.timeout, gs.connect, ('192.0.2.1', 80))
 36        except socket.error, e:
 37            # unreachable is also a valid outcome
 38            if e[0] != errno.EHOSTUNREACH:
 39                raise
 40
 41    def test_close_with_makefile(self):
 42        def accept_close_early(listener):
 43            # verify that the makefile and the socket are truly independent
 44            # by closing the socket prior to using the made file
 45            try:
 46                conn, addr = listener.accept()
 47                fd = conn.makefile()
 48                conn.close()
 49                fd.write('hello\n')
 50                fd.close()
 51                # socket._fileobjects are odd: writes don't check
 52                # whether the socket is closed or not, and you get an
 53                # AttributeError during flush if it is closed
 54                fd.write('a')
 55                self.assertRaises(Exception, fd.flush)
 56                self.assertRaises(socket.error, conn.send, 'b')
 57            finally:
 58                listener.close()
 59
 60        def accept_close_late(listener):
 61            # verify that the makefile and the socket are truly independent
 62            # by closing the made file and then sending a character
 63            try:
 64                conn, addr = listener.accept()
 65                fd = conn.makefile()
 66                fd.write('hello')
 67                fd.close()
 68                conn.send('\n')
 69                conn.close()
 70                fd.write('a')
 71                self.assertRaises(Exception, fd.flush)
 72                self.assertRaises(socket.error, conn.send, 'b')
 73            finally:
 74                listener.close()
 75                
 76        def did_it_work(server):
 77            client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 78            client.connect(('127.0.0.1', server.getsockname()[1]))
 79            fd = client.makefile()
 80            client.close()
 81            assert fd.readline() == 'hello\n'    
 82            assert fd.read() == ''
 83            fd.close()
 84            
 85        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 86        server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
 87        server.bind(('0.0.0.0', 0))
 88        server.listen(50)
 89        killer = eventlet.spawn(accept_close_early, server)
 90        did_it_work(server)
 91        killer.wait()
 92        
 93        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 94        server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
 95        server.bind(('0.0.0.0', 0))
 96        server.listen(50)
 97        killer = eventlet.spawn(accept_close_late, server)
 98        did_it_work(server)
 99        killer.wait()
100    
101    def test_del_closes_socket(self):
102        def accept_once(listener):
103            # delete/overwrite the original conn
104            # object, only keeping the file object around
105            # closing the file object should close everything
106            try:
107                conn, addr = listener.accept()
108                conn = conn.makefile()
109                conn.write('hello\n')
110                conn.close()
111                conn.write('a')
112                self.assertRaises(Exception, conn.flush)
113            finally:
114                listener.close()
115        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
116        server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
117        server.bind(('127.0.0.1', 0))
118        server.listen(50)
119        killer = eventlet.spawn(accept_once, server)
120        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
121        client.connect(('127.0.0.1', server.getsockname()[1]))
122        fd = client.makefile()
123        client.close()
124        assert fd.read() == 'hello\n'    
125        assert fd.read() == ''
126        
127        killer.wait()
128     
129    def test_full_duplex(self):
130        large_data = '*' * 10 * min_buf_size()
131        listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
132        listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
133        listener.bind(('127.0.0.1', 0))
134        listener.listen(50)
135        bufsized(listener)
136
137        def send_large(sock):
138            sock.sendall(large_data)
139            
140        def read_large(sock):
141            result = sock.recv(len(large_data))
142            expected = 'hello world'
143            while len(result) < len(large_data):
144                result += sock.recv(len(large_data))
145            self.assertEquals(result, large_data)
146
147        def server():
148            (sock, addr) = listener.accept()
149            sock = bufsized(sock)
150            send_large_coro = eventlet.spawn(send_large, sock)
151            eventlet.sleep(0)
152            result = sock.recv(10)
153            expected = 'hello world'
154            while len(result) < len(expected):
155                result += sock.recv(10)
156            self.assertEquals(result, expected)
157            send_large_coro.wait()
158                
159        server_evt = eventlet.spawn(server)
160        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
161        client.connect(('127.0.0.1', listener.getsockname()[1]))
162        bufsized(client)
163        large_evt = eventlet.spawn(read_large, client)
164        eventlet.sleep(0)
165        client.sendall('hello world')
166        server_evt.wait()
167        large_evt.wait()
168        client.close()
169     
170    def test_sendall(self):
171        # test adapted from Marcus Cavanaugh's email
172        # it may legitimately take a while, but will eventually complete
173        self.timer.cancel()
174        second_bytes = 10
175        def test_sendall_impl(many_bytes):
176            bufsize = max(many_bytes/15, 2)
177            def sender(listener):
178                (sock, addr) = listener.accept()
179                sock = bufsized(sock, size=bufsize)
180                sock.sendall('x'*many_bytes)
181                sock.sendall('y'*second_bytes)
182            
183            listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
184            listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
185            listener.bind(("", 0))
186            listener.listen(50)
187            sender_coro = eventlet.spawn(sender, listener)
188            client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
189            client.connect(('127.0.0.1', listener.getsockname()[1]))
190            bufsized(client, size=bufsize)
191            total = 0
192            while total < many_bytes:
193                data = client.recv(min(many_bytes - total, many_bytes/10))
194                if data == '':
195                    break
196                total += len(data)
197            
198            total2 = 0
199            while total < second_bytes:
200                data = client.recv(second_bytes)
201                if data == '':
202                    break
203                total2 += len(data)
204    
205            sender_coro.wait()
206            client.close()
207        
208        for bytes in (1000, 10000, 100000, 1000000):
209            test_sendall_impl(bytes)
210        
211    def test_wrap_socket(self):
212        try:
213            import ssl
214        except ImportError:
215            pass  # pre-2.6
216        else:
217            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
218            sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
219            sock.bind(('127.0.0.1', 0))
220            sock.listen(50)
221            ssl_sock = ssl.wrap_socket(sock)
222            
223    def test_timeout_and_final_write(self):
224        # This test verifies that a write on a socket that we've
225        # stopped listening for doesn't result in an incorrect switch
226        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
227        server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
228        server.bind(('127.0.0.1', 0))
229        server.listen(50)
230        bound_port = server.getsockname()[1]
231        
232        def sender(evt):
233            s2, addr = server.accept()
234            wrap_wfile = s2.makefile()
235            
236            eventlet.sleep(0.02)
237            wrap_wfile.write('hi')
238            s2.close()
239            evt.send('sent via event')
240
241        from eventlet import event
242        evt = event.Event()
243        eventlet.spawn(sender, evt)
244        eventlet.sleep(0)  # lets the socket enter accept mode, which
245                      # is necessary for connect to succeed on windows
246        try:
247            # try and get some data off of this pipe
248            # but bail before any is sent
249            eventlet.exc_after(0.01, eventlet.TimeoutError)
250            client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
251            client.connect(('127.0.0.1', bound_port))
252            wrap_rfile = client.makefile()
253            _c = wrap_rfile.read(1)
254            self.fail()
255        except eventlet.TimeoutError:
256            pass
257
258        result = evt.wait()
259        self.assertEquals(result, 'sent via event')
260        server.close()
261        client.close()
262        
263
264class TestGreenIoLong(LimitedTestCase):
265    TEST_TIMEOUT=10  # the test here might take a while depending on the OS
266    @skip_with_pyevent
267    def test_multiple_readers(self):
268        recvsize = 2 * min_buf_size()
269        sendsize = 10 * recvsize        
270        # test that we can have multiple coroutines reading
271        # from the same fd.  We make no guarantees about which one gets which
272        # bytes, but they should both get at least some
273        def reader(sock, results):
274            while True:
275                data = sock.recv(recvsize)
276                if data == '':
277                    break
278                results.append(data)
279            
280        results1 = []
281        results2 = []
282        listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
283        listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
284        listener.bind(('127.0.0.1', 0))
285        listener.listen(50)
286        def server():
287            (sock, addr) = listener.accept()
288            sock = bufsized(sock)
289            try:
290                c1 = eventlet.spawn(reader, sock, results1)
291                c2 = eventlet.spawn(reader, sock, results2)
292                c1.wait()
293                c2.wait()
294            finally:
295                c1.kill()
296                c2.kill()
297                sock.close()
298
299        server_coro = eventlet.spawn(server)
300        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
301        client.connect(('127.0.0.1', listener.getsockname()[1]))
302        bufsized(client)
303        client.sendall('*' * sendsize)
304        client.close()
305        server_coro.wait()
306        listener.close()
307        self.assert_(len(results1) > 0)
308        self.assert_(len(results2) > 0)
309        
310                        
311if __name__ == '__main__':
312    main()