|
|
|
@ -22,6 +22,7 @@ import grpc |
|
|
|
|
from grpc.framework.foundation import logging_pool |
|
|
|
|
|
|
|
|
|
from tests.unit.framework.common import test_constants |
|
|
|
|
from tests.unit.framework.common import bound_socket |
|
|
|
|
|
|
|
|
|
_REQUEST = b'\x00\x00\x00' |
|
|
|
|
_RESPONSE = b'\x00\x00\x01' |
|
|
|
@ -33,44 +34,6 @@ def _handle_unary_unary(unused_request, unused_servicer_context): |
|
|
|
|
return _RESPONSE |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _get_reuse_socket_option(): |
|
|
|
|
try: |
|
|
|
|
return socket.SO_REUSEPORT |
|
|
|
|
except AttributeError: |
|
|
|
|
# SO_REUSEPORT is unavailable on Windows, but SO_REUSEADDR |
|
|
|
|
# allows forcibly re-binding to a port |
|
|
|
|
return socket.SO_REUSEADDR |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _pick_and_bind_port(sock_opt): |
|
|
|
|
# Reserve a port, when we restart the server we want |
|
|
|
|
# to hold onto the port |
|
|
|
|
port = 0 |
|
|
|
|
for address_family in (socket.AF_INET6, socket.AF_INET): |
|
|
|
|
try: |
|
|
|
|
s = socket.socket(address_family, socket.SOCK_STREAM) |
|
|
|
|
except socket.error: |
|
|
|
|
continue # this address family is unavailable |
|
|
|
|
s.setsockopt(socket.SOL_SOCKET, sock_opt, 1) |
|
|
|
|
try: |
|
|
|
|
s.bind(('localhost', port)) |
|
|
|
|
# for socket.SOCK_STREAM sockets, it is necessary to call |
|
|
|
|
# listen to get the desired behavior. |
|
|
|
|
s.listen(1) |
|
|
|
|
port = s.getsockname()[1] |
|
|
|
|
except socket.error: |
|
|
|
|
# port was not available on the current address family |
|
|
|
|
# try again |
|
|
|
|
port = 0 |
|
|
|
|
break |
|
|
|
|
finally: |
|
|
|
|
s.close() |
|
|
|
|
if s: |
|
|
|
|
return port if port != 0 else _pick_and_bind_port(sock_opt) |
|
|
|
|
else: |
|
|
|
|
return None # no address family was available |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ReconnectTest(unittest.TestCase): |
|
|
|
|
|
|
|
|
|
def test_reconnect(self): |
|
|
|
@ -79,27 +42,24 @@ class ReconnectTest(unittest.TestCase): |
|
|
|
|
'UnaryUnary': |
|
|
|
|
grpc.unary_unary_rpc_method_handler(_handle_unary_unary) |
|
|
|
|
}) |
|
|
|
|
sock_opt = _get_reuse_socket_option() |
|
|
|
|
port = _pick_and_bind_port(sock_opt) |
|
|
|
|
self.assertIsNotNone(port) |
|
|
|
|
|
|
|
|
|
server = grpc.server(server_pool, (handler,)) |
|
|
|
|
server.add_insecure_port('[::]:{}'.format(port)) |
|
|
|
|
server.start() |
|
|
|
|
channel = grpc.insecure_channel('localhost:%d' % port) |
|
|
|
|
multi_callable = channel.unary_unary(_UNARY_UNARY) |
|
|
|
|
self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) |
|
|
|
|
server.stop(None) |
|
|
|
|
# By default, the channel connectivity is checked every 5s |
|
|
|
|
# GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS can be set to change |
|
|
|
|
# this. |
|
|
|
|
time.sleep(5.1) |
|
|
|
|
server = grpc.server(server_pool, (handler,)) |
|
|
|
|
server.add_insecure_port('[::]:{}'.format(port)) |
|
|
|
|
server.start() |
|
|
|
|
self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) |
|
|
|
|
server.stop(None) |
|
|
|
|
channel.close() |
|
|
|
|
with bound_socket() as (_, port): |
|
|
|
|
server = grpc.server(server_pool, (handler,)) |
|
|
|
|
server.add_insecure_port('[::]:{}'.format(port)) |
|
|
|
|
server.start() |
|
|
|
|
channel = grpc.insecure_channel('localhost:%d' % port) |
|
|
|
|
multi_callable = channel.unary_unary(_UNARY_UNARY) |
|
|
|
|
self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) |
|
|
|
|
server.stop(None) |
|
|
|
|
# By default, the channel connectivity is checked every 5s |
|
|
|
|
# GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS can be set to change |
|
|
|
|
# this. |
|
|
|
|
time.sleep(5.1) |
|
|
|
|
server = grpc.server(server_pool, (handler,)) |
|
|
|
|
server.add_insecure_port('[::]:{}'.format(port)) |
|
|
|
|
server.start() |
|
|
|
|
self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) |
|
|
|
|
server.stop(None) |
|
|
|
|
channel.close() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
|