PageRenderTime 25ms CodeModel.GetById 1ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/greenio_test.py

https://bitbucket.org/asvetlov/eventlet
Python | 344 lines | 320 code | 8 blank | 16 comment | 1 complexity | 13e6a47e56e3c824fb0b925e0754449f 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.Timeout(0.01)
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    def test_pipe_read(self):
264        # ensure that 'readline' works properly on GreenPipes when data is not
265        # immediately available (fd is nonblocking, was raising EAGAIN)
266        # also ensures that readline() terminates on '\n' and '\r\n'
267        r, w = os.pipe()
268
269        r = os.fdopen(r)
270        w = os.fdopen(w, 'w')
271
272        r = greenio.GreenPipe(r)
273        w = greenio.GreenPipe(w)
274
275        def writer():
276            eventlet.sleep(.1)
277
278            w.write('line\n')
279            w.flush()
280
281            w.write('line\r\n')
282            w.flush()
283
284        gt = eventlet.spawn(writer)
285
286        eventlet.sleep(0)
287
288        line = r.readline()
289        self.assertEquals(line, 'line\n')
290
291        line = r.readline()
292        self.assertEquals(line, 'line\r\n')
293
294        gt.wait()
295
296class TestGreenIoLong(LimitedTestCase):
297    TEST_TIMEOUT=10  # the test here might take a while depending on the OS
298    @skip_with_pyevent
299    def test_multiple_readers(self):
300        recvsize = 2 * min_buf_size()
301        sendsize = 10 * recvsize        
302        # test that we can have multiple coroutines reading
303        # from the same fd.  We make no guarantees about which one gets which
304        # bytes, but they should both get at least some
305        def reader(sock, results):
306            while True:
307                data = sock.recv(recvsize)
308                if data == '':
309                    break
310                results.append(data)
311            
312        results1 = []
313        results2 = []
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        def server():
319            (sock, addr) = listener.accept()
320            sock = bufsized(sock)
321            try:
322                c1 = eventlet.spawn(reader, sock, results1)
323                c2 = eventlet.spawn(reader, sock, results2)
324                c1.wait()
325                c2.wait()
326            finally:
327                c1.kill()
328                c2.kill()
329                sock.close()
330
331        server_coro = eventlet.spawn(server)
332        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
333        client.connect(('127.0.0.1', listener.getsockname()[1]))
334        bufsized(client)
335        client.sendall('*' * sendsize)
336        client.close()
337        server_coro.wait()
338        listener.close()
339        self.assert_(len(results1) > 0)
340        self.assert_(len(results2) > 0)
341        
342                        
343if __name__ == '__main__':
344    main()