blob: 4dd3316ffa0cdcdb523a8d8c87365b38b41bfe48 [file] [log] [blame]
Facundo Batista5a3b5242007-07-13 10:43:44 +00001import base64
Fred Drakeba613c32005-02-10 18:33:30 +00002import datetime
Skip Montanaro3e7bba92001-10-19 16:06:52 +00003import sys
Facundo Batista5a3b5242007-07-13 10:43:44 +00004import time
Skip Montanaro419abda2001-10-01 17:47:44 +00005import unittest
6import xmlrpclib
Facundo Batistaa53872b2007-08-14 13:35:00 +00007import SimpleXMLRPCServer
8import threading
Facundo Batista7f686fc2007-08-17 19:16:44 +00009import mimetools
Georg Brandl5d1b4d42007-12-07 09:07:10 +000010import httplib
11import socket
12import os
Barry Warsaw04f357c2002-07-23 19:04:11 +000013from test import test_support
Skip Montanaro419abda2001-10-01 17:47:44 +000014
Fred Drake22c07062005-02-11 17:59:08 +000015try:
16 unicode
17except NameError:
18 have_unicode = False
19else:
20 have_unicode = True
21
Skip Montanaro419abda2001-10-01 17:47:44 +000022alist = [{'astring': 'foo@bar.baz.spam',
23 'afloat': 7283.43,
Skip Montanaro3e7bba92001-10-19 16:06:52 +000024 'anint': 2**20,
25 'ashortlong': 2L,
Skip Montanaro419abda2001-10-01 17:47:44 +000026 'anotherlist': ['.zyx.41'],
27 'abase64': xmlrpclib.Binary("my dog has fleas"),
28 'boolean': xmlrpclib.False,
Andrew M. Kuchlingb12d97c2004-06-05 12:33:27 +000029 'unicode': u'\u4000\u6000\u8000',
30 u'ukey\u4000': 'regular value',
Fred Drakeba613c32005-02-10 18:33:30 +000031 'datetime1': xmlrpclib.DateTime('20050210T11:41:23'),
32 'datetime2': xmlrpclib.DateTime(
33 (2005, 02, 10, 11, 41, 23, 0, 1, -1)),
34 'datetime3': xmlrpclib.DateTime(
35 datetime.datetime(2005, 02, 10, 11, 41, 23)),
Facundo Batista5a3b5242007-07-13 10:43:44 +000036 'datetime4': xmlrpclib.DateTime(
37 datetime.date(2005, 02, 10)),
38 'datetime5': xmlrpclib.DateTime(
39 datetime.time(11, 41, 23)),
Skip Montanaro419abda2001-10-01 17:47:44 +000040 }]
41
42class XMLRPCTestCase(unittest.TestCase):
43
44 def test_dump_load(self):
45 self.assertEquals(alist,
46 xmlrpclib.loads(xmlrpclib.dumps((alist,)))[0][0])
47
Fred Drakeba613c32005-02-10 18:33:30 +000048 def test_dump_bare_datetime(self):
Skip Montanaro174dd222005-05-14 20:54:16 +000049 # This checks that an unwrapped datetime.date object can be handled
50 # by the marshalling code. This can't be done via test_dump_load()
51 # since with use_datetime set to 1 the unmarshaller would create
52 # datetime objects for the 'datetime[123]' keys as well
Fred Drakeba613c32005-02-10 18:33:30 +000053 dt = datetime.datetime(2005, 02, 10, 11, 41, 23)
54 s = xmlrpclib.dumps((dt,))
Skip Montanaro174dd222005-05-14 20:54:16 +000055 (newdt,), m = xmlrpclib.loads(s, use_datetime=1)
56 self.assertEquals(newdt, dt)
Fred Drakeba613c32005-02-10 18:33:30 +000057 self.assertEquals(m, None)
58
Skip Montanaro174dd222005-05-14 20:54:16 +000059 (newdt,), m = xmlrpclib.loads(s, use_datetime=0)
60 self.assertEquals(newdt, xmlrpclib.DateTime('20050210T11:41:23'))
61
62 def test_dump_bare_date(self):
63 # This checks that an unwrapped datetime.date object can be handled
64 # by the marshalling code. This can't be done via test_dump_load()
65 # since the unmarshaller produces a datetime object
66 d = datetime.datetime(2005, 02, 10, 11, 41, 23).date()
67 s = xmlrpclib.dumps((d,))
68 (newd,), m = xmlrpclib.loads(s, use_datetime=1)
69 self.assertEquals(newd.date(), d)
70 self.assertEquals(newd.time(), datetime.time(0, 0, 0))
71 self.assertEquals(m, None)
72
73 (newdt,), m = xmlrpclib.loads(s, use_datetime=0)
74 self.assertEquals(newdt, xmlrpclib.DateTime('20050210T00:00:00'))
75
76 def test_dump_bare_time(self):
77 # This checks that an unwrapped datetime.time object can be handled
78 # by the marshalling code. This can't be done via test_dump_load()
79 # since the unmarshaller produces a datetime object
80 t = datetime.datetime(2005, 02, 10, 11, 41, 23).time()
81 s = xmlrpclib.dumps((t,))
82 (newt,), m = xmlrpclib.loads(s, use_datetime=1)
83 today = datetime.datetime.now().date().strftime("%Y%m%d")
84 self.assertEquals(newt.time(), t)
85 self.assertEquals(newt.date(), datetime.datetime.now().date())
86 self.assertEquals(m, None)
87
88 (newdt,), m = xmlrpclib.loads(s, use_datetime=0)
89 self.assertEquals(newdt, xmlrpclib.DateTime('%sT11:41:23'%today))
90
Andrew M. Kuchlingbdb39012005-12-04 19:11:17 +000091 def test_bug_1164912 (self):
92 d = xmlrpclib.DateTime()
Tim Peters536cf992005-12-25 23:18:31 +000093 ((new_d,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((d,),
Andrew M. Kuchlingbdb39012005-12-04 19:11:17 +000094 methodresponse=True))
95 self.assert_(isinstance(new_d.value, str))
96
97 # Check that the output of dumps() is still an 8-bit string
98 s = xmlrpclib.dumps((new_d,), methodresponse=True)
99 self.assert_(isinstance(s, str))
100
Martin v. Löwis07529352006-11-19 18:51:54 +0000101 def test_newstyle_class(self):
102 class T(object):
103 pass
104 t = T()
105 t.x = 100
106 t.y = "Hello"
107 ((t2,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((t,)))
108 self.assertEquals(t2, t.__dict__)
109
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000110 def test_dump_big_long(self):
111 self.assertRaises(OverflowError, xmlrpclib.dumps, (2L**99,))
112
113 def test_dump_bad_dict(self):
114 self.assertRaises(TypeError, xmlrpclib.dumps, ({(1,2,3): 1},))
115
Facundo Batista5a3b5242007-07-13 10:43:44 +0000116 def test_dump_recursive_seq(self):
117 l = [1,2,3]
118 t = [3,4,5,l]
119 l.append(t)
120 self.assertRaises(TypeError, xmlrpclib.dumps, (l,))
121
122 def test_dump_recursive_dict(self):
123 d = {'1':1, '2':1}
124 t = {'3':3, 'd':d}
125 d['t'] = t
126 self.assertRaises(TypeError, xmlrpclib.dumps, (d,))
127
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000128 def test_dump_big_int(self):
129 if sys.maxint > 2L**31-1:
130 self.assertRaises(OverflowError, xmlrpclib.dumps,
131 (int(2L**34),))
132
Facundo Batista5a3b5242007-07-13 10:43:44 +0000133 xmlrpclib.dumps((xmlrpclib.MAXINT, xmlrpclib.MININT))
134 self.assertRaises(OverflowError, xmlrpclib.dumps, (xmlrpclib.MAXINT+1,))
135 self.assertRaises(OverflowError, xmlrpclib.dumps, (xmlrpclib.MININT-1,))
136
137 def dummy_write(s):
138 pass
139
140 m = xmlrpclib.Marshaller()
141 m.dump_int(xmlrpclib.MAXINT, dummy_write)
142 m.dump_int(xmlrpclib.MININT, dummy_write)
143 self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MAXINT+1, dummy_write)
144 self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MININT-1, dummy_write)
145
146
Andrew M. Kuchling0b852032003-04-25 00:27:24 +0000147 def test_dump_none(self):
148 value = alist + [None]
149 arg1 = (alist + [None],)
150 strg = xmlrpclib.dumps(arg1, allow_none=True)
151 self.assertEquals(value,
152 xmlrpclib.loads(strg)[0][0])
153 self.assertRaises(TypeError, xmlrpclib.dumps, (arg1,))
154
Fred Drake22c07062005-02-11 17:59:08 +0000155 def test_default_encoding_issues(self):
156 # SF bug #1115989: wrong decoding in '_stringify'
157 utf8 = """<?xml version='1.0' encoding='iso-8859-1'?>
158 <params>
159 <param><value>
160 <string>abc \x95</string>
161 </value></param>
162 <param><value>
163 <struct>
164 <member>
165 <name>def \x96</name>
166 <value><string>ghi \x97</string></value>
167 </member>
168 </struct>
169 </value></param>
170 </params>
171 """
Tim Petersf754f5f2005-04-08 18:00:59 +0000172
173 # sys.setdefaultencoding() normally doesn't exist after site.py is
174 # loaded. reload(sys) is the way to get it back.
Fred Drake22c07062005-02-11 17:59:08 +0000175 old_encoding = sys.getdefaultencoding()
Tim Petersf754f5f2005-04-08 18:00:59 +0000176 setdefaultencoding_existed = hasattr(sys, "setdefaultencoding")
Fred Drake22c07062005-02-11 17:59:08 +0000177 reload(sys) # ugh!
178 sys.setdefaultencoding("iso-8859-1")
179 try:
180 (s, d), m = xmlrpclib.loads(utf8)
181 finally:
182 sys.setdefaultencoding(old_encoding)
Tim Petersf754f5f2005-04-08 18:00:59 +0000183 if not setdefaultencoding_existed:
184 del sys.setdefaultencoding
185
Fred Drake22c07062005-02-11 17:59:08 +0000186 items = d.items()
187 if have_unicode:
188 self.assertEquals(s, u"abc \x95")
189 self.assert_(isinstance(s, unicode))
190 self.assertEquals(items, [(u"def \x96", u"ghi \x97")])
191 self.assert_(isinstance(items[0][0], unicode))
192 self.assert_(isinstance(items[0][1], unicode))
193 else:
194 self.assertEquals(s, "abc \xc2\x95")
195 self.assertEquals(items, [("def \xc2\x96", "ghi \xc2\x97")])
196
Facundo Batista5a3b5242007-07-13 10:43:44 +0000197
198class HelperTestCase(unittest.TestCase):
199 def test_escape(self):
200 self.assertEqual(xmlrpclib.escape("a&b"), "a&amp;b")
201 self.assertEqual(xmlrpclib.escape("a<b"), "a&lt;b")
202 self.assertEqual(xmlrpclib.escape("a>b"), "a&gt;b")
203
204class FaultTestCase(unittest.TestCase):
205 def test_repr(self):
206 f = xmlrpclib.Fault(42, 'Test Fault')
207 self.assertEqual(repr(f), "<Fault 42: 'Test Fault'>")
208 self.assertEqual(repr(f), str(f))
209
210 def test_dump_fault(self):
211 f = xmlrpclib.Fault(42, 'Test Fault')
212 s = xmlrpclib.dumps((f,))
213 (newf,), m = xmlrpclib.loads(s)
214 self.assertEquals(newf, {'faultCode': 42, 'faultString': 'Test Fault'})
215 self.assertEquals(m, None)
216
217 s = xmlrpclib.Marshaller().dumps(f)
218 self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, s)
219
220
221class DateTimeTestCase(unittest.TestCase):
222 def test_default(self):
223 t = xmlrpclib.DateTime()
224
225 def test_time(self):
226 d = 1181399930.036952
227 t = xmlrpclib.DateTime(d)
228 self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", time.localtime(d)))
229
230 def test_time_tuple(self):
231 d = (2007,6,9,10,38,50,5,160,0)
232 t = xmlrpclib.DateTime(d)
233 self.assertEqual(str(t), '20070609T10:38:50')
234
235 def test_time_struct(self):
236 d = time.localtime(1181399930.036952)
237 t = xmlrpclib.DateTime(d)
238 self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", d))
239
240 def test_datetime_datetime(self):
241 d = datetime.datetime(2007,1,2,3,4,5)
242 t = xmlrpclib.DateTime(d)
243 self.assertEqual(str(t), '20070102T03:04:05')
244
245 def test_datetime_date(self):
246 d = datetime.date(2007,9,8)
247 t = xmlrpclib.DateTime(d)
248 self.assertEqual(str(t), '20070908T00:00:00')
249
250 def test_datetime_time(self):
251 d = datetime.time(13,17,19)
252 # allow for date rollover by checking today's or tomorrow's dates
253 dd1 = datetime.datetime.now().date()
254 dd2 = dd1 + datetime.timedelta(days=1)
255 vals = (dd1.strftime('%Y%m%dT13:17:19'),
256 dd2.strftime('%Y%m%dT13:17:19'))
257 t = xmlrpclib.DateTime(d)
258 self.assertEqual(str(t) in vals, True)
259
260 def test_repr(self):
261 d = datetime.datetime(2007,1,2,3,4,5)
262 t = xmlrpclib.DateTime(d)
263 val ="<DateTime '20070102T03:04:05' at %x>" % id(t)
264 self.assertEqual(repr(t), val)
265
266 def test_decode(self):
267 d = ' 20070908T07:11:13 '
268 t1 = xmlrpclib.DateTime()
269 t1.decode(d)
270 tref = xmlrpclib.DateTime(datetime.datetime(2007,9,8,7,11,13))
271 self.assertEqual(t1, tref)
272
273 t2 = xmlrpclib._datetime(d)
274 self.assertEqual(t1, tref)
275
276class BinaryTestCase(unittest.TestCase):
277 def test_default(self):
278 t = xmlrpclib.Binary()
279 self.assertEqual(str(t), '')
280
281 def test_string(self):
282 d = '\x01\x02\x03abc123\xff\xfe'
283 t = xmlrpclib.Binary(d)
284 self.assertEqual(str(t), d)
285
286 def test_decode(self):
287 d = '\x01\x02\x03abc123\xff\xfe'
288 de = base64.encodestring(d)
289 t1 = xmlrpclib.Binary()
290 t1.decode(de)
291 self.assertEqual(str(t1), d)
292
293 t2 = xmlrpclib._binary(de)
294 self.assertEqual(str(t2), d)
295
296
Facundo Batistaa53872b2007-08-14 13:35:00 +0000297PORT = None
Skip Montanaro419abda2001-10-01 17:47:44 +0000298
Facundo Batistaa53872b2007-08-14 13:35:00 +0000299def http_server(evt, numrequests):
300 class TestInstanceClass:
301 def div(self, x, y):
Facundo Batistaa53872b2007-08-14 13:35:00 +0000302 return x // y
303
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000304 def _methodHelp(self, name):
305 if name == 'div':
306 return 'This is the div function'
307
308 def my_function():
309 '''This is my function'''
310 return True
311
Facundo Batistaa53872b2007-08-14 13:35:00 +0000312 try:
Facundo Batista7f686fc2007-08-17 19:16:44 +0000313 serv = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 0),
314 logRequests=False, bind_and_activate=False)
Facundo Batistaa53872b2007-08-14 13:35:00 +0000315 serv.socket.settimeout(3)
316 serv.server_bind()
317 global PORT
318 PORT = serv.socket.getsockname()[1]
319 serv.server_activate()
320 serv.register_introspection_functions()
321 serv.register_multicall_functions()
322 serv.register_function(pow)
323 serv.register_function(lambda x,y: x+y, 'add')
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000324 serv.register_function(my_function)
Facundo Batistaa53872b2007-08-14 13:35:00 +0000325 serv.register_instance(TestInstanceClass())
326
327 # handle up to 'numrequests' requests
328 while numrequests > 0:
329 serv.handle_request()
330 numrequests -= 1
331
332 except socket.timeout:
333 pass
334 finally:
335 serv.socket.close()
336 PORT = None
337 evt.set()
338
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000339def is_unavailable_exception(e):
340 '''Returns True if the given ProtocolError is the product of a server-side
341 exception caused by the 'temporarily unavailable' response sometimes
342 given by operations on non-blocking sockets.'''
343 # sometimes we get a -1 error code and/or empty headers
344 if e.errcode == -1 or e.headers is None:
345 return True
346
347 exc_mess = e.headers.get('X-exception')
348 if exc_mess and 'temporarily unavailable' in exc_mess.lower():
349 return True
350
351 return False
352
353# NOTE: The tests in SimpleServerTestCase will ignore failures caused by
354# "temporarily unavailable" exceptions raised in SimpleXMLRPCServer. This
355# condition occurs infrequently on some platforms, frequently on others, and
356# is apparently caused by using SimpleXMLRPCServer with a non-blocking socket.
357# If the server class is updated at some point in the future to handle this
358# situation more gracefully, these tests should be modified appropriately.
359
Facundo Batista7f686fc2007-08-17 19:16:44 +0000360class SimpleServerTestCase(unittest.TestCase):
Facundo Batistaa53872b2007-08-14 13:35:00 +0000361 def setUp(self):
Facundo Batista7f686fc2007-08-17 19:16:44 +0000362 # enable traceback reporting
363 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
364
Facundo Batistaa53872b2007-08-14 13:35:00 +0000365 self.evt = threading.Event()
Facundo Batista7f686fc2007-08-17 19:16:44 +0000366 # start server thread to handle requests
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000367 serv_args = (self.evt, 1)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000368 threading.Thread(target=http_server, args=serv_args).start()
Facundo Batistaa53872b2007-08-14 13:35:00 +0000369
370 # wait for port to be assigned to server
371 n = 1000
372 while n > 0 and PORT is None:
373 time.sleep(0.001)
374 n -= 1
375
376 time.sleep(0.5)
377
378 def tearDown(self):
379 # wait on the server thread to terminate
380 self.evt.wait()
381
Facundo Batista7f686fc2007-08-17 19:16:44 +0000382 # disable traceback reporting
383 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
384
Facundo Batistaa53872b2007-08-14 13:35:00 +0000385 def test_simple1(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000386 try:
387 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
388 self.assertEqual(p.pow(6,8), 6**8)
389 except xmlrpclib.ProtocolError, e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000390 # ignore failures due to non-blocking socket 'unavailable' errors
391 if not is_unavailable_exception(e):
392 # protocol error; provide additional information in test output
393 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000394
Christian Heimes6c29be52008-01-19 16:39:27 +0000395 # [ch] The test 404 is causing lots of false alarms.
396 def XXXtest_404(self):
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000397 # send POST with httplib, it should return 404 header and
398 # 'Not Found' message.
399 conn = httplib.HTTPConnection('localhost', PORT)
400 conn.request('POST', '/this-is-not-valid')
401 response = conn.getresponse()
402 conn.close()
403
404 self.assertEqual(response.status, 404)
405 self.assertEqual(response.reason, 'Not Found')
406
Facundo Batistaa53872b2007-08-14 13:35:00 +0000407 def test_introspection1(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000408 try:
409 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
410 meth = p.system.listMethods()
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000411 expected_methods = set(['pow', 'div', 'my_function', 'add',
412 'system.listMethods', 'system.methodHelp',
413 'system.methodSignature', 'system.multicall'])
Facundo Batistac65a5f12007-08-21 00:16:21 +0000414 self.assertEqual(set(meth), expected_methods)
415 except xmlrpclib.ProtocolError, e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000416 # ignore failures due to non-blocking socket 'unavailable' errors
417 if not is_unavailable_exception(e):
418 # protocol error; provide additional information in test output
419 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000420
421 def test_introspection2(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000422 try:
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000423 # test _methodHelp()
Facundo Batistac65a5f12007-08-21 00:16:21 +0000424 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
425 divhelp = p.system.methodHelp('div')
426 self.assertEqual(divhelp, 'This is the div function')
427 except xmlrpclib.ProtocolError, e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000428 # ignore failures due to non-blocking socket 'unavailable' errors
429 if not is_unavailable_exception(e):
430 # protocol error; provide additional information in test output
431 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000432
433 def test_introspection3(self):
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000434 try:
435 # test native doc
436 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
437 myfunction = p.system.methodHelp('my_function')
438 self.assertEqual(myfunction, 'This is my function')
439 except xmlrpclib.ProtocolError, e:
440 # ignore failures due to non-blocking socket 'unavailable' errors
441 if not is_unavailable_exception(e):
442 # protocol error; provide additional information in test output
443 self.fail("%s\n%s" % (e, e.headers))
444
445 def test_introspection4(self):
Facundo Batistaa53872b2007-08-14 13:35:00 +0000446 # the SimpleXMLRPCServer doesn't support signatures, but
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000447 # at least check that we can try making the call
Facundo Batistac65a5f12007-08-21 00:16:21 +0000448 try:
449 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
450 divsig = p.system.methodSignature('div')
451 self.assertEqual(divsig, 'signatures not supported')
452 except xmlrpclib.ProtocolError, e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000453 # ignore failures due to non-blocking socket 'unavailable' errors
454 if not is_unavailable_exception(e):
455 # protocol error; provide additional information in test output
456 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000457
458 def test_multicall(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000459 try:
460 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
461 multicall = xmlrpclib.MultiCall(p)
462 multicall.add(2,3)
463 multicall.pow(6,8)
464 multicall.div(127,42)
465 add_result, pow_result, div_result = multicall()
466 self.assertEqual(add_result, 2+3)
467 self.assertEqual(pow_result, 6**8)
468 self.assertEqual(div_result, 127//42)
469 except xmlrpclib.ProtocolError, e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000470 # ignore failures due to non-blocking socket 'unavailable' errors
471 if not is_unavailable_exception(e):
472 # protocol error; provide additional information in test output
473 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000474
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000475 def test_non_existing_multicall(self):
476 try:
477 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
478 multicall = xmlrpclib.MultiCall(p)
479 multicall.this_is_not_exists()
480 result = multicall()
481
482 # result.results contains;
483 # [{'faultCode': 1, 'faultString': '<type \'exceptions.Exception\'>:'
484 # 'method "this_is_not_exists" is not supported'>}]
485
486 self.assertEqual(result.results[0]['faultCode'], 1)
487 self.assertEqual(result.results[0]['faultString'],
488 '<type \'exceptions.Exception\'>:method "this_is_not_exists" '
489 'is not supported')
490 except xmlrpclib.ProtocolError, e:
491 # ignore failures due to non-blocking socket 'unavailable' errors
492 if not is_unavailable_exception(e):
493 # protocol error; provide additional information in test output
494 self.fail("%s\n%s" % (e, e.headers))
495
496 def test_dotted_attribute(self):
497 # this will raise AttirebuteError because code don't want us to use
498 # private methods
499 self.assertRaises(AttributeError,
500 SimpleXMLRPCServer.resolve_dotted_attribute, str, '__add')
501
502 self.assert_(SimpleXMLRPCServer.resolve_dotted_attribute(str, 'title'))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000503
Facundo Batista7f686fc2007-08-17 19:16:44 +0000504# This is a contrived way to make a failure occur on the server side
505# in order to test the _send_traceback_header flag on the server
506class FailingMessageClass(mimetools.Message):
507 def __getitem__(self, key):
508 key = key.lower()
509 if key == 'content-length':
510 return 'I am broken'
511 return mimetools.Message.__getitem__(self, key)
512
513
514class FailingServerTestCase(unittest.TestCase):
515 def setUp(self):
516 self.evt = threading.Event()
517 # start server thread to handle requests
518 serv_args = (self.evt, 2)
519 threading.Thread(target=http_server, args=serv_args).start()
520
521 # wait for port to be assigned to server
522 n = 1000
523 while n > 0 and PORT is None:
524 time.sleep(0.001)
525 n -= 1
526
527 time.sleep(0.5)
528
529 def tearDown(self):
530 # wait on the server thread to terminate
531 self.evt.wait()
532 # reset flag
533 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
534 # reset message class
535 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
536
537 def test_basic(self):
538 # check that flag is false by default
539 flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header
540 self.assertEqual(flagval, False)
541
Facundo Batistac65a5f12007-08-21 00:16:21 +0000542 # enable traceback reporting
543 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
544
545 # test a call that shouldn't fail just as a smoke test
546 try:
547 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
548 self.assertEqual(p.pow(6,8), 6**8)
549 except xmlrpclib.ProtocolError, e:
Facundo Batista492e5922007-08-29 10:28:28 +0000550 # ignore failures due to non-blocking socket 'unavailable' errors
551 if not is_unavailable_exception(e):
552 # protocol error; provide additional information in test output
553 self.fail("%s\n%s" % (e, e.headers))
Facundo Batista7f686fc2007-08-17 19:16:44 +0000554
555 def test_fail_no_info(self):
556 # use the broken message class
557 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
558
559 try:
560 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
561 p.pow(6,8)
562 except xmlrpclib.ProtocolError, e:
Facundo Batista492e5922007-08-29 10:28:28 +0000563 # ignore failures due to non-blocking socket 'unavailable' errors
564 if not is_unavailable_exception(e):
565 # The two server-side error headers shouldn't be sent back in this case
566 self.assertTrue(e.headers.get("X-exception") is None)
567 self.assertTrue(e.headers.get("X-traceback") is None)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000568 else:
569 self.fail('ProtocolError not raised')
570
571 def test_fail_with_info(self):
572 # use the broken message class
573 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
574
575 # Check that errors in the server send back exception/traceback
576 # info when flag is set
577 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
578
579 try:
580 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
581 p.pow(6,8)
582 except xmlrpclib.ProtocolError, e:
Facundo Batista492e5922007-08-29 10:28:28 +0000583 # ignore failures due to non-blocking socket 'unavailable' errors
584 if not is_unavailable_exception(e):
585 # We should get error info in the response
586 expected_err = "invalid literal for int() with base 10: 'I am broken'"
587 self.assertEqual(e.headers.get("x-exception"), expected_err)
588 self.assertTrue(e.headers.get("x-traceback") is not None)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000589 else:
590 self.fail('ProtocolError not raised')
591
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000592class CGIHandlerTestCase(unittest.TestCase):
593 def setUp(self):
594 self.cgi = SimpleXMLRPCServer.CGIXMLRPCRequestHandler()
595
596 def tearDown(self):
597 self.cgi = None
598
599 def test_cgi_get(self):
600 os.environ['REQUEST_METHOD'] = 'GET'
601 # if the method is GET and no request_text is given, it runs handle_get
602 # get sysout output
603 tmp = sys.stdout
604 sys.stdout = open(test_support.TESTFN, "w")
605 self.cgi.handle_request()
606 sys.stdout.close()
607 sys.stdout = tmp
608
609 # parse Status header
610 handle = open(test_support.TESTFN, "r").read()
611 status = handle.split()[1]
612 message = ' '.join(handle.split()[2:4])
613
614 self.assertEqual(status, '400')
615 self.assertEqual(message, 'Bad Request')
616
617 os.remove(test_support.TESTFN)
618 os.environ['REQUEST_METHOD'] = ''
619
620 def test_cgi_xmlrpc_response(self):
621 data = """<?xml version='1.0'?>
622<methodCall>
623 <methodName>test_method</methodName>
624 <params>
625 <param>
626 <value><string>foo</string></value>
627 </param>
628 <param>
629 <value><string>bar</string></value>
630 </param>
631 </params>
632</methodCall>
633"""
634 open("xmldata.txt", "w").write(data)
635 tmp1 = sys.stdin
636 tmp2 = sys.stdout
637
638 sys.stdin = open("xmldata.txt", "r")
639 sys.stdout = open(test_support.TESTFN, "w")
640
641 self.cgi.handle_request()
642
643 sys.stdin.close()
644 sys.stdout.close()
645 sys.stdin = tmp1
646 sys.stdout = tmp2
647
648 # will respond exception, if so, our goal is achieved ;)
649 handle = open(test_support.TESTFN, "r").read()
650
651 # start with 44th char so as not to get http header, we just need only xml
652 self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, handle[44:])
653
654 os.remove("xmldata.txt")
655 os.remove(test_support.TESTFN)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000656
Facundo Batistaa53872b2007-08-14 13:35:00 +0000657def test_main():
658 xmlrpc_tests = [XMLRPCTestCase, HelperTestCase, DateTimeTestCase,
659 BinaryTestCase, FaultTestCase]
660
661 # The test cases against a SimpleXMLRPCServer raise a socket error
662 # 10035 (WSAEWOULDBLOCK) in the server thread handle_request call when
663 # run on Windows. This only happens on the first test to run, but it
664 # fails every time and so these tests are skipped on win32 platforms.
665 if sys.platform != 'win32':
Facundo Batista7f686fc2007-08-17 19:16:44 +0000666 xmlrpc_tests.append(SimpleServerTestCase)
667 xmlrpc_tests.append(FailingServerTestCase)
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000668 xmlrpc_tests.append(CGIHandlerTestCase)
Facundo Batistaa53872b2007-08-14 13:35:00 +0000669
670 test_support.run_unittest(*xmlrpc_tests)
Skip Montanaro419abda2001-10-01 17:47:44 +0000671
672if __name__ == "__main__":
673 test_main()