|
|
|
@ -13,6 +13,7 @@ |
|
|
|
|
# limitations under the License. |
|
|
|
|
"""Tests behavior of the connectivity state.""" |
|
|
|
|
|
|
|
|
|
import asyncio |
|
|
|
|
import logging |
|
|
|
|
import threading |
|
|
|
|
import unittest |
|
|
|
@ -29,6 +30,13 @@ from tests_aio.unit._test_base import AioTestBase |
|
|
|
|
_INVALID_BACKEND_ADDRESS = '0.0.0.1:2' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def _block_until_certain_state(channel, expected_state): |
|
|
|
|
state = channel.get_state() |
|
|
|
|
while state != expected_state: |
|
|
|
|
await channel.wait_for_state_change(state) |
|
|
|
|
state = channel.get_state() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestConnectivityState(AioTestBase): |
|
|
|
|
|
|
|
|
|
async def setUp(self): |
|
|
|
@ -38,59 +46,65 @@ class TestConnectivityState(AioTestBase): |
|
|
|
|
await self._server.stop(None) |
|
|
|
|
|
|
|
|
|
async def test_unavailable_backend(self): |
|
|
|
|
channel = aio.insecure_channel(_INVALID_BACKEND_ADDRESS) |
|
|
|
|
|
|
|
|
|
async with aio.insecure_channel(_INVALID_BACKEND_ADDRESS) as channel: |
|
|
|
|
self.assertEqual(grpc.ChannelConnectivity.IDLE, |
|
|
|
|
channel.check_connectivity_state(False)) |
|
|
|
|
channel.get_state(False)) |
|
|
|
|
self.assertEqual(grpc.ChannelConnectivity.IDLE, |
|
|
|
|
channel.check_connectivity_state(True)) |
|
|
|
|
self.assertEqual( |
|
|
|
|
grpc.ChannelConnectivity.CONNECTING, await |
|
|
|
|
channel.watch_connectivity_state(grpc.ChannelConnectivity.IDLE)) |
|
|
|
|
self.assertEqual( |
|
|
|
|
grpc.ChannelConnectivity.TRANSIENT_FAILURE, await |
|
|
|
|
channel.watch_connectivity_state(grpc.ChannelConnectivity.CONNECTING |
|
|
|
|
)) |
|
|
|
|
channel.get_state(True)) |
|
|
|
|
|
|
|
|
|
await channel.close() |
|
|
|
|
async def waiting_transient_failure(): |
|
|
|
|
state = channel.get_state() |
|
|
|
|
while state != grpc.ChannelConnectivity.TRANSIENT_FAILURE: |
|
|
|
|
channel.wait_for_state_change(state) |
|
|
|
|
|
|
|
|
|
async def test_normal_backend(self): |
|
|
|
|
channel = aio.insecure_channel(self._server_address) |
|
|
|
|
# Should not time out |
|
|
|
|
await asyncio.wait_for( |
|
|
|
|
_block_until_certain_state( |
|
|
|
|
channel, grpc.ChannelConnectivity.TRANSIENT_FAILURE), |
|
|
|
|
test_constants.SHORT_TIMEOUT) |
|
|
|
|
|
|
|
|
|
current_state = channel.check_connectivity_state(True) |
|
|
|
|
async def test_normal_backend(self): |
|
|
|
|
async with aio.insecure_channel(self._server_address) as channel: |
|
|
|
|
current_state = channel.get_state(True) |
|
|
|
|
self.assertEqual(grpc.ChannelConnectivity.IDLE, current_state) |
|
|
|
|
|
|
|
|
|
deadline = time.time() + test_constants.SHORT_TIMEOUT |
|
|
|
|
|
|
|
|
|
while current_state != grpc.ChannelConnectivity.READY: |
|
|
|
|
current_state = await channel.watch_connectivity_state( |
|
|
|
|
current_state, deadline - time.time()) |
|
|
|
|
self.assertIsNotNone(current_state) |
|
|
|
|
|
|
|
|
|
await channel.close() |
|
|
|
|
# Should not time out |
|
|
|
|
await asyncio.wait_for( |
|
|
|
|
_block_until_certain_state(channel, |
|
|
|
|
grpc.ChannelConnectivity.READY), |
|
|
|
|
test_constants.SHORT_TIMEOUT) |
|
|
|
|
|
|
|
|
|
async def test_timeout(self): |
|
|
|
|
channel = aio.insecure_channel(self._server_address) |
|
|
|
|
|
|
|
|
|
async with aio.insecure_channel(self._server_address) as channel: |
|
|
|
|
self.assertEqual(grpc.ChannelConnectivity.IDLE, |
|
|
|
|
channel.check_connectivity_state(False)) |
|
|
|
|
channel.get_state(False)) |
|
|
|
|
|
|
|
|
|
# If timed out, the function should return None. |
|
|
|
|
self.assertIsNone(await channel.watch_connectivity_state( |
|
|
|
|
grpc.ChannelConnectivity.IDLE, test_constants.SHORT_TIMEOUT)) |
|
|
|
|
|
|
|
|
|
await channel.close() |
|
|
|
|
with self.assertRaises(asyncio.TimeoutError): |
|
|
|
|
await asyncio.wait_for( |
|
|
|
|
_block_until_certain_state(channel, |
|
|
|
|
grpc.ChannelConnectivity.READY), |
|
|
|
|
test_constants.SHORT_TIMEOUT) |
|
|
|
|
|
|
|
|
|
async def test_shutdown(self): |
|
|
|
|
channel = aio.insecure_channel(self._server_address) |
|
|
|
|
|
|
|
|
|
self.assertEqual(grpc.ChannelConnectivity.IDLE, |
|
|
|
|
channel.check_connectivity_state(False)) |
|
|
|
|
channel.get_state(False)) |
|
|
|
|
|
|
|
|
|
await channel.close() |
|
|
|
|
|
|
|
|
|
self.assertEqual(grpc.ChannelConnectivity.SHUTDOWN, |
|
|
|
|
channel.check_connectivity_state(False)) |
|
|
|
|
channel.get_state(True)) |
|
|
|
|
|
|
|
|
|
self.assertEqual(grpc.ChannelConnectivity.SHUTDOWN, |
|
|
|
|
channel.get_state(False)) |
|
|
|
|
|
|
|
|
|
# It can raise Exception since it is an usage error, but it should not |
|
|
|
|
# segfault or abort. |
|
|
|
|
with self.assertRaises(Exception): |
|
|
|
|
await channel.wait_for_state_change( |
|
|
|
|
grpc.ChannelConnectivity.SHUTDOWN) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
|