+++ /dev/null
-import base64\r
-import datetime\r
-import sys\r
-import time\r
-import unittest\r
-import xmlrpclib\r
-import SimpleXMLRPCServer\r
-import mimetools\r
-import httplib\r
-import socket\r
-import StringIO\r
-import os\r
-import re\r
-from test import test_support\r
-\r
-try:\r
- import threading\r
-except ImportError:\r
- threading = None\r
-\r
-try:\r
- unicode\r
-except NameError:\r
- have_unicode = False\r
-else:\r
- have_unicode = True\r
-\r
-alist = [{'astring': 'foo@bar.baz.spam',\r
- 'afloat': 7283.43,\r
- 'anint': 2**20,\r
- 'ashortlong': 2L,\r
- 'anotherlist': ['.zyx.41'],\r
- 'abase64': xmlrpclib.Binary("my dog has fleas"),\r
- 'boolean': xmlrpclib.False,\r
- 'unicode': u'\u4000\u6000\u8000',\r
- u'ukey\u4000': 'regular value',\r
- 'datetime1': xmlrpclib.DateTime('20050210T11:41:23'),\r
- 'datetime2': xmlrpclib.DateTime(\r
- (2005, 02, 10, 11, 41, 23, 0, 1, -1)),\r
- 'datetime3': xmlrpclib.DateTime(\r
- datetime.datetime(2005, 02, 10, 11, 41, 23)),\r
- }]\r
-\r
-class XMLRPCTestCase(unittest.TestCase):\r
-\r
- def test_dump_load(self):\r
- self.assertEqual(alist,\r
- xmlrpclib.loads(xmlrpclib.dumps((alist,)))[0][0])\r
-\r
- def test_dump_bare_datetime(self):\r
- # This checks that an unwrapped datetime.date object can be handled\r
- # by the marshalling code. This can't be done via test_dump_load()\r
- # since with use_datetime set to 1 the unmarshaller would create\r
- # datetime objects for the 'datetime[123]' keys as well\r
- dt = datetime.datetime(2005, 02, 10, 11, 41, 23)\r
- s = xmlrpclib.dumps((dt,))\r
- (newdt,), m = xmlrpclib.loads(s, use_datetime=1)\r
- self.assertEqual(newdt, dt)\r
- self.assertEqual(m, None)\r
-\r
- (newdt,), m = xmlrpclib.loads(s, use_datetime=0)\r
- self.assertEqual(newdt, xmlrpclib.DateTime('20050210T11:41:23'))\r
-\r
- def test_datetime_before_1900(self):\r
- # same as before but with a date before 1900\r
- dt = datetime.datetime(1, 02, 10, 11, 41, 23)\r
- s = xmlrpclib.dumps((dt,))\r
- (newdt,), m = xmlrpclib.loads(s, use_datetime=1)\r
- self.assertEqual(newdt, dt)\r
- self.assertEqual(m, None)\r
-\r
- (newdt,), m = xmlrpclib.loads(s, use_datetime=0)\r
- self.assertEqual(newdt, xmlrpclib.DateTime('00010210T11:41:23'))\r
-\r
- def test_cmp_datetime_DateTime(self):\r
- now = datetime.datetime.now()\r
- dt = xmlrpclib.DateTime(now.timetuple())\r
- self.assertTrue(dt == now)\r
- self.assertTrue(now == dt)\r
- then = now + datetime.timedelta(seconds=4)\r
- self.assertTrue(then >= dt)\r
- self.assertTrue(dt < then)\r
-\r
- def test_bug_1164912 (self):\r
- d = xmlrpclib.DateTime()\r
- ((new_d,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((d,),\r
- methodresponse=True))\r
- self.assertIsInstance(new_d.value, str)\r
-\r
- # Check that the output of dumps() is still an 8-bit string\r
- s = xmlrpclib.dumps((new_d,), methodresponse=True)\r
- self.assertIsInstance(s, str)\r
-\r
- def test_newstyle_class(self):\r
- class T(object):\r
- pass\r
- t = T()\r
- t.x = 100\r
- t.y = "Hello"\r
- ((t2,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((t,)))\r
- self.assertEqual(t2, t.__dict__)\r
-\r
- def test_dump_big_long(self):\r
- self.assertRaises(OverflowError, xmlrpclib.dumps, (2L**99,))\r
-\r
- def test_dump_bad_dict(self):\r
- self.assertRaises(TypeError, xmlrpclib.dumps, ({(1,2,3): 1},))\r
-\r
- def test_dump_recursive_seq(self):\r
- l = [1,2,3]\r
- t = [3,4,5,l]\r
- l.append(t)\r
- self.assertRaises(TypeError, xmlrpclib.dumps, (l,))\r
-\r
- def test_dump_recursive_dict(self):\r
- d = {'1':1, '2':1}\r
- t = {'3':3, 'd':d}\r
- d['t'] = t\r
- self.assertRaises(TypeError, xmlrpclib.dumps, (d,))\r
-\r
- def test_dump_big_int(self):\r
- if sys.maxint > 2L**31-1:\r
- self.assertRaises(OverflowError, xmlrpclib.dumps,\r
- (int(2L**34),))\r
-\r
- xmlrpclib.dumps((xmlrpclib.MAXINT, xmlrpclib.MININT))\r
- self.assertRaises(OverflowError, xmlrpclib.dumps, (xmlrpclib.MAXINT+1,))\r
- self.assertRaises(OverflowError, xmlrpclib.dumps, (xmlrpclib.MININT-1,))\r
-\r
- def dummy_write(s):\r
- pass\r
-\r
- m = xmlrpclib.Marshaller()\r
- m.dump_int(xmlrpclib.MAXINT, dummy_write)\r
- m.dump_int(xmlrpclib.MININT, dummy_write)\r
- self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MAXINT+1, dummy_write)\r
- self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MININT-1, dummy_write)\r
-\r
-\r
- def test_dump_none(self):\r
- value = alist + [None]\r
- arg1 = (alist + [None],)\r
- strg = xmlrpclib.dumps(arg1, allow_none=True)\r
- self.assertEqual(value,\r
- xmlrpclib.loads(strg)[0][0])\r
- self.assertRaises(TypeError, xmlrpclib.dumps, (arg1,))\r
-\r
- def test_default_encoding_issues(self):\r
- # SF bug #1115989: wrong decoding in '_stringify'\r
- utf8 = """<?xml version='1.0' encoding='iso-8859-1'?>\r
- <params>\r
- <param><value>\r
- <string>abc \x95</string>\r
- </value></param>\r
- <param><value>\r
- <struct>\r
- <member>\r
- <name>def \x96</name>\r
- <value><string>ghi \x97</string></value>\r
- </member>\r
- </struct>\r
- </value></param>\r
- </params>\r
- """\r
-\r
- # sys.setdefaultencoding() normally doesn't exist after site.py is\r
- # loaded. Import a temporary fresh copy to get access to it\r
- # but then restore the original copy to avoid messing with\r
- # other potentially modified sys module attributes\r
- old_encoding = sys.getdefaultencoding()\r
- with test_support.CleanImport('sys'):\r
- import sys as temp_sys\r
- temp_sys.setdefaultencoding("iso-8859-1")\r
- try:\r
- (s, d), m = xmlrpclib.loads(utf8)\r
- finally:\r
- temp_sys.setdefaultencoding(old_encoding)\r
-\r
- items = d.items()\r
- if have_unicode:\r
- self.assertEqual(s, u"abc \x95")\r
- self.assertIsInstance(s, unicode)\r
- self.assertEqual(items, [(u"def \x96", u"ghi \x97")])\r
- self.assertIsInstance(items[0][0], unicode)\r
- self.assertIsInstance(items[0][1], unicode)\r
- else:\r
- self.assertEqual(s, "abc \xc2\x95")\r
- self.assertEqual(items, [("def \xc2\x96", "ghi \xc2\x97")])\r
-\r
-\r
-class HelperTestCase(unittest.TestCase):\r
- def test_escape(self):\r
- self.assertEqual(xmlrpclib.escape("a&b"), "a&b")\r
- self.assertEqual(xmlrpclib.escape("a<b"), "a<b")\r
- self.assertEqual(xmlrpclib.escape("a>b"), "a>b")\r
-\r
-class FaultTestCase(unittest.TestCase):\r
- def test_repr(self):\r
- f = xmlrpclib.Fault(42, 'Test Fault')\r
- self.assertEqual(repr(f), "<Fault 42: 'Test Fault'>")\r
- self.assertEqual(repr(f), str(f))\r
-\r
- def test_dump_fault(self):\r
- f = xmlrpclib.Fault(42, 'Test Fault')\r
- s = xmlrpclib.dumps((f,))\r
- (newf,), m = xmlrpclib.loads(s)\r
- self.assertEqual(newf, {'faultCode': 42, 'faultString': 'Test Fault'})\r
- self.assertEqual(m, None)\r
-\r
- s = xmlrpclib.Marshaller().dumps(f)\r
- self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, s)\r
-\r
-\r
-class DateTimeTestCase(unittest.TestCase):\r
- def test_default(self):\r
- t = xmlrpclib.DateTime()\r
-\r
- def test_time(self):\r
- d = 1181399930.036952\r
- t = xmlrpclib.DateTime(d)\r
- self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", time.localtime(d)))\r
-\r
- def test_time_tuple(self):\r
- d = (2007,6,9,10,38,50,5,160,0)\r
- t = xmlrpclib.DateTime(d)\r
- self.assertEqual(str(t), '20070609T10:38:50')\r
-\r
- def test_time_struct(self):\r
- d = time.localtime(1181399930.036952)\r
- t = xmlrpclib.DateTime(d)\r
- self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", d))\r
-\r
- def test_datetime_datetime(self):\r
- d = datetime.datetime(2007,1,2,3,4,5)\r
- t = xmlrpclib.DateTime(d)\r
- self.assertEqual(str(t), '20070102T03:04:05')\r
-\r
- def test_repr(self):\r
- d = datetime.datetime(2007,1,2,3,4,5)\r
- t = xmlrpclib.DateTime(d)\r
- val ="<DateTime '20070102T03:04:05' at %x>" % id(t)\r
- self.assertEqual(repr(t), val)\r
-\r
- def test_decode(self):\r
- d = ' 20070908T07:11:13 '\r
- t1 = xmlrpclib.DateTime()\r
- t1.decode(d)\r
- tref = xmlrpclib.DateTime(datetime.datetime(2007,9,8,7,11,13))\r
- self.assertEqual(t1, tref)\r
-\r
- t2 = xmlrpclib._datetime(d)\r
- self.assertEqual(t1, tref)\r
-\r
-class BinaryTestCase(unittest.TestCase):\r
- def test_default(self):\r
- t = xmlrpclib.Binary()\r
- self.assertEqual(str(t), '')\r
-\r
- def test_string(self):\r
- d = '\x01\x02\x03abc123\xff\xfe'\r
- t = xmlrpclib.Binary(d)\r
- self.assertEqual(str(t), d)\r
-\r
- def test_decode(self):\r
- d = '\x01\x02\x03abc123\xff\xfe'\r
- de = base64.encodestring(d)\r
- t1 = xmlrpclib.Binary()\r
- t1.decode(de)\r
- self.assertEqual(str(t1), d)\r
-\r
- t2 = xmlrpclib._binary(de)\r
- self.assertEqual(str(t2), d)\r
-\r
-\r
-ADDR = PORT = URL = None\r
-\r
-# The evt is set twice. First when the server is ready to serve.\r
-# Second when the server has been shutdown. The user must clear\r
-# the event after it has been set the first time to catch the second set.\r
-def http_server(evt, numrequests, requestHandler=None):\r
- class TestInstanceClass:\r
- def div(self, x, y):\r
- return x // y\r
-\r
- def _methodHelp(self, name):\r
- if name == 'div':\r
- return 'This is the div function'\r
-\r
- def my_function():\r
- '''This is my function'''\r
- return True\r
-\r
- class MyXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):\r
- def get_request(self):\r
- # Ensure the socket is always non-blocking. On Linux, socket\r
- # attributes are not inherited like they are on *BSD and Windows.\r
- s, port = self.socket.accept()\r
- s.setblocking(True)\r
- return s, port\r
-\r
- if not requestHandler:\r
- requestHandler = SimpleXMLRPCServer.SimpleXMLRPCRequestHandler\r
- serv = MyXMLRPCServer(("localhost", 0), requestHandler,\r
- logRequests=False, bind_and_activate=False)\r
- try:\r
- serv.socket.settimeout(3)\r
- serv.server_bind()\r
- global ADDR, PORT, URL\r
- ADDR, PORT = serv.socket.getsockname()\r
- #connect to IP address directly. This avoids socket.create_connection()\r
- #trying to connect to to "localhost" using all address families, which\r
- #causes slowdown e.g. on vista which supports AF_INET6. The server listens\r
- #on AF_INET only.\r
- URL = "http://%s:%d"%(ADDR, PORT)\r
- serv.server_activate()\r
- serv.register_introspection_functions()\r
- serv.register_multicall_functions()\r
- serv.register_function(pow)\r
- serv.register_function(lambda x,y: x+y, 'add')\r
- serv.register_function(my_function)\r
- serv.register_instance(TestInstanceClass())\r
- evt.set()\r
-\r
- # handle up to 'numrequests' requests\r
- while numrequests > 0:\r
- serv.handle_request()\r
- numrequests -= 1\r
-\r
- except socket.timeout:\r
- pass\r
- finally:\r
- serv.socket.close()\r
- PORT = None\r
- evt.set()\r
-\r
-def http_multi_server(evt, numrequests, requestHandler=None):\r
- class TestInstanceClass:\r
- def div(self, x, y):\r
- return x // y\r
-\r
- def _methodHelp(self, name):\r
- if name == 'div':\r
- return 'This is the div function'\r
-\r
- def my_function():\r
- '''This is my function'''\r
- return True\r
-\r
- class MyXMLRPCServer(SimpleXMLRPCServer.MultiPathXMLRPCServer):\r
- def get_request(self):\r
- # Ensure the socket is always non-blocking. On Linux, socket\r
- # attributes are not inherited like they are on *BSD and Windows.\r
- s, port = self.socket.accept()\r
- s.setblocking(True)\r
- return s, port\r
-\r
- if not requestHandler:\r
- requestHandler = SimpleXMLRPCServer.SimpleXMLRPCRequestHandler\r
- class MyRequestHandler(requestHandler):\r
- rpc_paths = []\r
-\r
- serv = MyXMLRPCServer(("localhost", 0), MyRequestHandler,\r
- logRequests=False, bind_and_activate=False)\r
- serv.socket.settimeout(3)\r
- serv.server_bind()\r
- try:\r
- global ADDR, PORT, URL\r
- ADDR, PORT = serv.socket.getsockname()\r
- #connect to IP address directly. This avoids socket.create_connection()\r
- #trying to connect to to "localhost" using all address families, which\r
- #causes slowdown e.g. on vista which supports AF_INET6. The server listens\r
- #on AF_INET only.\r
- URL = "http://%s:%d"%(ADDR, PORT)\r
- serv.server_activate()\r
- paths = ["/foo", "/foo/bar"]\r
- for path in paths:\r
- d = serv.add_dispatcher(path, SimpleXMLRPCServer.SimpleXMLRPCDispatcher())\r
- d.register_introspection_functions()\r
- d.register_multicall_functions()\r
- serv.get_dispatcher(paths[0]).register_function(pow)\r
- serv.get_dispatcher(paths[1]).register_function(lambda x,y: x+y, 'add')\r
- evt.set()\r
-\r
- # handle up to 'numrequests' requests\r
- while numrequests > 0:\r
- serv.handle_request()\r
- numrequests -= 1\r
-\r
- except socket.timeout:\r
- pass\r
- finally:\r
- serv.socket.close()\r
- PORT = None\r
- evt.set()\r
-\r
-# This function prevents errors like:\r
-# <ProtocolError for localhost:57527/RPC2: 500 Internal Server Error>\r
-def is_unavailable_exception(e):\r
- '''Returns True if the given ProtocolError is the product of a server-side\r
- exception caused by the 'temporarily unavailable' response sometimes\r
- given by operations on non-blocking sockets.'''\r
-\r
- # sometimes we get a -1 error code and/or empty headers\r
- try:\r
- if e.errcode == -1 or e.headers is None:\r
- return True\r
- exc_mess = e.headers.get('X-exception')\r
- except AttributeError:\r
- # Ignore socket.errors here.\r
- exc_mess = str(e)\r
-\r
- if exc_mess and 'temporarily unavailable' in exc_mess.lower():\r
- return True\r
-\r
- return False\r
-\r
-@unittest.skipUnless(threading, 'Threading required for this test.')\r
-class BaseServerTestCase(unittest.TestCase):\r
- requestHandler = None\r
- request_count = 1\r
- threadFunc = staticmethod(http_server)\r
-\r
- def setUp(self):\r
- # enable traceback reporting\r
- SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True\r
-\r
- self.evt = threading.Event()\r
- # start server thread to handle requests\r
- serv_args = (self.evt, self.request_count, self.requestHandler)\r
- threading.Thread(target=self.threadFunc, args=serv_args).start()\r
-\r
- # wait for the server to be ready\r
- self.evt.wait(10)\r
- self.evt.clear()\r
-\r
- def tearDown(self):\r
- # wait on the server thread to terminate\r
- self.evt.wait(10)\r
-\r
- # disable traceback reporting\r
- SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False\r
-\r
-# NOTE: The tests in SimpleServerTestCase will ignore failures caused by\r
-# "temporarily unavailable" exceptions raised in SimpleXMLRPCServer. This\r
-# condition occurs infrequently on some platforms, frequently on others, and\r
-# is apparently caused by using SimpleXMLRPCServer with a non-blocking socket\r
-# If the server class is updated at some point in the future to handle this\r
-# situation more gracefully, these tests should be modified appropriately.\r
-\r
-class SimpleServerTestCase(BaseServerTestCase):\r
- def test_simple1(self):\r
- try:\r
- p = xmlrpclib.ServerProxy(URL)\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- except (xmlrpclib.ProtocolError, socket.error), e:\r
- # ignore failures due to non-blocking socket 'unavailable' errors\r
- if not is_unavailable_exception(e):\r
- # protocol error; provide additional information in test output\r
- self.fail("%s\n%s" % (e, getattr(e, "headers", "")))\r
-\r
- def test_nonascii(self):\r
- start_string = 'P\N{LATIN SMALL LETTER Y WITH CIRCUMFLEX}t'\r
- end_string = 'h\N{LATIN SMALL LETTER O WITH HORN}n'\r
-\r
- try:\r
- p = xmlrpclib.ServerProxy(URL)\r
- self.assertEqual(p.add(start_string, end_string),\r
- start_string + end_string)\r
- except (xmlrpclib.ProtocolError, socket.error) as e:\r
- # ignore failures due to non-blocking socket unavailable errors.\r
- if not is_unavailable_exception(e):\r
- # protocol error; provide additional information in test output\r
- self.fail("%s\n%s" % (e, getattr(e, "headers", "")))\r
-\r
-\r
- # [ch] The test 404 is causing lots of false alarms.\r
- def XXXtest_404(self):\r
- # send POST with httplib, it should return 404 header and\r
- # 'Not Found' message.\r
- conn = httplib.HTTPConnection(ADDR, PORT)\r
- conn.request('POST', '/this-is-not-valid')\r
- response = conn.getresponse()\r
- conn.close()\r
-\r
- self.assertEqual(response.status, 404)\r
- self.assertEqual(response.reason, 'Not Found')\r
-\r
- def test_introspection1(self):\r
- try:\r
- p = xmlrpclib.ServerProxy(URL)\r
- meth = p.system.listMethods()\r
- expected_methods = set(['pow', 'div', 'my_function', 'add',\r
- 'system.listMethods', 'system.methodHelp',\r
- 'system.methodSignature', 'system.multicall'])\r
- self.assertEqual(set(meth), expected_methods)\r
- except (xmlrpclib.ProtocolError, socket.error), e:\r
- # ignore failures due to non-blocking socket 'unavailable' errors\r
- if not is_unavailable_exception(e):\r
- # protocol error; provide additional information in test output\r
- self.fail("%s\n%s" % (e, getattr(e, "headers", "")))\r
-\r
- def test_introspection2(self):\r
- try:\r
- # test _methodHelp()\r
- p = xmlrpclib.ServerProxy(URL)\r
- divhelp = p.system.methodHelp('div')\r
- self.assertEqual(divhelp, 'This is the div function')\r
- except (xmlrpclib.ProtocolError, socket.error), e:\r
- # ignore failures due to non-blocking socket 'unavailable' errors\r
- if not is_unavailable_exception(e):\r
- # protocol error; provide additional information in test output\r
- self.fail("%s\n%s" % (e, getattr(e, "headers", "")))\r
-\r
- @unittest.skipIf(sys.flags.optimize >= 2,\r
- "Docstrings are omitted with -O2 and above")\r
- def test_introspection3(self):\r
- try:\r
- # test native doc\r
- p = xmlrpclib.ServerProxy(URL)\r
- myfunction = p.system.methodHelp('my_function')\r
- self.assertEqual(myfunction, 'This is my function')\r
- except (xmlrpclib.ProtocolError, socket.error), e:\r
- # ignore failures due to non-blocking socket 'unavailable' errors\r
- if not is_unavailable_exception(e):\r
- # protocol error; provide additional information in test output\r
- self.fail("%s\n%s" % (e, getattr(e, "headers", "")))\r
-\r
- def test_introspection4(self):\r
- # the SimpleXMLRPCServer doesn't support signatures, but\r
- # at least check that we can try making the call\r
- try:\r
- p = xmlrpclib.ServerProxy(URL)\r
- divsig = p.system.methodSignature('div')\r
- self.assertEqual(divsig, 'signatures not supported')\r
- except (xmlrpclib.ProtocolError, socket.error), e:\r
- # ignore failures due to non-blocking socket 'unavailable' errors\r
- if not is_unavailable_exception(e):\r
- # protocol error; provide additional information in test output\r
- self.fail("%s\n%s" % (e, getattr(e, "headers", "")))\r
-\r
- def test_multicall(self):\r
- try:\r
- p = xmlrpclib.ServerProxy(URL)\r
- multicall = xmlrpclib.MultiCall(p)\r
- multicall.add(2,3)\r
- multicall.pow(6,8)\r
- multicall.div(127,42)\r
- add_result, pow_result, div_result = multicall()\r
- self.assertEqual(add_result, 2+3)\r
- self.assertEqual(pow_result, 6**8)\r
- self.assertEqual(div_result, 127//42)\r
- except (xmlrpclib.ProtocolError, socket.error), e:\r
- # ignore failures due to non-blocking socket 'unavailable' errors\r
- if not is_unavailable_exception(e):\r
- # protocol error; provide additional information in test output\r
- self.fail("%s\n%s" % (e, getattr(e, "headers", "")))\r
-\r
- def test_non_existing_multicall(self):\r
- try:\r
- p = xmlrpclib.ServerProxy(URL)\r
- multicall = xmlrpclib.MultiCall(p)\r
- multicall.this_is_not_exists()\r
- result = multicall()\r
-\r
- # result.results contains;\r
- # [{'faultCode': 1, 'faultString': '<type \'exceptions.Exception\'>:'\r
- # 'method "this_is_not_exists" is not supported'>}]\r
-\r
- self.assertEqual(result.results[0]['faultCode'], 1)\r
- self.assertEqual(result.results[0]['faultString'],\r
- '<type \'exceptions.Exception\'>:method "this_is_not_exists" '\r
- 'is not supported')\r
- except (xmlrpclib.ProtocolError, socket.error), e:\r
- # ignore failures due to non-blocking socket 'unavailable' errors\r
- if not is_unavailable_exception(e):\r
- # protocol error; provide additional information in test output\r
- self.fail("%s\n%s" % (e, getattr(e, "headers", "")))\r
-\r
- def test_dotted_attribute(self):\r
- # Raises an AttributeError because private methods are not allowed.\r
- self.assertRaises(AttributeError,\r
- SimpleXMLRPCServer.resolve_dotted_attribute, str, '__add')\r
-\r
- self.assertTrue(SimpleXMLRPCServer.resolve_dotted_attribute(str, 'title'))\r
- # Get the test to run faster by sending a request with test_simple1.\r
- # This avoids waiting for the socket timeout.\r
- self.test_simple1()\r
-\r
-class MultiPathServerTestCase(BaseServerTestCase):\r
- threadFunc = staticmethod(http_multi_server)\r
- request_count = 2\r
- def test_path1(self):\r
- p = xmlrpclib.ServerProxy(URL+"/foo")\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- self.assertRaises(xmlrpclib.Fault, p.add, 6, 8)\r
- def test_path2(self):\r
- p = xmlrpclib.ServerProxy(URL+"/foo/bar")\r
- self.assertEqual(p.add(6,8), 6+8)\r
- self.assertRaises(xmlrpclib.Fault, p.pow, 6, 8)\r
-\r
-#A test case that verifies that a server using the HTTP/1.1 keep-alive mechanism\r
-#does indeed serve subsequent requests on the same connection\r
-class BaseKeepaliveServerTestCase(BaseServerTestCase):\r
- #a request handler that supports keep-alive and logs requests into a\r
- #class variable\r
- class RequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):\r
- parentClass = SimpleXMLRPCServer.SimpleXMLRPCRequestHandler\r
- protocol_version = 'HTTP/1.1'\r
- myRequests = []\r
- def handle(self):\r
- self.myRequests.append([])\r
- self.reqidx = len(self.myRequests)-1\r
- return self.parentClass.handle(self)\r
- def handle_one_request(self):\r
- result = self.parentClass.handle_one_request(self)\r
- self.myRequests[self.reqidx].append(self.raw_requestline)\r
- return result\r
-\r
- requestHandler = RequestHandler\r
- def setUp(self):\r
- #clear request log\r
- self.RequestHandler.myRequests = []\r
- return BaseServerTestCase.setUp(self)\r
-\r
-#A test case that verifies that a server using the HTTP/1.1 keep-alive mechanism\r
-#does indeed serve subsequent requests on the same connection\r
-class KeepaliveServerTestCase1(BaseKeepaliveServerTestCase):\r
- def test_two(self):\r
- p = xmlrpclib.ServerProxy(URL)\r
- #do three requests.\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- self.assertEqual(p.pow(6,8), 6**8)\r
-\r
- #they should have all been handled by a single request handler\r
- self.assertEqual(len(self.RequestHandler.myRequests), 1)\r
-\r
- #check that we did at least two (the third may be pending append\r
- #due to thread scheduling)\r
- self.assertGreaterEqual(len(self.RequestHandler.myRequests[-1]), 2)\r
-\r
-#test special attribute access on the serverproxy, through the __call__\r
-#function.\r
-class KeepaliveServerTestCase2(BaseKeepaliveServerTestCase):\r
- #ask for two keepalive requests to be handled.\r
- request_count=2\r
-\r
- def test_close(self):\r
- p = xmlrpclib.ServerProxy(URL)\r
- #do some requests with close.\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- p("close")() #this should trigger a new keep-alive request\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- self.assertEqual(p.pow(6,8), 6**8)\r
-\r
- #they should have all been two request handlers, each having logged at least\r
- #two complete requests\r
- self.assertEqual(len(self.RequestHandler.myRequests), 2)\r
- self.assertGreaterEqual(len(self.RequestHandler.myRequests[-1]), 2)\r
- self.assertGreaterEqual(len(self.RequestHandler.myRequests[-2]), 2)\r
-\r
- def test_transport(self):\r
- p = xmlrpclib.ServerProxy(URL)\r
- #do some requests with close.\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- p("transport").close() #same as above, really.\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- self.assertEqual(len(self.RequestHandler.myRequests), 2)\r
-\r
-#A test case that verifies that gzip encoding works in both directions\r
-#(for a request and the response)\r
-class GzipServerTestCase(BaseServerTestCase):\r
- #a request handler that supports keep-alive and logs requests into a\r
- #class variable\r
- class RequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):\r
- parentClass = SimpleXMLRPCServer.SimpleXMLRPCRequestHandler\r
- protocol_version = 'HTTP/1.1'\r
-\r
- def do_POST(self):\r
- #store content of last request in class\r
- self.__class__.content_length = int(self.headers["content-length"])\r
- return self.parentClass.do_POST(self)\r
- requestHandler = RequestHandler\r
-\r
- class Transport(xmlrpclib.Transport):\r
- #custom transport, stores the response length for our perusal\r
- fake_gzip = False\r
- def parse_response(self, response):\r
- self.response_length=int(response.getheader("content-length", 0))\r
- return xmlrpclib.Transport.parse_response(self, response)\r
-\r
- def send_content(self, connection, body):\r
- if self.fake_gzip:\r
- #add a lone gzip header to induce decode error remotely\r
- connection.putheader("Content-Encoding", "gzip")\r
- return xmlrpclib.Transport.send_content(self, connection, body)\r
-\r
- def setUp(self):\r
- BaseServerTestCase.setUp(self)\r
-\r
- def test_gzip_request(self):\r
- t = self.Transport()\r
- t.encode_threshold = None\r
- p = xmlrpclib.ServerProxy(URL, transport=t)\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- a = self.RequestHandler.content_length\r
- t.encode_threshold = 0 #turn on request encoding\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- b = self.RequestHandler.content_length\r
- self.assertTrue(a>b)\r
-\r
- def test_bad_gzip_request(self):\r
- t = self.Transport()\r
- t.encode_threshold = None\r
- t.fake_gzip = True\r
- p = xmlrpclib.ServerProxy(URL, transport=t)\r
- cm = self.assertRaisesRegexp(xmlrpclib.ProtocolError,\r
- re.compile(r"\b400\b"))\r
- with cm:\r
- p.pow(6, 8)\r
-\r
- def test_gsip_response(self):\r
- t = self.Transport()\r
- p = xmlrpclib.ServerProxy(URL, transport=t)\r
- old = self.requestHandler.encode_threshold\r
- self.requestHandler.encode_threshold = None #no encoding\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- a = t.response_length\r
- self.requestHandler.encode_threshold = 0 #always encode\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- b = t.response_length\r
- self.requestHandler.encode_threshold = old\r
- self.assertTrue(a>b)\r
-\r
-#Test special attributes of the ServerProxy object\r
-class ServerProxyTestCase(unittest.TestCase):\r
- def setUp(self):\r
- unittest.TestCase.setUp(self)\r
- if threading:\r
- self.url = URL\r
- else:\r
- # Without threading, http_server() and http_multi_server() will not\r
- # be executed and URL is still equal to None. 'http://' is a just\r
- # enough to choose the scheme (HTTP)\r
- self.url = 'http://'\r
-\r
- def test_close(self):\r
- p = xmlrpclib.ServerProxy(self.url)\r
- self.assertEqual(p('close')(), None)\r
-\r
- def test_transport(self):\r
- t = xmlrpclib.Transport()\r
- p = xmlrpclib.ServerProxy(self.url, transport=t)\r
- self.assertEqual(p('transport'), t)\r
-\r
-# This is a contrived way to make a failure occur on the server side\r
-# in order to test the _send_traceback_header flag on the server\r
-class FailingMessageClass(mimetools.Message):\r
- def __getitem__(self, key):\r
- key = key.lower()\r
- if key == 'content-length':\r
- return 'I am broken'\r
- return mimetools.Message.__getitem__(self, key)\r
-\r
-\r
-@unittest.skipUnless(threading, 'Threading required for this test.')\r
-class FailingServerTestCase(unittest.TestCase):\r
- def setUp(self):\r
- self.evt = threading.Event()\r
- # start server thread to handle requests\r
- serv_args = (self.evt, 1)\r
- threading.Thread(target=http_server, args=serv_args).start()\r
-\r
- # wait for the server to be ready\r
- self.evt.wait()\r
- self.evt.clear()\r
-\r
- def tearDown(self):\r
- # wait on the server thread to terminate\r
- self.evt.wait()\r
- # reset flag\r
- SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False\r
- # reset message class\r
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message\r
-\r
- def test_basic(self):\r
- # check that flag is false by default\r
- flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header\r
- self.assertEqual(flagval, False)\r
-\r
- # enable traceback reporting\r
- SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True\r
-\r
- # test a call that shouldn't fail just as a smoke test\r
- try:\r
- p = xmlrpclib.ServerProxy(URL)\r
- self.assertEqual(p.pow(6,8), 6**8)\r
- except (xmlrpclib.ProtocolError, socket.error), e:\r
- # ignore failures due to non-blocking socket 'unavailable' errors\r
- if not is_unavailable_exception(e):\r
- # protocol error; provide additional information in test output\r
- self.fail("%s\n%s" % (e, getattr(e, "headers", "")))\r
-\r
- def test_fail_no_info(self):\r
- # use the broken message class\r
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass\r
-\r
- try:\r
- p = xmlrpclib.ServerProxy(URL)\r
- p.pow(6,8)\r
- except (xmlrpclib.ProtocolError, socket.error), e:\r
- # ignore failures due to non-blocking socket 'unavailable' errors\r
- if not is_unavailable_exception(e) and hasattr(e, "headers"):\r
- # The two server-side error headers shouldn't be sent back in this case\r
- self.assertTrue(e.headers.get("X-exception") is None)\r
- self.assertTrue(e.headers.get("X-traceback") is None)\r
- else:\r
- self.fail('ProtocolError not raised')\r
-\r
- def test_fail_with_info(self):\r
- # use the broken message class\r
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass\r
-\r
- # Check that errors in the server send back exception/traceback\r
- # info when flag is set\r
- SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True\r
-\r
- try:\r
- p = xmlrpclib.ServerProxy(URL)\r
- p.pow(6,8)\r
- except (xmlrpclib.ProtocolError, socket.error), e:\r
- # ignore failures due to non-blocking socket 'unavailable' errors\r
- if not is_unavailable_exception(e) and hasattr(e, "headers"):\r
- # We should get error info in the response\r
- expected_err = "invalid literal for int() with base 10: 'I am broken'"\r
- self.assertEqual(e.headers.get("x-exception"), expected_err)\r
- self.assertTrue(e.headers.get("x-traceback") is not None)\r
- else:\r
- self.fail('ProtocolError not raised')\r
-\r
-class CGIHandlerTestCase(unittest.TestCase):\r
- def setUp(self):\r
- self.cgi = SimpleXMLRPCServer.CGIXMLRPCRequestHandler()\r
-\r
- def tearDown(self):\r
- self.cgi = None\r
-\r
- def test_cgi_get(self):\r
- with test_support.EnvironmentVarGuard() as env:\r
- env['REQUEST_METHOD'] = 'GET'\r
- # if the method is GET and no request_text is given, it runs handle_get\r
- # get sysout output\r
- with test_support.captured_stdout() as data_out:\r
- self.cgi.handle_request()\r
-\r
- # parse Status header\r
- data_out.seek(0)\r
- handle = data_out.read()\r
- status = handle.split()[1]\r
- message = ' '.join(handle.split()[2:4])\r
-\r
- self.assertEqual(status, '400')\r
- self.assertEqual(message, 'Bad Request')\r
-\r
-\r
- def test_cgi_xmlrpc_response(self):\r
- data = """<?xml version='1.0'?>\r
- <methodCall>\r
- <methodName>test_method</methodName>\r
- <params>\r
- <param>\r
- <value><string>foo</string></value>\r
- </param>\r
- <param>\r
- <value><string>bar</string></value>\r
- </param>\r
- </params>\r
- </methodCall>\r
- """\r
-\r
- with test_support.EnvironmentVarGuard() as env, \\r
- test_support.captured_stdout() as data_out, \\r
- test_support.captured_stdin() as data_in:\r
- data_in.write(data)\r
- data_in.seek(0)\r
- env['CONTENT_LENGTH'] = str(len(data))\r
- self.cgi.handle_request()\r
- data_out.seek(0)\r
-\r
- # will respond exception, if so, our goal is achieved ;)\r
- handle = data_out.read()\r
-\r
- # start with 44th char so as not to get http header, we just need only xml\r
- self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, handle[44:])\r
-\r
- # Also test the content-length returned by handle_request\r
- # Using the same test method inorder to avoid all the datapassing\r
- # boilerplate code.\r
- # Test for bug: http://bugs.python.org/issue5040\r
-\r
- content = handle[handle.find("<?xml"):]\r
-\r
- self.assertEqual(\r
- int(re.search('Content-Length: (\d+)', handle).group(1)),\r
- len(content))\r
-\r
-\r
-class FakeSocket:\r
-\r
- def __init__(self):\r
- self.data = StringIO.StringIO()\r
-\r
- def send(self, buf):\r
- self.data.write(buf)\r
- return len(buf)\r
-\r
- def sendall(self, buf):\r
- self.data.write(buf)\r
-\r
- def getvalue(self):\r
- return self.data.getvalue()\r
-\r
- def makefile(self, x='r', y=-1):\r
- raise RuntimeError\r
-\r
- def close(self):\r
- pass\r
-\r
-class FakeTransport(xmlrpclib.Transport):\r
- """A Transport instance that records instead of sending a request.\r
-\r
- This class replaces the actual socket used by httplib with a\r
- FakeSocket object that records the request. It doesn't provide a\r
- response.\r
- """\r
-\r
- def make_connection(self, host):\r
- conn = xmlrpclib.Transport.make_connection(self, host)\r
- conn.sock = self.fake_socket = FakeSocket()\r
- return conn\r
-\r
-class TransportSubclassTestCase(unittest.TestCase):\r
-\r
- def issue_request(self, transport_class):\r
- """Return an HTTP request made via transport_class."""\r
- transport = transport_class()\r
- proxy = xmlrpclib.ServerProxy("http://example.com/",\r
- transport=transport)\r
- try:\r
- proxy.pow(6, 8)\r
- except RuntimeError:\r
- return transport.fake_socket.getvalue()\r
- return None\r
-\r
- def test_custom_user_agent(self):\r
- class TestTransport(FakeTransport):\r
-\r
- def send_user_agent(self, conn):\r
- xmlrpclib.Transport.send_user_agent(self, conn)\r
- conn.putheader("X-Test", "test_custom_user_agent")\r
-\r
- req = self.issue_request(TestTransport)\r
- self.assertIn("X-Test: test_custom_user_agent\r\n", req)\r
-\r
- def test_send_host(self):\r
- class TestTransport(FakeTransport):\r
-\r
- def send_host(self, conn, host):\r
- xmlrpclib.Transport.send_host(self, conn, host)\r
- conn.putheader("X-Test", "test_send_host")\r
-\r
- req = self.issue_request(TestTransport)\r
- self.assertIn("X-Test: test_send_host\r\n", req)\r
-\r
- def test_send_request(self):\r
- class TestTransport(FakeTransport):\r
-\r
- def send_request(self, conn, url, body):\r
- xmlrpclib.Transport.send_request(self, conn, url, body)\r
- conn.putheader("X-Test", "test_send_request")\r
-\r
- req = self.issue_request(TestTransport)\r
- self.assertIn("X-Test: test_send_request\r\n", req)\r
-\r
- def test_send_content(self):\r
- class TestTransport(FakeTransport):\r
-\r
- def send_content(self, conn, body):\r
- conn.putheader("X-Test", "test_send_content")\r
- xmlrpclib.Transport.send_content(self, conn, body)\r
-\r
- req = self.issue_request(TestTransport)\r
- self.assertIn("X-Test: test_send_content\r\n", req)\r
-\r
-@test_support.reap_threads\r
-def test_main():\r
- xmlrpc_tests = [XMLRPCTestCase, HelperTestCase, DateTimeTestCase,\r
- BinaryTestCase, FaultTestCase, TransportSubclassTestCase]\r
- xmlrpc_tests.append(SimpleServerTestCase)\r
- xmlrpc_tests.append(KeepaliveServerTestCase1)\r
- xmlrpc_tests.append(KeepaliveServerTestCase2)\r
- try:\r
- import gzip\r
- xmlrpc_tests.append(GzipServerTestCase)\r
- except ImportError:\r
- pass #gzip not supported in this build\r
- xmlrpc_tests.append(MultiPathServerTestCase)\r
- xmlrpc_tests.append(ServerProxyTestCase)\r
- xmlrpc_tests.append(FailingServerTestCase)\r
- xmlrpc_tests.append(CGIHandlerTestCase)\r
-\r
- test_support.run_unittest(*xmlrpc_tests)\r
-\r
-if __name__ == "__main__":\r
- test_main()\r