PageRenderTime 57ms CodeModel.GetById 16ms app.highlight 34ms RepoModel.GetById 2ms app.codeStats 0ms

/Lib/test/test_asyncore.py

http://unladen-swallow.googlecode.com/
Python | 414 lines | 397 code | 15 blank | 2 comment | 3 complexity | 0867178cc82ea66eb17745a4479d5c59 MD5 | raw file
  1import asyncore
  2import unittest
  3import select
  4import os
  5import socket
  6import threading
  7import sys
  8import time
  9try:
 10    import _llvm
 11except ImportError:
 12    _llvm = None
 13
 14from test import test_support
 15from test.test_support import TESTFN, run_unittest, unlink
 16from StringIO import StringIO
 17
 18HOST = test_support.HOST
 19
 20class dummysocket:
 21    def __init__(self):
 22        self.closed = False
 23
 24    def close(self):
 25        self.closed = True
 26
 27    def fileno(self):
 28        return 42
 29
 30class dummychannel:
 31    def __init__(self):
 32        self.socket = dummysocket()
 33
 34    def close(self):
 35        self.socket.close()
 36
 37class exitingdummy:
 38    def __init__(self):
 39        pass
 40
 41    def handle_read_event(self):
 42        raise asyncore.ExitNow()
 43
 44    handle_write_event = handle_read_event
 45    handle_close = handle_read_event
 46    handle_expt_event = handle_read_event
 47
 48class crashingdummy:
 49    def __init__(self):
 50        self.error_handled = False
 51
 52    def handle_read_event(self):
 53        raise Exception()
 54
 55    handle_write_event = handle_read_event
 56    handle_close = handle_read_event
 57    handle_expt_event = handle_read_event
 58
 59    def handle_error(self):
 60        self.error_handled = True
 61
 62# used when testing senders; just collects what it gets until newline is sent
 63def capture_server(evt, buf, serv):
 64    try:
 65        serv.listen(5)
 66        conn, addr = serv.accept()
 67    except socket.timeout:
 68        pass
 69    else:
 70        n = 200
 71        while n > 0:
 72            r, w, e = select.select([conn], [], [])
 73            if r:
 74                data = conn.recv(10)
 75                # keep everything except for the newline terminator
 76                buf.write(data.replace('\n', ''))
 77                if '\n' in data:
 78                    break
 79            n -= 1
 80            time.sleep(0.01)
 81
 82        conn.close()
 83    finally:
 84        serv.close()
 85        evt.set()
 86
 87
 88class HelperFunctionTests(unittest.TestCase):
 89    def test_readwriteexc(self):
 90        # Check exception handling behavior of read, write and _exception
 91
 92        # check that ExitNow exceptions in the object handler method
 93        # bubbles all the way up through asyncore read/write/_exception calls
 94        tr1 = exitingdummy()
 95        self.assertRaises(asyncore.ExitNow, asyncore.read, tr1)
 96        self.assertRaises(asyncore.ExitNow, asyncore.write, tr1)
 97        self.assertRaises(asyncore.ExitNow, asyncore._exception, tr1)
 98
 99        # check that an exception other than ExitNow in the object handler
