blob: eb39d27759c3de90152bb12d992f7bb0e76e0a35 [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
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000395 def test_404(self):
396 # send POST with httplib, it should return 404 header and
397 # 'Not Found' message.
398 conn = httplib.HTTPConnection('localhost', PORT)
399 conn.request('POST', '/this-is-not-valid')
400 response = conn.getresponse()
401 conn.close()
402
403 self.assertEqual(response.status, 404)
404 self.assertEqual(response.reason, 'Not Found')
405
Facundo Batistaa53872b2007-08-14 13:35:00 +0000406 def test_introspection1(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000407 try:
408 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
409 meth = p.system.listMethods()
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000410 expected_methods = set(['pow', 'div', 'my_function', 'add',
411 'system.listMethods', 'system.methodHelp',
412 'system.methodSignature', 'system.multicall'])
Facundo Batistac65a5f12007-08-21 00:16:21 +0000413 self.assertEqual(set(meth), expected_methods)
414 except xmlrpclib.ProtocolError, e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000415 # ignore failures due to non-blocking socket 'unavailable' errors
416 if not is_unavailable_exception(e):
417 # protocol error; provide additional information in test output
418 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000419
420 def test_introspection2(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000421 try:
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000422 # test _methodHelp()
Facundo Batistac65a5f12007-08-21 00:16:21 +0000423 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
424 divhelp = p.system.methodHelp('div')
425 self.assertEqual(divhelp, 'This is the div function')
426 except xmlrpclib.ProtocolError, e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000427 # ignore failures due to non-blocking socket 'unavailable' errors
428 if not is_unavailable_exception(e):
429 # protocol error; provide additional information in test output
430 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000431
432 def test_introspection3(self):
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000433 try:
434 # test native doc
435 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
436 myfunction = p.system.methodHelp('my_function')
437 self.assertEqual(myfunction, 'This is my function')
438 except xmlrpclib.ProtocolError, e:
439 # ignore failures due to non-blocking socket 'unavailable' errors
440 if not is_unavailable_exception(e):
441 # protocol error; provide additional information in test output
442 self.fail("%s\n%s" % (e, e.headers))
443
444 def test_introspection4(self):
Facundo Batistaa53872b2007-08-14 13:35:00 +0000445 # the SimpleXMLRPCServer doesn't support signatures, but
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000446 # at least check that we can try making the call
Facundo Batistac65a5f12007-08-21 00:16:21 +0000447 try:
448 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
449 divsig = p.system.methodSignature('div')
450 self.assertEqual(divsig, 'signatures not supported')
451 except xmlrpclib.ProtocolError, e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000452 # ignore failures due to non-blocking socket 'unavailable' errors
453 if not is_unavailable_exception(e):
454 # protocol error; provide additional information in test output
455 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000456
457 def test_multicall(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000458 try:
459 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
460 multicall = xmlrpclib.MultiCall(p)
461 multicall.add(2,3)
462 multicall.pow(6,8)
463 multicall.div(127,42)
464 add_result, pow_result, div_result = multicall()
465 self.assertEqual(add_result, 2+3)
466 self.assertEqual(pow_result, 6**8)
467 self.assertEqual(div_result, 127//42)
468 except xmlrpclib.ProtocolError, e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000469 # ignore failures due to non-blocking socket 'unavailable' errors
470 if not is_unavailable_exception(e):
471 # protocol error; provide additional information in test output
472 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000473
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000474 def test_non_existing_multicall(self):
475 try:
476 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
477 multicall = xmlrpclib.MultiCall(p)
478 multicall.this_is_not_exists()
479 result = multicall()
480
481 # result.results contains;
482 # [{'faultCode': 1, 'faultString': '<type \'exceptions.Exception\'>:'
483 # 'method "this_is_not_exists" is not supported'>}]
484
485 self.assertEqual(result.results[0]['faultCode'], 1)
486 self.assertEqual(result.results[0]['faultString'],
487 '<type \'exceptions.Exception\'>:method "this_is_not_exists" '
488 'is not supported')
489 except xmlrpclib.ProtocolError, e:
490 # ignore failures due to non-blocking socket 'unavailable' errors
491 if not is_unavailable_exception(e):
492 # protocol error; provide additional information in test output
493 self.fail("%s\n%s" % (e, e.headers))
494
495 def test_dotted_attribute(self):
496 # this will raise AttirebuteError because code don't want us to use
497 # private methods
498 self.assertRaises(AttributeError,
499 SimpleXMLRPCServer.resolve_dotted_attribute, str, '__add')
500
501 self.assert_(SimpleXMLRPCServer.resolve_dotted_attribute(str, 'title'))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000502
Facundo Batista7f686fc2007-08-17 19:16:44 +0000503# This is a contrived way to make a failure occur on the server side
504# in order to test the _send_traceback_header flag on the server
505class FailingMessageClass(mimetools.Message):
506 def __getitem__(self, key):
507 key = key.lower()
508 if key == 'content-length':
509 return 'I am broken'
510 return mimetools.Message.__getitem__(self, key)
511
512
513class FailingServerTestCase(unittest.TestCase):
514 def setUp(self):
515 self.evt = threading.Event()
516 # start server thread to handle requests
517 serv_args = (self.evt, 2)
518 threading.Thread(target=http_server, args=serv_args).start()
519
520 # wait for port to be assigned to server
521 n = 1000
522 while n > 0 and PORT is None:
523 time.sleep(0.001)
524 n -= 1
525
526 time.sleep(0.5)
527
528 def tearDown(self):
529 # wait on the server thread to terminate
530 self.evt.wait()
531 # reset flag
532 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
533 # reset message class
534 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
535
536 def test_basic(self):
537 # check that flag is false by default
538 flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header
539 self.assertEqual(flagval, False)
540
Facundo Batistac65a5f12007-08-21 00:16:21 +0000541 # enable traceback reporting
542 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
543
544 # test a call that shouldn't fail just as a smoke test
545 try:
546 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
547 self.assertEqual(p.pow(6,8), 6**8)
548 except xmlrpclib.ProtocolError, e:
Facundo Batista492e5922007-08-29 10:28:28 +0000549 # ignore failures due to non-blocking socket 'unavailable' errors
550 if not is_unavailable_exception(e):
551 # protocol error; provide additional information in test output
552 self.fail("%s\n%s" % (e, e.headers))
Facundo Batista7f686fc2007-08-17 19:16:44 +0000553
554 def test_fail_no_info(self):
555 # use the broken message class
556 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
557
558 try:
559 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
560 p.pow(6,8)
561 except xmlrpclib.ProtocolError, e:
Facundo Batista492e5922007-08-29 10:28:28 +0000562 # ignore failures due to non-blocking socket 'unavailable' errors
563 if not is_unavailable_exception(e):
564 # The two server-side error headers shouldn't be sent back in this case
565 self.assertTrue(e.headers.get("X-exception") is None)
566 self.assertTrue(e.headers.get("X-traceback") is None)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000567 else:
568 self.fail('ProtocolError not raised')
569
570 def test_fail_with_info(self):
571 # use the broken message class
572 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
573
574 # Check that errors in the server send back exception/traceback
575 # info when flag is set
576 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
577
578 try:
579 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
580 p.pow(6,8)
581 except xmlrpclib.ProtocolError, e:
Facundo Batista492e5922007-08-29 10:28:28 +0000582 # ignore failures due to non-blocking socket 'unavailable' errors
583 if not is_unavailable_exception(e):
584 # We should get error info in the response
585 expected_err = "invalid literal for int() with base 10: 'I am broken'"
586 self.assertEqual(e.headers.get("x-exception"), expected_err)
587 self.assertTrue(e.headers.get("x-traceback") is not None)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000588 else:
589 self.fail('ProtocolError not raised')
590
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000591class CGIHandlerTestCase(unittest.TestCase):
592 def setUp(self):
593 self.cgi = SimpleXMLRPCServer.CGIXMLRPCRequestHandler()
594
595 def tearDown(self):
596 self.cgi = None
597
598 def test_cgi_get(self):
599 os.environ['REQUEST_METHOD'] = 'GET'
600 # if the method is GET and no request_text is given, it runs handle_get
601 # get sysout output
602 tmp = sys.stdout
603 sys.stdout = open(test_support.TESTFN, "w")
604 self.cgi.handle_request()
605 sys.stdout.close()
606 sys.stdout = tmp
607
608 # parse Status header
609 handle = open(test_support.TESTFN, "r").read()
610 status = handle.split()[1]
611 message = ' '.join(handle.split()[2:4])
612
613 self.assertEqual(status, '400')
614 self.assertEqual(message, 'Bad Request')
615
616 os.remove(test_support.TESTFN)
617 os.environ['REQUEST_METHOD'] = ''
618
619 def test_cgi_xmlrpc_response(self):
620 data = """<?xml version='1.0'?>
621<methodCall>
622 <methodName>test_method</methodName>
623 <params>
624 <param>
625 <value><string>foo</string></value>
626 </param>
627 <param>
628 <value><string>bar</string></value>
629 </param>
630 </params>
631</methodCall>
632"""
633 open("xmldata.txt", "w").write(data)
634 tmp1 = sys.stdin
635 tmp2 = sys.stdout
636
637 sys.stdin = open("xmldata.txt", "r")
638 sys.stdout = open(test_support.TESTFN, "w")
639
640 self.cgi.handle_request()
641
642 sys.stdin.close()
643 sys.stdout.close()
644 sys.stdin = tmp1
645 sys.stdout = tmp2
646
647 # will respond exception, if so, our goal is achieved ;)
648 handle = open(test_support.TESTFN, "r").read()
649
650 # start with 44th char so as not to get http header, we just need only xml
651 self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, handle[44:])
652
653 os.remove("xmldata.txt")
654 os.remove(test_support.TESTFN)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000655
Facundo Batistaa53872b2007-08-14 13:35:00 +0000656def test_main():
657 xmlrpc_tests = [XMLRPCTestCase, HelperTestCase, DateTimeTestCase,
658 BinaryTestCase, FaultTestCase]
659
660 # The test cases against a SimpleXMLRPCServer raise a socket error
661 # 10035 (WSAEWOULDBLOCK) in the server thread handle_request call when
662 # run on Windows. This only happens on the first test to run, but it
663 # fails every time and so these tests are skipped on win32 platforms.
664 if sys.platform != 'win32':
Facundo Batista7f686fc2007-08-17 19:16:44 +0000665 xmlrpc_tests.append(SimpleServerTestCase)
666 xmlrpc_tests.append(FailingServerTestCase)
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000667 xmlrpc_tests.append(CGIHandlerTestCase)
Facundo Batistaa53872b2007-08-14 13:35:00 +0000668
669 test_support.run_unittest(*xmlrpc_tests)
Skip Montanaro419abda2001-10-01 17:47:44 +0000670
671if __name__ == "__main__":
672 test_main()