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