blob: ad4b8d32d17e3d44a4b1bb97e9bfe368569dd01f [file] [log] [blame]
Benjamin Peterson76f71a52008-10-11 17:25:36 +00001"""Test script for poplib module."""
2
3# Modified by Giampaolo Rodola' to give poplib.POP3 and poplib.POP3_SSL
4# a real test suite
5
Facundo Batistab20c5002007-03-27 18:50:29 +00006import poplib
Benjamin Peterson76f71a52008-10-11 17:25:36 +00007import threading
8import asyncore
9import asynchat
10import socket
11import os
Facundo Batistab20c5002007-03-27 18:50:29 +000012import time
13
14from unittest import TestCase
15from test import test_support
Benjamin Peterson76f71a52008-10-11 17:25:36 +000016from test.test_support import HOST
Facundo Batistab20c5002007-03-27 18:50:29 +000017
18
Benjamin Peterson76f71a52008-10-11 17:25:36 +000019# the dummy data returned by server when LIST and RETR commands are issued
20LIST_RESP = '1 1\r\n2 2\r\n3 3\r\n4 4\r\n5 5\r\n.\r\n'
21RETR_RESP = """From: postmaster@python.org\
22\r\nContent-Type: text/plain\r\n\
23MIME-Version: 1.0\r\n\
24Subject: Dummy\r\n\
25\r\n\
26line1\r\n\
27line2\r\n\
28line3\r\n\
29.\r\n"""
Facundo Batistab20c5002007-03-27 18:50:29 +000030
Benjamin Peterson76f71a52008-10-11 17:25:36 +000031
32class DummyPOP3Handler(asynchat.async_chat):
33
34 def __init__(self, conn):
35 asynchat.async_chat.__init__(self, conn)
36 self.set_terminator("\r\n")
37 self.in_buffer = []
38 self.push('+OK dummy pop3 server ready.')
39
40 def collect_incoming_data(self, data):
41 self.in_buffer.append(data)
42
43 def found_terminator(self):
44 line = ''.join(self.in_buffer)
45 self.in_buffer = []
46 cmd = line.split(' ')[0].lower()
47 space = line.find(' ')
48 if space != -1:
49 arg = line[space + 1:]
50 else:
51 arg = ""
52 if hasattr(self, 'cmd_' + cmd):
53 method = getattr(self, 'cmd_' + cmd)
54 method(arg)
55 else:
56 self.push('-ERR unrecognized POP3 command "%s".' %cmd)
57
58 def handle_error(self):
59 raise
60
61 def push(self, data):
62 asynchat.async_chat.push(self, data + '\r\n')
63
64 def cmd_echo(self, arg):
65 # sends back the received string (used by the test suite)
66 self.push(arg)
67
68 def cmd_user(self, arg):
69 if arg != "guido":
70 self.push("-ERR no such user")
71 self.push('+OK password required')
72
73 def cmd_pass(self, arg):
74 if arg != "python":
75 self.push("-ERR wrong password")
76 self.push('+OK 10 messages')
77
78 def cmd_stat(self, arg):
79 self.push('+OK 10 100')
80
81 def cmd_list(self, arg):
82 if arg:
83 self.push('+OK %s %s' %(arg, arg))
84 else:
85 self.push('+OK')
86 asynchat.async_chat.push(self, LIST_RESP)
87
88 cmd_uidl = cmd_list
89
90 def cmd_retr(self, arg):
91 self.push('+OK %s bytes' %len(RETR_RESP))
92 asynchat.async_chat.push(self, RETR_RESP)
93
94 cmd_top = cmd_retr
95
96 def cmd_dele(self, arg):
97 self.push('+OK message marked for deletion.')
98
99 def cmd_noop(self, arg):
100 self.push('+OK done nothing.')
101
102 def cmd_rpop(self, arg):
103 self.push('+OK done nothing.')
104
105
106class DummyPOP3Server(asyncore.dispatcher, threading.Thread):
107
108 handler = DummyPOP3Handler
109
110 def __init__(self, address, af=socket.AF_INET):
111 threading.Thread.__init__(self)
112 asyncore.dispatcher.__init__(self)
113 self.create_socket(af, socket.SOCK_STREAM)
114 self.bind(address)
115 self.listen(5)
116 self.active = False
117 self.active_lock = threading.Lock()
118 self.host, self.port = self.socket.getsockname()[:2]
119
120 def start(self):
121 assert not self.active
122 self.__flag = threading.Event()
123 threading.Thread.start(self)
124 self.__flag.wait()
125
126 def run(self):
127 self.active = True
128 self.__flag.set()
129 while self.active and asyncore.socket_map:
130 self.active_lock.acquire()
131 asyncore.loop(timeout=0.1, count=1)
132 self.active_lock.release()
133 asyncore.close_all(ignore_all=True)
134
135 def stop(self):
136 assert self.active
137 self.active = False
138 self.join()
139
140 def handle_accept(self):
141 conn, addr = self.accept()
142 self.handler = self.handler(conn)
143 self.close()
144
145 def handle_connect(self):
146 self.close()
147 handle_read = handle_connect
148
149 def writable(self):
150 return 0
151
152 def handle_error(self):
153 raise
154
155
156class TestPOP3Class(TestCase):
157
158 def assertOK(self, resp):
159 self.assertTrue(resp.startswith("+OK"))
160
161 def setUp(self):
162 self.server = DummyPOP3Server((HOST, 0))
163 self.server.start()
164 self.client = poplib.POP3(self.server.host, self.server.port)
165
166 def tearDown(self):
167 self.client.quit()
168 self.server.stop()
169
170 def test_getwelcome(self):
171 self.assertEqual(self.client.getwelcome(), '+OK dummy pop3 server ready.')
172
173 def test_exceptions(self):
174 self.assertRaises(poplib.error_proto, self.client._shortcmd, 'echo -err')
175
176 def test_user(self):
177 self.assertOK(self.client.user('guido'))
178 self.assertRaises(poplib.error_proto, self.client.user, 'invalid')
179
180 def test_pass_(self):
181 self.assertOK(self.client.pass_('python'))
182 self.assertRaises(poplib.error_proto, self.client.user, 'invalid')
183
184 def test_stat(self):
185 self.assertEqual(self.client.stat(), (10, 100))
186
187 def test_list(self):
188 self.assertEqual(self.client.list()[1:],
189 (['1 1', '2 2', '3 3', '4 4', '5 5'], 25))
190 self.assertTrue(self.client.list('1').endswith("OK 1 1"))
191
192 def test_retr(self):
193 expected = ('+OK 116 bytes',
194 ['From: postmaster@python.org', 'Content-Type: text/plain',
195 'MIME-Version: 1.0', 'Subject: Dummy',
196 '', 'line1', 'line2', 'line3'],
197 113)
198 self.assertEqual(self.client.retr('foo'), expected)
199
200 def test_dele(self):
201 self.assertOK(self.client.dele('foo'))
202
203 def test_noop(self):
204 self.assertOK(self.client.noop())
205
206 def test_rpop(self):
207 self.assertOK(self.client.rpop('foo'))
208
209 def test_top(self):
210 expected = ('+OK 116 bytes',
211 ['From: postmaster@python.org', 'Content-Type: text/plain',
212 'MIME-Version: 1.0', 'Subject: Dummy', '',
213 'line1', 'line2', 'line3'],
214 113)
215 self.assertEqual(self.client.top(1, 1), expected)
216
217 def test_uidl(self):
218 self.client.uidl()
219 self.client.uidl('foo')
220
221
222SUPPORTS_SSL = False
223if hasattr(poplib, 'POP3_SSL'):
224 import ssl
225
226 SUPPORTS_SSL = True
227 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "keycert.pem")
228
229 class DummyPOP3_SSLHandler(DummyPOP3Handler):
230
231 def __init__(self, conn):
232 asynchat.async_chat.__init__(self, conn)
233 self.socket = ssl.wrap_socket(self.socket, certfile=CERTFILE,
234 server_side=True)
235 self.set_terminator("\r\n")
236 self.in_buffer = []
237 self.push('+OK dummy pop3 server ready.')
238
239 class TestPOP3_SSLClass(TestPOP3Class):
240 # repeat previous tests by using poplib.POP3_SSL
241
242 def setUp(self):
243 self.server = DummyPOP3Server((HOST, 0))
244 self.server.handler = DummyPOP3_SSLHandler
245 self.server.start()
246 self.client = poplib.POP3_SSL(self.server.host, self.server.port)
247
248 def test__all__(self):
249 self.assert_('POP3_SSL' in poplib.__all__)
250
251
252class TestTimeouts(TestCase):
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000253
Facundo Batistab20c5002007-03-27 18:50:29 +0000254 def setUp(self):
255 self.evt = threading.Event()
Trent Nelsone41b0062008-04-08 23:47:30 +0000256 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
257 self.sock.settimeout(3)
258 self.port = test_support.bind_port(self.sock)
Benjamin Peterson76f71a52008-10-11 17:25:36 +0000259 threading.Thread(target=self.server, args=(self.evt,self.sock)).start()
Facundo Batistab20c5002007-03-27 18:50:29 +0000260 time.sleep(.1)
261
262 def tearDown(self):
263 self.evt.wait()
264
Benjamin Peterson76f71a52008-10-11 17:25:36 +0000265 def server(self, evt, serv):
266 serv.listen(5)
267 try:
268 conn, addr = serv.accept()
269 except socket.timeout:
270 pass
271 else:
272 conn.send("+ Hola mundo\n")
273 conn.close()
274 finally:
275 serv.close()
276 evt.set()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000277
Facundo Batistab20c5002007-03-27 18:50:29 +0000278 def testTimeoutDefault(self):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000279 self.assertTrue(socket.getdefaulttimeout() is None)
280 socket.setdefaulttimeout(30)
281 try:
282 pop = poplib.POP3("localhost", self.port)
283 finally:
284 socket.setdefaulttimeout(None)
Facundo Batistab20c5002007-03-27 18:50:29 +0000285 self.assertEqual(pop.sock.gettimeout(), 30)
286 pop.sock.close()
287
288 def testTimeoutNone(self):
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000289 self.assertTrue(socket.getdefaulttimeout() is None)
Facundo Batistab20c5002007-03-27 18:50:29 +0000290 socket.setdefaulttimeout(30)
291 try:
Trent Nelsone41b0062008-04-08 23:47:30 +0000292 pop = poplib.POP3(HOST, self.port, timeout=None)
Facundo Batistab20c5002007-03-27 18:50:29 +0000293 finally:
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000294 socket.setdefaulttimeout(None)
295 self.assertTrue(pop.sock.gettimeout() is None)
Facundo Batistab20c5002007-03-27 18:50:29 +0000296 pop.sock.close()
297
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000298 def testTimeoutValue(self):
299 pop = poplib.POP3("localhost", self.port, timeout=30)
300 self.assertEqual(pop.sock.gettimeout(), 30)
301 pop.sock.close()
Facundo Batistab20c5002007-03-27 18:50:29 +0000302
303
Benjamin Peterson76f71a52008-10-11 17:25:36 +0000304def test_main():
305 tests = [TestPOP3Class, TestTimeouts]
306 if SUPPORTS_SSL:
307 tests.append(TestPOP3_SSLClass)
308 thread_info = test_support.threading_setup()
309 try:
310 test_support.run_unittest(*tests)
311 finally:
312 test_support.threading_cleanup(*thread_info)
313
Facundo Batistab20c5002007-03-27 18:50:29 +0000314
315if __name__ == '__main__':
316 test_main()