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:
CallCountingHelperPeer(CallCountingHelper * node)50 explicit CallCountingHelperPeer(CallCountingHelper* node) : node_(node) {}
last_call_started_millis() const51 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
GetJsonChild(grpc_json * parent,const char * key)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
ValidateJsonArraySize(grpc_json * json,const char * key,size_t expected_size)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
ValidateGetTopChannels(size_t expected_channels)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
ValidateGetServers(size_t expected_servers)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:
ChannelFixture(int max_trace_nodes=0)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
~ChannelFixture()139 ~ChannelFixture() { grpc_channel_destroy(channel_); }
140
channel()141 grpc_channel* channel() { return channel_; }
142
143 private:
144 grpc_channel* channel_;
145 };
146
147 class ServerFixture {
148 public:
ServerFixture(int max_trace_nodes=0)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
~ServerFixture()161 ~ServerFixture() { grpc_server_destroy(server_); }
162
server() const163 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
ValidateChildInteger(grpc_json * json,int64_t expect,const char * key)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
ValidateCounters(char * json_str,validate_channel_data_args args)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
ValidateChannel(ChannelNode * channel,validate_channel_data_args args)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
ValidateServer(ServerNode * server,validate_channel_data_args args)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
GetLastCallStartedMillis(CallCountingHelper * channel)215 grpc_millis GetLastCallStartedMillis(CallCountingHelper* channel) {
216 CallCountingHelperPeer peer(channel);
217 return peer.last_call_started_millis();
218 }
219
ChannelzSleep(int64_t sleep_us)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
TEST_P(ChannelzChannelTest,BasicChannel)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
TEST(ChannelzChannelTest,ChannelzDisabled)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
TEST_P(ChannelzChannelTest,BasicChannelAPIFunctionality)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
TEST_P(ChannelzChannelTest,LastCallStartedMillis)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
TEST(ChannelzGetTopChannelsTest,BasicGetTopChannelsTest)289 TEST(ChannelzGetTopChannelsTest, BasicGetTopChannelsTest) {
290 grpc_core::ExecCtx exec_ctx;
291 ChannelFixture channel;
292 ValidateGetTopChannels(1);
293 }
294
TEST(ChannelzGetTopChannelsTest,NoChannelsTest)295 TEST(ChannelzGetTopChannelsTest, NoChannelsTest) {
296 grpc_core::ExecCtx exec_ctx;
297 ValidateGetTopChannels(0);
298 }
299
TEST(ChannelzGetTopChannelsTest,ManyChannelsTest)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
TEST(ChannelzGetTopChannelsTest,InternalChannelTest)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
TEST_P(ChannelzServerTest,BasicServerAPIFunctionality)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
TEST(ChannelzGetServersTest,BasicGetServersTest)344 TEST(ChannelzGetServersTest, BasicGetServersTest) {
345 grpc_core::ExecCtx exec_ctx;
346 ServerFixture server;
347 ValidateGetServers(1);
348 }
349
TEST(ChannelzGetServersTest,NoServersTest)350 TEST(ChannelzGetServersTest, NoServersTest) {
351 grpc_core::ExecCtx exec_ctx;
352 ValidateGetServers(0);
353 }
354
TEST(ChannelzGetServersTest,ManyServersTest)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
main(int argc,char ** argv)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