1 /* 2 * 3 * Copyright 2017 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 #include <stdlib.h> 20 #include <string.h> 21 22 #include <gtest/gtest.h> 23 24 #include <grpc/support/alloc.h> 25 #include <grpc/support/log.h> 26 27 #include "src/core/lib/channel/channel_trace.h" 28 #include "src/core/lib/channel/channelz.h" 29 #include "src/core/lib/channel/channelz_registry.h" 30 #include "src/core/lib/gpr/useful.h" 31 #include "src/core/lib/iomgr/exec_ctx.h" 32 #include "src/core/lib/json/json.h" 33 #include "src/core/lib/surface/channel.h" 34 #include "src/core/lib/surface/server.h" 35 36 #include "test/core/util/test_config.h" 37 #include "test/cpp/util/channel_trace_proto_helper.h" 38 39 #include <grpc/support/string_util.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 namespace grpc_core { 44 namespace channelz { 45 namespace testing { 46 47 // testing peer to access channel internals 48 class CallCountingHelperPeer { 49 public: 50 explicit CallCountingHelperPeer(CallCountingHelper* node) : node_(node) {} 51 grpc_millis last_call_started_millis() const { 52 return (grpc_millis)gpr_atm_no_barrier_load( 53 &node_->last_call_started_millis_); 54 } 55 56 private: 57 CallCountingHelper* node_; 58 }; 59 60 namespace { 61 62 grpc_json* GetJsonChild(grpc_json* parent, const char* key) { 63 EXPECT_NE(parent, nullptr); 64 for (grpc_json* child = parent->child; child != nullptr; 65 child = child->next) { 66 if (child->key != nullptr && strcmp(child->key, key) == 0) return child; 67 } 68 return nullptr; 69 } 70 71 void ValidateJsonArraySize(grpc_json* json, const char* key, 72 size_t expected_size) { 73 grpc_json* arr = GetJsonChild(json, key); 74 if (expected_size == 0) { 75 ASSERT_EQ(arr, nullptr); 76 return; 77 } 78 ASSERT_NE(arr, nullptr); 79 ASSERT_EQ(arr->type, GRPC_JSON_ARRAY); 80 size_t count = 0; 81 for (grpc_json* child = arr->child; child != nullptr; child = child->next) { 82 ++count; 83 } 84 EXPECT_EQ(count, expected_size); 85 } 86 87 void ValidateGetTopChannels(size_t expected_channels) { 88 char* json_str = ChannelzRegistry::GetTopChannels(0); 89 grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str); 90 grpc_json* parsed_json = grpc_json_parse_string(json_str); 91 // This check will naturally have to change when we support pagination. 92 // tracked: https://github.com/grpc/grpc/issues/16019. 93 ValidateJsonArraySize(parsed_json, "channel", expected_channels); 94 grpc_json* end = GetJsonChild(parsed_json, "end"); 95 ASSERT_NE(end, nullptr); 96 EXPECT_EQ(end->type, GRPC_JSON_TRUE); 97 grpc_json_destroy(parsed_json); 98 gpr_free(json_str); 99 // also check that the core API formats this correctly 100 char* core_api_json_str = grpc_channelz_get_top_channels(0); 101 grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation( 102 core_api_json_str); 103 gpr_free(core_api_json_str); 104 } 105 106 void ValidateGetServers(size_t expected_servers) { 107 char* json_str = ChannelzRegistry::GetServers(0); 108 grpc::testing::ValidateGetServersResponseProtoJsonTranslation(json_str); 109 grpc_json* parsed_json = grpc_json_parse_string(json_str); 110 // This check will naturally have to change when we support pagination. 111 // tracked: https://github.com/grpc/grpc/issues/16019. 112 ValidateJsonArraySize(parsed_json, "server", expected_servers); 113 grpc_json* end = GetJsonChild(parsed_json, "end"); 114 ASSERT_NE(end, nullptr); 115 EXPECT_EQ(end->type, GRPC_JSON_TRUE); 116 grpc_json_destroy(parsed_json); 117 gpr_free(json_str); 118 // also check that the core API formats this correctly 119 char* core_api_json_str = grpc_channelz_get_servers(0); 120 grpc::testing::ValidateGetServersResponseProtoJsonTranslation( 121 core_api_json_str); 122 gpr_free(core_api_json_str); 123 } 124 125 class ChannelFixture { 126 public: 127 ChannelFixture(int max_trace_nodes = 0) { 128 grpc_arg client_a[2]; 129 client_a[0] = grpc_channel_arg_integer_create( 130 const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE), 131 max_trace_nodes); 132 client_a[1] = grpc_channel_arg_integer_create( 133 const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true); 134 grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a}; 135 channel_ = 136 grpc_insecure_channel_create("fake_target", &client_args, nullptr); 137 } 138 139 ~ChannelFixture() { grpc_channel_destroy(channel_); } 140 141 grpc_channel* channel() { return channel_; } 142 143 private: 144 grpc_channel* channel_; 145 }; 146 147 class ServerFixture { 148 public: 149 explicit ServerFixture(int max_trace_nodes = 0) { 150 grpc_arg server_a[] = { 151 grpc_channel_arg_integer_create( 152 const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE), 153 max_trace_nodes), 154 grpc_channel_arg_integer_create( 155 const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true), 156 }; 157 grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a}; 158 server_ = grpc_server_create(&server_args, nullptr); 159 } 160 161 ~ServerFixture() { grpc_server_destroy(server_); } 162 163 grpc_server* server() const { return server_; } 164 165 private: 166 grpc_server* server_; 167 }; 168 169 struct validate_channel_data_args { 170 int64_t calls_started; 171 int64_t calls_failed; 172 int64_t calls_succeeded; 173 }; 174 175 void ValidateChildInteger(grpc_json* json, int64_t expect, const char* key) { 176 grpc_json* gotten_json = GetJsonChild(json, key); 177 if (expect == 0) { 178 ASSERT_EQ(gotten_json, nullptr); 179 return; 180 } 181 ASSERT_NE(gotten_json, nullptr); 182 int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0); 183 EXPECT_EQ(gotten_number, expect); 184 } 185 186 void ValidateCounters(char* json_str, validate_channel_data_args args) { 187 grpc_json* json = grpc_json_parse_string(json_str); 188 ASSERT_NE(json, nullptr); 189 grpc_json* data = GetJsonChild(json, "data"); 190 ValidateChildInteger(data, args.calls_started, "callsStarted"); 191 ValidateChildInteger(data, args.calls_failed, "callsFailed"); 192 ValidateChildInteger(data, args.calls_succeeded, "callsSucceeded"); 193 grpc_json_destroy(json); 194 } 195 196 void ValidateChannel(ChannelNode* channel, validate_channel_data_args args) { 197 char* json_str = channel->RenderJsonString(); 198 grpc::testing::ValidateChannelProtoJsonTranslation(json_str); 199 ValidateCounters(json_str, args); 200 gpr_free(json_str); 201 // also check that the core API formats this the correct way 202 char* core_api_json_str = grpc_channelz_get_channel(channel->uuid()); 203 grpc::testing::ValidateGetChannelResponseProtoJsonTranslation( 204 core_api_json_str); 205 gpr_free(core_api_json_str); 206 } 207 208 void ValidateServer(ServerNode* server, validate_channel_data_args args) { 209 char* json_str = server->RenderJsonString(); 210 grpc::testing::ValidateServerProtoJsonTranslation(json_str); 211 ValidateCounters(json_str, args); 212 gpr_free(json_str); 213 } 214 215 grpc_millis GetLastCallStartedMillis(CallCountingHelper* channel) { 216 CallCountingHelperPeer peer(channel); 217 return peer.last_call_started_millis(); 218 } 219 220 void ChannelzSleep(int64_t sleep_us) { 221 gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), 222 gpr_time_from_micros(sleep_us, GPR_TIMESPAN))); 223 grpc_core::ExecCtx::Get()->InvalidateNow(); 224 } 225 226 } // anonymous namespace 227 228 class ChannelzChannelTest : public ::testing::TestWithParam<size_t> {}; 229 230 TEST_P(ChannelzChannelTest, BasicChannel) { 231 grpc_core::ExecCtx exec_ctx; 232 ChannelFixture channel(GetParam()); 233 ChannelNode* channelz_channel = 234 grpc_channel_get_channelz_node(channel.channel()); 235 ValidateChannel(channelz_channel, {0, 0, 0}); 236 } 237 238 TEST(ChannelzChannelTest, ChannelzDisabled) { 239 grpc_core::ExecCtx exec_ctx; 240 grpc_channel* channel = 241 grpc_insecure_channel_create("fake_target", nullptr, nullptr); 242 ChannelNode* channelz_channel = grpc_channel_get_channelz_node(channel); 243 ASSERT_EQ(channelz_channel, nullptr); 244 grpc_channel_destroy(channel); 245 } 246 247 TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) { 248 grpc_core::ExecCtx exec_ctx; 249 ChannelFixture channel(GetParam()); 250 ChannelNode* channelz_channel = 251 grpc_channel_get_channelz_node(channel.channel()); 252 channelz_channel->RecordCallStarted(); 253 channelz_channel->RecordCallFailed(); 254 channelz_channel->RecordCallSucceeded(); 255 ValidateChannel(channelz_channel, {1, 1, 1}); 256 channelz_channel->RecordCallStarted(); 257 channelz_channel->RecordCallFailed(); 258 channelz_channel->RecordCallSucceeded(); 259 channelz_channel->RecordCallStarted(); 260 channelz_channel->RecordCallFailed(); 261 channelz_channel->RecordCallSucceeded(); 262 ValidateChannel(channelz_channel, {3, 3, 3}); 263 } 264 265 TEST_P(ChannelzChannelTest, LastCallStartedMillis) { 266 grpc_core::ExecCtx exec_ctx; 267 CallCountingHelper counter; 268 // start a call to set the last call started timestamp 269 counter.RecordCallStarted(); 270 grpc_millis millis1 = GetLastCallStartedMillis(&counter); 271 // time gone by should not affect the timestamp 272 ChannelzSleep(100); 273 grpc_millis millis2 = GetLastCallStartedMillis(&counter); 274 EXPECT_EQ(millis1, millis2); 275 // calls succeeded or failed should not affect the timestamp 276 ChannelzSleep(100); 277 counter.RecordCallFailed(); 278 counter.RecordCallSucceeded(); 279 grpc_millis millis3 = GetLastCallStartedMillis(&counter); 280 EXPECT_EQ(millis1, millis3); 281 // another call started should affect the timestamp 282 // sleep for extra long to avoid flakes (since we cache Now()) 283 ChannelzSleep(5000); 284 counter.RecordCallStarted(); 285 grpc_millis millis4 = GetLastCallStartedMillis(&counter); 286 EXPECT_NE(millis1, millis4); 287 } 288 289 TEST(ChannelzGetTopChannelsTest, BasicGetTopChannelsTest) { 290 grpc_core::ExecCtx exec_ctx; 291 ChannelFixture channel; 292 ValidateGetTopChannels(1); 293 } 294 295 TEST(ChannelzGetTopChannelsTest, NoChannelsTest) { 296 grpc_core::ExecCtx exec_ctx; 297 ValidateGetTopChannels(0); 298 } 299 300 TEST(ChannelzGetTopChannelsTest, ManyChannelsTest) { 301 grpc_core::ExecCtx exec_ctx; 302 ChannelFixture channels[10]; 303 (void)channels; // suppress unused variable error 304 ValidateGetTopChannels(10); 305 } 306 307 TEST(ChannelzGetTopChannelsTest, InternalChannelTest) { 308 grpc_core::ExecCtx exec_ctx; 309 ChannelFixture channels[10]; 310 (void)channels; // suppress unused variable error 311 // create an internal channel 312 grpc_arg client_a[2]; 313 client_a[0] = grpc_channel_arg_integer_create( 314 const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), true); 315 client_a[1] = grpc_channel_arg_integer_create( 316 const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true); 317 grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a}; 318 grpc_channel* internal_channel = 319 grpc_insecure_channel_create("fake_target", &client_args, nullptr); 320 // The internal channel should not be returned from the request 321 ValidateGetTopChannels(10); 322 grpc_channel_destroy(internal_channel); 323 } 324 325 class ChannelzServerTest : public ::testing::TestWithParam<size_t> {}; 326 327 TEST_P(ChannelzServerTest, BasicServerAPIFunctionality) { 328 grpc_core::ExecCtx exec_ctx; 329 ServerFixture server(10); 330 ServerNode* channelz_server = grpc_server_get_channelz_node(server.server()); 331 channelz_server->RecordCallStarted(); 332 channelz_server->RecordCallFailed(); 333 channelz_server->RecordCallSucceeded(); 334 ValidateServer(channelz_server, {1, 1, 1}); 335 channelz_server->RecordCallStarted(); 336 channelz_server->RecordCallFailed(); 337 channelz_server->RecordCallSucceeded(); 338 channelz_server->RecordCallStarted(); 339 channelz_server->RecordCallFailed(); 340 channelz_server->RecordCallSucceeded(); 341 ValidateServer(channelz_server, {3, 3, 3}); 342 } 343 344 TEST(ChannelzGetServersTest, BasicGetServersTest) { 345 grpc_core::ExecCtx exec_ctx; 346 ServerFixture server; 347 ValidateGetServers(1); 348 } 349 350 TEST(ChannelzGetServersTest, NoServersTest) { 351 grpc_core::ExecCtx exec_ctx; 352 ValidateGetServers(0); 353 } 354 355 TEST(ChannelzGetServersTest, ManyServersTest) { 356 grpc_core::ExecCtx exec_ctx; 357 ServerFixture servers[10]; 358 (void)servers; // suppress unused variable error 359 ValidateGetServers(10); 360 } 361 362 INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest, 363 ::testing::Values(0, 1, 2, 6, 10, 15)); 364 365 INSTANTIATE_TEST_CASE_P(ChannelzServerTestSweep, ChannelzServerTest, 366 ::testing::Values(0, 1, 2, 6, 10, 15)); 367 368 } // namespace testing 369 } // namespace channelz 370 } // namespace grpc_core 371 372 int main(int argc, char** argv) { 373 grpc_test_init(argc, argv); 374 grpc_init(); 375 ::testing::InitGoogleTest(&argc, argv); 376 int ret = RUN_ALL_TESTS(); 377 grpc_shutdown(); 378 return ret; 379 } 380