Commit 15c97465 authored by Guido van Rossum's avatar Guido van Rossum

Patch 1373 by Adam Hupp.

Fixes intermittent errors in test_xmlrpc due to socket timeouts.
parent 204093ac
...@@ -260,7 +260,6 @@ def http_server(evt, numrequests): ...@@ -260,7 +260,6 @@ def http_server(evt, numrequests):
try: try:
serv = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 0), serv = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 0),
logRequests=False, bind_and_activate=False) logRequests=False, bind_and_activate=False)
serv.socket.settimeout(3)
serv.server_bind() serv.server_bind()
global PORT global PORT
PORT = serv.socket.getsockname()[1] PORT = serv.socket.getsockname()[1]
...@@ -284,26 +283,7 @@ def http_server(evt, numrequests): ...@@ -284,26 +283,7 @@ def http_server(evt, numrequests):
evt.set() evt.set()
def is_unavailable_exception(e):
'''Returns True if the given ProtocolError is the product of a server-side
exception caused by the 'temporarily unavailable' response sometimes
given by operations on non-blocking sockets.'''
# sometimes we get a -1 error code and/or empty headers
if e.errcode == -1 or e.headers is None:
return True
exc_mess = e.headers.get('X-exception')
if exc_mess and 'temporarily unavailable' in exc_mess.lower():
return True
return False
# NOTE: The tests in SimpleServerTestCase will ignore failures caused by
# "temporarily unavailable" exceptions raised in SimpleXMLRPCServer. This
# condition occurs infrequently on some platforms, frequently on others, and
# is apparently caused by using SimpleXMLRPCServer with a non-blocking socket.
# If the server class is updated at some point in the future to handle this
# situation more gracefully, these tests should be modified appropriately.
class SimpleServerTestCase(unittest.TestCase): class SimpleServerTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -335,10 +315,8 @@ class SimpleServerTestCase(unittest.TestCase): ...@@ -335,10 +315,8 @@ class SimpleServerTestCase(unittest.TestCase):
p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT) p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
self.assertEqual(p.pow(6,8), 6**8) self.assertEqual(p.pow(6,8), 6**8)
except xmlrpclib.ProtocolError as e: except xmlrpclib.ProtocolError as e:
# ignore failures due to non-blocking socket 'unavailable' errors # protocol error; provide additional information in test output
if not is_unavailable_exception(e): self.fail("%s\n%s" % (e, e.headers))
# protocol error; provide additional information in test output
self.fail("%s\n%s" % (e, e.headers))
def test_introspection1(self): def test_introspection1(self):
try: try:
...@@ -348,10 +326,8 @@ class SimpleServerTestCase(unittest.TestCase): ...@@ -348,10 +326,8 @@ class SimpleServerTestCase(unittest.TestCase):
'system.methodHelp', 'system.methodSignature', 'system.multicall']) 'system.methodHelp', 'system.methodSignature', 'system.multicall'])
self.assertEqual(set(meth), expected_methods) self.assertEqual(set(meth), expected_methods)
except xmlrpclib.ProtocolError as e: except xmlrpclib.ProtocolError as e:
# ignore failures due to non-blocking socket 'unavailable' errors # protocol error; provide additional information in test output
if not is_unavailable_exception(e): self.fail("%s\n%s" % (e, e.headers))
# protocol error; provide additional information in test output
self.fail("%s\n%s" % (e, e.headers))
def test_introspection2(self): def test_introspection2(self):
try: try:
...@@ -359,10 +335,8 @@ class SimpleServerTestCase(unittest.TestCase): ...@@ -359,10 +335,8 @@ class SimpleServerTestCase(unittest.TestCase):
divhelp = p.system.methodHelp('div') divhelp = p.system.methodHelp('div')
self.assertEqual(divhelp, 'This is the div function') self.assertEqual(divhelp, 'This is the div function')
except xmlrpclib.ProtocolError as e: except xmlrpclib.ProtocolError as e:
# ignore failures due to non-blocking socket 'unavailable' errors # protocol error; provide additional information in test output
if not is_unavailable_exception(e): self.fail("%s\n%s" % (e, e.headers))
# protocol error; provide additional information in test output
self.fail("%s\n%s" % (e, e.headers))
def test_introspection3(self): def test_introspection3(self):
# the SimpleXMLRPCServer doesn't support signatures, but # the SimpleXMLRPCServer doesn't support signatures, but
...@@ -372,10 +346,8 @@ class SimpleServerTestCase(unittest.TestCase): ...@@ -372,10 +346,8 @@ class SimpleServerTestCase(unittest.TestCase):
divsig = p.system.methodSignature('div') divsig = p.system.methodSignature('div')
self.assertEqual(divsig, 'signatures not supported') self.assertEqual(divsig, 'signatures not supported')
except xmlrpclib.ProtocolError as e: except xmlrpclib.ProtocolError as e:
# ignore failures due to non-blocking socket 'unavailable' errors # protocol error; provide additional information in test output
if not is_unavailable_exception(e): self.fail("%s\n%s" % (e, e.headers))
# protocol error; provide additional information in test output
self.fail("%s\n%s" % (e, e.headers))
def test_multicall(self): def test_multicall(self):
try: try:
...@@ -389,10 +361,8 @@ class SimpleServerTestCase(unittest.TestCase): ...@@ -389,10 +361,8 @@ class SimpleServerTestCase(unittest.TestCase):
self.assertEqual(pow_result, 6**8) self.assertEqual(pow_result, 6**8)
self.assertEqual(div_result, 127//42) self.assertEqual(div_result, 127//42)
except xmlrpclib.ProtocolError as e: except xmlrpclib.ProtocolError as e:
# ignore failures due to non-blocking socket 'unavailable' errors # protocol error; provide additional information in test output
if not is_unavailable_exception(e): self.fail("%s\n%s" % (e, e.headers))
# protocol error; provide additional information in test output
self.fail("%s\n%s" % (e, e.headers))
# This is a contrived way to make a failure occur on the server side # This is a contrived way to make a failure occur on the server side
...@@ -409,7 +379,7 @@ class FailingServerTestCase(unittest.TestCase): ...@@ -409,7 +379,7 @@ class FailingServerTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
self.evt = threading.Event() self.evt = threading.Event()
# start server thread to handle requests # start server thread to handle requests
serv_args = (self.evt, 2) serv_args = (self.evt, 1)
threading.Thread(target=http_server, args=serv_args).start() threading.Thread(target=http_server, args=serv_args).start()
# wait for port to be assigned to server # wait for port to be assigned to server
...@@ -441,10 +411,8 @@ class FailingServerTestCase(unittest.TestCase): ...@@ -441,10 +411,8 @@ class FailingServerTestCase(unittest.TestCase):
p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT) p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
self.assertEqual(p.pow(6,8), 6**8) self.assertEqual(p.pow(6,8), 6**8)
except xmlrpclib.ProtocolError as e: except xmlrpclib.ProtocolError as e:
# ignore failures due to non-blocking socket 'unavailable' errors # protocol error; provide additional information in test output
if not is_unavailable_exception(e): self.fail("%s\n%s" % (e, e.headers))
# protocol error; provide additional information in test output
self.fail("%s\n%s" % (e, e.headers))
def test_fail_no_info(self): def test_fail_no_info(self):
# use the broken message class # use the broken message class
...@@ -454,11 +422,9 @@ class FailingServerTestCase(unittest.TestCase): ...@@ -454,11 +422,9 @@ class FailingServerTestCase(unittest.TestCase):
p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT) p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
p.pow(6,8) p.pow(6,8)
except xmlrpclib.ProtocolError as e: except xmlrpclib.ProtocolError as e:
# ignore failures due to non-blocking socket 'unavailable' errors # The two server-side error headers shouldn't be sent back in this case
if not is_unavailable_exception(e): self.assertTrue(e.headers.get("X-exception") is None)
# The two server-side error headers shouldn't be sent back in this case self.assertTrue(e.headers.get("X-traceback") is None)
self.assertTrue(e.headers.get("X-exception") is None)
self.assertTrue(e.headers.get("X-traceback") is None)
else: else:
self.fail('ProtocolError not raised') self.fail('ProtocolError not raised')
...@@ -474,12 +440,10 @@ class FailingServerTestCase(unittest.TestCase): ...@@ -474,12 +440,10 @@ class FailingServerTestCase(unittest.TestCase):
p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT) p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
p.pow(6,8) p.pow(6,8)
except xmlrpclib.ProtocolError as e: except xmlrpclib.ProtocolError as e:
# ignore failures due to non-blocking socket 'unavailable' errors # We should get error info in the response
if not is_unavailable_exception(e): expected_err = "invalid literal for int() with base 10: 'I am broken'"
# We should get error info in the response self.assertEqual(e.headers.get("x-exception"), expected_err)
expected_err = "invalid literal for int() with base 10: 'I am broken'" self.assertTrue(e.headers.get("x-traceback") is not None)
self.assertEqual(e.headers.get("x-exception"), expected_err)
self.assertTrue(e.headers.get("x-traceback") is not None)
else: else:
self.fail('ProtocolError not raised') self.fail('ProtocolError not raised')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment