3 * Copyright 2017 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <gtest/gtest.h>
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
26 #include <grpc/support/string_util.h>
28 #include "src/core/lib/channel/channel_trace.h"
29 #include "src/core/lib/channel/channelz.h"
30 #include "src/core/lib/channel/channelz_registry.h"
31 #include "src/core/lib/gpr/useful.h"
32 #include "src/core/lib/iomgr/exec_ctx.h"
33 #include "src/core/lib/json/json.h"
34 #include "src/core/lib/surface/channel.h"
36 #include "test/core/util/test_config.h"
37 #include "test/cpp/util/channel_trace_proto_helper.h"
46 // testing peer to access channel internals
47 class ChannelNodePeer {
49 explicit ChannelNodePeer(ChannelNode* node) : node_(node) {}
50 ChannelTrace* trace() const { return &node_->trace_; }
56 size_t GetSizeofTraceEvent() { return sizeof(ChannelTrace::TraceEvent); }
60 grpc_json* GetJsonChild(grpc_json* parent, const char* key) {
61 EXPECT_NE(parent, nullptr);
62 for (grpc_json* child = parent->child; child != nullptr;
63 child = child->next) {
64 if (child->key != nullptr && strcmp(child->key, key) == 0) return child;
69 void ValidateJsonArraySize(grpc_json* json, const char* key,
70 size_t expected_size) {
71 grpc_json* arr = GetJsonChild(json, key);
72 // the events array should not be present if there are no events.
73 if (expected_size == 0) {
74 EXPECT_EQ(arr, nullptr);
77 ASSERT_NE(arr, nullptr);
78 ASSERT_EQ(arr->type, GRPC_JSON_ARRAY);
80 for (grpc_json* child = arr->child; child != nullptr; child = child->next) {
83 ASSERT_EQ(count, expected_size);
86 void ValidateChannelTraceData(grpc_json* json,
87 size_t num_events_logged_expected,
88 size_t actual_num_events_expected) {
89 ASSERT_NE(json, nullptr);
90 grpc_json* num_events_logged_json = GetJsonChild(json, "numEventsLogged");
91 ASSERT_NE(num_events_logged_json, nullptr);
92 grpc_json* start_time = GetJsonChild(json, "creationTimestamp");
93 ASSERT_NE(start_time, nullptr);
94 size_t num_events_logged =
95 (size_t)strtol(num_events_logged_json->value, nullptr, 0);
96 ASSERT_EQ(num_events_logged, num_events_logged_expected);
97 ValidateJsonArraySize(json, "events", actual_num_events_expected);
100 void AddSimpleTrace(ChannelTrace* tracer) {
101 tracer->AddTraceEvent(ChannelTrace::Severity::Info,
102 grpc_slice_from_static_string("simple trace"));
105 // checks for the existence of all the required members of the tracer.
106 void ValidateChannelTraceCustom(ChannelTrace* tracer, size_t num_events_logged,
107 size_t num_events_expected) {
108 grpc_json* json = tracer->RenderJson();
109 EXPECT_NE(json, nullptr);
110 char* json_str = grpc_json_dump_to_string(json, 0);
111 grpc_json_destroy(json);
112 grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str);
113 grpc_json* parsed_json = grpc_json_parse_string(json_str);
114 ValidateChannelTraceData(parsed_json, num_events_logged, num_events_expected);
115 grpc_json_destroy(parsed_json);
119 void ValidateChannelTrace(ChannelTrace* tracer, size_t num_events_logged) {
120 ValidateChannelTraceCustom(tracer, num_events_logged, num_events_logged);
123 class ChannelFixture {
125 ChannelFixture(int max_tracer_event_memory) {
126 grpc_arg client_a = grpc_channel_arg_integer_create(
127 const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
128 max_tracer_event_memory);
129 grpc_channel_args client_args = {1, &client_a};
131 grpc_insecure_channel_create("fake_target", &client_args, nullptr);
134 ~ChannelFixture() { grpc_channel_destroy(channel_); }
136 grpc_channel* channel() { return channel_; }
139 grpc_channel* channel_;
142 } // anonymous namespace
144 const int kEventListMemoryLimit = 1024 * 1024;
146 // Tests basic ChannelTrace functionality like construction, adding trace, and
148 TEST(ChannelTracerTest, BasicTest) {
149 grpc_core::ExecCtx exec_ctx;
150 ChannelTrace tracer(kEventListMemoryLimit);
151 AddSimpleTrace(&tracer);
152 AddSimpleTrace(&tracer);
153 tracer.AddTraceEvent(ChannelTrace::Severity::Info,
154 grpc_slice_from_static_string("trace three"));
155 tracer.AddTraceEvent(ChannelTrace::Severity::Error,
156 grpc_slice_from_static_string("trace four error"));
157 ValidateChannelTrace(&tracer, 4);
158 AddSimpleTrace(&tracer);
159 AddSimpleTrace(&tracer);
160 ValidateChannelTrace(&tracer, 6);
161 AddSimpleTrace(&tracer);
162 AddSimpleTrace(&tracer);
163 AddSimpleTrace(&tracer);
164 AddSimpleTrace(&tracer);
165 ValidateChannelTrace(&tracer, 10);
168 // Tests more complex functionality, like a parent channel tracking
169 // subchannles. This exercises the ref/unref patterns since the parent tracer
170 // and this function will both hold refs to the subchannel.
171 TEST(ChannelTracerTest, ComplexTest) {
172 grpc_core::ExecCtx exec_ctx;
173 ChannelTrace tracer(kEventListMemoryLimit);
174 AddSimpleTrace(&tracer);
175 AddSimpleTrace(&tracer);
176 ChannelFixture channel1(kEventListMemoryLimit);
177 RefCountedPtr<ChannelNode> sc1 = MakeRefCounted<ChannelNode>(
178 UniquePtr<char>(gpr_strdup("fake_target")), kEventListMemoryLimit, 0);
179 ChannelNodePeer sc1_peer(sc1.get());
180 tracer.AddTraceEventWithReference(
181 ChannelTrace::Severity::Info,
182 grpc_slice_from_static_string("subchannel one created"), sc1);
183 ValidateChannelTrace(&tracer, 3);
184 AddSimpleTrace(sc1_peer.trace());
185 AddSimpleTrace(sc1_peer.trace());
186 AddSimpleTrace(sc1_peer.trace());
187 ValidateChannelTrace(sc1_peer.trace(), 3);
188 AddSimpleTrace(sc1_peer.trace());
189 AddSimpleTrace(sc1_peer.trace());
190 AddSimpleTrace(sc1_peer.trace());
191 ValidateChannelTrace(sc1_peer.trace(), 6);
192 AddSimpleTrace(&tracer);
193 AddSimpleTrace(&tracer);
194 ValidateChannelTrace(&tracer, 5);
195 ChannelFixture channel2(kEventListMemoryLimit);
196 RefCountedPtr<ChannelNode> sc2 = MakeRefCounted<ChannelNode>(
197 UniquePtr<char>(gpr_strdup("fake_target")), kEventListMemoryLimit, 0);
198 tracer.AddTraceEventWithReference(
199 ChannelTrace::Severity::Info,
200 grpc_slice_from_static_string("LB channel two created"), sc2);
201 tracer.AddTraceEventWithReference(
202 ChannelTrace::Severity::Warning,
203 grpc_slice_from_static_string("subchannel one inactive"), sc1);
204 ValidateChannelTrace(&tracer, 7);
205 AddSimpleTrace(&tracer);
206 AddSimpleTrace(&tracer);
207 AddSimpleTrace(&tracer);
208 AddSimpleTrace(&tracer);
209 AddSimpleTrace(&tracer);
210 AddSimpleTrace(&tracer);
215 // Test a case in which the parent channel has subchannels and the subchannels
216 // have connections. Ensures that everything lives as long as it should then
218 TEST(ChannelTracerTest, TestNesting) {
219 grpc_core::ExecCtx exec_ctx;
220 ChannelTrace tracer(kEventListMemoryLimit);
221 AddSimpleTrace(&tracer);
222 AddSimpleTrace(&tracer);
223 ValidateChannelTrace(&tracer, 2);
224 ChannelFixture channel1(kEventListMemoryLimit);
225 RefCountedPtr<ChannelNode> sc1 = MakeRefCounted<ChannelNode>(
226 UniquePtr<char>(gpr_strdup("fake_target")), kEventListMemoryLimit, 0);
227 ChannelNodePeer sc1_peer(sc1.get());
228 tracer.AddTraceEventWithReference(
229 ChannelTrace::Severity::Info,
230 grpc_slice_from_static_string("subchannel one created"), sc1);
231 ValidateChannelTrace(&tracer, 3);
232 AddSimpleTrace(sc1_peer.trace());
233 ChannelFixture channel2(kEventListMemoryLimit);
234 RefCountedPtr<ChannelNode> conn1 = MakeRefCounted<ChannelNode>(
235 UniquePtr<char>(gpr_strdup("fake_target")), kEventListMemoryLimit, 0);
236 ChannelNodePeer conn1_peer(conn1.get());
237 // nesting one level deeper.
238 sc1_peer.trace()->AddTraceEventWithReference(
239 ChannelTrace::Severity::Info,
240 grpc_slice_from_static_string("connection one created"), conn1);
241 ValidateChannelTrace(&tracer, 3);
242 AddSimpleTrace(conn1_peer.trace());
243 AddSimpleTrace(&tracer);
244 AddSimpleTrace(&tracer);
245 ValidateChannelTrace(&tracer, 5);
246 ValidateChannelTrace(conn1_peer.trace(), 1);
247 ChannelFixture channel3(kEventListMemoryLimit);
248 RefCountedPtr<ChannelNode> sc2 = MakeRefCounted<ChannelNode>(
249 UniquePtr<char>(gpr_strdup("fake_target")), kEventListMemoryLimit, 0);
250 tracer.AddTraceEventWithReference(
251 ChannelTrace::Severity::Info,
252 grpc_slice_from_static_string("subchannel two created"), sc2);
253 // this trace should not get added to the parents children since it is already
254 // present in the tracer.
255 tracer.AddTraceEventWithReference(
256 ChannelTrace::Severity::Warning,
257 grpc_slice_from_static_string("subchannel one inactive"), sc1);
258 AddSimpleTrace(&tracer);
259 ValidateChannelTrace(&tracer, 8);
265 TEST(ChannelTracerTest, TestSmallMemoryLimit) {
266 grpc_core::ExecCtx exec_ctx;
267 // doesn't make sense, but serves a testing purpose for the channel tracing
268 // bookkeeping. All tracing events added should will get immediately garbage
270 const int kSmallMemoryLimit = 1;
271 ChannelTrace tracer(kSmallMemoryLimit);
272 AddSimpleTrace(&tracer);
273 AddSimpleTrace(&tracer);
274 tracer.AddTraceEvent(ChannelTrace::Severity::Info,
275 grpc_slice_from_static_string("trace three"));
276 tracer.AddTraceEvent(ChannelTrace::Severity::Error,
277 grpc_slice_from_static_string("trace four error"));
278 ValidateChannelTraceCustom(&tracer, 4, 0);
279 AddSimpleTrace(&tracer);
280 AddSimpleTrace(&tracer);
281 ValidateChannelTraceCustom(&tracer, 6, 0);
282 AddSimpleTrace(&tracer);
283 AddSimpleTrace(&tracer);
284 AddSimpleTrace(&tracer);
285 AddSimpleTrace(&tracer);
286 ValidateChannelTraceCustom(&tracer, 10, 0);
289 TEST(ChannelTracerTest, TestEviction) {
290 grpc_core::ExecCtx exec_ctx;
291 const int kTraceEventSize = GetSizeofTraceEvent();
292 const int kNumEvents = 5;
293 ChannelTrace tracer(kTraceEventSize * kNumEvents);
294 for (int i = 1; i <= kNumEvents; ++i) {
295 AddSimpleTrace(&tracer);
296 ValidateChannelTrace(&tracer, i);
298 // at this point the list is full, and each subsequent enntry will cause an
300 for (int i = 1; i <= kNumEvents; ++i) {
301 AddSimpleTrace(&tracer);
302 ValidateChannelTraceCustom(&tracer, kNumEvents + i, kNumEvents);
306 TEST(ChannelTracerTest, TestMultipleEviction) {
307 grpc_core::ExecCtx exec_ctx;
308 const int kTraceEventSize = GetSizeofTraceEvent();
309 const int kNumEvents = 5;
310 ChannelTrace tracer(kTraceEventSize * kNumEvents);
311 for (int i = 1; i <= kNumEvents; ++i) {
312 AddSimpleTrace(&tracer);
313 ValidateChannelTrace(&tracer, i);
315 // at this point the list is full, and each subsequent enntry will cause an
316 // eviction. We will now add in a trace event that has a copied string. This
317 // uses more memory, so it will cause a double eviciction
318 tracer.AddTraceEvent(
319 ChannelTrace::Severity::Info,
320 grpc_slice_from_copied_string(
321 "long enough string to trigger a multiple eviction"));
322 ValidateChannelTraceCustom(&tracer, kNumEvents + 1, kNumEvents - 1);
325 TEST(ChannelTracerTest, TestTotalEviction) {
326 grpc_core::ExecCtx exec_ctx;
327 const int kTraceEventSize = GetSizeofTraceEvent();
328 const int kNumEvents = 5;
329 ChannelTrace tracer(kTraceEventSize * kNumEvents);
330 for (int i = 1; i <= kNumEvents; ++i) {
331 AddSimpleTrace(&tracer);
332 ValidateChannelTrace(&tracer, i);
334 // at this point the list is full. Now we add such a big slice that
335 // everything gets evicted.
336 grpc_slice huge_slice = grpc_slice_malloc(kTraceEventSize * (kNumEvents + 1));
337 tracer.AddTraceEvent(ChannelTrace::Severity::Info, huge_slice);
338 ValidateChannelTraceCustom(&tracer, kNumEvents + 1, 0);
341 } // namespace testing
342 } // namespace channelz
343 } // namespace grpc_core
345 int main(int argc, char** argv) {
346 grpc::testing::TestEnvironment env(argc, argv);
348 ::testing::InitGoogleTest(&argc, argv);
349 int ret = RUN_ALL_TESTS();