Add test case reproducing #146 (fixed to behave consistently)

This commit is contained in:
joo 2020-12-04 15:55:39 +01:00
parent 7693961fb9
commit 93db454cb5
3 changed files with 48 additions and 8 deletions

View File

@ -479,6 +479,8 @@ class Connection(object):
self.write_packet(handshake)
def _handle_exception(self, exc, exc_info):
final_handler = self.handle_exception
# Call the current PacketReactor's exception handler.
try:
if self.reactor.handle_exception(exc, exc_info):
@ -499,9 +501,9 @@ class Connection(object):
caught = False
# Call the user-specified final exception handler.
if self.handle_exception not in (None, False):
if final_handler not in (None, False):
try:
self.handle_exception(exc, exc_info)
final_handler(exc, exc_info)
except Exception as new_exc:
exc, exc_info = new_exc, sys.exc_info()
@ -516,7 +518,7 @@ class Connection(object):
self.disconnect(immediate=True)
# If allowed by the final exception handler, re-raise the exception.
if self.handle_exception is None and not caught:
if final_handler is None and not caught:
exc_value, exc_tb = exc_info[1:]
raise exc_value.with_traceback(exc_tb)

View File

@ -70,11 +70,23 @@ class FakeClientHandler(object):
# Communicate with the client until disconnected.
try:
self._run_handshake()
try:
self.socket.shutdown(socket.SHUT_RDWR)
except IOError:
pass
except (FakeClientDisconnect, BrokenPipeError) as exc:
if not self.handle_abnormal_disconnect(exc):
raise
finally:
self.socket.close()
self.socket_file.close()
def handle_abnormal_disconnect(self, exc):
# Called when the client disconnects in an abnormal fashion. If this
# handler returns True, the error is ignored and is treated as a normal
# disconnection.
return False
def handle_connection(self):
# Called in the handshake state, just after the client connects,
# before any packets have been exchanged.
@ -363,7 +375,7 @@ class FakeServer(object):
'minecraft_version', 'client_handler_type', 'server_type', \
'packets_handshake', 'packets_login', 'packets_playing', \
'packets_status', 'lock', 'stopping', 'private_key', \
'public_key_bytes', 'test_case',
'public_key_bytes', 'test_case'
def __init__(self, minecraft_version=None, compression_threshold=None,
client_handler_type=FakeClientHandler, private_key=None,
@ -407,7 +419,7 @@ class FakeServer(object):
self.listen_socket = socket.socket()
self.listen_socket.settimeout(0.1)
self.listen_socket.bind(('localhost', 0))
self.listen_socket.listen(0)
self.listen_socket.listen(1)
self.lock = threading.Lock()
self.stopping = False
@ -581,8 +593,6 @@ class _FakeServerTest(unittest.TestCase):
if thread is not None and thread.is_alive():
errors.append({
'msg': 'Thread "%s" timed out.' % thread.name})
if client_exc_info[0] is None:
client_exc_info[0] = client.exc_info
except Exception:
errors.insert(0, {
'msg': 'Exception in main thread',

View File

@ -360,6 +360,34 @@ class HandleExceptionTest(ConnectTest):
client.connect()
class ExceptionReconnectTest(ConnectTest):
class CustomException(Exception):
pass
def setUp(self):
self.phase = 0
def _start_client(self, client):
@client.listener(clientbound.play.JoinGamePacket)
def handle_join_game(packet):
if self.phase == 0:
self.phase += 1
raise self.CustomException
else:
raise fake_server.FakeServerTestSuccess
@client.exception_handler(self.CustomException, early=True)
def handle_custom_exception(exc, exc_info):
client.disconnect(immediate=True)
client.connect()
client.connect()
class client_handler_type(ConnectTest.client_handler_type):
def handle_abnormal_disconnect(self, exc):
return True
class VersionNegotiationEdgeCases(fake_server._FakeServerTest):
earliest_version = SUPPORTED_PROTOCOL_VERSIONS[0]
latest_version = SUPPORTED_PROTOCOL_VERSIONS[-1]