PageRenderTime 72ms CodeModel.GetById 14ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 0ms

/Lib/test/test_xmlrpc.py

http://unladen-swallow.googlecode.com/
Python | 752 lines | 722 code | 23 blank | 7 comment | 2 complexity | 4cb0946e021a2226e0456fd569bdbea8 MD5 | raw file
  1import base64
  2import datetime
  3import sys
  4import time
  5import unittest
  6import xmlrpclib
  7import SimpleXMLRPCServer
  8import threading
  9import mimetools
 10import httplib
 11import socket
 12import StringIO
 13import os
 14from test import test_support
 15
 16try:
 17    unicode
 18except NameError:
 19    have_unicode = False
 20else:
 21    have_unicode = True
 22
 23alist = [{'astring': 'foo@bar.baz.spam',
 24          'afloat': 7283.43,
 25          'anint': 2**20,
 26          'ashortlong': 2L,
 27          'anotherlist': ['.zyx.41'],
 28          'abase64': xmlrpclib.Binary("my dog has fleas"),
 29          'boolean': xmlrpclib.False,
 30          'unicode': u'\u4000\u6000\u8000',
 31          u'ukey\u4000': 'regular value',
 32          'datetime1': xmlrpclib.DateTime('20050210T11:41:23'),
 33          'datetime2': xmlrpclib.DateTime(
 34                        (2005, 02, 10, 11, 41, 23, 0, 1, -1)),
 35          'datetime3': xmlrpclib.DateTime(
 36                        datetime.datetime(2005, 02, 10, 11, 41, 23)),
 37          }]
 38
 39class XMLRPCTestCase(unittest.TestCase):
 40
 41    def test_dump_load(self):
 42        self.assertEquals(alist,
 43                          xmlrpclib.loads(xmlrpclib.dumps((alist,)))[0][0])
 44
 45    def test_dump_bare_datetime(self):
 46        # This checks that an unwrapped datetime.date object can be handled
 47        # by the marshalling code.  This can't be done via test_dump_load()
 48        # since with use_datetime set to 1 the unmarshaller would create
 49        # datetime objects for the 'datetime[123]' keys as well
 50        dt = datetime.datetime(2005, 02, 10, 11, 41, 23)
 51        s = xmlrpclib.dumps((dt,))
 52        (newdt,), m = xmlrpclib.loads(s, use_datetime=1)
 53        self.assertEquals(newdt, dt)
 54        self.assertEquals(m, None)
 55
 56        (newdt,), m = xmlrpclib.loads(s, use_datetime=0)
 57        self.assertEquals(newdt, xmlrpclib.DateTime('20050210T11:41:23'))
 58
 59    def test_datetime_before_1900(self):
 60        # same as before but with a date before 1900
 61        dt = datetime.datetime(1, 02, 10, 11, 41, 23)
 62        s = xmlrpclib.dumps((dt,))
 63        (newdt,), m = xmlrpclib.loads(s, use_datetime=1)
 64        self.assertEquals(newdt, dt)
 65        self.assertEquals(m, None)
 66
 67        (newdt,), m = xmlrpclib.loads(s, use_datetime=0)
 68        self.assertEquals(newdt, xmlrpclib.DateTime('00010210T11:41:23'))
 69
 70    def test_cmp_datetime_DateTime(self):
 71        now = datetime.datetime.now()
 72        dt = xmlrpclib.DateTime(now.timetuple())
 73        self.assert_(dt == now)
 74        self.assert_(now == dt)
 75        then = now + datetime.timedelta(seconds=4)
 76        self.assert_(then >= dt)
 77        self.assert_(dt < then)
 78
 79    def test_bug_1164912 (self):
 80        d = xmlrpclib.DateTime()
 81        ((new_d,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((d,),
 82                                            methodresponse=True))
 83        self.assert_(isinstance(new_d.value, str))
 84
 85        # Check that the output of dumps() is still an 8-bit string
 86        s = xmlrpclib.dumps((new_d,), methodresponse=True)
 87        self.assert_(isinstance(s, str))
 88
 89    def test_newstyle_class(self):
 90        class T(object):
 91            pass
 92        t = T()
 93        t.x = 100
 94        t.y = "Hello"
 95        ((t2,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((t,)))
 96        self.assertEquals(t2, t.__dict__)
 97
 98    def test_dump_big_long(self):
 99        self.assertRaises(OverflowError, xmlrpclib.dumps, (2L**99,))
100
101    def test_dump_bad_dict(self):
102        self.assertRaises(TypeError, xmlrpclib.dumps, ({(1,2,3): 1},))
103
104    def test_dump_recursive_seq(self):
105        l = [1,2,3]
106        t = [3,4,5,l]
107        l.append(t)
108        self.assertRaises(TypeError, xmlrpclib.dumps, (l,))
109
110    def test_dump_recursive_dict(self):
111        d = {'1':1, '2':1}
112        t = {'3':3, 'd':d}
113        d['t'] = t
114        self.assertRaises(TypeError, xmlrpclib.dumps, (d,))
115
116    def test_dump_big_int(self):
117        if sys.maxint > 2L**31-1:
118            self.assertRaises(OverflowError, xmlrpclib.dumps,
119                              (int(2L**34),))
120
121        xmlrpclib.dumps((xmlrpclib.MAXINT, xmlrpclib.MININT))
122        self.assertRaises(OverflowError, xmlrpclib.dumps, (xmlrpclib.MAXINT+1,))
123        self.assertRaises(OverflowError, xmlrpclib.dumps, (xmlrpclib.MININT-1,))
124
125        def dummy_write(s):
126            pass
127
128        m = xmlrpclib.Marshaller()
129        m.dump_int(xmlrpclib.MAXINT, dummy_write)
130        m.dump_int(xmlrpclib.MININT, dummy_write)
131        self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MAXINT+1, dummy_write)
132        self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MININT-1, dummy_write)
133
134
135    def test_dump_none(self):
136        value = alist + [None]
137        arg1 = (alist + [None],)
138        strg = xmlrpclib.dumps(arg1, allow_none=True)
139        self.assertEquals(value,
140                          xmlrpclib.loads(strg)[0][0])
141        self.assertRaises(TypeError, xmlrpclib.dumps, (arg1,))
142
143    def test_default_encoding_issues(self):
144        # SF bug #1115989: wrong decoding in '_stringify'
145        utf8 = """<?xml version='1.0' encoding='iso-8859-1'?>
146                  <params>
147                    <param><value>
148                      <string>abc \x95</string>
149                      </value></param>
150                    <param><value>
151                      <struct>
152                        <member>
153                          <name>def \x96</name>
154                          <value><string>ghi \x97</string></value>
155                          </member>
156                        </struct>
157                      </value></param>
158                  </params>
159                  """
160
161        # sys.setdefaultencoding() normally doesn't exist after site.py is
162        # loaded.  reload(sys) is the way to get it back.
163        old_encoding = sys.getdefaultencoding()
164        setdefaultencoding_existed = hasattr(sys, "setdefaultencoding")
165        reload(sys) # ugh!
166        sys.setdefaultencoding("iso-8859-1")
167        try:
168            (s, d), m = xmlrpclib.loads(utf8)
169        finally:
170            sys.setdefaultencoding(old_encoding)
171            if not setdefaultencoding_existed:
172                del sys.setdefaultencoding
173
174        items = d.items()
175        if have_unicode:
176            self.assertEquals(s, u"abc \x95")
177            self.assert_(isinstance(s, unicode))
178            self.assertEquals(items, [(u"def \x96", u"ghi \x97")])
179            self.assert_(isinstance(items[0][0], unicode))
180            self.assert_(isinstance(items[0][1], unicode))
181        else:
182            self.assertEquals(s, "abc \xc2\x95")
183            self.assertEquals(items, [("def \xc2\x96", "ghi \xc2\x97")])
184
185
186class HelperTestCase(unittest.TestCase):
187    def test_escape(self):
188        self.assertEqual(xmlrpclib.escape("a&b"), "a&amp;b")
189        self.assertEqual(xmlrpclib.escape("a<b"), "a&lt;b")
190        self.assertEqual(xmlrpclib.escape("a>b"), "a&gt;b")
191
192class FaultTestCase(unittest.TestCase):
193    def test_repr(self):
194        f = xmlrpclib.Fault(42, 'Test Fault')
195        self.assertEqual(repr(f), "<Fault 42: 'Test Fault'>")
196        self.assertEqual(repr(f), str(f))
197
198    def test_dump_fault(self):
199        f = xmlrpclib.Fault(42, 'Test Fault')
200        s = xmlrpclib.dumps((f,))
201        (newf,), m = xmlrpclib.loads(s)
202        self.assertEquals(newf, {'faultCode': 42, 'faultString': 'Test Fault'})
203        self.assertEquals(m, None)
204
205        s = xmlrpclib.Marshaller().dumps(f)
206        self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, s)
207
208
209class DateTimeTestCase(unittest.TestCase):
210    def test_default(self):
211        t = xmlrpclib.DateTime()
212
213    def test_time(self):
214        d = 1181399930.036952
215        t = xmlrpclib.DateTime(d)
216        self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", time.localtime(d)))
217
218    def test_time_tuple(self):
219        d = (2007,6,9,10,38,50,5,160,0)
220        t = xmlrpclib.DateTime(d)
221        self.assertEqual(str(t), '20070609T10:38:50')
222
223    def test_time_struct(self):
224        d = time.localtime(1181399930.036952)
225        t = xmlrpclib.DateTime(d)
226        self.assertEqual(str(t),  time.strftime("%Y%m%dT%H:%M:%S", d))
227
228    def test_datetime_datetime(self):
229        d = datetime.datetime(2007,1,2,3,4,5)
230        t = xmlrpclib.DateTime(d)
231        self.assertEqual(str(t), '20070102T03:04:05')
232
233    def test_repr(self):
234        d = datetime.datetime(2007,1,2,3,4,5)
235        t = xmlrpclib.DateTime(d)
236        val ="<DateTime '20070102T03:04:05' at %x>" % id(t)
237        self.assertEqual(repr(t), val)
238
239    def test_decode(self):
240        d = ' 20070908T07:11:13  '
241        t1 = xmlrpclib.DateTime()
242        t1.decode(d)
243        tref = xmlrpclib.DateTime(datetime.datetime(2007,9,8,7,11,13))
244        self.assertEqual(t1, tref)
245
246        t2 = xmlrpclib._datetime(d)
247        self.assertEqual(t1, tref)
248
249class BinaryTestCase(unittest.TestCase):
250    def test_default(self):
251        t = xmlrpclib.Binary()
252        self.assertEqual(str(t), '')
253
254    def test_string(self):
255        d = '\x01\x02\x03abc123\xff\xfe'
256        t = xmlrpclib.Binary(d)
257        self.assertEqual(str(t), d)
258
259    def test_decode(self):
260        d = '\x01\x02\x03abc123\xff\xfe'
261        de = base64.encodestring(d)
262        t1 = xmlrpclib.Binary()
263        t1.decode(de)
264        self.assertEqual(str(t1), d)
265
266        t2 = xmlrpclib._binary(de)
267        self.assertEqual(str(t2), d)
268
269
270PORT = None
271
272# The evt is set twice.  First when the server is ready to serve.
273# Second when the server has been shutdown.  The user must clear
274# the event after it has been set the first time to catch the second set.
275def http_server(evt, numrequests):
276    class TestInstanceClass:
277        def div(self, x, y):
278            return x // y
279
280        def _methodHelp(self, name):
281            if name == 'div':
282                return 'This is the div function'
283
284    def my_function():
285        '''This is my function'''
286        return True
287
288    class MyXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
289        def get_request(self):
290            # Ensure the socket is always non-blocking.  On Linux, socket
291            # attributes are not inherited like they are on *BSD and Windows.
292            s, port = self.socket.accept()
293            s.setblocking(True)
294            return s, port
295
296    try:
297        serv = MyXMLRPCServer(("localhost", 0),
298                              logRequests=False, bind_and_activate=False)
299        serv.socket.settimeout(3)
300        serv.server_bind()
301        global PORT
302        PORT = serv.socket.getsockname()[1]
303        serv.server_activate()
304        serv.register_introspection_functions()
305        serv.register_multicall_functions()
306        serv.register_function(pow)
307        serv.register_function(lambda x,y: x+y, 'add')
308        serv.register_function(my_function)
309        serv.register_instance(TestInstanceClass())
310        evt.set()
311
312        # handle up to 'numrequests' requests
313        while numrequests > 0:
314            serv.handle_request()
315            numrequests -= 1
316
317    except socket.timeout:
318        pass
319    finally:
320        serv.socket.close()
321        PORT = None
322        evt.set()
323
324# This function prevents errors like:
325#    <ProtocolError for localhost:57527/RPC2: 500 Internal Server Error>
326def is_unavailable_exception(e):
327    '''Returns True if the given ProtocolError is the product of a server-side
328       exception caused by the 'temporarily unavailable' response sometimes
329       given by operations on non-blocking sockets.'''
330
331    # sometimes we get a -1 error code and/or empty headers
332    try:
333        if e.errcode == -1 or e.headers is None:
334            return True
335        exc_mess = e.headers.get('X-exception')
336    except AttributeError:
337        # Ignore socket.errors here.
338        exc_mess = str(e)
339
340    if exc_mess and 'temporarily unavailable' in exc_mess.lower():
341        return True
342
343    return False
344
345# NOTE: The tests in SimpleServerTestCase will ignore failures caused by
346# "temporarily unavailable" exceptions raised in SimpleXMLRPCServer.  This
347# condition occurs infrequently on some platforms, frequently on others, and
348# is apparently caused by using SimpleXMLRPCServer with a non-blocking socket.
349# If the server class is updated at some point in the future to handle this
350# situation more gracefully, these tests should be modified appropriately.
351
352class SimpleServerTestCase(unittest.TestCase):
353    def setUp(self):
354        # enable traceback reporting
355        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
356
357        self.evt = threading.Event()
358        # start server thread to handle requests
359        serv_args = (self.evt, 1)
360        threading.Thread(target=http_server, args=serv_args).start()
361
362        # wait for the server to be ready
363        self.evt.wait()
364        self.evt.clear()
365
366    def tearDown(self):
367        # wait on the server thread to terminate
368        self.evt.wait()
369
370        # disable traceback reporting
371        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
372
373    def test_simple1(self):
374        try:
375            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
376            self.assertEqual(p.pow(6,8), 6**8)
377        except (xmlrpclib.ProtocolError, socket.error), e:
378            # ignore failures due to non-blocking socket 'unavailable' errors
379            if not is_unavailable_exception(e):
380                # protocol error; provide additional information in test output
381                self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
382
383    # [ch] The test 404 is causing lots of false alarms.
384    def XXXtest_404(self):
385        # send POST with httplib, it should return 404 header and
386        # 'Not Found' message.
387        conn = httplib.HTTPConnection('localhost', PORT)
388        conn.request('POST', '/this-is-not-valid')
389        response = conn.getresponse()
390        conn.close()
391
392        self.assertEqual(response.status, 404)
393        self.assertEqual(response.reason, 'Not Found')
394
395    def test_introspection1(self):
396        try:
397            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
398            meth = p.system.listMethods()
399            expected_methods = set(['pow', 'div', 'my_function', 'add',
400                                    'system.listMethods', 'system.methodHelp',
401                                    'system.methodSignature', 'system.multicall'])
402            self.assertEqual(set(meth), expected_methods)
403        except (xmlrpclib.ProtocolError, socket.error), e:
404            # ignore failures due to non-blocking socket 'unavailable' errors
405            if not is_unavailable_exception(e):
406                # protocol error; provide additional information in test output
407                self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
408
409    def test_introspection2(self):
410        try:
411            # test _methodHelp()
412            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
413            divhelp = p.system.methodHelp('div')
414            self.assertEqual(divhelp, 'This is the div function')
415        except (xmlrpclib.ProtocolError, socket.error), e:
416            # 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, getattr(e, "headers", "")))
420
421    # This test relies on docstrings, which are omitted when -OO is passed.
422    if sys.flags.optimize <= 1:
423        def test_introspection3(self):
424            try:
425                # test native doc
426                p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
427                myfunction = p.system.methodHelp('my_function')
428                self.assertEqual(myfunction, 'This is my function')
429            except (xmlrpclib.ProtocolError, socket.error), e:
430                # ignore failures due to non-blocking socket 'unavailable'
431                # errors
432                if not is_unavailable_exception(e):
433                    # protocol error; provide additional information in test
434                    # output
435                    self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
436
437    def test_introspection4(self):
438        # the SimpleXMLRPCServer doesn't support signatures, but
439        # at least check that we can try making the call
440        try:
441            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
442            divsig = p.system.methodSignature('div')
443            self.assertEqual(divsig, 'signatures not supported')
444        except (xmlrpclib.ProtocolError, socket.error), e:
445            # ignore failures due to non-blocking socket 'unavailable' errors
446            if not is_unavailable_exception(e):
447                # protocol error; provide additional information in test output
448                self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
449
450    def test_multicall(self):
451        try:
452            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
453            multicall = xmlrpclib.MultiCall(p)
454            multicall.add(2,3)
455            multicall.pow(6,8)
456            multicall.div(127,42)
457            add_result, pow_result, div_result = multicall()
458            self.assertEqual(add_result, 2+3)
459            self.assertEqual(pow_result, 6**8)
460            self.assertEqual(div_result, 127//42)
461        except (xmlrpclib.ProtocolError, socket.error), e:
462            # ignore failures due to non-blocking socket 'unavailable' errors
463            if not is_unavailable_exception(e):
464                # protocol error; provide additional information in test output
465                self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
466
467    def test_non_existing_multicall(self):
468        try:
469            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
470            multicall = xmlrpclib.MultiCall(p)
471            multicall.this_is_not_exists()
472            result = multicall()
473
474            # result.results contains;
475            # [{'faultCode': 1, 'faultString': '<type \'exceptions.Exception\'>:'
476            #   'method "this_is_not_exists" is not supported'>}]
477
478            self.assertEqual(result.results[0]['faultCode'], 1)
479            self.assertEqual(result.results[0]['faultString'],
480                '<type \'exceptions.Exception\'>:method "this_is_not_exists" '
481                'is not supported')
482        except (xmlrpclib.ProtocolError, socket.error), e:
483            # ignore failures due to non-blocking socket 'unavailable' errors
484            if not is_unavailable_exception(e):
485                # protocol error; provide additional information in test output
486                self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
487
488    def test_dotted_attribute(self):
489        # Raises an AttributeError because private methods are not allowed.
490        self.assertRaises(AttributeError,
491                          SimpleXMLRPCServer.resolve_dotted_attribute, str, '__add')
492
493        self.assert_(SimpleXMLRPCServer.resolve_dotted_attribute(str, 'title'))
494        # Get the test to run faster by sending a request with test_simple1.
495        # This avoids waiting for the socket timeout.
496        self.test_simple1()
497
498# This is a contrived way to make a failure occur on the server side
499# in order to test the _send_traceback_header flag on the server
500class FailingMessageClass(mimetools.Message):
501    def __getitem__(self, key):
502        key = key.lower()
503        if key == 'content-length':
504            return 'I am broken'
505        return mimetools.Message.__getitem__(self, key)
506
507
508class FailingServerTestCase(unittest.TestCase):
509    def setUp(self):
510        self.evt = threading.Event()
511        # start server thread to handle requests
512        serv_args = (self.evt, 1)
513        threading.Thread(target=http_server, args=serv_args).start()
514
515        # wait for the server to be ready
516        self.evt.wait()
517        self.evt.clear()
518
519    def tearDown(self):
520        # wait on the server thread to terminate
521        self.evt.wait()
522        # reset flag
523        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
524        # reset message class
525        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
526
527    def test_basic(self):
528        # check that flag is false by default
529        flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header
530        self.assertEqual(flagval, False)
531
532        # enable traceback reporting
533        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
534
535        # test a call that shouldn't fail just as a smoke test
536        try:
537            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
538            self.assertEqual(p.pow(6,8), 6**8)
539        except (xmlrpclib.ProtocolError, socket.error), e:
540            # ignore failures due to non-blocking socket 'unavailable' errors
541            if not is_unavailable_exception(e):
542                # protocol error; provide additional information in test output
543                self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
544
545    def test_fail_no_info(self):
546        # use the broken message class
547        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
548
549        try:
550            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
551            p.pow(6,8)
552        except (xmlrpclib.ProtocolError, socket.error), e:
553            # ignore failures due to non-blocking socket 'unavailable' errors
554            if not is_unavailable_exception(e) and hasattr(e, "headers"):
555                # The two server-side error headers shouldn't be sent back in this case
556                self.assertTrue(e.headers.get("X-exception") is None)
557                self.assertTrue(e.headers.get("X-traceback") is None)
558        else:
559            self.fail('ProtocolError not raised')
560
561    def test_fail_with_info(self):
562        # use the broken message class
563        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
564
565        # Check that errors in the server send back exception/traceback
566        # info when flag is set
567        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
568
569        try:
570            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
571            p.pow(6,8)
572        except (xmlrpclib.ProtocolError, socket.error), e:
573            # ignore failures due to non-blocking socket 'unavailable' errors
574            if not is_unavailable_exception(e) and hasattr(e, "headers"):
575                # We should get error info in the response
576                expected_err = "invalid literal for int() with base 10: 'I am broken'"
577                self.assertEqual(e.headers.get("x-exception"), expected_err)
578                self.assertTrue(e.headers.get("x-traceback") is not None)
579        else:
580            self.fail('ProtocolError not raised')
581
582class CGIHandlerTestCase(unittest.TestCase):
583    def setUp(self):
584        self.cgi = SimpleXMLRPCServer.CGIXMLRPCRequestHandler()
585
586    def tearDown(self):
587        self.cgi = None
588
589    def test_cgi_get(self):
590        with test_support.EnvironmentVarGuard() as env:
591            env.set('REQUEST_METHOD', 'GET')
592            # if the method is GET and no request_text is given, it runs handle_get
593            # get sysout output
594            tmp = sys.stdout
595            sys.stdout = open(test_support.TESTFN, "w")
596            self.cgi.handle_request()
597            sys.stdout.close()
598            sys.stdout = tmp
599
600            # parse Status header
601            handle = open(test_support.TESTFN, "r").read()
602            status = handle.split()[1]
603            message = ' '.join(handle.split()[2:4])
604
605            self.assertEqual(status, '400')
606            self.assertEqual(message, 'Bad Request')
607
608            os.remove(test_support.TESTFN)
609
610    def test_cgi_xmlrpc_response(self):
611        data = """<?xml version='1.0'?>
612<methodCall>
613    <methodName>test_method</methodName>
614    <params>
615        <param>
616            <value><string>foo</string></value>
617        </param>
618        <param>
619            <value><string>bar</string></value>
620        </param>
621     </params>
622</methodCall>
623"""
624        open("xmldata.txt", "w").write(data)
625        tmp1 = sys.stdin
626        tmp2 = sys.stdout
627
628        sys.stdin = open("xmldata.txt", "r")
629        sys.stdout = open(test_support.TESTFN, "w")
630
631        with test_support.EnvironmentVarGuard() as env:
632            env.set('CONTENT_LENGTH', str(len(data)))
633            self.cgi.handle_request()
634
635        sys.stdin.close()
636        sys.stdout.close()
637        sys.stdin = tmp1
638        sys.stdout = tmp2
639
640        # will respond exception, if so, our goal is achieved ;)
641        handle = open(test_support.TESTFN, "r").read()
642
643        # start with 44th char so as not to get http header, we just need only xml
644        self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, handle[44:])
645
646        os.remove("xmldata.txt")
647        os.remove(test_support.TESTFN)
648
649class FakeSocket:
650
651    def __init__(self):
652        self.data = StringIO.StringIO()
653
654    def send(self, buf):
655        self.data.write(buf)
656        return len(buf)
657
658    def sendall(self, buf):
659        self.data.write(buf)
660
661    def getvalue(self):
662        return self.data.getvalue()
663
664    def makefile(self, x, y):
665        raise RuntimeError
666
667class FakeTransport(xmlrpclib.Transport):
668    """A Transport instance that records instead of sending a request.
669
670    This class replaces the actual socket used by httplib with a
671    FakeSocket object that records the request.  It doesn't provide a
672    response.
673    """
674
675    def make_connection(self, host):
676        conn = xmlrpclib.Transport.make_connection(self, host)
677        conn._conn.sock = self.fake_socket = FakeSocket()
678        return conn
679
680class TransportSubclassTestCase(unittest.TestCase):
681
682    def issue_request(self, transport_class):
683        """Return an HTTP request made via transport_class."""
684        transport = transport_class()
685        proxy = xmlrpclib.ServerProxy("http://example.com/",
686                                      transport=transport)
687        try:
688            proxy.pow(6, 8)
689        except RuntimeError:
690            return transport.fake_socket.getvalue()
691        return None
692
693    def test_custom_user_agent(self):
694        class TestTransport(FakeTransport):
695
696            def send_user_agent(self, conn):
697                xmlrpclib.Transport.send_user_agent(self, conn)
698                conn.putheader("X-Test", "test_custom_user_agent")
699
700        req = self.issue_request(TestTransport)
701        self.assert_("X-Test: test_custom_user_agent\r\n" in req)
702
703    def test_send_host(self):
704        class TestTransport(FakeTransport):
705
706            def send_host(self, conn, host):
707                xmlrpclib.Transport.send_host(self, conn, host)
708                conn.putheader("X-Test", "test_send_host")
709
710        req = self.issue_request(TestTransport)
711        self.assert_("X-Test: test_send_host\r\n" in req)
712
713    def test_send_request(self):
714        class TestTransport(FakeTransport):
715
716            def send_request(self, conn, url, body):
717                xmlrpclib.Transport.send_request(self, conn, url, body)
718                conn.putheader("X-Test", "test_send_request")
719
720        req = self.issue_request(TestTransport)
721        self.assert_("X-Test: test_send_request\r\n" in req)
722
723    def test_send_content(self):
724        class TestTransport(FakeTransport):
725
726            def send_content(self, conn, body):
727                conn.putheader("X-Test", "test_send_content")
728                xmlrpclib.Transport.send_content(self, conn, body)
729
730        req = self.issue_request(TestTransport)
731        self.assert_("X-Test: test_send_content\r\n" in req)
732
733def test_main():
734    if sys.flags.optimize >= 2:
735        print >>sys.stderr, "test_xmlrpc -- skipping some tests due to -O flag."
736        sys.stderr.flush()
737    xmlrpc_tests = [XMLRPCTestCase, HelperTestCase, DateTimeTestCase,
738         BinaryTestCase, FaultTestCase, TransportSubclassTestCase]
739
740    # The test cases against a SimpleXMLRPCServer raise a socket error
741    # 10035 (WSAEWOULDBLOCK) in the server thread handle_request call when
742    # run on Windows. This only happens on the first test to run, but it
743    # fails every time and so these tests are skipped on win32 platforms.
744    if sys.platform != 'win32':
745        xmlrpc_tests.append(SimpleServerTestCase)
746        xmlrpc_tests.append(FailingServerTestCase)
747        xmlrpc_tests.append(CGIHandlerTestCase)
748
749    test_support.run_unittest(*xmlrpc_tests)
750
751if __name__ == "__main__":
752    test_main()