blob: 7dfabcf415ff98018c6501840fe818258f76f39d [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):
306 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
307 self.assertEqual(p.pow(6,8), 6**8)
308
309 def test_introspection1(self):
310 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
311 meth = p.system.listMethods()
312 expected_methods = set(['pow', 'div', 'add', 'system.listMethods',
313 'system.methodHelp', 'system.methodSignature', 'system.multicall'])
314 self.assertEqual(set(meth), expected_methods)
315
316 def test_introspection2(self):
317 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
318 divhelp = p.system.methodHelp('div')
319 self.assertEqual(divhelp, 'This is the div function')
320
321 def test_introspection3(self):
322 # the SimpleXMLRPCServer doesn't support signatures, but
323 # at least check that we can try
324 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
325 divsig = p.system.methodSignature('div')
326 self.assertEqual(divsig, 'signatures not supported')
327
328 def test_multicall(self):
329 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
330 multicall = xmlrpclib.MultiCall(p)
331 multicall.add(2,3)
332 multicall.pow(6,8)
333 multicall.div(127,42)
334 add_result, pow_result, div_result = multicall()
335 self.assertEqual(add_result, 2+3)
336 self.assertEqual(pow_result, 6**8)
337 self.assertEqual(div_result, 127//42)
338
339
Guido van Rossum61e21b52007-08-20 19:06:03 +0000340# This is a contrived way to make a failure occur on the server side
341# in order to test the _send_traceback_header flag on the server
342class FailingMessageClass(mimetools.Message):
343 def __getitem__(self, key):
344 key = key.lower()
345 if key == 'content-length':
346 return 'I am broken'
347 return mimetools.Message.__getitem__(self, key)
348
349
350class FailingServerTestCase(unittest.TestCase):
351 def setUp(self):
352 self.evt = threading.Event()
353 # start server thread to handle requests
354 serv_args = (self.evt, 2)
355 threading.Thread(target=http_server, args=serv_args).start()
356
357 # wait for port to be assigned to server
358 n = 1000
359 while n > 0 and PORT is None:
360 time.sleep(0.001)
361 n -= 1
362
363 time.sleep(0.5)
364
365 def tearDown(self):
366 # wait on the server thread to terminate
367 self.evt.wait()
368 # reset flag
369 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
370 # reset message class
371 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
372
373 def test_basic(self):
374 # check that flag is false by default
375 flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header
376 self.assertEqual(flagval, False)
377
378 # test a call that won't fail just as a smoke test
379 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
380 self.assertEqual(p.pow(6,8), 6**8)
381
382 def test_fail_no_info(self):
383 # use the broken message class
384 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
385
386 try:
387 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
388 p.pow(6,8)
389 except xmlrpclib.ProtocolError as e:
390 # The two server-side error headers shouldn't be sent back in this case
391 self.assertTrue(e.headers.get("X-exception") is None)
392 self.assertTrue(e.headers.get("X-traceback") is None)
393 else:
394 self.fail('ProtocolError not raised')
395
396 def test_fail_with_info(self):
397 # use the broken message class
398 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
399
400 # Check that errors in the server send back exception/traceback
401 # info when flag is set
402 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
403
404 try:
405 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
406 p.pow(6,8)
407 except xmlrpclib.ProtocolError as e:
408 # We should get error info in the response
409 expected_err = "invalid literal for int() with base 10: 'I am broken'"
410 self.assertEqual(e.headers.get("x-exception"), expected_err)
411 self.assertTrue(e.headers.get("x-traceback") is not None)
412 else:
413 self.fail('ProtocolError not raised')
414
415
Guido van Rossumaf554a02007-08-16 23:48:43 +0000416def test_main():
417 xmlrpc_tests = [XMLRPCTestCase, HelperTestCase, DateTimeTestCase,
418 BinaryTestCase, FaultTestCase]
419
420 # The test cases against a SimpleXMLRPCServer raise a socket error
421 # 10035 (WSAEWOULDBLOCK) in the server thread handle_request call when
422 # run on Windows. This only happens on the first test to run, but it
423 # fails every time and so these tests are skipped on win32 platforms.
424 if sys.platform != 'win32':
Guido van Rossum61e21b52007-08-20 19:06:03 +0000425 xmlrpc_tests.append(SimpleServerTestCase)
426 xmlrpc_tests.append(FailingServerTestCase)
Guido van Rossumaf554a02007-08-16 23:48:43 +0000427
428 test_support.run_unittest(*xmlrpc_tests)
Skip Montanaro419abda2001-10-01 17:47:44 +0000429
430if __name__ == "__main__":
431 test_main()