100        # method causes the handle_error method to get called
101        tr2 = crashingdummy()
102        asyncore.read(tr2)
103        self.assertEqual(tr2.error_handled, True)
104
105        tr2 = crashingdummy()
106        asyncore.write(tr2)
107        self.assertEqual(tr2.error_handled, True)
108
109        tr2 = crashingdummy()
110        asyncore._exception(tr2)
111        self.assertEqual(tr2.error_handled, True)
112
113    # asyncore.readwrite uses constants in the select module that
114    # are not present in Windows systems (see this thread:
115    # http://mail.python.org/pipermail/python-list/2001-October/109973.html)
116    # These constants should be present as long as poll is available
117
118    if hasattr(select, 'poll'):
119        def test_readwrite(self):
120            # Check that correct methods are called by readwrite()
121
122            attributes = ('read', 'expt', 'write', 'closed', 'error_handled')
123
124            expected = (
125                (select.POLLIN, 'read'),
126                (select.POLLPRI, 'expt'),
127                (select.POLLOUT, 'write'),
128                (select.POLLERR, 'closed'),
129                (select.POLLHUP, 'closed'),
130                (select.POLLNVAL, 'closed'),
131                )
132
133            class testobj:
134                def __init__(self):
135                    self.read = False
136                    self.write = False
137                    self.closed = False
138                    self.expt = False
139                    self.error_handled = False
140
141                def handle_read_event(self):
142                    self.read = True
143
144                def handle_write_event(self):
145                    self.write = True
146
147                def handle_close(self):
148                    self.closed = True
149
150                def handle_expt_event(self):
151                    self.expt = True
152
153                def handle_error(self):
154                    self.error_handled = True
155
156            for flag, expectedattr in expected:
157                tobj = testobj()
158                self.assertEqual(getattr(tobj, expectedattr), False)
159                asyncore.readwrite(tobj, flag)
160
161                # Only the attribute modified by the routine we expect to be
162                # called should be True.
163                for attr in attributes:
164                    self.assertEqual(getattr(tobj, attr), attr==expectedattr)
165
166                # check that ExitNow exceptions in the object handler method
167                # bubbles all the way up through asyncore readwrite call
168                tr1 = exitingdummy()
169                self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag)
170
171                # check that an exception other than ExitNow in the object handler
172                # method causes the handle_error method to get called
173                tr2 = crashingdummy()
174                self.assertEqual(tr2.error_handled, False)
175                asyncore.readwrite(tr2, flag)
176                self.assertEqual(tr2.error_handled, True)
177
178    def test_closeall(self):
179        self.closeall_check(False)
180
181    def test_closeall_default(self):
182        self.closeall_check(True)
183
184    def closeall_check(self, usedefault):
185        # Check that close_all() closes everything in a given map
186
187        l = []
188        testmap = {}
189        for i in range(10):
190            c = dummychannel()
191            l.append(c)
192            self.assertEqual(c.socket.closed, False)
193            testmap[i] = c
194
195        if usedefault:
196            socketmap = asyncore.socket_map
197            try:
198                asyncore.socket_map = testmap
199                asyncore.close_all()
200            finally:
201                testmap, asyncore.socket_map = asyncore.socket_map, socketmap
202        else:
203            asyncore.close_all(testmap)
204
205        self.assertEqual(len(testmap), 0)
206
207        for c in l:
208            self.assertEqual(c.socket.closed, True)
209
210    def test_compact_traceback(self):
211        try:
212            raise Exception("I don't like spam!")
213        except:
214            real_t, real_v, real_tb = sys.exc_info()
215            r = asyncore.compact_traceback()
216        else:
217            self.fail("Expected exception")
218
219        (f, function, line), t, v, info = r
220        self.assertEqual(os.path.split(f)[-1], 'test_asyncore.py')
221        self.assertEqual(function, 'test_compact_traceback')
222        self.assertEqual(t, real_t)
223        self.assertEqual(v, real_v)
224        self.assertEqual(info, '[%s|%s|%s]' % (f, function, line))
225
226
227class DispatcherTests(unittest.TestCase):
228    def setUp(self):
229        pass
230
231    def tearDown(self):
232        asyncore.close_all()
233
234    def test_basic(self):
235        d = asyncore.dispatcher()
236        self.assertEqual(d.readable(), True)
237        self.assertEqual(d.writable(), True)
238
239    def test_repr(self):
240        d = asyncore.dispatcher()
241        self.assertEqual(repr(d), '<asyncore.dispatcher at %#x>' % id(d))
242
243    def test_log(self):
244        d = asyncore.dispatcher()
245
246        # capture output of dispatcher.log() (to stderr)
247        fp = StringIO()
248        stderr = sys.stderr
249        l1 = "Lovely spam! Wonderful spam!"
250        l2 = "I don't like spam!"
251        try:
252            sys.stderr = fp
253            d.log(l1)
254            d.log(l2)
255        finally:
256            sys.stderr = stderr
257
258        lines = fp.getvalue().splitlines()
259        self.assertEquals(lines, ['log: %s' % l1, 'log: %s' % l2])
260
261    def test_log_info(self):
262        d = asyncore.dispatcher()
263
264        # capture output of dispatcher.log_info() (to stdout via print)
265        fp = StringIO()
266        stdout = sys.stdout
267        l1 = "Have you got anything without spam?"
268        l2 = "Why can't she have egg bacon spam and sausage?"
269        l3 = "THAT'S got spam in it!"
270        try:
271            sys.stdout = fp
272            d.log_info(l1, 'EGGS')
273            d.log_info(l2)
274            d.log_info(l3, 'SPAM')
275        finally:
276            sys.stdout = stdout
277
278        lines = fp.getvalue().splitlines()
279        expected = ['EGGS: %s' % l1, 'info: %s' % l2, 'SPAM: %s' % l3]
280
281        self.assertEquals(lines, expected)
282
283    def test_unhandled(self):
284        d = asyncore.dispatcher()
285        d.ignore_log_types = ()
286
287        # capture output of dispatcher.log_info() (to stdout via print)
288        fp = StringIO()
289        stdout = sys.stdout
290        try:
291            sys.stdout = fp
292            d.handle_expt()
293            d.handle_read()
294            d.handle_write()
295            d.handle_connect()
296            d.handle_accept()
297        finally:
298            sys.stdout = stdout
299
300        lines = fp.getvalue().splitlines()
301        expected = ['warning: unhandled incoming priority event',
302                    'warning: unhandled read event',
303                    'warning: unhandled write event',
304                    'warning: unhandled connect event',
305                    'warning: unhandled accept event']
306        self.assertEquals(lines, expected)
307
308
309
310class dispatcherwithsend_noread(asyncore.dispatcher_with_send):
311    def readable(self):
312        return False
313
314    def handle_connect(self):
315        pass
316
317class DispatcherWithSendTests(unittest.TestCase):
318    usepoll = False
319
320    def setUp(self):
321        # This test is sensitive to random pauses, so we disable the JIT if it
322        # is present.
323        if _llvm:
324            self.orig_jit_control = _llvm.get_jit_control()
325            _llvm.set_jit_control("never")
326
327    def tearDown(self):
328        if _llvm:
329            _llvm.set_jit_control(self.orig_jit_control)
330        asyncore.close_all()
331
332    def test_send(self):
333        self.evt = threading.Event()
334        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
335        self.sock.settimeout(3)
336        self.port = test_support.bind_port(self.sock)
337
338        cap = StringIO()
339        args = (self.evt, cap, self.sock)
340        threading.Thread(target=capture_server, args=args).start()
341
342        # wait a little longer for the server to initialize (it sometimes
343        # refuses connections on slow machines without this wait)
344        time.sleep(0.2)
345
346        data = "Suppose there isn't a 16-ton weight?"
347        d = dispatcherwithsend_noread()
348        d.create_socket(socket.AF_INET, socket.SOCK_STREAM)
349        d.connect((HOST, self.port))
350
351        # give time for socket to connect
352        time.sleep(0.1)
353
354        d.send(data)
355        d.send(data)
356        d.send('\n')
357
358        n = 1000
359        while d.out_buffer and n > 0:
360            asyncore.poll()
361            n -= 1
362
363        self.evt.wait()
364
365        self.assertEqual(cap.getvalue(), data*2)
366
367
368class DispatcherWithSendTests_UsePoll(DispatcherWithSendTests):
369    usepoll = True
370
371if hasattr(asyncore, 'file_wrapper'):
372    class FileWrapperTest(unittest.TestCase):
373        def setUp(self):
374            self.d = "It's not dead, it's sleeping!"
375            file(TESTFN, 'w').write(self.d)
376
377        def tearDown(self):
378            unlink(TESTFN)
379
380        def test_recv(self):
381            fd = os.open(TESTFN, os.O_RDONLY)
382            w = asyncore.file_wrapper(fd)
383            os.close(fd)
384
385            self.assertNotEqual(w.fd, fd)
386            self.assertNotEqual(w.fileno(), fd)
387            self.assertEqual(w.recv(13), "It's not dead")
388            self.assertEqual(w.read(6), ", it's")
389            w.close()
390            self.assertRaises(OSError, w.read, 1)
391
392        def test_send(self):
393            d1 = "Come again?"
394            d2 = "I want to buy some cheese."
395            fd = os.open(TESTFN, os.O_WRONLY | os.O_APPEND)
396            w = asyncore.file_wrapper(fd)
397            os.close(fd)
398
399            w.write(d1)
400            w.send(d2)
401            w.close()
402            self.assertEqual(file(TESTFN).read(), self.d + d1 + d2)
403
404
405def test_main():
406    tests = [HelperFunctionTests, DispatcherTests, DispatcherWithSendTests,
407             DispatcherWithSendTests_UsePoll]
408    if hasattr(asyncore, 'file_wrapper'):
409        tests.append(FileWrapperTest)
410
411    run_unittest(*tests)
412
413if __name__ == "__main__":
414    test_main()