blob: 03080ab88669efe34fd34512f9937451359f71b2 [file] [log] [blame]
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001import base64
Fred Drakeba613c32005-02-10 18:33:30 +00002import datetime
Skip Montanaro3e7bba92001-10-19 16:06:52 +00003import sys
Guido van Rossumb5a755e2007-07-18 18:15:48 +00004import time
Skip Montanaro419abda2001-10-01 17:47:44 +00005import unittest
6import xmlrpclib
Guido van Rossumaf554a02007-08-16 23:48:43 +00007import SimpleXMLRPCServer
8import threading
Guido van Rossum61e21b52007-08-20 19:06:03 +00009import mimetools
Barry Warsaw04f357c2002-07-23 19:04:11 +000010from test import test_support
Skip Montanaro419abda2001-10-01 17:47:44 +000011
12alist = [{'astring': 'foo@bar.baz.spam',
13 'afloat': 7283.43,
Skip Montanaro3e7bba92001-10-19 16:06:52 +000014 'anint': 2**20,
Guido van Rossume2a383d2007-01-15 16:59:06 +000015 'ashortlong': 2,
Skip Montanaro419abda2001-10-01 17:47:44 +000016 'anotherlist': ['.zyx.41'],
17 'abase64': xmlrpclib.Binary("my dog has fleas"),
Guido van Rossume7ba4952007-06-06 23:52:48 +000018 'boolean': False,
Guido van Rossumef87d6e2007-05-02 19:09:54 +000019 'unicode': '\u4000\u6000\u8000',
20 'ukey\u4000': 'regular value',
Fred Drakeba613c32005-02-10 18:33:30 +000021 'datetime1': xmlrpclib.DateTime('20050210T11:41:23'),
22 'datetime2': xmlrpclib.DateTime(
Guido van Rossumcd16bf62007-06-13 18:07:49 +000023 (2005, 2, 10, 11, 41, 23, 0, 1, -1)),
Fred Drakeba613c32005-02-10 18:33:30 +000024 'datetime3': xmlrpclib.DateTime(
Guido van Rossumcd16bf62007-06-13 18:07:49 +000025 datetime.datetime(2005, 2, 10, 11, 41, 23)),
Guido van Rossumb5a755e2007-07-18 18:15:48 +000026 'datetime4': xmlrpclib.DateTime(
27 datetime.date(2005, 2, 10)),
28 'datetime5': xmlrpclib.DateTime(
29 datetime.time(11, 41, 23)),
Skip Montanaro419abda2001-10-01 17:47:44 +000030 }]
31
32class XMLRPCTestCase(unittest.TestCase):
33
34 def test_dump_load(self):
35 self.assertEquals(alist,
36 xmlrpclib.loads(xmlrpclib.dumps((alist,)))[0][0])
37
Fred Drakeba613c32005-02-10 18:33:30 +000038 def test_dump_bare_datetime(self):
Skip Montanaro174dd222005-05-14 20:54:16 +000039 # This checks that an unwrapped datetime.date object can be handled
40 # by the marshalling code. This can't be done via test_dump_load()
41 # since with use_datetime set to 1 the unmarshaller would create
42 # datetime objects for the 'datetime[123]' keys as well
Guido van Rossumcd16bf62007-06-13 18:07:49 +000043 dt = datetime.datetime(2005, 2, 10, 11, 41, 23)
Fred Drakeba613c32005-02-10 18:33:30 +000044 s = xmlrpclib.dumps((dt,))
Skip Montanaro174dd222005-05-14 20:54:16 +000045 (newdt,), m = xmlrpclib.loads(s, use_datetime=1)
46 self.assertEquals(newdt, dt)
Fred Drakeba613c32005-02-10 18:33:30 +000047 self.assertEquals(m, None)
48
Skip Montanaro174dd222005-05-14 20:54:16 +000049 (newdt,), m = xmlrpclib.loads(s, use_datetime=0)
50 self.assertEquals(newdt, xmlrpclib.DateTime('20050210T11:41:23'))
51
52 def test_dump_bare_date(self):
53 # This checks that an unwrapped datetime.date object can be handled
54 # by the marshalling code. This can't be done via test_dump_load()
55 # since the unmarshaller produces a datetime object
Guido van Rossumcd16bf62007-06-13 18:07:49 +000056 d = datetime.datetime(2005, 2, 10, 11, 41, 23).date()
Skip Montanaro174dd222005-05-14 20:54:16 +000057 s = xmlrpclib.dumps((d,))
58 (newd,), m = xmlrpclib.loads(s, use_datetime=1)
59 self.assertEquals(newd.date(), d)
60 self.assertEquals(newd.time(), datetime.time(0, 0, 0))
61 self.assertEquals(m, None)
62
63 (newdt,), m = xmlrpclib.loads(s, use_datetime=0)
64 self.assertEquals(newdt, xmlrpclib.DateTime('20050210T00:00:00'))
65
66 def test_dump_bare_time(self):
67 # This checks that an unwrapped datetime.time object can be handled
68 # by the marshalling code. This can't be done via test_dump_load()
69 # since the unmarshaller produces a datetime object
Guido van Rossumcd16bf62007-06-13 18:07:49 +000070 t = datetime.datetime(2005, 2, 10, 11, 41, 23).time()
Skip Montanaro174dd222005-05-14 20:54:16 +000071 s = xmlrpclib.dumps((t,))
72 (newt,), m = xmlrpclib.loads(s, use_datetime=1)
73 today = datetime.datetime.now().date().strftime("%Y%m%d")
74 self.assertEquals(newt.time(), t)
75 self.assertEquals(newt.date(), datetime.datetime.now().date())
76 self.assertEquals(m, None)
77
78 (newdt,), m = xmlrpclib.loads(s, use_datetime=0)
79 self.assertEquals(newdt, xmlrpclib.DateTime('%sT11:41:23'%today))
80
Andrew M. Kuchlingbdb39012005-12-04 19:11:17 +000081 def test_bug_1164912 (self):
82 d = xmlrpclib.DateTime()
Tim Peters536cf992005-12-25 23:18:31 +000083 ((new_d,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((d,),
Andrew M. Kuchlingbdb39012005-12-04 19:11:17 +000084 methodresponse=True))
85 self.assert_(isinstance(new_d.value, str))
86
87 # Check that the output of dumps() is still an 8-bit string
88 s = xmlrpclib.dumps((new_d,), methodresponse=True)
89 self.assert_(isinstance(s, str))
90
Thomas Wouters89f507f2006-12-13 04:49:30 +000091 def test_newstyle_class(self):
92 class T(object):
93 pass
94 t = T()
95 t.x = 100
96 t.y = "Hello"
97 ((t2,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((t,)))
98 self.assertEquals(t2, t.__dict__)
99
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000100 def test_dump_big_long(self):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000101 self.assertRaises(OverflowError, xmlrpclib.dumps, (2**99,))
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000102
103 def test_dump_bad_dict(self):
104 self.assertRaises(TypeError, xmlrpclib.dumps, ({(1,2,3): 1},))
105
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000106 def test_dump_recursive_seq(self):
107 l = [1,2,3]
108 t = [3,4,5,l]
109 l.append(t)
110 self.assertRaises(TypeError, xmlrpclib.dumps, (l,))
111
112 def test_dump_recursive_dict(self):
113 d = {'1':1, '2':1}
114 t = {'3':3, 'd':d}
115 d['t'] = t
116 self.assertRaises(TypeError, xmlrpclib.dumps, (d,))
117
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000118 def test_dump_big_int(self):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000119 if sys.maxint > 2**31-1:
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000120 self.assertRaises(OverflowError, xmlrpclib.dumps,
Guido van Rossume2a383d2007-01-15 16:59:06 +0000121 (int(2**34),))
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000122
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000123 xmlrpclib.dumps((xmlrpclib.MAXINT, xmlrpclib.MININT))
124 self.assertRaises(OverflowError, xmlrpclib.dumps, (xmlrpclib.MAXINT+1,))
125 self.assertRaises(OverflowError, xmlrpclib.dumps, (xmlrpclib.MININT-1,))
126
127 def dummy_write(s):
128 pass
129
130 m = xmlrpclib.Marshaller()
131 m.dump_int(xmlrpclib.MAXINT, dummy_write)
132 m.dump_int(xmlrpclib.MININT, dummy_write)
133 self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MAXINT+1, dummy_write)
134 self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MININT-1, dummy_write)
135
136
Andrew M. Kuchling0b852032003-04-25 00:27:24 +0000137 def test_dump_none(self):
138 value = alist + [None]
139 arg1 = (alist + [None],)
140 strg = xmlrpclib.dumps(arg1, allow_none=True)
141 self.assertEquals(value,
142 xmlrpclib.loads(strg)[0][0])
143 self.assertRaises(TypeError, xmlrpclib.dumps, (arg1,))
144
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000145
146class HelperTestCase(unittest.TestCase):
147 def test_escape(self):
148 self.assertEqual(xmlrpclib.escape("a&b"), "a&b")
149 self.assertEqual(xmlrpclib.escape("a<b"), "a&lt;b")
150 self.assertEqual(xmlrpclib.escape("a>b"), "a&gt;b")
151
152class FaultTestCase(unittest.TestCase):
153 def test_repr(self):
154 f = xmlrpclib.Fault(42, 'Test Fault')
155 self.assertEqual(repr(f), "<Fault 42: 'Test Fault'>")
156 self.assertEqual(repr(f), str(f))
157
158 def test_dump_fault(self):
159 f = xmlrpclib.Fault(42, 'Test Fault')
160 s = xmlrpclib.dumps((f,))
161 (newf,), m = xmlrpclib.loads(s)
162 self.assertEquals(newf, {'faultCode': 42, 'faultString': 'Test Fault'})
163 self.assertEquals(m, None)
164
165 s = xmlrpclib.Marshaller().dumps(f)
166 self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, s)
167
168
169class DateTimeTestCase(unittest.TestCase):
170 def test_default(self):
171 t = xmlrpclib.DateTime()
172
173 def test_time(self):
174 d = 1181399930.036952
175 t = xmlrpclib.DateTime(d)
176 self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", time.localtime(d)))
177
178 def test_time_tuple(self):
179 d = (2007,6,9,10,38,50,5,160,0)
180 t = xmlrpclib.DateTime(d)
181 self.assertEqual(str(t), '20070609T10:38:50')
182
183 def test_time_struct(self):
184 d = time.localtime(1181399930.036952)
185 t = xmlrpclib.DateTime(d)
186 self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", d))
187
188 def test_datetime_datetime(self):
189 d = datetime.datetime(2007,1,2,3,4,5)
190 t = xmlrpclib.DateTime(d)
191 self.assertEqual(str(t), '20070102T03:04:05')
192
193 def test_datetime_date(self):
194 d = datetime.date(2007,9,8)
195 t = xmlrpclib.DateTime(d)
196 self.assertEqual(str(t), '20070908T00:00:00')
197
198 def test_datetime_time(self):
199 d = datetime.time(13,17,19)
200 # allow for date rollover by checking today's or tomorrow's dates
201 dd1 = datetime.datetime.now().date()
202 dd2 = dd1 + datetime.timedelta(days=1)
203 vals = (dd1.strftime('%Y%m%dT13:17:19'),
204 dd2.strftime('%Y%m%dT13:17:19'))
205 t = xmlrpclib.DateTime(d)
206 self.assertEqual(str(t) in vals, True)
207
208 def test_repr(self):
209 d = datetime.datetime(2007,1,2,3,4,5)
210 t = xmlrpclib.DateTime(d)
211 val ="<DateTime '20070102T03:04:05' at %x>" % id(t)
212 self.assertEqual(repr(t), val)
213
214 def test_decode(self):
215 d = ' 20070908T07:11:13 '
216 t1 = xmlrpclib.DateTime()
217 t1.decode(d)
218 tref = xmlrpclib.DateTime(datetime.datetime(2007,9,8,7,11,13))
219 self.assertEqual(t1, tref)
220
221 t2 = xmlrpclib._datetime(d)
222 self.assertEqual(t1, tref)
223
224class BinaryTestCase(unittest.TestCase):
225 def test_default(self):
226 t = xmlrpclib.Binary()
227 self.assertEqual(str(t), '')
228
229 def test_string(self):
230 d = '\x01\x02\x03abc123\xff\xfe'
231 t = xmlrpclib.Binary(d)
232 self.assertEqual(str(t), d)
233
234 def test_decode(self):
235 d = '\x01\x02\x03abc123\xff\xfe'
236 de = base64.encodestring(d)
237 t1 = xmlrpclib.Binary()
238 t1.decode(de)
239 self.assertEqual(str(t1), d)
240
241 t2 = xmlrpclib._binary(de)
242 self.assertEqual(str(t2), d)
243
244
Guido van Rossumaf554a02007-08-16 23:48:43 +0000245PORT = None
Skip Montanaro419abda2001-10-01 17:47:44 +0000246
Guido van Rossumaf554a02007-08-16 23:48:43 +0000247def http_server(evt, numrequests):
248 class TestInstanceClass:
249 def div(self, x, y):
250 '''This is the div function'''
251 return x // y
252
Guido van Rossumaf554a02007-08-16 23:48:43 +0000253 try:
Guido van Rossum61e21b52007-08-20 19:06:03 +0000254 serv = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 0),
255 logRequests=False, bind_and_activate=False)
Guido van Rossumaf554a02007-08-16 23:48:43 +0000256 serv.socket.settimeout(3)
257 serv.server_bind()
258 global PORT
259 PORT = serv.socket.getsockname()[1]
260 serv.server_activate()
261 serv.register_introspection_functions()
262 serv.register_multicall_functions()
263 serv.register_function(pow)
264 serv.register_function(lambda x,y: x+y, 'add')
265 serv.register_instance(TestInstanceClass())
266
267 # handle up to 'numrequests' requests
268 while numrequests > 0:
269 serv.handle_request()
270 numrequests -= 1
271
272 except socket.timeout:
273 pass
274 finally:
275 serv.socket.close()
276 PORT = None
277 evt.set()
278
279
Guido van Rossum61e21b52007-08-20 19:06:03 +0000280class SimpleServerTestCase(unittest.TestCase):
Guido van Rossumaf554a02007-08-16 23:48:43 +0000281 def setUp(self):
Guido van Rossum61e21b52007-08-20 19:06:03 +0000282 # enable traceback reporting
283 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
284
Guido van Rossumaf554a02007-08-16 23:48:43 +0000285 self.evt = threading.Event()
Guido van Rossum61e21b52007-08-20 19:06:03 +0000286 # start server thread to handle requests
287 serv_args = (self.evt, 2)
288 threading.Thread(target=http_server, args=serv_args).start()
Guido van Rossumaf554a02007-08-16 23:48:43 +0000289
290 # wait for port to be assigned to server
291 n = 1000
292 while n > 0 and PORT is None:
293 time.sleep(0.001)
294 n -= 1
295
296 time.sleep(0.5)
297
298 def tearDown(self):
299 # wait on the server thread to terminate
300 self.evt.wait()
301
Guido van Rossum61e21b52007-08-20 19:06:03 +0000302 # disable traceback reporting
303 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
304
Guido van Rossumaf554a02007-08-16 23:48:43 +0000305 def test_simple1(self):
Guido van Rossum04110fb2007-08-24 16:32:05 +0000306 try:
307 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
308 self.assertEqual(p.pow(6,8), 6**8)
Guido van Rossum7f19f662007-08-24 16:47:58 +0000309 except xmlrpclib.ProtocolError as e:
Guido van Rossum04110fb2007-08-24 16:32:05 +0000310 # protocol error; provide additional information in test output
311 self.fail("%s\n%s" % (e, e.headers))
Guido van Rossumaf554a02007-08-16 23:48:43 +0000312
313 def test_introspection1(self):
Guido van Rossum04110fb2007-08-24 16:32:05 +0000314 try:
315 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
316 meth = p.system.listMethods()
317 expected_methods = set(['pow', 'div', 'add', 'system.listMethods',
318 'system.methodHelp', 'system.methodSignature', 'system.multicall'])
319 self.assertEqual(set(meth), expected_methods)
Guido van Rossum7f19f662007-08-24 16:47:58 +0000320 except xmlrpclib.ProtocolError as e:
Guido van Rossum04110fb2007-08-24 16:32:05 +0000321 # protocol error; provide additional information in test output
322 self.fail("%s\n%s" % (e, e.headers))
Guido van Rossumaf554a02007-08-16 23:48:43 +0000323
324 def test_introspection2(self):
Guido van Rossum04110fb2007-08-24 16:32:05 +0000325 try:
326 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
327 divhelp = p.system.methodHelp('div')
328 self.assertEqual(divhelp, 'This is the div function')
Guido van Rossum7f19f662007-08-24 16:47:58 +0000329 except xmlrpclib.ProtocolError as e:
Guido van Rossum04110fb2007-08-24 16:32:05 +0000330 # protocol error; provide additional information in test output
331 self.fail("%s\n%s" % (e, e.headers))
Guido van Rossumaf554a02007-08-16 23:48:43 +0000332
333 def test_introspection3(self):
334 # the SimpleXMLRPCServer doesn't support signatures, but
335 # at least check that we can try
Guido van Rossum04110fb2007-08-24 16:32:05 +0000336 try:
337 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
338 divsig = p.system.methodSignature('div')
339 self.assertEqual(divsig, 'signatures not supported')
Guido van Rossum7f19f662007-08-24 16:47:58 +0000340 except xmlrpclib.ProtocolError as e:
Guido van Rossum04110fb2007-08-24 16:32:05 +0000341 # protocol error; provide additional information in test output
342 self.fail("%s\n%s" % (e, e.headers))
Guido van Rossumaf554a02007-08-16 23:48:43 +0000343
344 def test_multicall(self):
Guido van Rossum04110fb2007-08-24 16:32:05 +0000345 try:
346 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
347 multicall = xmlrpclib.MultiCall(p)
348 multicall.add(2,3)
349 multicall.pow(6,8)
350 multicall.div(127,42)
351 add_result, pow_result, div_result = multicall()
352 self.assertEqual(add_result, 2+3)
353 self.assertEqual(pow_result, 6**8)
354 self.assertEqual(div_result, 127//42)
Guido van Rossum7f19f662007-08-24 16:47:58 +0000355 except xmlrpclib.ProtocolError as e:
Guido van Rossum04110fb2007-08-24 16:32:05 +0000356 # protocol error; provide additional information in test output
357 self.fail("%s\n%s" % (e, e.headers))
Guido van Rossumaf554a02007-08-16 23:48:43 +0000358
359
Guido van Rossum61e21b52007-08-20 19:06:03 +0000360# This is a contrived way to make a failure occur on the server side
361# in order to test the _send_traceback_header flag on the server
362class FailingMessageClass(mimetools.Message):
363 def __getitem__(self, key):
364 key = key.lower()
365 if key == 'content-length':
366 return 'I am broken'
367 return mimetools.Message.__getitem__(self, key)
368
369
370class FailingServerTestCase(unittest.TestCase):
371 def setUp(self):
372 self.evt = threading.Event()
373 # start server thread to handle requests
374 serv_args = (self.evt, 2)
375 threading.Thread(target=http_server, args=serv_args).start()
376
377 # wait for port to be assigned to server
378 n = 1000
379 while n > 0 and PORT is None:
380 time.sleep(0.001)
381 n -= 1
382
383 time.sleep(0.5)
384
385 def tearDown(self):
386 # wait on the server thread to terminate
387 self.evt.wait()
388 # reset flag
389 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
390 # reset message class
391 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
392
393 def test_basic(self):
394 # check that flag is false by default
395 flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header
396 self.assertEqual(flagval, False)
397
Guido van Rossum04110fb2007-08-24 16:32:05 +0000398 # enable traceback reporting
399 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
400
401 # test a call that shouldn't fail just as a smoke test
402 try:
403 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
404 self.assertEqual(p.pow(6,8), 6**8)
Guido van Rossum7f19f662007-08-24 16:47:58 +0000405 except xmlrpclib.ProtocolError as e:
Guido van Rossum04110fb2007-08-24 16:32:05 +0000406 # protocol error; provide additional information in test output
407 self.fail("%s\n%s" % (e, e.headers))
Guido van Rossum61e21b52007-08-20 19:06:03 +0000408
409 def test_fail_no_info(self):
410 # use the broken message class
411 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
412
413 try:
414 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
415 p.pow(6,8)
416 except xmlrpclib.ProtocolError as e:
417 # The two server-side error headers shouldn't be sent back in this case
418 self.assertTrue(e.headers.get("X-exception") is None)
419 self.assertTrue(e.headers.get("X-traceback") is None)
420 else:
421 self.fail('ProtocolError not raised')
422
423 def test_fail_with_info(self):
424 # use the broken message class
425 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
426
427 # Check that errors in the server send back exception/traceback
428 # info when flag is set
429 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
430
431 try:
432 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
433 p.pow(6,8)
434 except xmlrpclib.ProtocolError as e:
435 # We should get error info in the response
436 expected_err = "invalid literal for int() with base 10: 'I am broken'"
437 self.assertEqual(e.headers.get("x-exception"), expected_err)
438 self.assertTrue(e.headers.get("x-traceback") is not None)
439 else:
440 self.fail('ProtocolError not raised')
441
442
Guido van Rossumaf554a02007-08-16 23:48:43 +0000443def test_main():
444 xmlrpc_tests = [XMLRPCTestCase, HelperTestCase, DateTimeTestCase,
445 BinaryTestCase, FaultTestCase]
446
447 # The test cases against a SimpleXMLRPCServer raise a socket error
448 # 10035 (WSAEWOULDBLOCK) in the server thread handle_request call when
449 # run on Windows. This only happens on the first test to run, but it
450 # fails every time and so these tests are skipped on win32 platforms.
451 if sys.platform != 'win32':
Guido van Rossum61e21b52007-08-20 19:06:03 +0000452 xmlrpc_tests.append(SimpleServerTestCase)
453 xmlrpc_tests.append(FailingServerTestCase)
Guido van Rossumaf554a02007-08-16 23:48:43 +0000454
455 test_support.run_unittest(*xmlrpc_tests)
Skip Montanaro419abda2001-10-01 17:47:44 +0000456
457if __name__ == "__main__":
458 test_main()