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
34 #include "test/core/util/test_config.h"
35 #include "test/cpp/util/channel_trace_proto_helper.h"
36
37 #include <stdlib.h>
38 #include <string.h>
39
40 namespace grpc_core {
41 namespace channelz {
42 namespace testing {
43
44 // testing peer to access channel internals
45 class ChannelNodePeer {
46 public:
ChannelNodePeer(ChannelNode * node)47 explicit ChannelNodePeer(ChannelNode* node) : node_(node) {}
trace() const48 ChannelTrace* trace() const { return &node_->trace_; }
49
50 private:
51 ChannelNode* node_;
52 };
53
54 namespace {
55
GetJsonChild(grpc_json * parent,const char * key)56 grpc_json* GetJsonChild(grpc_json* parent, const char* key) {
57 EXPECT_NE(parent, nullptr);
58 for (grpc_json* child = parent->child; child != nullptr;
59 child = child->next) {
60 if (child->key != nullptr && strcmp(child->key, key) == 0) return child;
61 }
62 return nullptr;
63 }
64
ValidateJsonArraySize(grpc_json * json,const char * key,size_t expected_size)65 void ValidateJsonArraySize(grpc_json* json, const char* key,
66 size_t expected_size) {
67 grpc_json* arr = GetJsonChild(json, key);
68 ASSERT_NE(arr, nullptr);
69 ASSERT_EQ(arr->type, GRPC_JSON_ARRAY);
70 size_t count = 0;
71 for (grpc_json* child = arr->child; child != nullptr; child = child->next) {
72 ++count;
73 }
74 ASSERT_EQ(count, expected_size);
75 }
76
ValidateChannelTraceData(grpc_json * json,size_t num_events_logged_expected,size_t actual_num_events_expected)77 void ValidateChannelTraceData(grpc_json* json,
78 size_t num_events_logged_expected,
79 size_t actual_num_events_expected) {
80 ASSERT_NE(json, nullptr);
81 grpc_json* num_events_logged_json = GetJsonChild(json, "numEventsLogged");
82 ASSERT_NE(num_events_logged_json, nullptr);
83 grpc_json* start_time = GetJsonChild(json, "creationTimestamp");
84 ASSERT_NE(start_time, nullptr);
85 size_t num_events_logged =
86 (size_t)strtol(num_events_logged_json->value, nullptr, 0);
87 ASSERT_EQ(num_events_logged, num_events_logged_expected);
88 ValidateJsonArraySize(json, "events", actual_num_events_expected);
89 }
90
AddSimpleTrace(ChannelTrace * tracer)91 void AddSimpleTrace(ChannelTrace* tracer) {
92 tracer->AddTraceEvent(ChannelTrace::Severity::Info,
93 grpc_slice_from_static_string("simple trace"));
94 }
95
96 // checks for the existence of all the required members of the tracer.
ValidateChannelTrace(ChannelTrace * tracer,size_t expected_num_event_logged,size_t max_nodes)97 void ValidateChannelTrace(ChannelTrace* tracer,
98 size_t expected_num_event_logged, size_t max_nodes) {
99 if (!max_nodes) return;
100 grpc_json* json = tracer->RenderJson();
101 EXPECT_NE(json, nullptr);
102 char* json_str = grpc_json_dump_to_string(json, 0);
103 grpc_json_destroy(json);
104 grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str);
105 grpc_json* parsed_json = grpc_json_parse_string(json_str);
106 ValidateChannelTraceData(parsed_json, expected_num_event_logged,
107 GPR_MIN(expected_num_event_logged, max_nodes));
108 grpc_json_destroy(parsed_json);
109 gpr_free(json_str);
110 }
111
112 class ChannelFixture {
113 public:
ChannelFixture(int max_trace_nodes)114 ChannelFixture(int max_trace_nodes) {
115 grpc_arg client_a;
116 client_a.type = GRPC_ARG_INTEGER;
117 client_a.key =
118 const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
119 client_a.value.integer = max_trace_nodes;
120 grpc_channel_args client_args = {1, &client_a};
121 channel_ =
122 grpc_insecure_channel_create("fake_target", &client_args, nullptr);
123 }
124
~ChannelFixture()125 ~ChannelFixture() { grpc_channel_destroy(channel_); }
126
channel()127 grpc_channel* channel() { return channel_; }
128
129 private:
130 grpc_channel* channel_;
131 };
132
133 } // anonymous namespace
134
135 class ChannelTracerTest : public ::testing::TestWithParam<size_t> {};
136
137 // Tests basic ChannelTrace functionality like construction, adding trace, and
138 // lookups by uuid.
TEST_P(ChannelTracerTest,BasicTest)139 TEST_P(ChannelTracerTest, BasicTest) {
140 grpc_core::ExecCtx exec_ctx;
141 ChannelTrace tracer(GetParam());
142 AddSimpleTrace(&tracer);
143 AddSimpleTrace(&tracer);
144 tracer.AddTraceEvent(ChannelTrace::Severity::Info,
145 grpc_slice_from_static_string("trace three"));
146 tracer.AddTraceEvent(ChannelTrace::Severity::Error,
147 grpc_slice_from_static_string("trace four error"));
148 ValidateChannelTrace(&tracer, 4, GetParam());
149 AddSimpleTrace(&tracer);
150 AddSimpleTrace(&tracer);
151 ValidateChannelTrace(&tracer, 6, GetParam());
152 AddSimpleTrace(&tracer);
153 AddSimpleTrace(&tracer);
154 AddSimpleTrace(&tracer);
155 AddSimpleTrace(&tracer);
156 ValidateChannelTrace(&tracer, 10, GetParam());
157 }
158
159 // Tests more complex functionality, like a parent channel tracking
160 // subchannles. This exercises the ref/unref patterns since the parent tracer
161 // and this function will both hold refs to the subchannel.
TEST_P(ChannelTracerTest,ComplexTest)162 TEST_P(ChannelTracerTest, ComplexTest) {
163 grpc_core::ExecCtx exec_ctx;
164 ChannelTrace tracer(GetParam());
165 AddSimpleTrace(&tracer);
166 AddSimpleTrace(&tracer);
167 ChannelFixture channel1(GetParam());
168 RefCountedPtr<ChannelNode> sc1 =
169 MakeRefCounted<ChannelNode>(channel1.channel(), GetParam(), true);
170 ChannelNodePeer sc1_peer(sc1.get());
171 tracer.AddTraceEventWithReference(
172 ChannelTrace::Severity::Info,
173 grpc_slice_from_static_string("subchannel one created"), sc1);
174 ValidateChannelTrace(&tracer, 3, GetParam());
175 AddSimpleTrace(sc1_peer.trace());
176 AddSimpleTrace(sc1_peer.trace());
177 AddSimpleTrace(sc1_peer.trace());
178 ValidateChannelTrace(sc1_peer.trace(), 3, GetParam());
179 AddSimpleTrace(sc1_peer.trace());
180 AddSimpleTrace(sc1_peer.trace());
181 AddSimpleTrace(sc1_peer.trace());
182 ValidateChannelTrace(sc1_peer.trace(), 6, GetParam());
183 AddSimpleTrace(&tracer);
184 AddSimpleTrace(&tracer);
185 ValidateChannelTrace(&tracer, 5, GetParam());
186 ChannelFixture channel2(GetParam());
187 RefCountedPtr<ChannelNode> sc2 =
188 MakeRefCounted<ChannelNode>(channel2.channel(), GetParam(), true);
189 tracer.AddTraceEventWithReference(
190 ChannelTrace::Severity::Info,
191 grpc_slice_from_static_string("LB channel two created"), sc2);
192 tracer.AddTraceEventWithReference(
193 ChannelTrace::Severity::Warning,
194 grpc_slice_from_static_string("subchannel one inactive"), sc1);
195 ValidateChannelTrace(&tracer, 7, GetParam());
196 AddSimpleTrace(&tracer);
197 AddSimpleTrace(&tracer);
198 AddSimpleTrace(&tracer);
199 AddSimpleTrace(&tracer);
200 AddSimpleTrace(&tracer);
201 AddSimpleTrace(&tracer);
202 sc1.reset();
203 sc2.reset();
204 }
205
206 // Test a case in which the parent channel has subchannels and the subchannels
207 // have connections. Ensures that everything lives as long as it should then
208 // gets deleted.
TEST_P(ChannelTracerTest,TestNesting)209 TEST_P(ChannelTracerTest, TestNesting) {
210 grpc_core::ExecCtx exec_ctx;
211 ChannelTrace tracer(GetParam());
212 AddSimpleTrace(&tracer);
213 AddSimpleTrace(&tracer);
214 ValidateChannelTrace(&tracer, 2, GetParam());
215 ChannelFixture channel1(GetParam());
216 RefCountedPtr<ChannelNode> sc1 =
217 MakeRefCounted<ChannelNode>(channel1.channel(), GetParam(), true);
218 ChannelNodePeer sc1_peer(sc1.get());
219 tracer.AddTraceEventWithReference(
220 ChannelTrace::Severity::Info,
221 grpc_slice_from_static_string("subchannel one created"), sc1);
222 ValidateChannelTrace(&tracer, 3, GetParam());
223 AddSimpleTrace(sc1_peer.trace());
224 ChannelFixture channel2(GetParam());
225 RefCountedPtr<ChannelNode> conn1 =
226 MakeRefCounted<ChannelNode>(channel2.channel(), GetParam(), true);
227 ChannelNodePeer conn1_peer(conn1.get());
228 // nesting one level deeper.
229 sc1_peer.trace()->AddTraceEventWithReference(
230 ChannelTrace::Severity::Info,
231 grpc_slice_from_static_string("connection one created"), conn1);
232 ValidateChannelTrace(&tracer, 3, GetParam());
233 AddSimpleTrace(conn1_peer.trace());
234 AddSimpleTrace(&tracer);
235 AddSimpleTrace(&tracer);
236 ValidateChannelTrace(&tracer, 5, GetParam());
237 ValidateChannelTrace(conn1_peer.trace(), 1, GetParam());
238 ChannelFixture channel3(GetParam());
239 RefCountedPtr<ChannelNode> sc2 =
240 MakeRefCounted<ChannelNode>(channel3.channel(), GetParam(), true);
241 tracer.AddTraceEventWithReference(
242 ChannelTrace::Severity::Info,
243 grpc_slice_from_static_string("subchannel two created"), sc2);
244 // this trace should not get added to the parents children since it is already
245 // present in the tracer.
246 tracer.AddTraceEventWithReference(
247 ChannelTrace::Severity::Warning,
248 grpc_slice_from_static_string("subchannel one inactive"), sc1);
249 AddSimpleTrace(&tracer);
250 ValidateChannelTrace(&tracer, 8, GetParam());
251 sc1.reset();
252 sc2.reset();
253 conn1.reset();
254 }
255
256 INSTANTIATE_TEST_CASE_P(ChannelTracerTestSweep, ChannelTracerTest,
257 ::testing::Values(0, 1, 2, 6, 10, 15));
258
259 } // namespace testing
260 } // namespace channelz
261 } // namespace grpc_core
262
main(int argc,char ** argv)263 int main(int argc, char** argv) {
264 grpc_test_init(argc, argv);
265 grpc_init();
266 ::testing::InitGoogleTest(&argc, argv);
267 int ret = RUN_ALL_TESTS();
268 grpc_shutdown();
269 return ret;
270 }
271