blob: 17d7a7a134fc09dc5557a1954b1bc903ddf5ebd5 [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
Neal Norwitz653272f2008-01-26 07:26:12 +0000299# The evt is set twice. First when the server is ready to serve.
300# Second when the server has been shutdown. The user must clear
301# the event after it has been set the first time to catch the second set.
Facundo Batistaa53872b2007-08-14 13:35:00 +0000302def http_server(evt, numrequests):
303 class TestInstanceClass:
304 def div(self, x, y):
Facundo Batistaa53872b2007-08-14 13:35:00 +0000305 return x // y
306
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000307 def _methodHelp(self, name):
308 if name == 'div':
309 return 'This is the div function'
310
311 def my_function():
312 '''This is my function'''
313 return True
314
Facundo Batistaa53872b2007-08-14 13:35:00 +0000315 try:
Facundo Batista7f686fc2007-08-17 19:16:44 +0000316 serv = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 0),
317 logRequests=False, bind_and_activate=False)
Facundo Batistaa53872b2007-08-14 13:35:00 +0000318 serv.socket.settimeout(3)
319 serv.server_bind()
320 global PORT
321 PORT = serv.socket.getsockname()[1]
322 serv.server_activate()
323 serv.register_introspection_functions()
324 serv.register_multicall_functions()
325 serv.register_function(pow)
326 serv.register_function(lambda x,y: x+y, 'add')
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000327 serv.register_function(my_function)
Facundo Batistaa53872b2007-08-14 13:35:00 +0000328 serv.register_instance(TestInstanceClass())
Neal Norwitz653272f2008-01-26 07:26:12 +0000329 evt.set()
Facundo Batistaa53872b2007-08-14 13:35:00 +0000330
331 # handle up to 'numrequests' requests
332 while numrequests > 0:
333 serv.handle_request()
334 numrequests -= 1
335
336 except socket.timeout:
337 pass
338 finally:
339 serv.socket.close()
340 PORT = None
341 evt.set()
342
Neal Norwitz08b50eb2008-01-26 08:26:00 +0000343# This function prevents errors like:
344# <ProtocolError for localhost:57527/RPC2: 500 Internal Server Error>
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000345def is_unavailable_exception(e):
346 '''Returns True if the given ProtocolError is the product of a server-side
347 exception caused by the 'temporarily unavailable' response sometimes
348 given by operations on non-blocking sockets.'''
Neal Norwitz653272f2008-01-26 07:26:12 +0000349
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000350 # sometimes we get a -1 error code and/or empty headers
351 if e.errcode == -1 or e.headers is None:
352 return True
353
354 exc_mess = e.headers.get('X-exception')
355 if exc_mess and 'temporarily unavailable' in exc_mess.lower():
356 return True
357
358 return False
359
360# NOTE: The tests in SimpleServerTestCase will ignore failures caused by
361# "temporarily unavailable" exceptions raised in SimpleXMLRPCServer. This
362# condition occurs infrequently on some platforms, frequently on others, and
363# is apparently caused by using SimpleXMLRPCServer with a non-blocking socket.
364# If the server class is updated at some point in the future to handle this
365# situation more gracefully, these tests should be modified appropriately.
366
Facundo Batista7f686fc2007-08-17 19:16:44 +0000367class SimpleServerTestCase(unittest.TestCase):
Facundo Batistaa53872b2007-08-14 13:35:00 +0000368 def setUp(self):
Facundo Batista7f686fc2007-08-17 19:16:44 +0000369 # enable traceback reporting
370 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
371
Facundo Batistaa53872b2007-08-14 13:35:00 +0000372 self.evt = threading.Event()
Facundo Batista7f686fc2007-08-17 19:16:44 +0000373 # start server thread to handle requests
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000374 serv_args = (self.evt, 1)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000375 threading.Thread(target=http_server, args=serv_args).start()
Facundo Batistaa53872b2007-08-14 13:35:00 +0000376
Neal Norwitz653272f2008-01-26 07:26:12 +0000377 # wait for the server to be ready
378 self.evt.wait()
379 self.evt.clear()
Facundo Batistaa53872b2007-08-14 13:35:00 +0000380
381 def tearDown(self):
382 # wait on the server thread to terminate
383 self.evt.wait()
384
Facundo Batista7f686fc2007-08-17 19:16:44 +0000385 # disable traceback reporting
386 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
387
Facundo Batistaa53872b2007-08-14 13:35:00 +0000388 def test_simple1(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000389 try:
390 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
391 self.assertEqual(p.pow(6,8), 6**8)
Neal Norwitz183c5342008-01-27 17:11:11 +0000392 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000393 # ignore failures due to non-blocking socket 'unavailable' errors
394 if not is_unavailable_exception(e):
395 # protocol error; provide additional information in test output
396 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000397
Christian Heimes6c29be52008-01-19 16:39:27 +0000398 # [ch] The test 404 is causing lots of false alarms.
399 def XXXtest_404(self):
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000400 # send POST with httplib, it should return 404 header and
401 # 'Not Found' message.
402 conn = httplib.HTTPConnection('localhost', PORT)
403 conn.request('POST', '/this-is-not-valid')
404 response = conn.getresponse()
405 conn.close()
406
407 self.assertEqual(response.status, 404)
408 self.assertEqual(response.reason, 'Not Found')
409
Facundo Batistaa53872b2007-08-14 13:35:00 +0000410 def test_introspection1(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000411 try:
412 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
413 meth = p.system.listMethods()
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000414 expected_methods = set(['pow', 'div', 'my_function', 'add',
415 'system.listMethods', 'system.methodHelp',
416 'system.methodSignature', 'system.multicall'])
Facundo Batistac65a5f12007-08-21 00:16:21 +0000417 self.assertEqual(set(meth), expected_methods)
Neal Norwitz183c5342008-01-27 17:11:11 +0000418 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000419 # ignore failures due to non-blocking socket 'unavailable' errors
420 if not is_unavailable_exception(e):
421 # protocol error; provide additional information in test output
422 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000423
424 def test_introspection2(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000425 try:
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000426 # test _methodHelp()
Facundo Batistac65a5f12007-08-21 00:16:21 +0000427 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
428 divhelp = p.system.methodHelp('div')
429 self.assertEqual(divhelp, 'This is the div function')
Neal Norwitz183c5342008-01-27 17:11:11 +0000430 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000431 # ignore failures due to non-blocking socket 'unavailable' errors
432 if not is_unavailable_exception(e):
433 # protocol error; provide additional information in test output
434 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000435
436 def test_introspection3(self):
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000437 try:
438 # test native doc
439 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
440 myfunction = p.system.methodHelp('my_function')
441 self.assertEqual(myfunction, 'This is my function')
Neal Norwitz183c5342008-01-27 17:11:11 +0000442 except (xmlrpclib.ProtocolError, socket.error), e:
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000443 # ignore failures due to non-blocking socket 'unavailable' errors
444 if not is_unavailable_exception(e):
445 # protocol error; provide additional information in test output
446 self.fail("%s\n%s" % (e, e.headers))
447
448 def test_introspection4(self):
Facundo Batistaa53872b2007-08-14 13:35:00 +0000449 # the SimpleXMLRPCServer doesn't support signatures, but
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000450 # at least check that we can try making the call
Facundo Batistac65a5f12007-08-21 00:16:21 +0000451 try:
452 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
453 divsig = p.system.methodSignature('div')
454 self.assertEqual(divsig, 'signatures not supported')
Neal Norwitz183c5342008-01-27 17:11:11 +0000455 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000456 # ignore failures due to non-blocking socket 'unavailable' errors
457 if not is_unavailable_exception(e):
458 # protocol error; provide additional information in test output
459 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000460
461 def test_multicall(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000462 try:
463 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
464 multicall = xmlrpclib.MultiCall(p)
465 multicall.add(2,3)
466 multicall.pow(6,8)
467 multicall.div(127,42)
468 add_result, pow_result, div_result = multicall()
469 self.assertEqual(add_result, 2+3)
470 self.assertEqual(pow_result, 6**8)
471 self.assertEqual(div_result, 127//42)
Neal Norwitz183c5342008-01-27 17:11:11 +0000472 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000473 # ignore failures due to non-blocking socket 'unavailable' errors
474 if not is_unavailable_exception(e):
475 # protocol error; provide additional information in test output
476 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000477
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000478 def test_non_existing_multicall(self):
479 try:
480 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
481 multicall = xmlrpclib.MultiCall(p)
482 multicall.this_is_not_exists()
483 result = multicall()
484
485 # result.results contains;
486 # [{'faultCode': 1, 'faultString': '<type \'exceptions.Exception\'>:'
487 # 'method "this_is_not_exists" is not supported'>}]
488
489 self.assertEqual(result.results[0]['faultCode'], 1)
490 self.assertEqual(result.results[0]['faultString'],
491 '<type \'exceptions.Exception\'>:method "this_is_not_exists" '
492 'is not supported')
Neal Norwitz183c5342008-01-27 17:11:11 +0000493 except (xmlrpclib.ProtocolError, socket.error), e:
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000494 # ignore failures due to non-blocking socket 'unavailable' errors
495 if not is_unavailable_exception(e):
496 # protocol error; provide additional information in test output
497 self.fail("%s\n%s" % (e, e.headers))
498
499 def test_dotted_attribute(self):
500 # this will raise AttirebuteError because code don't want us to use
501 # private methods
502 self.assertRaises(AttributeError,
503 SimpleXMLRPCServer.resolve_dotted_attribute, str, '__add')
504
505 self.assert_(SimpleXMLRPCServer.resolve_dotted_attribute(str, 'title'))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000506
Facundo Batista7f686fc2007-08-17 19:16:44 +0000507# This is a contrived way to make a failure occur on the server side
508# in order to test the _send_traceback_header flag on the server
509class FailingMessageClass(mimetools.Message):
510 def __getitem__(self, key):
511 key = key.lower()
512 if key == 'content-length':
513 return 'I am broken'
514 return mimetools.Message.__getitem__(self, key)
515
516
517class FailingServerTestCase(unittest.TestCase):
518 def setUp(self):
519 self.evt = threading.Event()
520 # start server thread to handle requests
521 serv_args = (self.evt, 2)
522 threading.Thread(target=http_server, args=serv_args).start()
523
Neal Norwitz653272f2008-01-26 07:26:12 +0000524 # wait for the server to be ready
525 self.evt.wait()
526 self.evt.clear()
Facundo Batista7f686fc2007-08-17 19:16:44 +0000527
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)
Neal Norwitz183c5342008-01-27 17:11:11 +0000548 except (xmlrpclib.ProtocolError, socket.error), 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)
Neal Norwitz183c5342008-01-27 17:11:11 +0000561 except (xmlrpclib.ProtocolError, socket.error), 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)
Neal Norwitz183c5342008-01-27 17:11:11 +0000581 except (xmlrpclib.ProtocolError, socket.error), 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()