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 "src/core/lib/channel/channelz.h"
20
21 #include <stdlib.h>
22
23 #include <algorithm>
24 #include <atomic>
25 #include <chrono>
26 #include <memory>
27 #include <vector>
28
29 #include "absl/status/status.h"
30 #include "absl/status/statusor.h"
31 #include "gtest/gtest.h"
32
33 #include <grpc/event_engine/event_engine.h>
34 #include <grpc/grpc.h>
35 #include <grpc/grpc_security.h>
36 #include <grpc/impl/channel_arg_names.h>
37 #include <grpc/support/alloc.h>
38 #include <grpc/support/json.h>
39 #include <grpc/support/time.h>
40
41 #include "src/core/lib/channel/channel_args.h"
42 #include "src/core/lib/channel/channelz_registry.h"
43 #include "src/core/lib/event_engine/default_event_engine.h"
44 #include "src/core/lib/gpr/useful.h"
45 #include "src/core/lib/gprpp/notification.h"
46 #include "src/core/lib/iomgr/exec_ctx.h"
47 #include "src/core/lib/json/json.h"
48 #include "src/core/lib/json/json_reader.h"
49 #include "src/core/lib/surface/channel.h"
50 #include "src/core/lib/surface/server.h"
51 #include "test/core/event_engine/event_engine_test_utils.h"
52 #include "test/core/util/test_config.h"
53 #include "test/cpp/util/channel_trace_proto_helper.h"
54
55 using grpc_event_engine::experimental::GetDefaultEventEngine;
56 using grpc_event_engine::experimental::WaitForSingleOwner;
57
58 namespace grpc_core {
59 namespace channelz {
60 namespace testing {
61
62 // testing peer to access channel internals
63 class CallCountingHelperPeer {
64 public:
CallCountingHelperPeer(CallCountingHelper * node)65 explicit CallCountingHelperPeer(CallCountingHelper* node) : node_(node) {}
66
last_call_started_time() const67 gpr_timespec last_call_started_time() const {
68 return gpr_cycle_counter_to_time(
69 node_->last_call_started_cycle_.load(std::memory_order_relaxed));
70 }
71
72 private:
73 CallCountingHelper* node_;
74 };
75
76 namespace {
77
GetUuidListFromArray(const Json::Array & arr)78 std::vector<intptr_t> GetUuidListFromArray(const Json::Array& arr) {
79 std::vector<intptr_t> uuids;
80 for (const Json& value : arr) {
81 EXPECT_EQ(value.type(), Json::Type::kObject);
82 if (value.type() != Json::Type::kObject) continue;
83 const Json::Object& object = value.object();
84 auto it = object.find("ref");
85 EXPECT_NE(it, object.end());
86 if (it == object.end()) continue;
87 EXPECT_EQ(it->second.type(), Json::Type::kObject);
88 if (it->second.type() != Json::Type::kObject) continue;
89 const Json::Object& ref_object = it->second.object();
90 it = ref_object.find("channelId");
91 EXPECT_NE(it, ref_object.end());
92 if (it != ref_object.end()) {
93 uuids.push_back(atoi(it->second.string().c_str()));
94 }
95 }
96 return uuids;
97 }
98
ValidateJsonArraySize(const Json & array,size_t expected)99 void ValidateJsonArraySize(const Json& array, size_t expected) {
100 if (expected == 0) {
101 ASSERT_EQ(array.type(), Json::Type::kNull);
102 } else {
103 ASSERT_EQ(array.type(), Json::Type::kArray);
104 EXPECT_EQ(array.array().size(), expected);
105 }
106 }
107
ValidateJsonEnd(const Json & json,bool end)108 void ValidateJsonEnd(const Json& json, bool end) {
109 auto it = json.object().find("end");
110 if (end) {
111 ASSERT_NE(it, json.object().end());
112 ASSERT_EQ(it->second.type(), Json::Type::kBoolean);
113 EXPECT_TRUE(it->second.boolean());
114 } else {
115 ASSERT_EQ(it, json.object().end());
116 }
117 }
118
ValidateGetTopChannels(size_t expected_channels)119 void ValidateGetTopChannels(size_t expected_channels) {
120 std::string json_str = ChannelzRegistry::GetTopChannels(0);
121 grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(
122 json_str.c_str());
123 auto parsed_json = JsonParse(json_str);
124 ASSERT_TRUE(parsed_json.ok()) << parsed_json.status();
125 ASSERT_EQ(parsed_json->type(), Json::Type::kObject);
126 // This check will naturally have to change when we support pagination.
127 // tracked: https://github.com/grpc/grpc/issues/16019.
128 Json channel_json;
129 auto it = parsed_json->object().find("channel");
130 if (it != parsed_json->object().end()) channel_json = it->second;
131 ValidateJsonArraySize(channel_json, expected_channels);
132 ValidateJsonEnd(*parsed_json, true);
133 // Also check that the core API formats this correctly.
134 char* core_api_json_str = grpc_channelz_get_top_channels(0);
135 grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(
136 core_api_json_str);
137 gpr_free(core_api_json_str);
138 }
139
ValidateGetServers(size_t expected_servers)140 void ValidateGetServers(size_t expected_servers) {
141 std::string json_str = ChannelzRegistry::GetServers(0);
142 grpc::testing::ValidateGetServersResponseProtoJsonTranslation(
143 json_str.c_str());
144 auto parsed_json = JsonParse(json_str);
145 ASSERT_TRUE(parsed_json.ok()) << parsed_json.status();
146 ASSERT_EQ(parsed_json->type(), Json::Type::kObject);
147 // This check will naturally have to change when we support pagination.
148 // tracked: https://github.com/grpc/grpc/issues/16019.
149 Json server_json;
150 auto it = parsed_json->object().find("server");
151 if (it != parsed_json->object().end()) server_json = it->second;
152 ValidateJsonArraySize(server_json, expected_servers);
153 ValidateJsonEnd(*parsed_json, true);
154 // Also check that the core API formats this correctly.
155 char* core_api_json_str = grpc_channelz_get_servers(0);
156 grpc::testing::ValidateGetServersResponseProtoJsonTranslation(
157 core_api_json_str);
158 gpr_free(core_api_json_str);
159 }
160
161 class ChannelFixture {
162 public:
ChannelFixture(int max_tracer_event_memory=0)163 explicit ChannelFixture(int max_tracer_event_memory = 0) {
164 grpc_arg client_a[] = {
165 grpc_channel_arg_integer_create(
166 const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
167 max_tracer_event_memory),
168 grpc_channel_arg_integer_create(
169 const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true)};
170 grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
171 grpc_channel_credentials* creds = grpc_insecure_credentials_create();
172 channel_ = grpc_channel_create("fake_target", creds, &client_args);
173 grpc_channel_credentials_release(creds);
174 }
175
~ChannelFixture()176 ~ChannelFixture() { grpc_channel_destroy(channel_); }
177
channel()178 grpc_channel* channel() { return channel_; }
179
180 private:
181 grpc_channel* channel_;
182 };
183
184 class ServerFixture {
185 public:
ServerFixture(int max_tracer_event_memory=0)186 explicit ServerFixture(int max_tracer_event_memory = 0) {
187 grpc_arg server_a[] = {
188 grpc_channel_arg_integer_create(
189 const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
190 max_tracer_event_memory),
191 grpc_channel_arg_integer_create(
192 const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true),
193 };
194 grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a};
195 server_ = grpc_server_create(&server_args, nullptr);
196 }
197
~ServerFixture()198 ~ServerFixture() { grpc_server_destroy(server_); }
199
server() const200 grpc_server* server() const { return server_; }
201
202 private:
203 grpc_server* server_;
204 };
205
206 struct ValidateChannelDataArgs {
207 int64_t calls_started;
208 int64_t calls_failed;
209 int64_t calls_succeeded;
210 };
211
ValidateChildInteger(const Json::Object & object,const std::string & key,int64_t expected)212 void ValidateChildInteger(const Json::Object& object, const std::string& key,
213 int64_t expected) {
214 auto it = object.find(key);
215 if (expected == 0) {
216 ASSERT_EQ(it, object.end());
217 return;
218 }
219 ASSERT_NE(it, object.end());
220 ASSERT_EQ(it->second.type(), Json::Type::kString);
221 int64_t gotten_number =
222 static_cast<int64_t>(strtol(it->second.string().c_str(), nullptr, 0));
223 EXPECT_EQ(gotten_number, expected);
224 }
225
ValidateCounters(const std::string & json_str,const ValidateChannelDataArgs & args)226 void ValidateCounters(const std::string& json_str,
227 const ValidateChannelDataArgs& args) {
228 auto json = JsonParse(json_str);
229 ASSERT_TRUE(json.ok()) << json.status();
230 ASSERT_EQ(json->type(), Json::Type::kObject);
231 const Json::Object& object = json->object();
232 auto it = object.find("data");
233 ASSERT_NE(it, object.end());
234 const Json& data = it->second;
235 ASSERT_EQ(data.type(), Json::Type::kObject);
236 ValidateChildInteger(data.object(), "callsStarted", args.calls_started);
237 ValidateChildInteger(data.object(), "callsFailed", args.calls_failed);
238 ValidateChildInteger(data.object(), "callsSucceeded", args.calls_succeeded);
239 }
240
ValidateChannel(ChannelNode * channel,const ValidateChannelDataArgs & args)241 void ValidateChannel(ChannelNode* channel,
242 const ValidateChannelDataArgs& args) {
243 std::string json_str = channel->RenderJsonString();
244 grpc::testing::ValidateChannelProtoJsonTranslation(json_str.c_str());
245 ValidateCounters(json_str, args);
246 // also check that the core API formats this the correct way
247 char* core_api_json_str = grpc_channelz_get_channel(channel->uuid());
248 grpc::testing::ValidateGetChannelResponseProtoJsonTranslation(
249 core_api_json_str);
250 gpr_free(core_api_json_str);
251 }
252
ValidateServer(ServerNode * server,const ValidateChannelDataArgs & args)253 void ValidateServer(ServerNode* server, const ValidateChannelDataArgs& args) {
254 std::string json_str = server->RenderJsonString();
255 grpc::testing::ValidateServerProtoJsonTranslation(json_str.c_str());
256 ValidateCounters(json_str, args);
257 // also check that the core API formats this the correct way
258 char* core_api_json_str = grpc_channelz_get_server(server->uuid());
259 grpc::testing::ValidateGetServerResponseProtoJsonTranslation(
260 core_api_json_str);
261 gpr_free(core_api_json_str);
262 }
263
GetLastCallStartedTime(CallCountingHelper * channel)264 gpr_timespec GetLastCallStartedTime(CallCountingHelper* channel) {
265 CallCountingHelperPeer peer(channel);
266 return peer.last_call_started_time();
267 }
268
ChannelzSleep(int64_t sleep_us)269 void ChannelzSleep(int64_t sleep_us) {
270 gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
271 gpr_time_from_micros(sleep_us, GPR_TIMESPAN)));
272 ExecCtx::Get()->InvalidateNow();
273 }
274
275 } // anonymous namespace
276
277 class ChannelzChannelTest : public ::testing::TestWithParam<size_t> {};
278
TEST_P(ChannelzChannelTest,BasicChannel)279 TEST_P(ChannelzChannelTest, BasicChannel) {
280 ExecCtx exec_ctx;
281 ChannelFixture channel(GetParam());
282 ChannelNode* channelz_channel =
283 grpc_channel_get_channelz_node(channel.channel());
284 ValidateChannel(channelz_channel, {0, 0, 0});
285 }
286
TEST(ChannelzChannelTest,ChannelzDisabled)287 TEST(ChannelzChannelTest, ChannelzDisabled) {
288 ExecCtx exec_ctx;
289 // explicitly disable channelz
290 grpc_arg arg[] = {
291 grpc_channel_arg_integer_create(
292 const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
293 0),
294 grpc_channel_arg_integer_create(
295 const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), false)};
296 grpc_channel_args args = {GPR_ARRAY_SIZE(arg), arg};
297 grpc_channel_credentials* creds = grpc_insecure_credentials_create();
298 grpc_channel* channel = grpc_channel_create("fake_target", creds, &args);
299 grpc_channel_credentials_release(creds);
300 ChannelNode* channelz_channel = grpc_channel_get_channelz_node(channel);
301 ASSERT_EQ(channelz_channel, nullptr);
302 grpc_channel_destroy(channel);
303 }
304
TEST_P(ChannelzChannelTest,BasicChannelAPIFunctionality)305 TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) {
306 ExecCtx exec_ctx;
307 ChannelFixture channel(GetParam());
308 ChannelNode* channelz_channel =
309 grpc_channel_get_channelz_node(channel.channel());
310 channelz_channel->RecordCallStarted();
311 channelz_channel->RecordCallFailed();
312 channelz_channel->RecordCallSucceeded();
313 ValidateChannel(channelz_channel, {1, 1, 1});
314 channelz_channel->RecordCallStarted();
315 channelz_channel->RecordCallFailed();
316 channelz_channel->RecordCallSucceeded();
317 channelz_channel->RecordCallStarted();
318 channelz_channel->RecordCallFailed();
319 channelz_channel->RecordCallSucceeded();
320 ValidateChannel(channelz_channel, {3, 3, 3});
321 }
322
TEST_P(ChannelzChannelTest,LastCallStartedTime)323 TEST_P(ChannelzChannelTest, LastCallStartedTime) {
324 ExecCtx exec_ctx;
325 CallCountingHelper counter;
326 // start a call to set the last call started timestamp
327 counter.RecordCallStarted();
328 gpr_timespec time1 = GetLastCallStartedTime(&counter);
329 // time gone by should not affect the timestamp
330 ChannelzSleep(100);
331 gpr_timespec time2 = GetLastCallStartedTime(&counter);
332 EXPECT_EQ(gpr_time_cmp(time1, time2), 0);
333 // calls succeeded or failed should not affect the timestamp
334 ChannelzSleep(100);
335 counter.RecordCallFailed();
336 counter.RecordCallSucceeded();
337 gpr_timespec time3 = GetLastCallStartedTime(&counter);
338 EXPECT_EQ(gpr_time_cmp(time1, time3), 0);
339 // another call started should affect the timestamp
340 // sleep for extra long to avoid flakes (since we cache Now())
341 ChannelzSleep(5000);
342 counter.RecordCallStarted();
343 gpr_timespec time4 = GetLastCallStartedTime(&counter);
344 EXPECT_NE(gpr_time_cmp(time1, time4), 0);
345 }
346
347 class ChannelzRegistryBasedTest : public ::testing::TestWithParam<size_t> {
348 protected:
349 // ensure we always have a fresh registry for tests.
SetUp()350 void SetUp() override {
351 WaitForSingleOwner(GetDefaultEventEngine());
352 ChannelzRegistry::TestOnlyReset();
353 }
354
TearDown()355 void TearDown() override {
356 WaitForSingleOwner(GetDefaultEventEngine());
357 ChannelzRegistry::TestOnlyReset();
358 }
359 };
360
TEST_F(ChannelzRegistryBasedTest,BasicGetTopChannelsTest)361 TEST_F(ChannelzRegistryBasedTest, BasicGetTopChannelsTest) {
362 ExecCtx exec_ctx;
363 ChannelFixture channel;
364 ValidateGetTopChannels(1);
365 }
366
TEST_F(ChannelzRegistryBasedTest,NoChannelsTest)367 TEST_F(ChannelzRegistryBasedTest, NoChannelsTest) {
368 ExecCtx exec_ctx;
369 ValidateGetTopChannels(0);
370 }
371
TEST_F(ChannelzRegistryBasedTest,ManyChannelsTest)372 TEST_F(ChannelzRegistryBasedTest, ManyChannelsTest) {
373 ExecCtx exec_ctx;
374 ChannelFixture channels[10];
375 (void)channels; // suppress unused variable error
376 ValidateGetTopChannels(10);
377 }
378
TEST_F(ChannelzRegistryBasedTest,GetTopChannelsPagination)379 TEST_F(ChannelzRegistryBasedTest, GetTopChannelsPagination) {
380 ExecCtx exec_ctx;
381 // This is over the pagination limit.
382 ChannelFixture channels[150];
383 (void)channels; // suppress unused variable error
384 std::string json_str = ChannelzRegistry::GetTopChannels(0);
385 grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(
386 json_str.c_str());
387 auto parsed_json = JsonParse(json_str);
388 ASSERT_TRUE(parsed_json.ok()) << parsed_json.status();
389 ASSERT_EQ(parsed_json->type(), Json::Type::kObject);
390 // 100 is the pagination limit.
391 Json channel_json;
392 auto it = parsed_json->object().find("channel");
393 if (it != parsed_json->object().end()) channel_json = it->second;
394 ValidateJsonArraySize(channel_json, 100);
395 ValidateJsonEnd(*parsed_json, false);
396 // Now we get the rest.
397 json_str = ChannelzRegistry::GetTopChannels(101);
398 grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(
399 json_str.c_str());
400 parsed_json = JsonParse(json_str);
401 ASSERT_TRUE(parsed_json.ok()) << parsed_json.status();
402 ASSERT_EQ(parsed_json->type(), Json::Type::kObject);
403 channel_json = Json();
404 it = parsed_json->object().find("channel");
405 if (it != parsed_json->object().end()) channel_json = it->second;
406 ValidateJsonArraySize(channel_json, 50);
407 ValidateJsonEnd(*parsed_json, true);
408 }
409
TEST_F(ChannelzRegistryBasedTest,GetTopChannelsUuidCheck)410 TEST_F(ChannelzRegistryBasedTest, GetTopChannelsUuidCheck) {
411 const intptr_t kNumChannels = 50;
412 ExecCtx exec_ctx;
413 ChannelFixture channels[kNumChannels];
414 (void)channels; // suppress unused variable error
415 std::string json_str = ChannelzRegistry::GetTopChannels(0);
416 auto parsed_json = JsonParse(json_str);
417 ASSERT_TRUE(parsed_json.ok()) << parsed_json.status();
418 ASSERT_EQ(parsed_json->type(), Json::Type::kObject);
419 Json channel_json;
420 auto it = parsed_json->object().find("channel");
421 if (it != parsed_json->object().end()) channel_json = it->second;
422 ValidateJsonArraySize(channel_json, kNumChannels);
423 std::vector<intptr_t> uuids = GetUuidListFromArray(channel_json.array());
424 for (int i = 0; i < kNumChannels; ++i) {
425 EXPECT_EQ(i + 1, uuids[i]);
426 }
427 }
428
TEST_F(ChannelzRegistryBasedTest,GetTopChannelsMiddleUuidCheck)429 TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMiddleUuidCheck) {
430 const intptr_t kNumChannels = 50;
431 const intptr_t kMidQuery = 40;
432 ExecCtx exec_ctx;
433 ChannelFixture channels[kNumChannels];
434 (void)channels; // suppress unused variable error
435 // Only query for the end of the channels.
436 std::string json_str = ChannelzRegistry::GetTopChannels(kMidQuery);
437 auto parsed_json = JsonParse(json_str);
438 ASSERT_TRUE(parsed_json.ok()) << parsed_json.status();
439 ASSERT_EQ(parsed_json->type(), Json::Type::kObject);
440 Json channel_json;
441 auto it = parsed_json->object().find("channel");
442 if (it != parsed_json->object().end()) channel_json = it->second;
443 ValidateJsonArraySize(channel_json, kNumChannels - kMidQuery + 1);
444 std::vector<intptr_t> uuids = GetUuidListFromArray(channel_json.array());
445 for (size_t i = 0; i < uuids.size(); ++i) {
446 EXPECT_EQ(static_cast<intptr_t>(kMidQuery + i), uuids[i]);
447 }
448 }
449
TEST_F(ChannelzRegistryBasedTest,GetTopChannelsNoHitUuid)450 TEST_F(ChannelzRegistryBasedTest, GetTopChannelsNoHitUuid) {
451 ExecCtx exec_ctx;
452 ChannelFixture pre_channels[40]; // will take uuid[1, 40]
453 (void)pre_channels; // suppress unused variable error
454 ServerFixture servers[10]; // will take uuid[41, 50]
455 (void)servers; // suppress unused variable error
456 ChannelFixture channels[10]; // will take uuid[51, 60]
457 (void)channels; // suppress unused variable error
458 // Query in the middle of the server channels.
459 std::string json_str = ChannelzRegistry::GetTopChannels(45);
460 auto parsed_json = JsonParse(json_str);
461 ASSERT_TRUE(parsed_json.ok()) << parsed_json.status();
462 ASSERT_EQ(parsed_json->type(), Json::Type::kObject);
463 Json channel_json;
464 auto it = parsed_json->object().find("channel");
465 if (it != parsed_json->object().end()) channel_json = it->second;
466 ValidateJsonArraySize(channel_json, 10);
467 std::vector<intptr_t> uuids = GetUuidListFromArray(channel_json.array());
468 for (size_t i = 0; i < uuids.size(); ++i) {
469 EXPECT_EQ(static_cast<intptr_t>(51 + i), uuids[i]);
470 }
471 }
472
TEST_F(ChannelzRegistryBasedTest,GetTopChannelsMoreGaps)473 TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMoreGaps) {
474 ExecCtx exec_ctx;
475 ChannelFixture channel_with_uuid1;
476 { ServerFixture channel_with_uuid2; }
477 ChannelFixture channel_with_uuid3;
478 { ServerFixture server_with_uuid4; }
479 ChannelFixture channel_with_uuid5;
480 // Current state of list: [1, NULL, 3, NULL, 5]
481 std::string json_str = ChannelzRegistry::GetTopChannels(2);
482 auto parsed_json = JsonParse(json_str);
483 ASSERT_TRUE(parsed_json.ok()) << parsed_json.status();
484 ASSERT_EQ(parsed_json->type(), Json::Type::kObject);
485 Json channel_json;
486 auto it = parsed_json->object().find("channel");
487 if (it != parsed_json->object().end()) channel_json = it->second;
488 ValidateJsonArraySize(channel_json, 2);
489 std::vector<intptr_t> uuids = GetUuidListFromArray(channel_json.array());
490 EXPECT_EQ(3, uuids[0]);
491 EXPECT_EQ(5, uuids[1]);
492 json_str = ChannelzRegistry::GetTopChannels(4);
493 parsed_json = JsonParse(json_str);
494 ASSERT_TRUE(parsed_json.ok()) << parsed_json.status();
495 ASSERT_EQ(parsed_json->type(), Json::Type::kObject);
496 channel_json = Json();
497 it = parsed_json->object().find("channel");
498 if (it != parsed_json->object().end()) channel_json = it->second;
499 ValidateJsonArraySize(channel_json, 1);
500 uuids = GetUuidListFromArray(channel_json.array());
501 EXPECT_EQ(5, uuids[0]);
502 }
503
TEST_F(ChannelzRegistryBasedTest,GetTopChannelsUuidAfterCompaction)504 TEST_F(ChannelzRegistryBasedTest, GetTopChannelsUuidAfterCompaction) {
505 const intptr_t kLoopIterations = 50;
506 ExecCtx exec_ctx;
507 std::vector<std::unique_ptr<ChannelFixture>> even_channels;
508 {
509 // these will delete and unregister themselves after this block.
510 std::vector<std::unique_ptr<ChannelFixture>> odd_channels;
511 for (int i = 0; i < kLoopIterations; i++) {
512 odd_channels.push_back(std::make_unique<ChannelFixture>());
513 even_channels.push_back(std::make_unique<ChannelFixture>());
514 }
515 }
516 Notification done;
517 grpc_event_engine::experimental::GetDefaultEventEngine()->RunAfter(
518 std::chrono::seconds(5 * grpc_test_slowdown_factor()), [&] {
519 ExecCtx exec_ctx;
520 std::string json_str = ChannelzRegistry::GetTopChannels(0);
521 auto parsed_json = JsonParse(json_str);
522 ASSERT_TRUE(parsed_json.ok()) << parsed_json.status();
523 ASSERT_EQ(parsed_json->type(), Json::Type::kObject);
524 Json channel_json;
525 auto it = parsed_json->object().find("channel");
526 if (it != parsed_json->object().end()) channel_json = it->second;
527 ValidateJsonArraySize(channel_json, kLoopIterations);
528 std::vector<intptr_t> uuids =
529 GetUuidListFromArray(channel_json.array());
530 for (int i = 0; i < kLoopIterations; ++i) {
531 // only the even uuids will still be present.
532 EXPECT_EQ((i + 1) * 2, uuids[i]);
533 }
534 done.Notify();
535 });
536 done.WaitForNotification();
537 }
538
TEST_F(ChannelzRegistryBasedTest,InternalChannelTest)539 TEST_F(ChannelzRegistryBasedTest, InternalChannelTest) {
540 ExecCtx exec_ctx;
541 ChannelFixture channels[10];
542 (void)channels; // suppress unused variable error
543 // create an internal channel
544 grpc_arg client_a[] = {
545 grpc_channel_arg_integer_create(
546 const_cast<char*>(GRPC_ARG_CHANNELZ_IS_INTERNAL_CHANNEL), 1),
547 grpc_channel_arg_integer_create(
548 const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true),
549 };
550 grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
551 grpc_channel_credentials* creds = grpc_insecure_credentials_create();
552 grpc_channel* internal_channel =
553 grpc_channel_create("fake_target", creds, &client_args);
554 grpc_channel_credentials_release(creds);
555 // The internal channel should not be returned from the request
556 ValidateGetTopChannels(10);
557 grpc_channel_destroy(internal_channel);
558 }
559
TEST(ChannelzServerTest,BasicServerAPIFunctionality)560 TEST(ChannelzServerTest, BasicServerAPIFunctionality) {
561 ExecCtx exec_ctx;
562 ServerFixture server(10);
563 ServerNode* channelz_server = Server::FromC(server.server())->channelz_node();
564 channelz_server->RecordCallStarted();
565 channelz_server->RecordCallFailed();
566 channelz_server->RecordCallSucceeded();
567 ValidateServer(channelz_server, {1, 1, 1});
568 channelz_server->RecordCallStarted();
569 channelz_server->RecordCallFailed();
570 channelz_server->RecordCallSucceeded();
571 channelz_server->RecordCallStarted();
572 channelz_server->RecordCallFailed();
573 channelz_server->RecordCallSucceeded();
574 ValidateServer(channelz_server, {3, 3, 3});
575 }
576
TEST_F(ChannelzRegistryBasedTest,BasicGetServersTest)577 TEST_F(ChannelzRegistryBasedTest, BasicGetServersTest) {
578 ExecCtx exec_ctx;
579 ServerFixture server;
580 ValidateGetServers(1);
581 }
582
TEST_F(ChannelzRegistryBasedTest,NoServersTest)583 TEST_F(ChannelzRegistryBasedTest, NoServersTest) {
584 ExecCtx exec_ctx;
585 ValidateGetServers(0);
586 }
587
TEST_F(ChannelzRegistryBasedTest,ManyServersTest)588 TEST_F(ChannelzRegistryBasedTest, ManyServersTest) {
589 ExecCtx exec_ctx;
590 ServerFixture servers[10];
591 (void)servers; // suppress unused variable error
592 ValidateGetServers(10);
593 }
594
595 INSTANTIATE_TEST_SUITE_P(ChannelzChannelTestSweep, ChannelzChannelTest,
596 ::testing::Values(0, 8, 64, 1024, 1024 * 1024));
597
598 } // namespace testing
599 } // namespace channelz
600 } // namespace grpc_core
601
main(int argc,char ** argv)602 int main(int argc, char** argv) {
603 grpc::testing::TestEnvironment env(&argc, argv);
604 grpc_init();
605 ::testing::InitGoogleTest(&argc, argv);
606 int ret = RUN_ALL_TESTS();
607 grpc_shutdown();
608 return ret;
609 }
610