blob: 14528d8800857fe85b51420fd81db88d86d4deae [file] [log] [blame]
R. David Murray59beec32009-03-30 19:04:00 +00001# test asynchat
Guido van Rossum66172522001-04-06 16:32:22 +00002
Guido van Rossumdca060c2001-04-06 16:43:49 +00003import asyncore, asynchat, socket, threading, time
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +00004import unittest
Facundo Batista49504422007-07-31 03:03:34 +00005import sys
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +00006from test import test_support
Guido van Rossum66172522001-04-06 16:32:22 +00007
R. David Murray59beec32009-03-30 19:04:00 +00008# Skip tests if thread module does not exist.
9test_support.import_module('thread')
10
Trent Nelsone41b0062008-04-08 23:47:30 +000011HOST = test_support.HOST
Facundo Batistaec624232007-07-29 14:23:08 +000012SERVER_QUIT = 'QUIT\n'
Guido van Rossum66172522001-04-06 16:32:22 +000013
14class echo_server(threading.Thread):
Facundo Batistaec624232007-07-29 14:23:08 +000015 # parameter to determine the number of bytes passed back to the
16 # client each send
17 chunk_size = 1
Guido van Rossum66172522001-04-06 16:32:22 +000018
Neal Norwitz6e070812008-01-27 01:44:05 +000019 def __init__(self, event):
20 threading.Thread.__init__(self)
21 self.event = event
Trent Nelsone41b0062008-04-08 23:47:30 +000022 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
23 self.port = test_support.bind_port(self.sock)
Neal Norwitz6e070812008-01-27 01:44:05 +000024
Guido van Rossum66172522001-04-06 16:32:22 +000025 def run(self):
Trent Nelsone41b0062008-04-08 23:47:30 +000026 self.sock.listen(1)
Neal Norwitz6e070812008-01-27 01:44:05 +000027 self.event.set()
Trent Nelsone41b0062008-04-08 23:47:30 +000028 conn, client = self.sock.accept()
Facundo Batistaec624232007-07-29 14:23:08 +000029 self.buffer = ""
30 # collect data until quit message is seen
31 while SERVER_QUIT not in self.buffer:
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +000032 data = conn.recv(1)
Guido van Rossum66172522001-04-06 16:32:22 +000033 if not data:
34 break
Facundo Batistaec624232007-07-29 14:23:08 +000035 self.buffer = self.buffer + data
36
37 # remove the SERVER_QUIT message
38 self.buffer = self.buffer.replace(SERVER_QUIT, '')
39
40 # re-send entire set of collected data
41 try:
42 # this may fail on some tests, such as test_close_when_done, since
43 # the client closes the channel when it's done sending
44 while self.buffer:
45 n = conn.send(self.buffer[:self.chunk_size])
46 time.sleep(0.001)
47 self.buffer = self.buffer[n:]
48 except:
49 pass
50
Guido van Rossum66172522001-04-06 16:32:22 +000051 conn.close()
Trent Nelsone41b0062008-04-08 23:47:30 +000052 self.sock.close()
Guido van Rossum66172522001-04-06 16:32:22 +000053
54class echo_client(asynchat.async_chat):
55
Trent Nelsone41b0062008-04-08 23:47:30 +000056 def __init__(self, terminator, server_port):
Guido van Rossum66172522001-04-06 16:32:22 +000057 asynchat.async_chat.__init__(self)
Facundo Batistaec624232007-07-29 14:23:08 +000058 self.contents = []
Guido van Rossum66172522001-04-06 16:32:22 +000059 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
Trent Nelsone41b0062008-04-08 23:47:30 +000060 self.connect((HOST, server_port))
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +000061 self.set_terminator(terminator)
Facundo Batistaec624232007-07-29 14:23:08 +000062 self.buffer = ''
Guido van Rossum66172522001-04-06 16:32:22 +000063
64 def handle_connect(self):
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +000065 pass
Facundo Batista49504422007-07-31 03:03:34 +000066
67 if sys.platform == 'darwin':
68 # select.poll returns a select.POLLHUP at the end of the tests
69 # on darwin, so just ignore it
70 def handle_expt(self):
71 pass
Guido van Rossum66172522001-04-06 16:32:22 +000072
73 def collect_incoming_data(self, data):
Facundo Batistaec624232007-07-29 14:23:08 +000074 self.buffer += data
Guido van Rossum66172522001-04-06 16:32:22 +000075
76 def found_terminator(self):
Facundo Batistaec624232007-07-29 14:23:08 +000077 self.contents.append(self.buffer)
Guido van Rossum66172522001-04-06 16:32:22 +000078 self.buffer = ""
Guido van Rossum66172522001-04-06 16:32:22 +000079
Guido van Rossum66172522001-04-06 16:32:22 +000080
Neal Norwitz6e070812008-01-27 01:44:05 +000081def start_echo_server():
82 event = threading.Event()
83 s = echo_server(event)
84 s.start()
85 event.wait()
86 event.clear()
87 time.sleep(0.01) # Give server time to start accepting.
88 return s, event
89
90
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +000091class TestAsynchat(unittest.TestCase):
Facundo Batistaec624232007-07-29 14:23:08 +000092 usepoll = False
93
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +000094 def setUp (self):
95 pass
96
97 def tearDown (self):
98 pass
99
Facundo Batistaec624232007-07-29 14:23:08 +0000100 def line_terminator_check(self, term, server_chunk):
Neal Norwitz6e070812008-01-27 01:44:05 +0000101 event = threading.Event()
102 s = echo_server(event)
Facundo Batistaec624232007-07-29 14:23:08 +0000103 s.chunk_size = server_chunk
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000104 s.start()
Neal Norwitz6e070812008-01-27 01:44:05 +0000105 event.wait()
106 event.clear()
107 time.sleep(0.01) # Give server time to start accepting.
Trent Nelsone41b0062008-04-08 23:47:30 +0000108 c = echo_client(term, s.port)
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000109 c.push("hello ")
Facundo Batistaec624232007-07-29 14:23:08 +0000110 c.push("world%s" % term)
111 c.push("I'm not dead yet!%s" % term)
112 c.push(SERVER_QUIT)
Facundo Batista49504422007-07-31 03:03:34 +0000113 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
Michael W. Hudson73909422005-06-20 13:45:34 +0000114 s.join()
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000115
Facundo Batistaec624232007-07-29 14:23:08 +0000116 self.assertEqual(c.contents, ["hello world", "I'm not dead yet!"])
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000117
Facundo Batistaec624232007-07-29 14:23:08 +0000118 # the line terminator tests below check receiving variously-sized
119 # chunks back from the server in order to exercise all branches of
120 # async_chat.handle_read
121
122 def test_line_terminator1(self):
123 # test one-character terminator
124 for l in (1,2,3):
125 self.line_terminator_check('\n', l)
126
127 def test_line_terminator2(self):
128 # test two-character terminator
129 for l in (1,2,3):
130 self.line_terminator_check('\r\n', l)
131
132 def test_line_terminator3(self):
133 # test three-character terminator
134 for l in (1,2,3):
135 self.line_terminator_check('qqq', l)
136
137 def numeric_terminator_check(self, termlen):
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000138 # Try reading a fixed number of bytes
Neal Norwitz6e070812008-01-27 01:44:05 +0000139 s, event = start_echo_server()
Trent Nelsone41b0062008-04-08 23:47:30 +0000140 c = echo_client(termlen, s.port)
Facundo Batistaec624232007-07-29 14:23:08 +0000141 data = "hello world, I'm not dead yet!\n"
142 c.push(data)
143 c.push(SERVER_QUIT)
Facundo Batista49504422007-07-31 03:03:34 +0000144 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
Michael W. Hudson73909422005-06-20 13:45:34 +0000145 s.join()
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000146
Facundo Batistaec624232007-07-29 14:23:08 +0000147 self.assertEqual(c.contents, [data[:termlen]])
148
149 def test_numeric_terminator1(self):
150 # check that ints & longs both work (since type is
151 # explicitly checked in async_chat.handle_read)
152 self.numeric_terminator_check(1)
153 self.numeric_terminator_check(1L)
154
155 def test_numeric_terminator2(self):
156 self.numeric_terminator_check(6L)
157
158 def test_none_terminator(self):
159 # Try reading a fixed number of bytes
Neal Norwitz6e070812008-01-27 01:44:05 +0000160 s, event = start_echo_server()
Trent Nelsone41b0062008-04-08 23:47:30 +0000161 c = echo_client(None, s.port)
Facundo Batistaec624232007-07-29 14:23:08 +0000162 data = "hello world, I'm not dead yet!\n"
163 c.push(data)
164 c.push(SERVER_QUIT)
Facundo Batista49504422007-07-31 03:03:34 +0000165 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
Facundo Batistaec624232007-07-29 14:23:08 +0000166 s.join()
167
168 self.assertEqual(c.contents, [])
169 self.assertEqual(c.buffer, data)
170
171 def test_simple_producer(self):
Neal Norwitz6e070812008-01-27 01:44:05 +0000172 s, event = start_echo_server()
Trent Nelsone41b0062008-04-08 23:47:30 +0000173 c = echo_client('\n', s.port)
Facundo Batistaec624232007-07-29 14:23:08 +0000174 data = "hello world\nI'm not dead yet!\n"
175 p = asynchat.simple_producer(data+SERVER_QUIT, buffer_size=8)
176 c.push_with_producer(p)
Facundo Batista49504422007-07-31 03:03:34 +0000177 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
Facundo Batistaec624232007-07-29 14:23:08 +0000178 s.join()
179
180 self.assertEqual(c.contents, ["hello world", "I'm not dead yet!"])
181
182 def test_string_producer(self):
Neal Norwitz6e070812008-01-27 01:44:05 +0000183 s, event = start_echo_server()
Trent Nelsone41b0062008-04-08 23:47:30 +0000184 c = echo_client('\n', s.port)
Facundo Batistaec624232007-07-29 14:23:08 +0000185 data = "hello world\nI'm not dead yet!\n"
186 c.push_with_producer(data+SERVER_QUIT)
Facundo Batista49504422007-07-31 03:03:34 +0000187 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
Facundo Batistaec624232007-07-29 14:23:08 +0000188 s.join()
189
190 self.assertEqual(c.contents, ["hello world", "I'm not dead yet!"])
191
192 def test_empty_line(self):
193 # checks that empty lines are handled correctly
Neal Norwitz6e070812008-01-27 01:44:05 +0000194 s, event = start_echo_server()
Trent Nelsone41b0062008-04-08 23:47:30 +0000195 c = echo_client('\n', s.port)
Facundo Batistaec624232007-07-29 14:23:08 +0000196 c.push("hello world\n\nI'm not dead yet!\n")
197 c.push(SERVER_QUIT)
Facundo Batista49504422007-07-31 03:03:34 +0000198 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
Facundo Batistaec624232007-07-29 14:23:08 +0000199 s.join()
200
201 self.assertEqual(c.contents, ["hello world", "", "I'm not dead yet!"])
202
203 def test_close_when_done(self):
Neal Norwitz6e070812008-01-27 01:44:05 +0000204 s, event = start_echo_server()
Trent Nelsone41b0062008-04-08 23:47:30 +0000205 c = echo_client('\n', s.port)
Facundo Batistaec624232007-07-29 14:23:08 +0000206 c.push("hello world\nI'm not dead yet!\n")
207 c.push(SERVER_QUIT)
208 c.close_when_done()
Facundo Batista49504422007-07-31 03:03:34 +0000209 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
Facundo Batistaec624232007-07-29 14:23:08 +0000210 s.join()
211
212 self.assertEqual(c.contents, [])
213 # the server might have been able to send a byte or two back, but this
214 # at least checks that it received something and didn't just fail
215 # (which could still result in the client not having received anything)
216 self.assertTrue(len(s.buffer) > 0)
217
218
219class TestAsynchat_WithPoll(TestAsynchat):
220 usepoll = True
221
222class TestHelperFunctions(unittest.TestCase):
223 def test_find_prefix_at_end(self):
224 self.assertEqual(asynchat.find_prefix_at_end("qwerty\r", "\r\n"), 1)
225 self.assertEqual(asynchat.find_prefix_at_end("qwertydkjf", "\r\n"), 0)
226
227class TestFifo(unittest.TestCase):
228 def test_basic(self):
229 f = asynchat.fifo()
230 f.push(7)
231 f.push('a')
232 self.assertEqual(len(f), 2)
233 self.assertEqual(f.first(), 7)
234 self.assertEqual(f.pop(), (1, 7))
235 self.assertEqual(len(f), 1)
236 self.assertEqual(f.first(), 'a')
237 self.assertEqual(f.is_empty(), False)
238 self.assertEqual(f.pop(), (1, 'a'))
239 self.assertEqual(len(f), 0)
240 self.assertEqual(f.is_empty(), True)
241 self.assertEqual(f.pop(), (0, None))
242
243 def test_given_list(self):
244 f = asynchat.fifo(['x', 17, 3])
245 self.assertEqual(len(f), 3)
246 self.assertEqual(f.pop(), (1, 'x'))
247 self.assertEqual(f.pop(), (1, 17))
248 self.assertEqual(f.pop(), (1, 3))
249 self.assertEqual(f.pop(), (0, None))
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000250
251
252def test_main(verbose=None):
Facundo Batistaec624232007-07-29 14:23:08 +0000253 test_support.run_unittest(TestAsynchat, TestAsynchat_WithPoll,
254 TestHelperFunctions, TestFifo)
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000255
256if __name__ == "__main__":
257 test_main(verbose=True)