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/lib/channel/channel_trace.h"
20
21 #include <stdlib.h>
22
23 #include <string>
24
25 #include "gtest/gtest.h"
26
27 #include <grpc/grpc.h>
28 #include <grpc/grpc_security.h>
29 #include <grpc/impl/channel_arg_names.h>
30
31 #include "src/core/lib/channel/channel_args.h"
32 #include "src/core/lib/channel/channelz.h"
33 #include "src/core/lib/iomgr/exec_ctx.h"
34 #include "src/core/lib/json/json.h"
35 #include "src/core/lib/json/json_writer.h"
36 #include "test/core/util/test_config.h"
37 #include "test/cpp/util/channel_trace_proto_helper.h"
38
39 namespace grpc_core {
40 namespace channelz {
41 namespace testing {
42
43 // testing peer to access channel internals
44 class ChannelNodePeer {
45 public:
ChannelNodePeer(ChannelNode * node)46 explicit ChannelNodePeer(ChannelNode* node) : node_(node) {}
trace() const47 ChannelTrace* trace() const { return &node_->trace_; }
48
49 private:
50 ChannelNode* node_;
51 };
52
GetSizeofTraceEvent()53 size_t GetSizeofTraceEvent() { return sizeof(ChannelTrace::TraceEvent); }
54
55 namespace {
56
ValidateJsonArraySize(const Json & array,size_t expected)57 void ValidateJsonArraySize(const Json& array, size_t expected) {
58 if (expected == 0) {
59 ASSERT_EQ(array.type(), Json::Type::kNull);
60 } else {
61 ASSERT_EQ(array.type(), Json::Type::kArray);
62 EXPECT_EQ(array.array().size(), expected);
63 }
64 }
65
ValidateChannelTraceData(const Json & json,size_t num_events_logged_expected,size_t actual_num_events_expected)66 void ValidateChannelTraceData(const Json& json,
67 size_t num_events_logged_expected,
68 size_t actual_num_events_expected) {
69 ASSERT_EQ(json.type(), Json::Type::kObject);
70 Json::Object object = json.object();
71 Json& num_events_logged_json = object["numEventsLogged"];
72 ASSERT_EQ(num_events_logged_json.type(), Json::Type::kString);
73 size_t num_events_logged = static_cast<size_t>(
74 strtol(num_events_logged_json.string().c_str(), nullptr, 0));
75 ASSERT_EQ(num_events_logged, num_events_logged_expected);
76 Json& start_time_json = object["creationTimestamp"];
77 ASSERT_EQ(start_time_json.type(), Json::Type::kString);
78 ValidateJsonArraySize(object["events"], actual_num_events_expected);
79 }
80
AddSimpleTrace(ChannelTrace * tracer)81 void AddSimpleTrace(ChannelTrace* tracer) {
82 tracer->AddTraceEvent(ChannelTrace::Severity::Info,
83 grpc_slice_from_static_string("simple trace"));
84 }
85
86 // checks for the existence of all the required members of the tracer.
ValidateChannelTraceCustom(ChannelTrace * tracer,size_t num_events_logged,size_t num_events_expected)87 void ValidateChannelTraceCustom(ChannelTrace* tracer, size_t num_events_logged,
88 size_t num_events_expected) {
89 Json json = tracer->RenderJson();
90 ASSERT_EQ(json.type(), Json::Type::kObject);
91 std::string json_str = JsonDump(json);
92 grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str.c_str());
93 ValidateChannelTraceData(json, num_events_logged, num_events_expected);
94 }
95
ValidateChannelTrace(ChannelTrace * tracer,size_t num_events_logged)96 void ValidateChannelTrace(ChannelTrace* tracer, size_t num_events_logged) {
97 ValidateChannelTraceCustom(tracer, num_events_logged, num_events_logged);
98 }
99
100 class ChannelFixture {
101 public:
ChannelFixture(int max_tracer_event_memory)102 explicit ChannelFixture(int max_tracer_event_memory) {
103 grpc_arg client_a = grpc_channel_arg_integer_create(
104 const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
105 max_tracer_event_memory);
106 grpc_channel_args client_args = {1, &client_a};
107 grpc_channel_credentials* creds = grpc_insecure_credentials_create();
108 channel_ = grpc_channel_create("fake_target", creds, &client_args);
109 grpc_channel_credentials_release(creds);
110 }
111
~ChannelFixture()112 ~ChannelFixture() { grpc_channel_destroy(channel_); }
113
channel()114 grpc_channel* channel() { return channel_; }
115
116 private:
117 grpc_channel* channel_;
118 };
119
120 } // anonymous namespace
121
122 const int kEventListMemoryLimit = 1024 * 1024;
123
124 // Tests basic ChannelTrace functionality like construction, adding trace, and
125 // lookups by uuid.
TEST(ChannelTracerTest,BasicTest)126 TEST(ChannelTracerTest, BasicTest) {
127 ExecCtx exec_ctx;
128 ChannelTrace tracer(kEventListMemoryLimit);
129 AddSimpleTrace(&tracer);
130 AddSimpleTrace(&tracer);
131 tracer.AddTraceEvent(ChannelTrace::Severity::Info,
132 grpc_slice_from_static_string("trace three"));
133 tracer.AddTraceEvent(ChannelTrace::Severity::Error,
134 grpc_slice_from_static_string("trace four error"));
135 ValidateChannelTrace(&tracer, 4);
136 AddSimpleTrace(&tracer);
137 AddSimpleTrace(&tracer);
138 ValidateChannelTrace(&tracer, 6);
139 AddSimpleTrace(&tracer);
140 AddSimpleTrace(&tracer);
141 AddSimpleTrace(&tracer);
142 AddSimpleTrace(&tracer);
143 ValidateChannelTrace(&tracer, 10);
144 }
145
146 // Tests more complex functionality, like a parent channel tracking
147 // subchannles. This exercises the ref/unref patterns since the parent tracer
148 // and this function will both hold refs to the subchannel.
TEST(ChannelTracerTest,ComplexTest)149 TEST(ChannelTracerTest, ComplexTest) {
150 ExecCtx exec_ctx;
151 ChannelTrace tracer(kEventListMemoryLimit);
152 AddSimpleTrace(&tracer);
153 AddSimpleTrace(&tracer);
154 ChannelFixture channel1(kEventListMemoryLimit);
155 RefCountedPtr<ChannelNode> sc1 =
156 MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
157 ChannelNodePeer sc1_peer(sc1.get());
158 tracer.AddTraceEventWithReference(
159 ChannelTrace::Severity::Info,
160 grpc_slice_from_static_string("subchannel one created"), sc1);
161 ValidateChannelTrace(&tracer, 3);
162 AddSimpleTrace(sc1_peer.trace());
163 AddSimpleTrace(sc1_peer.trace());
164 AddSimpleTrace(sc1_peer.trace());
165 ValidateChannelTrace(sc1_peer.trace(), 3);
166 AddSimpleTrace(sc1_peer.trace());
167 AddSimpleTrace(sc1_peer.trace());
168 AddSimpleTrace(sc1_peer.trace());
169 ValidateChannelTrace(sc1_peer.trace(), 6);
170 AddSimpleTrace(&tracer);
171 AddSimpleTrace(&tracer);
172 ValidateChannelTrace(&tracer, 5);
173 ChannelFixture channel2(kEventListMemoryLimit);
174 RefCountedPtr<ChannelNode> sc2 =
175 MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
176 tracer.AddTraceEventWithReference(
177 ChannelTrace::Severity::Info,
178 grpc_slice_from_static_string("LB channel two created"), sc2);
179 tracer.AddTraceEventWithReference(
180 ChannelTrace::Severity::Warning,
181 grpc_slice_from_static_string("subchannel one inactive"), sc1);
182 ValidateChannelTrace(&tracer, 7);
183 AddSimpleTrace(&tracer);
184 AddSimpleTrace(&tracer);
185 AddSimpleTrace(&tracer);
186 AddSimpleTrace(&tracer);
187 AddSimpleTrace(&tracer);
188 AddSimpleTrace(&tracer);
189 sc1.reset();
190 sc2.reset();
191 }
192
193 // Test a case in which the parent channel has subchannels and the subchannels
194 // have connections. Ensures that everything lives as long as it should then
195 // gets deleted.
TEST(ChannelTracerTest,TestNesting)196 TEST(ChannelTracerTest, TestNesting) {
197 ExecCtx exec_ctx;
198 ChannelTrace tracer(kEventListMemoryLimit);
199 AddSimpleTrace(&tracer);
200 AddSimpleTrace(&tracer);
201 ValidateChannelTrace(&tracer, 2);
202 ChannelFixture channel1(kEventListMemoryLimit);
203 RefCountedPtr<ChannelNode> sc1 =
204 MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
205 ChannelNodePeer sc1_peer(sc1.get());
206 tracer.AddTraceEventWithReference(
207 ChannelTrace::Severity::Info,
208 grpc_slice_from_static_string("subchannel one created"), sc1);
209 ValidateChannelTrace(&tracer, 3);
210 AddSimpleTrace(sc1_peer.trace());
211 ChannelFixture channel2(kEventListMemoryLimit);
212 RefCountedPtr<ChannelNode> conn1 =
213 MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
214 ChannelNodePeer conn1_peer(conn1.get());
215 // nesting one level deeper.
216 sc1_peer.trace()->AddTraceEventWithReference(
217 ChannelTrace::Severity::Info,
218 grpc_slice_from_static_string("connection one created"), conn1);
219 ValidateChannelTrace(&tracer, 3);
220 AddSimpleTrace(conn1_peer.trace());
221 AddSimpleTrace(&tracer);
222 AddSimpleTrace(&tracer);
223 ValidateChannelTrace(&tracer, 5);
224 ValidateChannelTrace(conn1_peer.trace(), 1);
225 ChannelFixture channel3(kEventListMemoryLimit);
226 RefCountedPtr<ChannelNode> sc2 =
227 MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
228 tracer.AddTraceEventWithReference(
229 ChannelTrace::Severity::Info,
230 grpc_slice_from_static_string("subchannel two created"), sc2);
231 // this trace should not get added to the parents children since it is already
232 // present in the tracer.
233 tracer.AddTraceEventWithReference(
234 ChannelTrace::Severity::Warning,
235 grpc_slice_from_static_string("subchannel one inactive"), sc1);
236 AddSimpleTrace(&tracer);
237 ValidateChannelTrace(&tracer, 8);
238 sc1.reset();
239 sc2.reset();
240 conn1.reset();
241 }
242
TEST(ChannelTracerTest,TestSmallMemoryLimit)243 TEST(ChannelTracerTest, TestSmallMemoryLimit) {
244 ExecCtx exec_ctx;
245 // doesn't make sense, but serves a testing purpose for the channel tracing
246 // bookkeeping. All tracing events added should will get immediately garbage
247 // collected.
248 const int kSmallMemoryLimit = 1;
249 ChannelTrace tracer(kSmallMemoryLimit);
250 AddSimpleTrace(&tracer);
251 AddSimpleTrace(&tracer);
252 tracer.AddTraceEvent(ChannelTrace::Severity::Info,
253 grpc_slice_from_static_string("trace three"));
254 tracer.AddTraceEvent(ChannelTrace::Severity::Error,
255 grpc_slice_from_static_string("trace four error"));
256 ValidateChannelTraceCustom(&tracer, 4, 0);
257 AddSimpleTrace(&tracer);
258 AddSimpleTrace(&tracer);
259 ValidateChannelTraceCustom(&tracer, 6, 0);
260 AddSimpleTrace(&tracer);
261 AddSimpleTrace(&tracer);
262 AddSimpleTrace(&tracer);
263 AddSimpleTrace(&tracer);
264 ValidateChannelTraceCustom(&tracer, 10, 0);
265 }
266
TEST(ChannelTracerTest,TestEviction)267 TEST(ChannelTracerTest, TestEviction) {
268 ExecCtx exec_ctx;
269 const int kTraceEventSize = GetSizeofTraceEvent();
270 const int kNumEvents = 5;
271 ChannelTrace tracer(kTraceEventSize * kNumEvents);
272 for (int i = 1; i <= kNumEvents; ++i) {
273 AddSimpleTrace(&tracer);
274 ValidateChannelTrace(&tracer, i);
275 }
276 // at this point the list is full, and each subsequent enntry will cause an
277 // eviction.
278 for (int i = 1; i <= kNumEvents; ++i) {
279 AddSimpleTrace(&tracer);
280 ValidateChannelTraceCustom(&tracer, kNumEvents + i, kNumEvents);
281 }
282 }
283
TEST(ChannelTracerTest,TestMultipleEviction)284 TEST(ChannelTracerTest, TestMultipleEviction) {
285 ExecCtx exec_ctx;
286 const int kTraceEventSize = GetSizeofTraceEvent();
287 const int kNumEvents = 5;
288 ChannelTrace tracer(kTraceEventSize * kNumEvents);
289 for (int i = 1; i <= kNumEvents; ++i) {
290 AddSimpleTrace(&tracer);
291 ValidateChannelTrace(&tracer, i);
292 }
293 // at this point the list is full, and each subsequent enntry will cause an
294 // eviction. We will now add in a trace event that has a copied string. This
295 // uses more memory, so it will cause a double eviciction
296 tracer.AddTraceEvent(
297 ChannelTrace::Severity::Info,
298 grpc_slice_from_copied_string(
299 "long enough string to trigger a multiple eviction"));
300 ValidateChannelTraceCustom(&tracer, kNumEvents + 1, kNumEvents - 1);
301 }
302
TEST(ChannelTracerTest,TestTotalEviction)303 TEST(ChannelTracerTest, TestTotalEviction) {
304 ExecCtx exec_ctx;
305 const int kTraceEventSize = GetSizeofTraceEvent();
306 const int kNumEvents = 5;
307 ChannelTrace tracer(kTraceEventSize * kNumEvents);
308 for (int i = 1; i <= kNumEvents; ++i) {
309 AddSimpleTrace(&tracer);
310 ValidateChannelTrace(&tracer, i);
311 }
312 // at this point the list is full. Now we add such a big slice that
313 // everything gets evicted.
314 grpc_slice huge_slice = grpc_slice_malloc(kTraceEventSize * (kNumEvents + 1));
315 tracer.AddTraceEvent(ChannelTrace::Severity::Info, huge_slice);
316 ValidateChannelTraceCustom(&tracer, kNumEvents + 1, 0);
317 }
318
319 } // namespace testing
320 } // namespace channelz
321 } // namespace grpc_core
322
main(int argc,char ** argv)323 int main(int argc, char** argv) {
324 grpc::testing::TestEnvironment env(&argc, argv);
325 grpc_init();
326 ::testing::InitGoogleTest(&argc, argv);
327 int ret = RUN_ALL_TESTS();
328 grpc_shutdown();
329 return ret;
330 }
331