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