blob: d12f52972657586fd57caedc6e244b66eb858b6e [file] [log] [blame]
ncteisenc3c6e062018-05-09 11:10:21 -07001/*
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"
ncteisen9a1bb052018-05-30 16:17:06 -070028#include "src/core/lib/channel/channelz.h"
ncteisenc3c6e062018-05-09 11:10:21 -070029#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"
ncteisen9a1bb052018-05-30 16:17:06 -070033#include "src/core/lib/surface/channel.h"
ncteisenc3c6e062018-05-09 11:10:21 -070034
35#include "test/core/util/test_config.h"
36#include "test/cpp/util/channel_trace_proto_helper.h"
37
ncteisenc3c6e062018-05-09 11:10:21 -070038#include <grpc/support/string_util.h>
39#include <stdlib.h>
40#include <string.h>
41
42namespace grpc_core {
ncteisen9a1bb052018-05-30 16:17:06 -070043namespace channelz {
ncteisenc3c6e062018-05-09 11:10:21 -070044namespace testing {
ncteisenc845ba62018-06-07 10:14:55 -070045
46// testing peer to access channel internals
ncteisen6c987cb2018-06-08 09:30:12 -070047class ChannelNodePeer {
ncteisenc845ba62018-06-07 10:14:55 -070048 public:
ncteisen6c987cb2018-06-08 09:30:12 -070049 ChannelNodePeer(ChannelNode* channel) : channel_(channel) {}
Noah Eisenea424b82018-06-07 13:02:48 -070050 grpc_millis last_call_started_millis() {
51 return (grpc_millis)gpr_atm_no_barrier_load(
52 &channel_->last_call_started_millis_);
53 }
54
ncteisenc845ba62018-06-07 10:14:55 -070055 private:
ncteisen6c987cb2018-06-08 09:30:12 -070056 ChannelNode* channel_;
ncteisenc845ba62018-06-07 10:14:55 -070057};
58
ncteisen9a1bb052018-05-30 16:17:06 -070059namespace {
ncteisenc3c6e062018-05-09 11:10:21 -070060
ncteisen9a1bb052018-05-30 16:17:06 -070061grpc_json* GetJsonChild(grpc_json* parent, const char* key) {
62 EXPECT_NE(parent, nullptr);
63 for (grpc_json* child = parent->child; child != nullptr;
64 child = child->next) {
65 if (child->key != nullptr && strcmp(child->key, key) == 0) return child;
66 }
67 return nullptr;
68}
69
ncteisen97066fd2018-07-13 14:05:27 -070070void ValidateJsonArraySize(grpc_json* json, const char* key,
71 size_t expected_size) {
72 grpc_json* arr = GetJsonChild(json, key);
73 if (expected_size == 0) {
74 ASSERT_EQ(arr, nullptr);
75 return;
76 }
77 ASSERT_NE(arr, nullptr);
78 ASSERT_EQ(arr->type, GRPC_JSON_ARRAY);
79 size_t count = 0;
80 for (grpc_json* child = arr->child; child != nullptr; child = child->next) {
81 ++count;
82 }
ncteisen5d373c42018-07-17 11:57:31 -070083 EXPECT_EQ(count, expected_size);
ncteisen97066fd2018-07-13 14:05:27 -070084}
85
86void ValidateGetTopChannels(size_t expected_channels) {
87 char* json_str = ChannelzRegistry::GetTopChannels(0);
88 grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str);
89 grpc_json* parsed_json = grpc_json_parse_string(json_str);
90 // This check will naturally have to change when we support pagination.
91 // tracked: https://github.com/grpc/grpc/issues/16019.
92 ValidateJsonArraySize(parsed_json, "channel", expected_channels);
93 grpc_json* end = GetJsonChild(parsed_json, "end");
ncteisen5d373c42018-07-17 11:57:31 -070094 ASSERT_NE(end, nullptr);
ncteisen97066fd2018-07-13 14:05:27 -070095 EXPECT_EQ(end->type, GRPC_JSON_TRUE);
96 grpc_json_destroy(parsed_json);
97 gpr_free(json_str);
98}
99
ncteisen9a1bb052018-05-30 16:17:06 -0700100class ChannelFixture {
101 public:
ncteisen97066fd2018-07-13 14:05:27 -0700102 ChannelFixture(int max_trace_nodes = 0) {
ncteisenc7166ae2018-06-15 11:04:37 -0400103 grpc_arg client_a[2];
ncteisen5d373c42018-07-17 11:57:31 -0700104 client_a[0] = grpc_channel_arg_integer_create(
105 const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE),
106 max_trace_nodes);
107 client_a[1] = grpc_channel_arg_integer_create(
108 const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true);
ncteisenc7166ae2018-06-15 11:04:37 -0400109 grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
ncteisen9a1bb052018-05-30 16:17:06 -0700110 channel_ =
111 grpc_insecure_channel_create("fake_target", &client_args, nullptr);
112 }
113
114 ~ChannelFixture() { grpc_channel_destroy(channel_); }
115
116 grpc_channel* channel() { return channel_; }
117
118 private:
119 grpc_channel* channel_;
120};
121
122struct validate_channel_data_args {
123 int64_t calls_started;
124 int64_t calls_failed;
125 int64_t calls_succeeded;
126};
127
128void ValidateChildInteger(grpc_json* json, int64_t expect, const char* key) {
129 grpc_json* gotten_json = GetJsonChild(json, key);
ncteisen97066fd2018-07-13 14:05:27 -0700130 if (expect == 0) {
131 ASSERT_EQ(gotten_json, nullptr);
132 return;
133 }
ncteisenc7166ae2018-06-15 11:04:37 -0400134 ASSERT_NE(gotten_json, nullptr);
ncteisen9a1bb052018-05-30 16:17:06 -0700135 int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0);
136 EXPECT_EQ(gotten_number, expect);
137}
138
ncteisen9b488f72018-06-07 18:38:28 -0700139void ValidateCounters(char* json_str, validate_channel_data_args args) {
ncteisen9a1bb052018-05-30 16:17:06 -0700140 grpc_json* json = grpc_json_parse_string(json_str);
ncteisenc7166ae2018-06-15 11:04:37 -0400141 ASSERT_NE(json, nullptr);
ncteisen9a1bb052018-05-30 16:17:06 -0700142 grpc_json* data = GetJsonChild(json, "data");
143 ValidateChildInteger(data, args.calls_started, "callsStarted");
144 ValidateChildInteger(data, args.calls_failed, "callsFailed");
145 ValidateChildInteger(data, args.calls_succeeded, "callsSucceeded");
146 grpc_json_destroy(json);
ncteisen9b488f72018-06-07 18:38:28 -0700147}
148
ncteisen6c987cb2018-06-08 09:30:12 -0700149void ValidateChannel(ChannelNode* channel, validate_channel_data_args args) {
ncteisen97066fd2018-07-13 14:05:27 -0700150 char* json_str = channel->RenderJsonString();
ncteisen9b488f72018-06-07 18:38:28 -0700151 grpc::testing::ValidateChannelProtoJsonTranslation(json_str);
152 ValidateCounters(json_str, args);
ncteisen9a1bb052018-05-30 16:17:06 -0700153 gpr_free(json_str);
154}
155
ncteisen6c987cb2018-06-08 09:30:12 -0700156grpc_millis GetLastCallStartedMillis(ChannelNode* channel) {
157 ChannelNodePeer peer(channel);
ncteisenc845ba62018-06-07 10:14:55 -0700158 return peer.last_call_started_millis();
ncteisen9a1bb052018-05-30 16:17:06 -0700159}
160
161void ChannelzSleep(int64_t sleep_us) {
162 gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
163 gpr_time_from_micros(sleep_us, GPR_TIMESPAN)));
164 grpc_core::ExecCtx::Get()->InvalidateNow();
165}
166
167} // anonymous namespace
168
169class ChannelzChannelTest : public ::testing::TestWithParam<size_t> {};
170
171TEST_P(ChannelzChannelTest, BasicChannel) {
172 grpc_core::ExecCtx exec_ctx;
173 ChannelFixture channel(GetParam());
ncteisen16280c72018-06-08 09:44:25 -0700174 ChannelNode* channelz_channel =
175 grpc_channel_get_channelz_node(channel.channel());
ncteisen97066fd2018-07-13 14:05:27 -0700176 ValidateChannel(channelz_channel, {0, 0, 0});
ncteisen9a1bb052018-05-30 16:17:06 -0700177}
178
ncteisenc7166ae2018-06-15 11:04:37 -0400179TEST(ChannelzChannelTest, ChannelzDisabled) {
180 grpc_core::ExecCtx exec_ctx;
181 grpc_channel* channel =
182 grpc_insecure_channel_create("fake_target", nullptr, nullptr);
183 ChannelNode* channelz_channel = grpc_channel_get_channelz_node(channel);
ncteisen1ab12872018-06-19 17:09:53 -0700184 ASSERT_EQ(channelz_channel, nullptr);
ncteisen4d1da602018-06-15 14:54:26 -0400185 grpc_channel_destroy(channel);
ncteisenc7166ae2018-06-15 11:04:37 -0400186}
187
ncteisen9a1bb052018-05-30 16:17:06 -0700188TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) {
189 grpc_core::ExecCtx exec_ctx;
190 ChannelFixture channel(GetParam());
ncteisen16280c72018-06-08 09:44:25 -0700191 ChannelNode* channelz_channel =
192 grpc_channel_get_channelz_node(channel.channel());
ncteisenc845ba62018-06-07 10:14:55 -0700193 channelz_channel->RecordCallStarted();
194 channelz_channel->RecordCallFailed();
195 channelz_channel->RecordCallSucceeded();
ncteisen9a1bb052018-05-30 16:17:06 -0700196 ValidateChannel(channelz_channel, {1, 1, 1});
ncteisenc845ba62018-06-07 10:14:55 -0700197 channelz_channel->RecordCallStarted();
198 channelz_channel->RecordCallFailed();
199 channelz_channel->RecordCallSucceeded();
200 channelz_channel->RecordCallStarted();
201 channelz_channel->RecordCallFailed();
202 channelz_channel->RecordCallSucceeded();
ncteisen9a1bb052018-05-30 16:17:06 -0700203 ValidateChannel(channelz_channel, {3, 3, 3});
204}
205
ncteisend23739e2018-06-07 12:55:15 -0700206TEST_P(ChannelzChannelTest, LastCallStartedMillis) {
ncteisen9a1bb052018-05-30 16:17:06 -0700207 grpc_core::ExecCtx exec_ctx;
208 ChannelFixture channel(GetParam());
ncteisen16280c72018-06-08 09:44:25 -0700209 ChannelNode* channelz_channel =
210 grpc_channel_get_channelz_node(channel.channel());
ncteisen9a1bb052018-05-30 16:17:06 -0700211 // start a call to set the last call started timestamp
ncteisenc845ba62018-06-07 10:14:55 -0700212 channelz_channel->RecordCallStarted();
213 grpc_millis millis1 = GetLastCallStartedMillis(channelz_channel);
ncteisen9a1bb052018-05-30 16:17:06 -0700214 // time gone by should not affect the timestamp
215 ChannelzSleep(100);
ncteisenc845ba62018-06-07 10:14:55 -0700216 grpc_millis millis2 = GetLastCallStartedMillis(channelz_channel);
217 EXPECT_EQ(millis1, millis2);
ncteisen9a1bb052018-05-30 16:17:06 -0700218 // calls succeeded or failed should not affect the timestamp
219 ChannelzSleep(100);
ncteisenc845ba62018-06-07 10:14:55 -0700220 channelz_channel->RecordCallFailed();
221 channelz_channel->RecordCallSucceeded();
222 grpc_millis millis3 = GetLastCallStartedMillis(channelz_channel);
223 EXPECT_EQ(millis1, millis3);
ncteisen9a1bb052018-05-30 16:17:06 -0700224 // another call started should affect the timestamp
225 // sleep for extra long to avoid flakes (since we cache Now())
226 ChannelzSleep(5000);
ncteisenc845ba62018-06-07 10:14:55 -0700227 channelz_channel->RecordCallStarted();
228 grpc_millis millis4 = GetLastCallStartedMillis(channelz_channel);
229 EXPECT_NE(millis1, millis4);
ncteisen9a1bb052018-05-30 16:17:06 -0700230}
231
ncteisen97066fd2018-07-13 14:05:27 -0700232TEST(ChannelzGetTopChannelsTest, BasicTest) {
233 grpc_core::ExecCtx exec_ctx;
234 ChannelFixture channel;
235 ValidateGetTopChannels(1);
236}
237
238TEST(ChannelzGetTopChannelsTest, NoChannelsTest) {
239 grpc_core::ExecCtx exec_ctx;
240 ValidateGetTopChannels(0);
241}
242
243TEST(ChannelzGetTopChannelsTest, ManyChannelsTest) {
244 grpc_core::ExecCtx exec_ctx;
245 ChannelFixture channels[10];
246 (void)channels; // suppress unused variable error
247 ValidateGetTopChannels(10);
248}
249
250TEST(ChannelzGetTopChannelsTest, InternalChannelTest) {
251 grpc_core::ExecCtx exec_ctx;
252 ChannelFixture channels[10];
253 (void)channels; // suppress unused variable error
254 // create an internal channel
255 grpc_arg client_a[2];
ncteisen5d373c42018-07-17 11:57:31 -0700256 client_a[0] = grpc_channel_arg_integer_create(
257 const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), true);
258 client_a[1] = grpc_channel_arg_integer_create(
259 const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true);
ncteisen97066fd2018-07-13 14:05:27 -0700260 grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
261 grpc_channel* internal_channel =
262 grpc_insecure_channel_create("fake_target", &client_args, nullptr);
263 // The internal channel should not be returned from the request
264 ValidateGetTopChannels(10);
265 grpc_channel_destroy(internal_channel);
266}
267
ncteisen9a1bb052018-05-30 16:17:06 -0700268INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest,
269 ::testing::Values(0, 1, 2, 6, 10, 15));
ncteisenc3c6e062018-05-09 11:10:21 -0700270
271} // namespace testing
ncteisen9a1bb052018-05-30 16:17:06 -0700272} // namespace channelz
ncteisenc3c6e062018-05-09 11:10:21 -0700273} // namespace grpc_core
274
275int main(int argc, char** argv) {
276 grpc_test_init(argc, argv);
277 grpc_init();
278 ::testing::InitGoogleTest(&argc, argv);
279 int ret = RUN_ALL_TESTS();
280 grpc_shutdown();
281 return ret;
282}