mirror of https://github.com/grpc/grpc.git
Merge pull request #21621 from lidizheng/aio-connectivity
[Aio] Implement connectivity state related APIspull/21662/head
commit
4bc37f9eea
12 changed files with 273 additions and 26 deletions
@ -0,0 +1,16 @@ |
||||
# Copyright 2020 The gRPC Authors |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
UNREACHABLE_TARGET = '0.0.0.1:1111' |
||||
UNARY_CALL_WITH_SLEEP_VALUE = 0.2 |
@ -0,0 +1,118 @@ |
||||
# Copyright 2019 The gRPC Authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
"""Tests behavior of the connectivity state.""" |
||||
|
||||
import asyncio |
||||
import logging |
||||
import threading |
||||
import time |
||||
import unittest |
||||
|
||||
import grpc |
||||
from grpc.experimental import aio |
||||
|
||||
from tests.unit.framework.common import test_constants |
||||
from tests_aio.unit._constants import UNREACHABLE_TARGET |
||||
from tests_aio.unit._test_base import AioTestBase |
||||
from tests_aio.unit._test_server import start_test_server |
||||
|
||||
|
||||
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): |
||||
self._server_address, self._server = await start_test_server() |
||||
|
||||
async def tearDown(self): |
||||
await self._server.stop(None) |
||||
|
||||
async def test_unavailable_backend(self): |
||||
async with aio.insecure_channel(UNREACHABLE_TARGET) as channel: |
||||
self.assertEqual(grpc.ChannelConnectivity.IDLE, |
||||
channel.get_state(False)) |
||||
self.assertEqual(grpc.ChannelConnectivity.IDLE, |
||||
channel.get_state(True)) |
||||
|
||||
# Should not time out |
||||
await asyncio.wait_for( |
||||
_block_until_certain_state( |
||||
channel, grpc.ChannelConnectivity.TRANSIENT_FAILURE), |
||||
test_constants.SHORT_TIMEOUT) |
||||
|
||||
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) |
||||
|
||||
# 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): |
||||
async with aio.insecure_channel(self._server_address) as channel: |
||||
self.assertEqual(grpc.ChannelConnectivity.IDLE, |
||||
channel.get_state(False)) |
||||
|
||||
# If timed out, the function should return None. |
||||
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.get_state(False)) |
||||
|
||||
# Waiting for changes in a separate coroutine |
||||
wait_started = asyncio.Event() |
||||
|
||||
async def a_pending_wait(): |
||||
wait_started.set() |
||||
await channel.wait_for_state_change(grpc.ChannelConnectivity.IDLE) |
||||
|
||||
pending_task = self.loop.create_task(a_pending_wait()) |
||||
await wait_started.wait() |
||||
|
||||
await channel.close() |
||||
|
||||
self.assertEqual(grpc.ChannelConnectivity.SHUTDOWN, |
||||
channel.get_state(True)) |
||||
|
||||
self.assertEqual(grpc.ChannelConnectivity.SHUTDOWN, |
||||
channel.get_state(False)) |
||||
|
||||
# Make sure there isn't any exception in the task |
||||
await pending_task |
||||
|
||||
# It can raise exceptions since it is an usage error, but it should not |
||||
# segfault or abort. |
||||
with self.assertRaises(RuntimeError): |
||||
await channel.wait_for_state_change( |
||||
grpc.ChannelConnectivity.SHUTDOWN) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig(level=logging.DEBUG) |
||||
unittest.main(verbosity=2) |
Loading…
Reference in new issue