• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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