• 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 
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