blob: 70a6b39f6892a884fb25dfdfd5625f7964950967 [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
Neal Norwitzed444e52008-01-27 18:19:04 +0000351 try:
352 if e.errcode == -1 or e.headers is None:
353 return True
354 exc_mess = e.headers.get('X-exception')
355 except AttributeError:
356 # Ignore socket.errors here.
357 exc_mess = str(e)
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000358
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000359 if exc_mess and 'temporarily unavailable' in exc_mess.lower():
360 return True
361
362 return False
363
364# NOTE: The tests in SimpleServerTestCase will ignore failures caused by
365# "temporarily unavailable" exceptions raised in SimpleXMLRPCServer. This
366# condition occurs infrequently on some platforms, frequently on others, and
367# is apparently caused by using SimpleXMLRPCServer with a non-blocking socket.
368# If the server class is updated at some point in the future to handle this
369# situation more gracefully, these tests should be modified appropriately.
370
Facundo Batista7f686fc2007-08-17 19:16:44 +0000371class SimpleServerTestCase(unittest.TestCase):
Facundo Batistaa53872b2007-08-14 13:35:00 +0000372 def setUp(self):
Facundo Batista7f686fc2007-08-17 19:16:44 +0000373 # enable traceback reporting
374 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
375
Facundo Batistaa53872b2007-08-14 13:35:00 +0000376 self.evt = threading.Event()
Facundo Batista7f686fc2007-08-17 19:16:44 +0000377 # start server thread to handle requests
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000378 serv_args = (self.evt, 1)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000379 threading.Thread(target=http_server, args=serv_args).start()
Facundo Batistaa53872b2007-08-14 13:35:00 +0000380
Neal Norwitz653272f2008-01-26 07:26:12 +0000381 # wait for the server to be ready
382 self.evt.wait()
383 self.evt.clear()
Facundo Batistaa53872b2007-08-14 13:35:00 +0000384
385 def tearDown(self):
386 # wait on the server thread to terminate
387 self.evt.wait()
388
Facundo Batista7f686fc2007-08-17 19:16:44 +0000389 # disable traceback reporting
390 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
391
Facundo Batistaa53872b2007-08-14 13:35:00 +0000392 def test_simple1(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000393 try:
394 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
395 self.assertEqual(p.pow(6,8), 6**8)
Neal Norwitz183c5342008-01-27 17:11:11 +0000396 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000397 # ignore failures due to non-blocking socket 'unavailable' errors
398 if not is_unavailable_exception(e):
399 # protocol error; provide additional information in test output
400 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000401
Christian Heimes6c29be52008-01-19 16:39:27 +0000402 # [ch] The test 404 is causing lots of false alarms.
403 def XXXtest_404(self):
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000404 # send POST with httplib, it should return 404 header and
405 # 'Not Found' message.
406 conn = httplib.HTTPConnection('localhost', PORT)
407 conn.request('POST', '/this-is-not-valid')
408 response = conn.getresponse()
409 conn.close()
410
411 self.assertEqual(response.status, 404)
412 self.assertEqual(response.reason, 'Not Found')
413
Facundo Batistaa53872b2007-08-14 13:35:00 +0000414 def test_introspection1(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000415 try:
416 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
417 meth = p.system.listMethods()
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000418 expected_methods = set(['pow', 'div', 'my_function', 'add',
419 'system.listMethods', 'system.methodHelp',
420 'system.methodSignature', 'system.multicall'])
Facundo Batistac65a5f12007-08-21 00:16:21 +0000421 self.assertEqual(set(meth), expected_methods)
Neal Norwitz183c5342008-01-27 17:11:11 +0000422 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000423 # ignore failures due to non-blocking socket 'unavailable' errors
424 if not is_unavailable_exception(e):
425 # protocol error; provide additional information in test output
426 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000427
428 def test_introspection2(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000429 try:
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000430 # test _methodHelp()
Facundo Batistac65a5f12007-08-21 00:16:21 +0000431 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
432 divhelp = p.system.methodHelp('div')
433 self.assertEqual(divhelp, 'This is the div function')
Neal Norwitz183c5342008-01-27 17:11:11 +0000434 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000435 # ignore failures due to non-blocking socket 'unavailable' errors
436 if not is_unavailable_exception(e):
437 # protocol error; provide additional information in test output
438 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000439
440 def test_introspection3(self):
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000441 try:
442 # test native doc
443 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
444 myfunction = p.system.methodHelp('my_function')
445 self.assertEqual(myfunction, 'This is my function')
Neal Norwitz183c5342008-01-27 17:11:11 +0000446 except (xmlrpclib.ProtocolError, socket.error), e:
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000447 # ignore failures due to non-blocking socket 'unavailable' errors
448 if not is_unavailable_exception(e):
449 # protocol error; provide additional information in test output
450 self.fail("%s\n%s" % (e, e.headers))
451
452 def test_introspection4(self):
Facundo Batistaa53872b2007-08-14 13:35:00 +0000453 # the SimpleXMLRPCServer doesn't support signatures, but
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000454 # at least check that we can try making the call
Facundo Batistac65a5f12007-08-21 00:16:21 +0000455 try:
456 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
457 divsig = p.system.methodSignature('div')
458 self.assertEqual(divsig, 'signatures not supported')
Neal Norwitz183c5342008-01-27 17:11:11 +0000459 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000460 # ignore failures due to non-blocking socket 'unavailable' errors
461 if not is_unavailable_exception(e):
462 # protocol error; provide additional information in test output
463 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000464
465 def test_multicall(self):
Facundo Batistac65a5f12007-08-21 00:16:21 +0000466 try:
467 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
468 multicall = xmlrpclib.MultiCall(p)
469 multicall.add(2,3)
470 multicall.pow(6,8)
471 multicall.div(127,42)
472 add_result, pow_result, div_result = multicall()
473 self.assertEqual(add_result, 2+3)
474 self.assertEqual(pow_result, 6**8)
475 self.assertEqual(div_result, 127//42)
Neal Norwitz183c5342008-01-27 17:11:11 +0000476 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batistaf91ad6a2007-08-27 01:15:34 +0000477 # ignore failures due to non-blocking socket 'unavailable' errors
478 if not is_unavailable_exception(e):
479 # protocol error; provide additional information in test output
480 self.fail("%s\n%s" % (e, e.headers))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000481
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000482 def test_non_existing_multicall(self):
483 try:
484 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
485 multicall = xmlrpclib.MultiCall(p)
486 multicall.this_is_not_exists()
487 result = multicall()
488
489 # result.results contains;
490 # [{'faultCode': 1, 'faultString': '<type \'exceptions.Exception\'>:'
491 # 'method "this_is_not_exists" is not supported'>}]
492
493 self.assertEqual(result.results[0]['faultCode'], 1)
494 self.assertEqual(result.results[0]['faultString'],
495 '<type \'exceptions.Exception\'>:method "this_is_not_exists" '
496 'is not supported')
Neal Norwitz183c5342008-01-27 17:11:11 +0000497 except (xmlrpclib.ProtocolError, socket.error), e:
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000498 # ignore failures due to non-blocking socket 'unavailable' errors
499 if not is_unavailable_exception(e):
500 # protocol error; provide additional information in test output
501 self.fail("%s\n%s" % (e, e.headers))
502
503 def test_dotted_attribute(self):
504 # this will raise AttirebuteError because code don't want us to use
505 # private methods
506 self.assertRaises(AttributeError,
507 SimpleXMLRPCServer.resolve_dotted_attribute, str, '__add')
508
509 self.assert_(SimpleXMLRPCServer.resolve_dotted_attribute(str, 'title'))
Facundo Batistaa53872b2007-08-14 13:35:00 +0000510
Facundo Batista7f686fc2007-08-17 19:16:44 +0000511# This is a contrived way to make a failure occur on the server side
512# in order to test the _send_traceback_header flag on the server
513class FailingMessageClass(mimetools.Message):
514 def __getitem__(self, key):
515 key = key.lower()
516 if key == 'content-length':
517 return 'I am broken'
518 return mimetools.Message.__getitem__(self, key)
519
520
521class FailingServerTestCase(unittest.TestCase):
522 def setUp(self):
523 self.evt = threading.Event()
524 # start server thread to handle requests
525 serv_args = (self.evt, 2)
526 threading.Thread(target=http_server, args=serv_args).start()
527
Neal Norwitz653272f2008-01-26 07:26:12 +0000528 # wait for the server to be ready
529 self.evt.wait()
530 self.evt.clear()
Facundo Batista7f686fc2007-08-17 19:16:44 +0000531
532 def tearDown(self):
533 # wait on the server thread to terminate
534 self.evt.wait()
535 # reset flag
536 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
537 # reset message class
538 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
539
540 def test_basic(self):
541 # check that flag is false by default
542 flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header
543 self.assertEqual(flagval, False)
544
Facundo Batistac65a5f12007-08-21 00:16:21 +0000545 # enable traceback reporting
546 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
547
548 # test a call that shouldn't fail just as a smoke test
549 try:
550 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
551 self.assertEqual(p.pow(6,8), 6**8)
Neal Norwitz183c5342008-01-27 17:11:11 +0000552 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batista492e5922007-08-29 10:28:28 +0000553 # ignore failures due to non-blocking socket 'unavailable' errors
554 if not is_unavailable_exception(e):
555 # protocol error; provide additional information in test output
556 self.fail("%s\n%s" % (e, e.headers))
Facundo Batista7f686fc2007-08-17 19:16:44 +0000557
558 def test_fail_no_info(self):
559 # use the broken message class
560 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
561
562 try:
563 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
564 p.pow(6,8)
Neal Norwitz183c5342008-01-27 17:11:11 +0000565 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batista492e5922007-08-29 10:28:28 +0000566 # ignore failures due to non-blocking socket 'unavailable' errors
567 if not is_unavailable_exception(e):
568 # The two server-side error headers shouldn't be sent back in this case
569 self.assertTrue(e.headers.get("X-exception") is None)
570 self.assertTrue(e.headers.get("X-traceback") is None)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000571 else:
572 self.fail('ProtocolError not raised')
573
574 def test_fail_with_info(self):
575 # use the broken message class
576 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
577
578 # Check that errors in the server send back exception/traceback
579 # info when flag is set
580 SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
581
582 try:
583 p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
584 p.pow(6,8)
Neal Norwitz183c5342008-01-27 17:11:11 +0000585 except (xmlrpclib.ProtocolError, socket.error), e:
Facundo Batista492e5922007-08-29 10:28:28 +0000586 # ignore failures due to non-blocking socket 'unavailable' errors
587 if not is_unavailable_exception(e):
588 # We should get error info in the response
589 expected_err = "invalid literal for int() with base 10: 'I am broken'"
590 self.assertEqual(e.headers.get("x-exception"), expected_err)
591 self.assertTrue(e.headers.get("x-traceback") is not None)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000592 else:
593 self.fail('ProtocolError not raised')
594
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000595class CGIHandlerTestCase(unittest.TestCase):
596 def setUp(self):
597 self.cgi = SimpleXMLRPCServer.CGIXMLRPCRequestHandler()
598
599 def tearDown(self):
600 self.cgi = None
601
602 def test_cgi_get(self):
603 os.environ['REQUEST_METHOD'] = 'GET'
604 # if the method is GET and no request_text is given, it runs handle_get
605 # get sysout output
606 tmp = sys.stdout
607 sys.stdout = open(test_support.TESTFN, "w")
608 self.cgi.handle_request()
609 sys.stdout.close()
610 sys.stdout = tmp
611
612 # parse Status header
613 handle = open(test_support.TESTFN, "r").read()
614 status = handle.split()[1]
615 message = ' '.join(handle.split()[2:4])
616
617 self.assertEqual(status, '400')
618 self.assertEqual(message, 'Bad Request')
619
620 os.remove(test_support.TESTFN)
621 os.environ['REQUEST_METHOD'] = ''
622
623 def test_cgi_xmlrpc_response(self):
624 data = """<?xml version='1.0'?>
625<methodCall>
626 <methodName>test_method</methodName>
627 <params>
628 <param>
629 <value><string>foo</string></value>
630 </param>
631 <param>
632 <value><string>bar</string></value>
633 </param>
634 </params>
635</methodCall>
636"""
637 open("xmldata.txt", "w").write(data)
638 tmp1 = sys.stdin
639 tmp2 = sys.stdout
640
641 sys.stdin = open("xmldata.txt", "r")
642 sys.stdout = open(test_support.TESTFN, "w")
643
644 self.cgi.handle_request()
645
646 sys.stdin.close()
647 sys.stdout.close()
648 sys.stdin = tmp1
649 sys.stdout = tmp2
650
651 # will respond exception, if so, our goal is achieved ;)
652 handle = open(test_support.TESTFN, "r").read()
653
654 # start with 44th char so as not to get http header, we just need only xml
655 self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, handle[44:])
656
657 os.remove("xmldata.txt")
658 os.remove(test_support.TESTFN)
Facundo Batista7f686fc2007-08-17 19:16:44 +0000659
Facundo Batistaa53872b2007-08-14 13:35:00 +0000660def test_main():
661 xmlrpc_tests = [XMLRPCTestCase, HelperTestCase, DateTimeTestCase,
662 BinaryTestCase, FaultTestCase]
663
664 # The test cases against a SimpleXMLRPCServer raise a socket error
665 # 10035 (WSAEWOULDBLOCK) in the server thread handle_request call when
666 # run on Windows. This only happens on the first test to run, but it
667 # fails every time and so these tests are skipped on win32 platforms.
668 if sys.platform != 'win32':
Facundo Batista7f686fc2007-08-17 19:16:44 +0000669 xmlrpc_tests.append(SimpleServerTestCase)
670 xmlrpc_tests.append(FailingServerTestCase)
Georg Brandl5d1b4d42007-12-07 09:07:10 +0000671 xmlrpc_tests.append(CGIHandlerTestCase)
Facundo Batistaa53872b2007-08-14 13:35:00 +0000672
673 test_support.run_unittest(*xmlrpc_tests)
Skip Montanaro419abda2001-10-01 17:47:44 +0000674
675if __name__ == "__main__":
676 test_main()