|  | @@ -67,9 +67,39 @@ grpc_json* GetJsonChild(grpc_json* parent, const char* key) {
 | 
	
		
			
				|  |  |    return nullptr;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +void ValidateJsonArraySize(grpc_json* json, const char* key,
 | 
	
		
			
				|  |  | +                           size_t expected_size) {
 | 
	
		
			
				|  |  | +  grpc_json* arr = GetJsonChild(json, key);
 | 
	
		
			
				|  |  | +  if (expected_size == 0) {
 | 
	
		
			
				|  |  | +    ASSERT_EQ(arr, nullptr);
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  ASSERT_NE(arr, nullptr);
 | 
	
		
			
				|  |  | +  ASSERT_EQ(arr->type, GRPC_JSON_ARRAY);
 | 
	
		
			
				|  |  | +  size_t count = 0;
 | 
	
		
			
				|  |  | +  for (grpc_json* child = arr->child; child != nullptr; child = child->next) {
 | 
	
		
			
				|  |  | +    ++count;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  ASSERT_EQ(count, expected_size);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void ValidateGetTopChannels(size_t expected_channels) {
 | 
	
		
			
				|  |  | +  char* json_str = ChannelzRegistry::GetTopChannels(0);
 | 
	
		
			
				|  |  | +  grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str);
 | 
	
		
			
				|  |  | +  grpc_json* parsed_json = grpc_json_parse_string(json_str);
 | 
	
		
			
				|  |  | +  // This check will naturally have to change when we support pagination.
 | 
	
		
			
				|  |  | +  // tracked: https://github.com/grpc/grpc/issues/16019.
 | 
	
		
			
				|  |  | +  ValidateJsonArraySize(parsed_json, "channel", expected_channels);
 | 
	
		
			
				|  |  | +  grpc_json* end = GetJsonChild(parsed_json, "end");
 | 
	
		
			
				|  |  | +  EXPECT_NE(end, nullptr);
 | 
	
		
			
				|  |  | +  EXPECT_EQ(end->type, GRPC_JSON_TRUE);
 | 
	
		
			
				|  |  | +  grpc_json_destroy(parsed_json);
 | 
	
		
			
				|  |  | +  gpr_free(json_str);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  class ChannelFixture {
 | 
	
		
			
				|  |  |   public:
 | 
	
		
			
				|  |  | -  ChannelFixture(int max_trace_nodes) {
 | 
	
		
			
				|  |  | +  ChannelFixture(int max_trace_nodes = 0) {
 | 
	
		
			
				|  |  |      grpc_arg client_a[2];
 | 
	
		
			
				|  |  |      client_a[0].type = GRPC_ARG_INTEGER;
 | 
	
		
			
				|  |  |      client_a[0].key =
 | 
	
	
		
			
				|  | @@ -99,6 +129,10 @@ struct validate_channel_data_args {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void ValidateChildInteger(grpc_json* json, int64_t expect, const char* key) {
 | 
	
		
			
				|  |  |    grpc_json* gotten_json = GetJsonChild(json, key);
 | 
	
		
			
				|  |  | +  if (expect == 0) {
 | 
	
		
			
				|  |  | +    ASSERT_EQ(gotten_json, nullptr);
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    ASSERT_NE(gotten_json, nullptr);
 | 
	
		
			
				|  |  |    int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0);
 | 
	
		
			
				|  |  |    EXPECT_EQ(gotten_number, expect);
 | 
	
	
		
			
				|  | @@ -115,7 +149,7 @@ void ValidateCounters(char* json_str, validate_channel_data_args args) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void ValidateChannel(ChannelNode* channel, validate_channel_data_args args) {
 | 
	
		
			
				|  |  | -  char* json_str = channel->RenderJSON();
 | 
	
		
			
				|  |  | +  char* json_str = channel->RenderJsonString();
 | 
	
		
			
				|  |  |    grpc::testing::ValidateChannelProtoJsonTranslation(json_str);
 | 
	
		
			
				|  |  |    ValidateCounters(json_str, args);
 | 
	
		
			
				|  |  |    gpr_free(json_str);
 | 
	
	
		
			
				|  | @@ -141,9 +175,7 @@ TEST_P(ChannelzChannelTest, BasicChannel) {
 | 
	
		
			
				|  |  |    ChannelFixture channel(GetParam());
 | 
	
		
			
				|  |  |    ChannelNode* channelz_channel =
 | 
	
		
			
				|  |  |        grpc_channel_get_channelz_node(channel.channel());
 | 
	
		
			
				|  |  | -  char* json_str = channelz_channel->RenderJSON();
 | 
	
		
			
				|  |  | -  ValidateCounters(json_str, {0, 0, 0});
 | 
	
		
			
				|  |  | -  gpr_free(json_str);
 | 
	
		
			
				|  |  | +  ValidateChannel(channelz_channel, {0, 0, 0});
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  TEST(ChannelzChannelTest, ChannelzDisabled) {
 | 
	
	
		
			
				|  | @@ -199,6 +231,45 @@ TEST_P(ChannelzChannelTest, LastCallStartedMillis) {
 | 
	
		
			
				|  |  |    EXPECT_NE(millis1, millis4);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +TEST(ChannelzGetTopChannelsTest, BasicTest) {
 | 
	
		
			
				|  |  | +  grpc_core::ExecCtx exec_ctx;
 | 
	
		
			
				|  |  | +  ChannelFixture channel;
 | 
	
		
			
				|  |  | +  ValidateGetTopChannels(1);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST(ChannelzGetTopChannelsTest, NoChannelsTest) {
 | 
	
		
			
				|  |  | +  grpc_core::ExecCtx exec_ctx;
 | 
	
		
			
				|  |  | +  ValidateGetTopChannels(0);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST(ChannelzGetTopChannelsTest, ManyChannelsTest) {
 | 
	
		
			
				|  |  | +  grpc_core::ExecCtx exec_ctx;
 | 
	
		
			
				|  |  | +  ChannelFixture channels[10];
 | 
	
		
			
				|  |  | +  (void)channels;  // suppress unused variable error
 | 
	
		
			
				|  |  | +  ValidateGetTopChannels(10);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST(ChannelzGetTopChannelsTest, InternalChannelTest) {
 | 
	
		
			
				|  |  | +  grpc_core::ExecCtx exec_ctx;
 | 
	
		
			
				|  |  | +  ChannelFixture channels[10];
 | 
	
		
			
				|  |  | +  (void)channels;  // suppress unused variable error
 | 
	
		
			
				|  |  | +  // create an internal channel
 | 
	
		
			
				|  |  | +  grpc_arg client_a[2];
 | 
	
		
			
				|  |  | +  client_a[0].type = GRPC_ARG_INTEGER;
 | 
	
		
			
				|  |  | +  client_a[0].key =
 | 
	
		
			
				|  |  | +      const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL);
 | 
	
		
			
				|  |  | +  client_a[0].value.integer = 1;
 | 
	
		
			
				|  |  | +  client_a[1].type = GRPC_ARG_INTEGER;
 | 
	
		
			
				|  |  | +  client_a[1].key = const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ);
 | 
	
		
			
				|  |  | +  client_a[1].value.integer = true;
 | 
	
		
			
				|  |  | +  grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
 | 
	
		
			
				|  |  | +  grpc_channel* internal_channel =
 | 
	
		
			
				|  |  | +      grpc_insecure_channel_create("fake_target", &client_args, nullptr);
 | 
	
		
			
				|  |  | +  // The internal channel should not be returned from the request
 | 
	
		
			
				|  |  | +  ValidateGetTopChannels(10);
 | 
	
		
			
				|  |  | +  grpc_channel_destroy(internal_channel);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest,
 | 
	
		
			
				|  |  |                          ::testing::Values(0, 1, 2, 6, 10, 15));
 | 
	
		
			
				|  |  |  
 |