blob: 082fde9823965681712c94aae41b96d83cc3b943 [file] [log] [blame]
Guido van Rossum66172522001-04-06 16:32:22 +00001# test asynchat -- requires threading
2
Georg Brandl2067bfd2008-05-25 13:05:15 +00003import _thread as thread # If this fails, we can't test this module
Guido van Rossumdca060c2001-04-06 16:43:49 +00004import asyncore, asynchat, socket, threading, time
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +00005import unittest
Guido van Rossum806c2462007-08-06 23:33:07 +00006import sys
Benjamin Petersonee8712c2008-05-20 21:35:26 +00007from test import support
Guido van Rossum66172522001-04-06 16:32:22 +00008
Benjamin Petersonee8712c2008-05-20 21:35:26 +00009HOST = support.HOST
Guido van Rossum806c2462007-08-06 23:33:07 +000010SERVER_QUIT = b'QUIT\n'
Guido van Rossum66172522001-04-06 16:32:22 +000011
12class echo_server(threading.Thread):
Guido van Rossum806c2462007-08-06 23:33:07 +000013 # parameter to determine the number of bytes passed back to the
14 # client each send
15 chunk_size = 1
Guido van Rossum66172522001-04-06 16:32:22 +000016
Christian Heimesaf98da12008-01-27 15:18:18 +000017 def __init__(self, event):
18 threading.Thread.__init__(self)
19 self.event = event
Christian Heimes5e696852008-04-09 08:37:03 +000020 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000021 self.port = support.bind_port(self.sock)
Christian Heimesaf98da12008-01-27 15:18:18 +000022
Guido van Rossum66172522001-04-06 16:32:22 +000023 def run(self):
Christian Heimes5e696852008-04-09 08:37:03 +000024 self.sock.listen(1)
Christian Heimesaf98da12008-01-27 15:18:18 +000025 self.event.set()
Christian Heimes5e696852008-04-09 08:37:03 +000026 conn, client = self.sock.accept()
Guido van Rossum806c2462007-08-06 23:33:07 +000027 self.buffer = b""
28 # collect data until quit message is seen
29 while SERVER_QUIT not in self.buffer:
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +000030 data = conn.recv(1)
Guido van Rossum66172522001-04-06 16:32:22 +000031 if not data:
32 break
Guido van Rossum806c2462007-08-06 23:33:07 +000033 self.buffer = self.buffer + data
34
35 # remove the SERVER_QUIT message
36 self.buffer = self.buffer.replace(SERVER_QUIT, b'')
37
38 # re-send entire set of collected data
39 try:
40 # this may fail on some tests, such as test_close_when_done, since
41 # the client closes the channel when it's done sending
42 while self.buffer:
43 n = conn.send(self.buffer[:self.chunk_size])
44 time.sleep(0.001)
45 self.buffer = self.buffer[n:]
46 except:
47 pass
48
Guido van Rossum66172522001-04-06 16:32:22 +000049 conn.close()
Christian Heimes5e696852008-04-09 08:37:03 +000050 self.sock.close()
Guido van Rossum66172522001-04-06 16:32:22 +000051
52class echo_client(asynchat.async_chat):
53
Christian Heimes5e696852008-04-09 08:37:03 +000054 def __init__(self, terminator, server_port):
Guido van Rossum66172522001-04-06 16:32:22 +000055 asynchat.async_chat.__init__(self)
Guido van Rossum806c2462007-08-06 23:33:07 +000056 self.contents = []
Guido van Rossum66172522001-04-06 16:32:22 +000057 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
Christian Heimes5e696852008-04-09 08:37:03 +000058 self.connect((HOST, server_port))
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +000059 self.set_terminator(terminator)
Guido van Rossum076da092007-07-12 07:58:54 +000060 self.buffer = b""
Guido van Rossum66172522001-04-06 16:32:22 +000061
62 def handle_connect(self):
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +000063 pass
Guido van Rossum806c2462007-08-06 23:33:07 +000064
65 if sys.platform == 'darwin':
66 # select.poll returns a select.POLLHUP at the end of the tests
67 # on darwin, so just ignore it
68 def handle_expt(self):
69 pass
Guido van Rossum66172522001-04-06 16:32:22 +000070
71 def collect_incoming_data(self, data):
Guido van Rossum806c2462007-08-06 23:33:07 +000072 self.buffer += data
Guido van Rossum66172522001-04-06 16:32:22 +000073
74 def found_terminator(self):
Guido van Rossum806c2462007-08-06 23:33:07 +000075 self.contents.append(self.buffer)
Guido van Rossum076da092007-07-12 07:58:54 +000076 self.buffer = b""
Guido van Rossum66172522001-04-06 16:32:22 +000077
Guido van Rossum66172522001-04-06 16:32:22 +000078
Christian Heimesaf98da12008-01-27 15:18:18 +000079def start_echo_server():
80 event = threading.Event()
81 s = echo_server(event)
82 s.start()
83 event.wait()
84 event.clear()
85 time.sleep(0.01) # Give server time to start accepting.
86 return s, event
87
88
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +000089class TestAsynchat(unittest.TestCase):
Guido van Rossum806c2462007-08-06 23:33:07 +000090 usepoll = False
91
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +000092 def setUp (self):
93 pass
94
95 def tearDown (self):
96 pass
97
Guido van Rossum806c2462007-08-06 23:33:07 +000098 def line_terminator_check(self, term, server_chunk):
Christian Heimesaf98da12008-01-27 15:18:18 +000099 event = threading.Event()
100 s = echo_server(event)
Guido van Rossum806c2462007-08-06 23:33:07 +0000101 s.chunk_size = server_chunk
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000102 s.start()
Christian Heimesaf98da12008-01-27 15:18:18 +0000103 event.wait()
104 event.clear()
105 time.sleep(0.01) # Give server time to start accepting.
Christian Heimes5e696852008-04-09 08:37:03 +0000106 c = echo_client(term, s.port)
Guido van Rossum806c2462007-08-06 23:33:07 +0000107 c.push(b"hello ")
Jeremy Hyltonb4df71f2007-08-29 14:56:40 +0000108 c.push(bytes("world%s" % term, "ascii"))
109 c.push(bytes("I'm not dead yet!%s" % term, "ascii"))
Guido van Rossum806c2462007-08-06 23:33:07 +0000110 c.push(SERVER_QUIT)
111 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
Michael W. Hudson73909422005-06-20 13:45:34 +0000112 s.join()
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000113
Guido van Rossum806c2462007-08-06 23:33:07 +0000114 self.assertEqual(c.contents, [b"hello world", b"I'm not dead yet!"])
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000115
Guido van Rossum806c2462007-08-06 23:33:07 +0000116 # the line terminator tests below check receiving variously-sized
117 # chunks back from the server in order to exercise all branches of
118 # async_chat.handle_read
119
120 def test_line_terminator1(self):
121 # test one-character terminator
122 for l in (1,2,3):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000123 self.line_terminator_check('\n', l)
Guido van Rossum806c2462007-08-06 23:33:07 +0000124
125 def test_line_terminator2(self):
126 # test two-character terminator
127 for l in (1,2,3):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000128 self.line_terminator_check('\r\n', l)
Guido van Rossum806c2462007-08-06 23:33:07 +0000129
130 def test_line_terminator3(self):
131 # test three-character terminator
132 for l in (1,2,3):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000133 self.line_terminator_check('qqq', l)
Guido van Rossum806c2462007-08-06 23:33:07 +0000134
135 def numeric_terminator_check(self, termlen):
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000136 # Try reading a fixed number of bytes
Christian Heimesaf98da12008-01-27 15:18:18 +0000137 s, event = start_echo_server()
Christian Heimes5e696852008-04-09 08:37:03 +0000138 c = echo_client(termlen, s.port)
Guido van Rossum806c2462007-08-06 23:33:07 +0000139 data = b"hello world, I'm not dead yet!\n"
140 c.push(data)
141 c.push(SERVER_QUIT)
142 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
Michael W. Hudson73909422005-06-20 13:45:34 +0000143 s.join()
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000144
Guido van Rossum806c2462007-08-06 23:33:07 +0000145 self.assertEqual(c.contents, [data[:termlen]])
146
147 def test_numeric_terminator1(self):
148 # check that ints & longs both work (since type is
149 # explicitly checked in async_chat.handle_read)
150 self.numeric_terminator_check(1)
151
152 def test_numeric_terminator2(self):
153 self.numeric_terminator_check(6)
154
155 def test_none_terminator(self):
156 # Try reading a fixed number of bytes
Christian Heimesaf98da12008-01-27 15:18:18 +0000157 s, event = start_echo_server()
Christian Heimes5e696852008-04-09 08:37:03 +0000158 c = echo_client(None, s.port)
Guido van Rossum806c2462007-08-06 23:33:07 +0000159 data = b"hello world, I'm not dead yet!\n"
160 c.push(data)
161 c.push(SERVER_QUIT)
162 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
163 s.join()
164
165 self.assertEqual(c.contents, [])
166 self.assertEqual(c.buffer, data)
167
168 def test_simple_producer(self):
Christian Heimesaf98da12008-01-27 15:18:18 +0000169 s, event = start_echo_server()
Christian Heimes5e696852008-04-09 08:37:03 +0000170 c = echo_client(b'\n', s.port)
Guido van Rossum806c2462007-08-06 23:33:07 +0000171 data = b"hello world\nI'm not dead yet!\n"
172 p = asynchat.simple_producer(data+SERVER_QUIT, buffer_size=8)
173 c.push_with_producer(p)
174 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
175 s.join()
176
177 self.assertEqual(c.contents, [b"hello world", b"I'm not dead yet!"])
178
179 def test_string_producer(self):
Christian Heimesaf98da12008-01-27 15:18:18 +0000180 s, event = start_echo_server()
Christian Heimes5e696852008-04-09 08:37:03 +0000181 c = echo_client(b'\n', s.port)
Guido van Rossum806c2462007-08-06 23:33:07 +0000182 data = b"hello world\nI'm not dead yet!\n"
183 c.push_with_producer(data+SERVER_QUIT)
184 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
185 s.join()
186
187 self.assertEqual(c.contents, [b"hello world", b"I'm not dead yet!"])
188
189 def test_empty_line(self):
190 # checks that empty lines are handled correctly
Christian Heimesaf98da12008-01-27 15:18:18 +0000191 s, event = start_echo_server()
Christian Heimes5e696852008-04-09 08:37:03 +0000192 c = echo_client(b'\n', s.port)
193 c.push("hello world\n\nI'm not dead yet!\n")
Guido van Rossum806c2462007-08-06 23:33:07 +0000194 c.push(SERVER_QUIT)
195 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
196 s.join()
197
198 self.assertEqual(c.contents,
199 [b"hello world", b"", b"I'm not dead yet!"])
200
201 def test_close_when_done(self):
Christian Heimesaf98da12008-01-27 15:18:18 +0000202 s, event = start_echo_server()
Christian Heimes5e696852008-04-09 08:37:03 +0000203 c = echo_client(b'\n', s.port)
204 c.push("hello world\nI'm not dead yet!\n")
Guido van Rossum806c2462007-08-06 23:33:07 +0000205 c.push(SERVER_QUIT)
206 c.close_when_done()
207 asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01)
208 s.join()
209
210 self.assertEqual(c.contents, [])
211 # the server might have been able to send a byte or two back, but this
212 # at least checks that it received something and didn't just fail
213 # (which could still result in the client not having received anything)
214 self.assertTrue(len(s.buffer) > 0)
215
216
217class TestAsynchat_WithPoll(TestAsynchat):
218 usepoll = True
219
220class TestHelperFunctions(unittest.TestCase):
221 def test_find_prefix_at_end(self):
222 self.assertEqual(asynchat.find_prefix_at_end("qwerty\r", "\r\n"), 1)
223 self.assertEqual(asynchat.find_prefix_at_end("qwertydkjf", "\r\n"), 0)
224
225class TestFifo(unittest.TestCase):
226 def test_basic(self):
227 f = asynchat.fifo()
228 f.push(7)
229 f.push(b'a')
230 self.assertEqual(len(f), 2)
231 self.assertEqual(f.first(), 7)
232 self.assertEqual(f.pop(), (1, 7))
233 self.assertEqual(len(f), 1)
234 self.assertEqual(f.first(), b'a')
235 self.assertEqual(f.is_empty(), False)
236 self.assertEqual(f.pop(), (1, b'a'))
237 self.assertEqual(len(f), 0)
238 self.assertEqual(f.is_empty(), True)
239 self.assertEqual(f.pop(), (0, None))
240
241 def test_given_list(self):
242 f = asynchat.fifo([b'x', 17, 3])
243 self.assertEqual(len(f), 3)
244 self.assertEqual(f.pop(), (1, b'x'))
245 self.assertEqual(f.pop(), (1, 17))
246 self.assertEqual(f.pop(), (1, 3))
247 self.assertEqual(f.pop(), (0, None))
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000248
249
250def test_main(verbose=None):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000251 support.run_unittest(TestAsynchat, TestAsynchat_WithPoll,
Guido van Rossum806c2462007-08-06 23:33:07 +0000252 TestHelperFunctions, TestFifo)
Andrew M. Kuchling5ac25342005-06-09 14:56:31 +0000253
254if __name__ == "__main__":
255 test_main(verbose=True)