• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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