mirror of https://github.com/grpc/grpc.git
parent
c333aac060
commit
5d8a5ef8c7
8 changed files with 730 additions and 124 deletions
@ -0,0 +1,66 @@ |
||||
# 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. |
||||
"""AsyncIO version of Channelz servicer.""" |
||||
|
||||
from grpc.experimental import aio |
||||
|
||||
import grpc_channelz.v1.channelz_pb2 as _channelz_pb2 |
||||
import grpc_channelz.v1.channelz_pb2_grpc as _channelz_pb2_grpc |
||||
from grpc_channelz.v1._servicer import ChannelzServicer as _SyncChannelzServicer |
||||
|
||||
|
||||
class ChannelzServicer(_channelz_pb2_grpc.ChannelzServicer): |
||||
"""AsyncIO servicer for handling RPCs for service statuses.""" |
||||
|
||||
@staticmethod |
||||
async def GetTopChannels(request: _channelz_pb2.GetTopChannelsRequest, |
||||
context: aio.ServicerContext |
||||
) -> _channelz_pb2.GetTopChannelsResponse: |
||||
return _SyncChannelzServicer.GetTopChannels(request, context) |
||||
|
||||
@staticmethod |
||||
async def GetServers(request: _channelz_pb2.GetServersRequest, |
||||
context: aio.ServicerContext |
||||
) -> _channelz_pb2.GetServersResponse: |
||||
return _SyncChannelzServicer.GetServers(request, context) |
||||
|
||||
@staticmethod |
||||
async def GetServer(request: _channelz_pb2.GetServerRequest, |
||||
context: aio.ServicerContext |
||||
) -> _channelz_pb2.GetServerResponse: |
||||
return _SyncChannelzServicer.GetServer(request, context) |
||||
|
||||
@staticmethod |
||||
async def GetServerSockets(request: _channelz_pb2.GetServerSocketsRequest, |
||||
context: aio.ServicerContext |
||||
) -> _channelz_pb2.GetServerSocketsResponse: |
||||
return _SyncChannelzServicer.GetServerSockets(request, context) |
||||
|
||||
@staticmethod |
||||
async def GetChannel(request: _channelz_pb2.GetChannelRequest, |
||||
context: aio.ServicerContext |
||||
) -> _channelz_pb2.GetChannelResponse: |
||||
return _SyncChannelzServicer.GetChannel(request, context) |
||||
|
||||
@staticmethod |
||||
async def GetSubchannel(request: _channelz_pb2.GetSubchannelRequest, |
||||
context: aio.ServicerContext |
||||
) -> _channelz_pb2.GetSubchannelResponse: |
||||
return _SyncChannelzServicer.GetSubchannel(request, context) |
||||
|
||||
@staticmethod |
||||
async def GetSocket(request: _channelz_pb2.GetSocketRequest, |
||||
context: aio.ServicerContext |
||||
) -> _channelz_pb2.GetSocketResponse: |
||||
return _SyncChannelzServicer.GetSocket(request, context) |
@ -0,0 +1,120 @@ |
||||
# 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. |
||||
"""Channelz debug service implementation in gRPC Python.""" |
||||
|
||||
import grpc |
||||
from grpc._cython import cygrpc |
||||
|
||||
import grpc_channelz.v1.channelz_pb2 as _channelz_pb2 |
||||
import grpc_channelz.v1.channelz_pb2_grpc as _channelz_pb2_grpc |
||||
|
||||
from google.protobuf import json_format |
||||
|
||||
|
||||
class ChannelzServicer(_channelz_pb2_grpc.ChannelzServicer): |
||||
"""Servicer handling RPCs for service statuses.""" |
||||
|
||||
@staticmethod |
||||
def GetTopChannels(request, context): |
||||
try: |
||||
return json_format.Parse( |
||||
cygrpc.channelz_get_top_channels(request.start_channel_id), |
||||
_channelz_pb2.GetTopChannelsResponse(), |
||||
) |
||||
except (ValueError, json_format.ParseError) as e: |
||||
context.set_code(grpc.StatusCode.INTERNAL) |
||||
context.set_details(str(e)) |
||||
|
||||
@staticmethod |
||||
def GetServers(request, context): |
||||
try: |
||||
return json_format.Parse( |
||||
cygrpc.channelz_get_servers(request.start_server_id), |
||||
_channelz_pb2.GetServersResponse(), |
||||
) |
||||
except (ValueError, json_format.ParseError) as e: |
||||
context.set_code(grpc.StatusCode.INTERNAL) |
||||
context.set_details(str(e)) |
||||
|
||||
@staticmethod |
||||
def GetServer(request, context): |
||||
try: |
||||
return json_format.Parse( |
||||
cygrpc.channelz_get_server(request.server_id), |
||||
_channelz_pb2.GetServerResponse(), |
||||
) |
||||
except ValueError as e: |
||||
context.set_code(grpc.StatusCode.NOT_FOUND) |
||||
context.set_details(str(e)) |
||||
except json_format.ParseError as e: |
||||
context.set_code(grpc.StatusCode.INTERNAL) |
||||
context.set_details(str(e)) |
||||
|
||||
@staticmethod |
||||
def GetServerSockets(request, context): |
||||
try: |
||||
return json_format.Parse( |
||||
cygrpc.channelz_get_server_sockets(request.server_id, |
||||
request.start_socket_id, |
||||
request.max_results), |
||||
_channelz_pb2.GetServerSocketsResponse(), |
||||
) |
||||
except ValueError as e: |
||||
context.set_code(grpc.StatusCode.NOT_FOUND) |
||||
context.set_details(str(e)) |
||||
except json_format.ParseError as e: |
||||
context.set_code(grpc.StatusCode.INTERNAL) |
||||
context.set_details(str(e)) |
||||
|
||||
@staticmethod |
||||
def GetChannel(request, context): |
||||
try: |
||||
return json_format.Parse( |
||||
cygrpc.channelz_get_channel(request.channel_id), |
||||
_channelz_pb2.GetChannelResponse(), |
||||
) |
||||
except ValueError as e: |
||||
context.set_code(grpc.StatusCode.NOT_FOUND) |
||||
context.set_details(str(e)) |
||||
except json_format.ParseError as e: |
||||
context.set_code(grpc.StatusCode.INTERNAL) |
||||
context.set_details(str(e)) |
||||
|
||||
@staticmethod |
||||
def GetSubchannel(request, context): |
||||
try: |
||||
return json_format.Parse( |
||||
cygrpc.channelz_get_subchannel(request.subchannel_id), |
||||
_channelz_pb2.GetSubchannelResponse(), |
||||
) |
||||
except ValueError as e: |
||||
context.set_code(grpc.StatusCode.NOT_FOUND) |
||||
context.set_details(str(e)) |
||||
except json_format.ParseError as e: |
||||
context.set_code(grpc.StatusCode.INTERNAL) |
||||
context.set_details(str(e)) |
||||
|
||||
@staticmethod |
||||
def GetSocket(request, context): |
||||
try: |
||||
return json_format.Parse( |
||||
cygrpc.channelz_get_socket(request.socket_id), |
||||
_channelz_pb2.GetSocketResponse(), |
||||
) |
||||
except ValueError as e: |
||||
context.set_code(grpc.StatusCode.NOT_FOUND) |
||||
context.set_details(str(e)) |
||||
except json_format.ParseError as e: |
||||
context.set_code(grpc.StatusCode.INTERNAL) |
||||
context.set_details(str(e)) |
@ -0,0 +1,29 @@ |
||||
# 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. |
||||
|
||||
package(default_visibility = ["//visibility:public"]) |
||||
|
||||
py_test( |
||||
name = "channelz_servicer_test", |
||||
size = "small", |
||||
srcs = ["channelz_servicer_test.py"], |
||||
imports = ["../../"], |
||||
python_version = "PY3", |
||||
deps = [ |
||||
"//src/python/grpcio/grpc:grpcio", |
||||
"//src/python/grpcio_channelz/grpc_channelz/v1:grpc_channelz", |
||||
"//src/python/grpcio_tests/tests/unit/framework/common", |
||||
"//src/python/grpcio_tests/tests_aio/unit:_test_base", |
||||
], |
||||
) |
@ -0,0 +1,13 @@ |
||||
# 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. |
@ -0,0 +1,446 @@ |
||||
# 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. |
||||
"""Tests of grpc_channelz.v1.channelz.""" |
||||
|
||||
import unittest |
||||
import logging |
||||
import asyncio |
||||
|
||||
import grpc |
||||
from grpc.experimental import aio |
||||
|
||||
from grpc_channelz.v1 import channelz |
||||
from grpc_channelz.v1 import channelz_pb2 |
||||
from grpc_channelz.v1 import channelz_pb2_grpc |
||||
|
||||
from tests.unit.framework.common import test_constants |
||||
from tests_aio.unit._test_base import AioTestBase |
||||
|
||||
aio.shutdown_grpc_aio() |
||||
|
||||
_SUCCESSFUL_UNARY_UNARY = '/test/SuccessfulUnaryUnary' |
||||
_FAILED_UNARY_UNARY = '/test/FailedUnaryUnary' |
||||
_SUCCESSFUL_STREAM_STREAM = '/test/SuccessfulStreamStream' |
||||
|
||||
_REQUEST = b'\x00\x00\x00' |
||||
_RESPONSE = b'\x01\x01\x01' |
||||
|
||||
_DISABLE_REUSE_PORT = (('grpc.so_reuseport', 0),) |
||||
_ENABLE_CHANNELZ = (('grpc.enable_channelz', 1),) |
||||
_DISABLE_CHANNELZ = (('grpc.enable_channelz', 0),) |
||||
|
||||
|
||||
async def _successful_unary_unary(request, servicer_context): |
||||
return _RESPONSE |
||||
|
||||
|
||||
async def _failed_unary_unary(request, servicer_context): |
||||
servicer_context.set_code(grpc.StatusCode.INTERNAL) |
||||
servicer_context.set_details("Channelz Test Intended Failure") |
||||
|
||||
|
||||
async def _successful_stream_stream(request_iterator, servicer_context): |
||||
async for _ in request_iterator: |
||||
yield _RESPONSE |
||||
|
||||
|
||||
class _GenericHandler(grpc.GenericRpcHandler): |
||||
|
||||
def service(self, handler_call_details): |
||||
if handler_call_details.method == _SUCCESSFUL_UNARY_UNARY: |
||||
return grpc.unary_unary_rpc_method_handler(_successful_unary_unary) |
||||
elif handler_call_details.method == _FAILED_UNARY_UNARY: |
||||
return grpc.unary_unary_rpc_method_handler(_failed_unary_unary) |
||||
elif handler_call_details.method == _SUCCESSFUL_STREAM_STREAM: |
||||
return grpc.stream_stream_rpc_method_handler( |
||||
_successful_stream_stream) |
||||
else: |
||||
return None |
||||
|
||||
|
||||
class _ChannelServerPair(object): |
||||
|
||||
async def start(self): |
||||
# Server will enable channelz service |
||||
self.server = aio.server(options=_DISABLE_REUSE_PORT + _ENABLE_CHANNELZ) |
||||
port = self.server.add_insecure_port('[::]:0') |
||||
self.server.add_generic_rpc_handlers((_GenericHandler(),)) |
||||
await self.server.start() |
||||
|
||||
# Channel will enable channelz service... |
||||
self.channel = aio.insecure_channel('localhost:%d' % port, |
||||
options=_ENABLE_CHANNELZ) |
||||
|
||||
|
||||
# Stores channel-server pairs globally, since the memory deallocation is |
||||
# non-deterministic in both Core and Python with multiple threads. The |
||||
# destroyed Channelz node might still present. So, as a work around, this |
||||
# test doesn't close channel-server-pairs between cases. |
||||
_pairs = [] |
||||
|
||||
|
||||
async def _generate_channel_server_pairs(n): |
||||
"""Creates channel-server pairs globally, returns their indexes.""" |
||||
new_pairs = [_ChannelServerPair() for i in range(n)] |
||||
for pair in new_pairs: |
||||
await pair.start() |
||||
_pairs.extend(new_pairs) |
||||
return list(range(len(_pairs) - n, len(_pairs))) |
||||
|
||||
|
||||
class ChannelzServicerTest(AioTestBase): |
||||
|
||||
async def setUp(self): |
||||
self._pairs = [] |
||||
# This server is for Channelz info fetching only |
||||
# It self should not enable Channelz |
||||
self._server = aio.server(options=_DISABLE_REUSE_PORT + |
||||
_DISABLE_CHANNELZ) |
||||
port = self._server.add_insecure_port('[::]:0') |
||||
channelz.add_channelz_servicer(self._server) |
||||
await self._server.start() |
||||
|
||||
# This channel is used to fetch Channelz info only |
||||
# Channelz should not be enabled |
||||
self._channel = aio.insecure_channel('localhost:%d' % port, |
||||
options=_DISABLE_CHANNELZ) |
||||
self._channelz_stub = channelz_pb2_grpc.ChannelzStub(self._channel) |
||||
|
||||
async def tearDown(self): |
||||
await self._server.stop(None) |
||||
await self._channel.close() |
||||
|
||||
async def _send_successful_unary_unary(self, idx): |
||||
call = _pairs[idx].channel.unary_unary(_SUCCESSFUL_UNARY_UNARY)( |
||||
_REQUEST) |
||||
self.assertEqual(grpc.StatusCode.OK, await call.code()) |
||||
|
||||
async def _send_failed_unary_unary(self, idx): |
||||
try: |
||||
await _pairs[idx].channel.unary_unary(_FAILED_UNARY_UNARY)(_REQUEST) |
||||
except grpc.RpcError: |
||||
return |
||||
else: |
||||
self.fail("This call supposed to fail") |
||||
|
||||
async def _send_successful_stream_stream(self, idx): |
||||
call = _pairs[idx].channel.stream_stream(_SUCCESSFUL_STREAM_STREAM)( |
||||
iter([_REQUEST] * test_constants.STREAM_LENGTH)) |
||||
cnt = 0 |
||||
async for _ in call: |
||||
cnt += 1 |
||||
self.assertEqual(cnt, test_constants.STREAM_LENGTH) |
||||
|
||||
async def _get_channel_id(self, idx): |
||||
"""Channel id may not be consecutive""" |
||||
resp = await self._channelz_stub.GetTopChannels( |
||||
channelz_pb2.GetTopChannelsRequest(start_channel_id=0)) |
||||
self.assertGreater(len(resp.channel), idx) |
||||
return resp.channel[idx].ref.channel_id |
||||
|
||||
async def _get_server_by_id(self, idx): |
||||
"""Server id may not be consecutive""" |
||||
resp = await self._channelz_stub.GetServers( |
||||
channelz_pb2.GetServersRequest(start_server_id=0)) |
||||
return resp.server[idx] |
||||
|
||||
async def test_get_top_channels_basic(self): |
||||
before = await self._channelz_stub.GetTopChannels( |
||||
channelz_pb2.GetTopChannelsRequest(start_channel_id=0)) |
||||
await _generate_channel_server_pairs(1) |
||||
after = await self._channelz_stub.GetTopChannels( |
||||
channelz_pb2.GetTopChannelsRequest(start_channel_id=0)) |
||||
self.assertEqual(len(after.channel) - len(before.channel), 1) |
||||
self.assertEqual(after.end, True) |
||||
|
||||
async def test_get_top_channels_high_start_id(self): |
||||
await _generate_channel_server_pairs(1) |
||||
resp = await self._channelz_stub.GetTopChannels( |
||||
channelz_pb2.GetTopChannelsRequest(start_channel_id=10000)) |
||||
self.assertEqual(len(resp.channel), 0) |
||||
self.assertEqual(resp.end, True) |
||||
|
||||
async def test_successful_request(self): |
||||
idx = await _generate_channel_server_pairs(1) |
||||
await self._send_successful_unary_unary(idx[0]) |
||||
resp = await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest( |
||||
channel_id=await self._get_channel_id(idx[0]))) |
||||
self.assertEqual(resp.channel.data.calls_started, 1) |
||||
self.assertEqual(resp.channel.data.calls_succeeded, 1) |
||||
self.assertEqual(resp.channel.data.calls_failed, 0) |
||||
|
||||
async def test_failed_request(self): |
||||
idx = await _generate_channel_server_pairs(1) |
||||
await self._send_failed_unary_unary(idx[0]) |
||||
resp = await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest( |
||||
channel_id=await self._get_channel_id(idx[0]))) |
||||
self.assertEqual(resp.channel.data.calls_started, 1) |
||||
self.assertEqual(resp.channel.data.calls_succeeded, 0) |
||||
self.assertEqual(resp.channel.data.calls_failed, 1) |
||||
|
||||
async def test_many_requests(self): |
||||
idx = await _generate_channel_server_pairs(1) |
||||
k_success = 7 |
||||
k_failed = 9 |
||||
for i in range(k_success): |
||||
await self._send_successful_unary_unary(idx[0]) |
||||
for i in range(k_failed): |
||||
await self._send_failed_unary_unary(idx[0]) |
||||
resp = await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest( |
||||
channel_id=await self._get_channel_id(idx[0]))) |
||||
self.assertEqual(resp.channel.data.calls_started, k_success + k_failed) |
||||
self.assertEqual(resp.channel.data.calls_succeeded, k_success) |
||||
self.assertEqual(resp.channel.data.calls_failed, k_failed) |
||||
|
||||
async def test_many_requests_many_channel(self): |
||||
k_channels = 4 |
||||
idx = await _generate_channel_server_pairs(k_channels) |
||||
k_success = 11 |
||||
k_failed = 13 |
||||
for i in range(k_success): |
||||
await self._send_successful_unary_unary(idx[0]) |
||||
await self._send_successful_unary_unary(idx[2]) |
||||
for i in range(k_failed): |
||||
await self._send_failed_unary_unary(idx[1]) |
||||
await self._send_failed_unary_unary(idx[2]) |
||||
|
||||
# The first channel saw only successes |
||||
resp = await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest( |
||||
channel_id=await self._get_channel_id(idx[0]))) |
||||
self.assertEqual(resp.channel.data.calls_started, k_success) |
||||
self.assertEqual(resp.channel.data.calls_succeeded, k_success) |
||||
self.assertEqual(resp.channel.data.calls_failed, 0) |
||||
|
||||
# The second channel saw only failures |
||||
resp = await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest( |
||||
channel_id=await self._get_channel_id(idx[1]))) |
||||
self.assertEqual(resp.channel.data.calls_started, k_failed) |
||||
self.assertEqual(resp.channel.data.calls_succeeded, 0) |
||||
self.assertEqual(resp.channel.data.calls_failed, k_failed) |
||||
|
||||
# The third channel saw both successes and failures |
||||
resp = await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest( |
||||
channel_id=await self._get_channel_id(idx[2]))) |
||||
self.assertEqual(resp.channel.data.calls_started, k_success + k_failed) |
||||
self.assertEqual(resp.channel.data.calls_succeeded, k_success) |
||||
self.assertEqual(resp.channel.data.calls_failed, k_failed) |
||||
|
||||
# The fourth channel saw nothing |
||||
resp = await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest( |
||||
channel_id=await self._get_channel_id(idx[3]))) |
||||
self.assertEqual(resp.channel.data.calls_started, 0) |
||||
self.assertEqual(resp.channel.data.calls_succeeded, 0) |
||||
self.assertEqual(resp.channel.data.calls_failed, 0) |
||||
|
||||
async def test_many_subchannels(self): |
||||
k_channels = 4 |
||||
idx = await _generate_channel_server_pairs(k_channels) |
||||
k_success = 17 |
||||
k_failed = 19 |
||||
for i in range(k_success): |
||||
await self._send_successful_unary_unary(idx[0]) |
||||
await self._send_successful_unary_unary(idx[2]) |
||||
for i in range(k_failed): |
||||
await self._send_failed_unary_unary(idx[1]) |
||||
await self._send_failed_unary_unary(idx[2]) |
||||
|
||||
for i in range(k_channels): |
||||
gc_resp = await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest( |
||||
channel_id=await self._get_channel_id(idx[i]))) |
||||
# If no call performed in the channel, there shouldn't be any subchannel |
||||
if gc_resp.channel.data.calls_started == 0: |
||||
self.assertEqual(len(gc_resp.channel.subchannel_ref), 0) |
||||
continue |
||||
|
||||
# Otherwise, the subchannel should exist |
||||
self.assertGreater(len(gc_resp.channel.subchannel_ref), 0) |
||||
gsc_resp = await self._channelz_stub.GetSubchannel( |
||||
channelz_pb2.GetSubchannelRequest( |
||||
subchannel_id=gc_resp.channel.subchannel_ref[0]. |
||||
subchannel_id)) |
||||
self.assertEqual(gc_resp.channel.data.calls_started, |
||||
gsc_resp.subchannel.data.calls_started) |
||||
self.assertEqual(gc_resp.channel.data.calls_succeeded, |
||||
gsc_resp.subchannel.data.calls_succeeded) |
||||
self.assertEqual(gc_resp.channel.data.calls_failed, |
||||
gsc_resp.subchannel.data.calls_failed) |
||||
|
||||
async def test_server_call(self): |
||||
idx = await _generate_channel_server_pairs(1) |
||||
k_success = 23 |
||||
k_failed = 29 |
||||
for i in range(k_success): |
||||
await self._send_successful_unary_unary(idx[0]) |
||||
for i in range(k_failed): |
||||
await self._send_failed_unary_unary(idx[0]) |
||||
|
||||
resp = await self._get_server_by_id(idx[0]) |
||||
self.assertEqual(resp.data.calls_started, k_success + k_failed) |
||||
self.assertEqual(resp.data.calls_succeeded, k_success) |
||||
self.assertEqual(resp.data.calls_failed, k_failed) |
||||
|
||||
async def test_many_subchannels_and_sockets(self): |
||||
k_channels = 4 |
||||
idx = await _generate_channel_server_pairs(k_channels) |
||||
k_success = 3 |
||||
k_failed = 5 |
||||
for i in range(k_success): |
||||
await self._send_successful_unary_unary(idx[0]) |
||||
await self._send_successful_unary_unary(idx[2]) |
||||
for i in range(k_failed): |
||||
await self._send_failed_unary_unary(idx[1]) |
||||
await self._send_failed_unary_unary(idx[2]) |
||||
|
||||
for i in range(k_channels): |
||||
gc_resp = await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest( |
||||
channel_id=await self._get_channel_id(idx[i]))) |
||||
|
||||
# If no call performed in the channel, there shouldn't be any subchannel |
||||
if gc_resp.channel.data.calls_started == 0: |
||||
self.assertEqual(len(gc_resp.channel.subchannel_ref), 0) |
||||
continue |
||||
|
||||
# Otherwise, the subchannel should exist |
||||
self.assertGreater(len(gc_resp.channel.subchannel_ref), 0) |
||||
gsc_resp = await self._channelz_stub.GetSubchannel( |
||||
channelz_pb2.GetSubchannelRequest( |
||||
subchannel_id=gc_resp.channel.subchannel_ref[0]. |
||||
subchannel_id)) |
||||
self.assertEqual(len(gsc_resp.subchannel.socket_ref), 1) |
||||
|
||||
gs_resp = await self._channelz_stub.GetSocket( |
||||
channelz_pb2.GetSocketRequest( |
||||
socket_id=gsc_resp.subchannel.socket_ref[0].socket_id)) |
||||
self.assertEqual(gsc_resp.subchannel.data.calls_started, |
||||
gs_resp.socket.data.streams_started) |
||||
self.assertEqual(gsc_resp.subchannel.data.calls_started, |
||||
gs_resp.socket.data.streams_succeeded) |
||||
# Calls started == messages sent, only valid for unary calls |
||||
self.assertEqual(gsc_resp.subchannel.data.calls_started, |
||||
gs_resp.socket.data.messages_sent) |
||||
|
||||
async def test_streaming_rpc(self): |
||||
idx = await _generate_channel_server_pairs(1) |
||||
# In C++, the argument for _send_successful_stream_stream is message length. |
||||
# Here the argument is still channel idx, to be consistent with the other two. |
||||
await self._send_successful_stream_stream(idx[0]) |
||||
|
||||
gc_resp = await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest( |
||||
channel_id=await self._get_channel_id(idx[0]))) |
||||
self.assertEqual(gc_resp.channel.data.calls_started, 1) |
||||
self.assertEqual(gc_resp.channel.data.calls_succeeded, 1) |
||||
self.assertEqual(gc_resp.channel.data.calls_failed, 0) |
||||
# Subchannel exists |
||||
self.assertGreater(len(gc_resp.channel.subchannel_ref), 0) |
||||
|
||||
gsc_resp = await self._channelz_stub.GetSubchannel( |
||||
channelz_pb2.GetSubchannelRequest( |
||||
subchannel_id=gc_resp.channel.subchannel_ref[0].subchannel_id)) |
||||
self.assertEqual(gsc_resp.subchannel.data.calls_started, 1) |
||||
self.assertEqual(gsc_resp.subchannel.data.calls_succeeded, 1) |
||||
self.assertEqual(gsc_resp.subchannel.data.calls_failed, 0) |
||||
# Socket exists |
||||
self.assertEqual(len(gsc_resp.subchannel.socket_ref), 1) |
||||
|
||||
gs_resp = await self._channelz_stub.GetSocket( |
||||
channelz_pb2.GetSocketRequest( |
||||
socket_id=gsc_resp.subchannel.socket_ref[0].socket_id)) |
||||
self.assertEqual(gs_resp.socket.data.streams_started, 1) |
||||
self.assertEqual(gs_resp.socket.data.streams_succeeded, 1) |
||||
self.assertEqual(gs_resp.socket.data.streams_failed, 0) |
||||
self.assertEqual(gs_resp.socket.data.messages_sent, |
||||
test_constants.STREAM_LENGTH) |
||||
self.assertEqual(gs_resp.socket.data.messages_received, |
||||
test_constants.STREAM_LENGTH) |
||||
|
||||
async def test_server_sockets(self): |
||||
idx = await _generate_channel_server_pairs(1) |
||||
await self._send_successful_unary_unary(idx[0]) |
||||
await self._send_failed_unary_unary(idx[0]) |
||||
|
||||
resp = await self._get_server_by_id(idx[0]) |
||||
self.assertEqual(resp.data.calls_started, 2) |
||||
self.assertEqual(resp.data.calls_succeeded, 1) |
||||
self.assertEqual(resp.data.calls_failed, 1) |
||||
|
||||
gss_resp = await self._channelz_stub.GetServerSockets( |
||||
channelz_pb2.GetServerSocketsRequest(server_id=resp.ref.server_id, |
||||
start_socket_id=0)) |
||||
# If the RPC call failed, it will raise a grpc.RpcError |
||||
# So, if there is no exception raised, considered pass |
||||
|
||||
async def test_server_listen_sockets(self): |
||||
idx = await _generate_channel_server_pairs(1) |
||||
|
||||
resp = await self._get_server_by_id(idx[0]) |
||||
self.assertEqual(len(resp.listen_socket), 1) |
||||
|
||||
gs_resp = await self._channelz_stub.GetSocket( |
||||
channelz_pb2.GetSocketRequest( |
||||
socket_id=resp.listen_socket[0].socket_id)) |
||||
# If the RPC call failed, it will raise a grpc.RpcError |
||||
# So, if there is no exception raised, considered pass |
||||
|
||||
async def test_invalid_query_get_server(self): |
||||
with self.assertRaises(aio.AioRpcError) as exception_context: |
||||
await self._channelz_stub.GetServer( |
||||
channelz_pb2.GetServerRequest(server_id=10000)) |
||||
self.assertEqual(grpc.StatusCode.NOT_FOUND, |
||||
exception_context.exception.code()) |
||||
|
||||
async def test_invalid_query_get_channel(self): |
||||
with self.assertRaises(aio.AioRpcError) as exception_context: |
||||
await self._channelz_stub.GetChannel( |
||||
channelz_pb2.GetChannelRequest(channel_id=10000)) |
||||
self.assertEqual(grpc.StatusCode.NOT_FOUND, |
||||
exception_context.exception.code()) |
||||
|
||||
async def test_invalid_query_get_subchannel(self): |
||||
with self.assertRaises(aio.AioRpcError) as exception_context: |
||||
await self._channelz_stub.GetSubchannel( |
||||
channelz_pb2.GetSubchannelRequest(subchannel_id=10000)) |
||||
self.assertEqual(grpc.StatusCode.NOT_FOUND, |
||||
exception_context.exception.code()) |
||||
|
||||
async def test_invalid_query_get_socket(self): |
||||
with self.assertRaises(aio.AioRpcError) as exception_context: |
||||
await self._channelz_stub.GetSocket( |
||||
channelz_pb2.GetSocketRequest(socket_id=10000)) |
||||
self.assertEqual(grpc.StatusCode.NOT_FOUND, |
||||
exception_context.exception.code()) |
||||
|
||||
async def test_invalid_query_get_server_sockets(self): |
||||
with self.assertRaises(aio.AioRpcError) as exception_context: |
||||
await self._channelz_stub.GetServerSockets( |
||||
channelz_pb2.GetServerSocketsRequest( |
||||
server_id=10000, |
||||
start_socket_id=0, |
||||
)) |
||||
self.assertEqual(grpc.StatusCode.NOT_FOUND, |
||||
exception_context.exception.code()) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig(level=logging.DEBUG) |
||||
unittest.main(verbosity=2) |
Loading…
Reference in new issue