[channelz] modernize channel trace test

pull/36582/head
Mark D. Roth 7 months ago
parent 32e03171e7
commit 49c0fa8a7a
  1. 8
      src/core/channelz/channelz.h
  2. 418
      test/core/channelz/channel_trace_test.cc
  3. 35
      test/cpp/util/channel_trace_proto_helper.cc
  4. 22
      test/cpp/util/channel_trace_proto_helper.h

@ -72,7 +72,7 @@ class ListenSocketNode;
namespace testing { namespace testing {
class CallCountingHelperPeer; class CallCountingHelperPeer;
class ChannelNodePeer; class SubchannelNodePeer;
} // namespace testing } // namespace testing
// base class for all channelz entities // base class for all channelz entities
@ -228,9 +228,6 @@ class ChannelNode final : public BaseNode {
void RemoveChildSubchannel(intptr_t child_uuid); void RemoveChildSubchannel(intptr_t child_uuid);
private: private:
// Allows the channel trace test to access trace_.
friend class testing::ChannelNodePeer;
void PopulateChildRefs(Json::Object* json); void PopulateChildRefs(Json::Object* json);
std::string target_; std::string target_;
@ -277,6 +274,9 @@ class SubchannelNode final : public BaseNode {
void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
private: private:
// Allows the channel trace test to access trace_.
friend class testing::SubchannelNodePeer;
std::atomic<grpc_connectivity_state> connectivity_state_{GRPC_CHANNEL_IDLE}; std::atomic<grpc_connectivity_state> connectivity_state_{GRPC_CHANNEL_IDLE};
Mutex socket_mu_; Mutex socket_mu_;
RefCountedPtr<SocketNode> child_socket_ ABSL_GUARDED_BY(socket_mu_); RefCountedPtr<SocketNode> child_socket_ ABSL_GUARDED_BY(socket_mu_);

@ -20,10 +20,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <list>
#include <string> #include <string>
#include <thread> #include <thread>
#include "absl/synchronization/notification.h" #include "absl/synchronization/notification.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <grpc/credentials.h> #include <grpc/credentials.h>
@ -43,82 +45,126 @@ namespace grpc_core {
namespace channelz { namespace channelz {
namespace testing { namespace testing {
// testing peer to access channel internals // Testing peer to access channel internals.
class ChannelNodePeer { class SubchannelNodePeer {
public: public:
explicit ChannelNodePeer(ChannelNode* node) : node_(node) {} explicit SubchannelNodePeer(SubchannelNode* node) : node_(node) {}
ChannelTrace* trace() const { return &node_->trace_; } ChannelTrace* trace() const { return &node_->trace_; }
private: private:
ChannelNode* node_; SubchannelNode* node_;
}; };
size_t GetSizeofTraceEvent() { return sizeof(ChannelTrace::TraceEvent); } size_t GetSizeofTraceEvent() { return sizeof(ChannelTrace::TraceEvent); }
namespace { namespace {
void ValidateJsonArraySize(const Json& array, size_t expected) { MATCHER_P(IsJsonString, expected, "is JSON string") {
if (expected == 0) { if (!::testing::ExplainMatchResult(Json::Type::kString, arg.type(),
ASSERT_EQ(array.type(), Json::Type::kNull); result_listener)) {
} else { return false;
ASSERT_EQ(array.type(), Json::Type::kArray);
EXPECT_EQ(array.array().size(), expected);
} }
return ::testing::ExplainMatchResult(expected, arg.string(), result_listener);
} }
void ValidateChannelTraceData(const Json& json, MATCHER_P(IsJsonStringNumber, expected, "is JSON string containing number") {
size_t num_events_logged_expected, if (!::testing::ExplainMatchResult(Json::Type::kString, arg.type(),
size_t actual_num_events_expected) { result_listener)) {
ASSERT_EQ(json.type(), Json::Type::kObject); return false;
Json::Object object = json.object(); }
Json& num_events_logged_json = object["numEventsLogged"]; int actual;
ASSERT_EQ(num_events_logged_json.type(), Json::Type::kString); if (!absl::SimpleAtoi(arg.string(), &actual)) {
size_t num_events_logged = static_cast<size_t>( *result_listener << "JSON string \"" << arg.string()
strtol(num_events_logged_json.string().c_str(), nullptr, 0)); << " does not contain numeric value";
ASSERT_EQ(num_events_logged, num_events_logged_expected); return false;
Json& start_time_json = object["creationTimestamp"]; }
ASSERT_EQ(start_time_json.type(), Json::Type::kString); return ::testing::ExplainMatchResult(expected, actual, result_listener);
ValidateJsonArraySize(object["events"], actual_num_events_expected);
} }
void AddSimpleTrace(ChannelTrace* tracer) { MATCHER_P(IsJsonObject, matcher, "is JSON object") {
tracer->AddTraceEvent(ChannelTrace::Severity::Info, if (!::testing::ExplainMatchResult(Json::Type::kObject, arg.type(),
grpc_slice_from_static_string("simple trace")); result_listener)) {
return false;
}
return ::testing::ExplainMatchResult(matcher, arg.object(), result_listener);
} }
// checks for the existence of all the required members of the tracer. MATCHER_P(IsJsonArray, matcher, "is JSON array") {
void ValidateChannelTraceCustom(ChannelTrace* tracer, size_t num_events_logged, if (!::testing::ExplainMatchResult(Json::Type::kArray, arg.type(),
size_t num_events_expected) { result_listener)) {
Json json = tracer->RenderJson(); return false;
ASSERT_EQ(json.type(), Json::Type::kObject); }
std::string json_str = JsonDump(json); return ::testing::ExplainMatchResult(matcher, arg.array(), result_listener);
grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str.c_str());
ValidateChannelTraceData(json, num_events_logged, num_events_expected);
} }
void ValidateChannelTrace(ChannelTrace* tracer, size_t num_events_logged) { MATCHER_P2(IsTraceEvent, description, severity, "is trace event") {
ValidateChannelTraceCustom(tracer, num_events_logged, num_events_logged); return ::testing::ExplainMatchResult(
IsJsonObject(::testing::ElementsAre(
::testing::Pair("description", IsJsonString(description)),
::testing::Pair("severity", IsJsonString(severity)),
::testing::Pair("timestamp", IsJsonString(::testing::_)))),
arg, result_listener);
} }
class ChannelFixture { MATCHER_P3(IsTraceEventWithChannelRef, description, severity, channel_ref,
public: "is trace event with channel ref") {
explicit ChannelFixture(int max_tracer_event_memory) { return ::testing::ExplainMatchResult(
grpc_arg client_a = grpc_channel_arg_integer_create( IsJsonObject(::testing::ElementsAre(
const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE), ::testing::Pair("channelRef",
max_tracer_event_memory); IsJsonObject(::testing::ElementsAre(::testing::Pair(
grpc_channel_args client_args = {1, &client_a}; "channelId", IsJsonStringNumber(channel_ref))))),
grpc_channel_credentials* creds = grpc_insecure_credentials_create(); ::testing::Pair("description", IsJsonString(description)),
channel_ = grpc_channel_create("fake_target", creds, &client_args); ::testing::Pair("severity", IsJsonString(severity)),
grpc_channel_credentials_release(creds); ::testing::Pair("timestamp", IsJsonString(::testing::_)))),
} arg, result_listener);
}
MATCHER_P3(IsTraceEventWithSubchannelRef, description, severity, subchannel_ref,
"is trace event with subchannel ref") {
return ::testing::ExplainMatchResult(
IsJsonObject(::testing::ElementsAre(
::testing::Pair("description", IsJsonString(description)),
::testing::Pair("severity", IsJsonString(severity)),
::testing::Pair(
"subchannelRef",
IsJsonObject(::testing::ElementsAre(::testing::Pair(
"subchannelId", IsJsonStringNumber(subchannel_ref))))),
::testing::Pair("timestamp", IsJsonString(::testing::_)))),
arg, result_listener);
}
~ChannelFixture() { grpc_channel_destroy(channel_); } MATCHER(IsEmptyChannelTrace, "is empty channel trace") {
return ::testing::ExplainMatchResult(
IsJsonObject(::testing::ElementsAre(
::testing::Pair("creationTimestamp", IsJsonString(::testing::_)))),
arg, result_listener);
}
grpc_channel* channel() { return channel_; } MATCHER_P2(IsChannelTrace, num_events_logged_expected, events_matcher,
"is channel trace") {
return ::testing::ExplainMatchResult(
IsJsonObject(::testing::ElementsAre(
::testing::Pair("creationTimestamp", IsJsonString(::testing::_)),
::testing::Pair("events", IsJsonArray(events_matcher)),
::testing::Pair("numEventsLogged",
IsJsonStringNumber(num_events_logged_expected)))),
arg, result_listener);
}
private: MATCHER_P(IsEmptyChannelTrace, num_events_logged_expected,
grpc_channel* channel_; "is empty channel trace") {
}; return ::testing::ExplainMatchResult(
IsJsonObject(::testing::ElementsAre(
::testing::Pair("creationTimestamp", IsJsonString(::testing::_)),
::testing::Pair("numEventsLogged",
IsJsonStringNumber(num_events_logged_expected)))),
arg, result_listener);
}
void ValidateJsonProtoTranslation(const Json& json) {
std::string json_str = JsonDump(json);
grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str.c_str());
}
} // anonymous namespace } // anonymous namespace
@ -129,21 +175,36 @@ const int kEventListMemoryLimit = 1024 * 1024;
TEST(ChannelTracerTest, BasicTest) { TEST(ChannelTracerTest, BasicTest) {
ExecCtx exec_ctx; ExecCtx exec_ctx;
ChannelTrace tracer(kEventListMemoryLimit); ChannelTrace tracer(kEventListMemoryLimit);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
tracer.AddTraceEvent(ChannelTrace::Severity::Info, tracer.AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("trace three")); grpc_slice_from_static_string("one"));
tracer.AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("two"));
tracer.AddTraceEvent(ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("three"));
tracer.AddTraceEvent(ChannelTrace::Severity::Error, tracer.AddTraceEvent(ChannelTrace::Severity::Error,
grpc_slice_from_static_string("trace four error")); grpc_slice_from_static_string("four"));
ValidateChannelTrace(&tracer, 4); Json json = tracer.RenderJson();
AddSimpleTrace(&tracer); ValidateJsonProtoTranslation(json);
AddSimpleTrace(&tracer); EXPECT_THAT(json, IsChannelTrace(4, ::testing::ElementsAre(
ValidateChannelTrace(&tracer, 6); IsTraceEvent("one", "CT_INFO"),
AddSimpleTrace(&tracer); IsTraceEvent("two", "CT_INFO"),
AddSimpleTrace(&tracer); IsTraceEvent("three", "CT_WARNING"),
AddSimpleTrace(&tracer); IsTraceEvent("four", "CT_ERROR"))))
AddSimpleTrace(&tracer); << JsonDump(json);
ValidateChannelTrace(&tracer, 10); tracer.AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("five"));
tracer.AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("six"));
json = tracer.RenderJson();
ValidateJsonProtoTranslation(json);
EXPECT_THAT(json, IsChannelTrace(6, ::testing::ElementsAre(
IsTraceEvent("one", "CT_INFO"),
IsTraceEvent("two", "CT_INFO"),
IsTraceEvent("three", "CT_WARNING"),
IsTraceEvent("four", "CT_ERROR"),
IsTraceEvent("five", "CT_INFO"),
IsTraceEvent("six", "CT_INFO"))))
<< JsonDump(json);
} }
// Tests more complex functionality, like a parent channel tracking // Tests more complex functionality, like a parent channel tracking
@ -152,119 +213,80 @@ TEST(ChannelTracerTest, BasicTest) {
TEST(ChannelTracerTest, ComplexTest) { TEST(ChannelTracerTest, ComplexTest) {
ExecCtx exec_ctx; ExecCtx exec_ctx;
ChannelTrace tracer(kEventListMemoryLimit); ChannelTrace tracer(kEventListMemoryLimit);
AddSimpleTrace(&tracer); tracer.AddTraceEvent(ChannelTrace::Severity::Info,
AddSimpleTrace(&tracer); grpc_slice_from_static_string("one"));
ChannelFixture channel1(kEventListMemoryLimit); tracer.AddTraceEvent(ChannelTrace::Severity::Info,
RefCountedPtr<ChannelNode> sc1 = grpc_slice_from_static_string("two"));
MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0); auto subchannel_node = MakeRefCounted<SubchannelNode>("ipv4:1.2.3.4:5678",
ChannelNodePeer sc1_peer(sc1.get()); kEventListMemoryLimit);
tracer.AddTraceEventWithReference( auto* subchannel_node_trace =
ChannelTrace::Severity::Info, SubchannelNodePeer(subchannel_node.get()).trace();
grpc_slice_from_static_string("subchannel one created"), sc1);
ValidateChannelTrace(&tracer, 3);
AddSimpleTrace(sc1_peer.trace());
AddSimpleTrace(sc1_peer.trace());
AddSimpleTrace(sc1_peer.trace());
ValidateChannelTrace(sc1_peer.trace(), 3);
AddSimpleTrace(sc1_peer.trace());
AddSimpleTrace(sc1_peer.trace());
AddSimpleTrace(sc1_peer.trace());
ValidateChannelTrace(sc1_peer.trace(), 6);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
ValidateChannelTrace(&tracer, 5);
ChannelFixture channel2(kEventListMemoryLimit);
RefCountedPtr<ChannelNode> sc2 =
MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("LB channel two created"), sc2);
tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("subchannel one inactive"), sc1);
ValidateChannelTrace(&tracer, 7);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
sc1.reset();
sc2.reset();
}
// Test a case in which the parent channel has subchannels and the subchannels
// have connections. Ensures that everything lives as long as it should then
// gets deleted.
TEST(ChannelTracerTest, TestNesting) {
ExecCtx exec_ctx;
ChannelTrace tracer(kEventListMemoryLimit);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
ValidateChannelTrace(&tracer, 2);
ChannelFixture channel1(kEventListMemoryLimit);
RefCountedPtr<ChannelNode> sc1 =
MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
ChannelNodePeer sc1_peer(sc1.get());
tracer.AddTraceEventWithReference( tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Info, ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1); grpc_slice_from_static_string("subchannel one created"), subchannel_node);
ValidateChannelTrace(&tracer, 3); Json json = tracer.RenderJson();
AddSimpleTrace(sc1_peer.trace()); ValidateJsonProtoTranslation(json);
ChannelFixture channel2(kEventListMemoryLimit); EXPECT_THAT(json,
RefCountedPtr<ChannelNode> conn1 = IsChannelTrace(3, ::testing::ElementsAre(
MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0); IsTraceEvent("one", "CT_INFO"),
ChannelNodePeer conn1_peer(conn1.get()); IsTraceEvent("two", "CT_INFO"),
// nesting one level deeper. IsTraceEventWithSubchannelRef(
sc1_peer.trace()->AddTraceEventWithReference( "subchannel one created", "CT_INFO",
ChannelTrace::Severity::Info, subchannel_node->uuid()))))
grpc_slice_from_static_string("connection one created"), conn1); << JsonDump(json);
ValidateChannelTrace(&tracer, 3); subchannel_node_trace->AddTraceEvent(ChannelTrace::Severity::Info,
AddSimpleTrace(conn1_peer.trace()); grpc_slice_from_static_string("one"));
AddSimpleTrace(&tracer); json = subchannel_node_trace->RenderJson();
AddSimpleTrace(&tracer); ValidateJsonProtoTranslation(json);
ValidateChannelTrace(&tracer, 5); EXPECT_THAT(
ValidateChannelTrace(conn1_peer.trace(), 1); json,
ChannelFixture channel3(kEventListMemoryLimit); IsChannelTrace(1, ::testing::ElementsAre(IsTraceEvent("one", "CT_INFO"))))
RefCountedPtr<ChannelNode> sc2 = << JsonDump(json);
tracer.AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("three"));
auto channel_node =
MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0); MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
tracer.AddTraceEventWithReference( tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Info, ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel two created"), sc2); grpc_slice_from_static_string("LB channel two created"), channel_node);
// this trace should not get added to the parents children since it is already
// present in the tracer.
tracer.AddTraceEventWithReference( tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Warning, ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("subchannel one inactive"), sc1); grpc_slice_from_static_string("subchannel one inactive"),
AddSimpleTrace(&tracer); subchannel_node);
ValidateChannelTrace(&tracer, 8); json = tracer.RenderJson();
sc1.reset(); ValidateJsonProtoTranslation(json);
sc2.reset(); EXPECT_THAT(
conn1.reset(); json,
IsChannelTrace(
6,
::testing::ElementsAre(
IsTraceEvent("one", "CT_INFO"), IsTraceEvent("two", "CT_INFO"),
IsTraceEventWithSubchannelRef("subchannel one created", "CT_INFO",
subchannel_node->uuid()),
IsTraceEvent("three", "CT_INFO"),
IsTraceEventWithChannelRef("LB channel two created", "CT_INFO",
channel_node->uuid()),
IsTraceEventWithSubchannelRef("subchannel one inactive",
"CT_WARNING",
subchannel_node->uuid()))))
<< JsonDump(json);
} }
TEST(ChannelTracerTest, TestSmallMemoryLimit) { TEST(ChannelTracerTest, TestSmallMemoryLimit) {
ExecCtx exec_ctx; ExecCtx exec_ctx;
// doesn't make sense, but serves a testing purpose for the channel tracing // Doesn't make sense in practice, but serves a testing purpose for the
// bookkeeping. All tracing events added should will get immediately garbage // channel tracing bookkeeping. All tracing events added should get
// collected. // immediately garbage collected.
const int kSmallMemoryLimit = 1; const int kSmallMemoryLimit = 1;
ChannelTrace tracer(kSmallMemoryLimit); ChannelTrace tracer(kSmallMemoryLimit);
AddSimpleTrace(&tracer); const size_t kNumEvents = 4;
AddSimpleTrace(&tracer); for (size_t i = 0; i < kNumEvents; ++i) {
tracer.AddTraceEvent(ChannelTrace::Severity::Info, tracer.AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("trace three")); grpc_slice_from_static_string("trace"));
tracer.AddTraceEvent(ChannelTrace::Severity::Error, }
grpc_slice_from_static_string("trace four error")); Json json = tracer.RenderJson();
ValidateChannelTraceCustom(&tracer, 4, 0); ValidateJsonProtoTranslation(json);
AddSimpleTrace(&tracer); EXPECT_THAT(json, IsEmptyChannelTrace(kNumEvents)) << JsonDump(json);
AddSimpleTrace(&tracer);
ValidateChannelTraceCustom(&tracer, 6, 0);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
ValidateChannelTraceCustom(&tracer, 10, 0);
} }
TEST(ChannelTracerTest, TestEviction) { TEST(ChannelTracerTest, TestEviction) {
@ -272,15 +294,28 @@ TEST(ChannelTracerTest, TestEviction) {
const int kTraceEventSize = GetSizeofTraceEvent(); const int kTraceEventSize = GetSizeofTraceEvent();
const int kNumEvents = 5; const int kNumEvents = 5;
ChannelTrace tracer(kTraceEventSize * kNumEvents); ChannelTrace tracer(kTraceEventSize * kNumEvents);
std::list<::testing::Matcher<Json>> matchers;
for (int i = 1; i <= kNumEvents; ++i) { for (int i = 1; i <= kNumEvents; ++i) {
AddSimpleTrace(&tracer); tracer.AddTraceEvent(ChannelTrace::Severity::Info,
ValidateChannelTrace(&tracer, i); grpc_slice_from_static_string("trace"));
matchers.push_back(IsTraceEvent("trace", "CT_INFO"));
Json json = tracer.RenderJson();
ValidateJsonProtoTranslation(json);
EXPECT_THAT(json, IsChannelTrace(i, ::testing::ElementsAreArray(matchers)))
<< JsonDump(json);
} }
// at this point the list is full, and each subsequent enntry will cause an // At this point the list is full, and each subsequent enntry will cause an
// eviction. // eviction.
for (int i = 1; i <= kNumEvents; ++i) { for (int i = 1; i <= kNumEvents; ++i) {
AddSimpleTrace(&tracer); tracer.AddTraceEvent(ChannelTrace::Severity::Info,
ValidateChannelTraceCustom(&tracer, kNumEvents + i, kNumEvents); grpc_slice_from_static_string("new"));
matchers.pop_front();
matchers.push_back(IsTraceEvent("new", "CT_INFO"));
Json json = tracer.RenderJson();
ValidateJsonProtoTranslation(json);
EXPECT_THAT(json, IsChannelTrace(kNumEvents + i,
::testing::ElementsAreArray(matchers)))
<< JsonDump(json);
} }
} }
@ -289,18 +324,32 @@ TEST(ChannelTracerTest, TestMultipleEviction) {
const int kTraceEventSize = GetSizeofTraceEvent(); const int kTraceEventSize = GetSizeofTraceEvent();
const int kNumEvents = 5; const int kNumEvents = 5;
ChannelTrace tracer(kTraceEventSize * kNumEvents); ChannelTrace tracer(kTraceEventSize * kNumEvents);
std::list<::testing::Matcher<Json>> matchers;
for (int i = 1; i <= kNumEvents; ++i) { for (int i = 1; i <= kNumEvents; ++i) {
AddSimpleTrace(&tracer); tracer.AddTraceEvent(ChannelTrace::Severity::Info,
ValidateChannelTrace(&tracer, i); grpc_slice_from_static_string("trace"));
matchers.push_back(IsTraceEvent("trace", "CT_INFO"));
Json json = tracer.RenderJson();
ValidateJsonProtoTranslation(json);
EXPECT_THAT(json, IsChannelTrace(i, ::testing::ElementsAreArray(matchers)))
<< JsonDump(json);
} }
// at this point the list is full, and each subsequent enntry will cause an // At this point the list is full, and each subsequent enntry will cause an
// eviction. We will now add in a trace event that has a copied string. This // eviction. We will now add in a trace event that has a copied string. This
// uses more memory, so it will cause a double eviciction // uses more memory, so it will cause a double eviciction.
tracer.AddTraceEvent( tracer.AddTraceEvent(
ChannelTrace::Severity::Info, ChannelTrace::Severity::Info,
grpc_slice_from_copied_string( grpc_slice_from_copied_string(
"long enough string to trigger a multiple eviction")); "long enough string to trigger a multiple eviction"));
ValidateChannelTraceCustom(&tracer, kNumEvents + 1, kNumEvents - 1); matchers.pop_front();
matchers.pop_front();
matchers.push_back(IsTraceEvent(
"long enough string to trigger a multiple eviction", "CT_INFO"));
Json json = tracer.RenderJson();
ValidateJsonProtoTranslation(json);
EXPECT_THAT(json, IsChannelTrace(kNumEvents + 1,
::testing::ElementsAreArray(matchers)))
<< JsonDump(json);
} }
TEST(ChannelTracerTest, TestTotalEviction) { TEST(ChannelTracerTest, TestTotalEviction) {
@ -308,15 +357,23 @@ TEST(ChannelTracerTest, TestTotalEviction) {
const int kTraceEventSize = GetSizeofTraceEvent(); const int kTraceEventSize = GetSizeofTraceEvent();
const int kNumEvents = 5; const int kNumEvents = 5;
ChannelTrace tracer(kTraceEventSize * kNumEvents); ChannelTrace tracer(kTraceEventSize * kNumEvents);
std::list<::testing::Matcher<Json>> matchers;
for (int i = 1; i <= kNumEvents; ++i) { for (int i = 1; i <= kNumEvents; ++i) {
AddSimpleTrace(&tracer); tracer.AddTraceEvent(ChannelTrace::Severity::Info,
ValidateChannelTrace(&tracer, i); grpc_slice_from_static_string("trace"));
matchers.push_back(IsTraceEvent("trace", "CT_INFO"));
Json json = tracer.RenderJson();
ValidateJsonProtoTranslation(json);
EXPECT_THAT(json, IsChannelTrace(i, ::testing::ElementsAreArray(matchers)))
<< JsonDump(json);
} }
// at this point the list is full. Now we add such a big slice that // At this point the list is full. Now we add such a big slice that
// everything gets evicted. // everything gets evicted.
grpc_slice huge_slice = grpc_slice_malloc(kTraceEventSize * (kNumEvents + 1)); grpc_slice huge_slice = grpc_slice_malloc(kTraceEventSize * (kNumEvents + 1));
tracer.AddTraceEvent(ChannelTrace::Severity::Info, huge_slice); tracer.AddTraceEvent(ChannelTrace::Severity::Info, huge_slice);
ValidateChannelTraceCustom(&tracer, kNumEvents + 1, 0); Json json = tracer.RenderJson();
ValidateJsonProtoTranslation(json);
EXPECT_THAT(json, IsEmptyChannelTrace(kNumEvents + 1)) << JsonDump(json);
} }
// Tests that the code is thread-safe. // Tests that the code is thread-safe.
@ -328,7 +385,8 @@ TEST(ChannelTracerTest, ThreadSafety) {
for (size_t i = 0; i < 10; ++i) { for (size_t i = 0; i < 10; ++i) {
threads.push_back(std::make_unique<std::thread>([&]() { threads.push_back(std::make_unique<std::thread>([&]() {
do { do {
AddSimpleTrace(&tracer); tracer.AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("trace"));
} while (!done.HasBeenNotified()); } while (!done.HasBeenNotified());
})); }));
} }

@ -73,41 +73,44 @@ void VaidateProtoJsonTranslation(const std::string& json_str) {
namespace testing { namespace testing {
void ValidateChannelTraceProtoJsonTranslation(const char* json_c_str) { void ValidateChannelTraceProtoJsonTranslation(const std::string& json_string) {
VaidateProtoJsonTranslation<grpc::channelz::v1::ChannelTrace>(json_c_str); VaidateProtoJsonTranslation<grpc::channelz::v1::ChannelTrace>(json_string);
} }
void ValidateChannelProtoJsonTranslation(const char* json_c_str) { void ValidateChannelProtoJsonTranslation(const std::string& json_string) {
VaidateProtoJsonTranslation<grpc::channelz::v1::Channel>(json_c_str); VaidateProtoJsonTranslation<grpc::channelz::v1::Channel>(json_string);
} }
void ValidateGetTopChannelsResponseProtoJsonTranslation( void ValidateGetTopChannelsResponseProtoJsonTranslation(
const char* json_c_str) { const std::string& json_string) {
VaidateProtoJsonTranslation<grpc::channelz::v1::GetTopChannelsResponse>( VaidateProtoJsonTranslation<grpc::channelz::v1::GetTopChannelsResponse>(
json_c_str); json_string);
} }
void ValidateGetChannelResponseProtoJsonTranslation(const char* json_c_str) { void ValidateGetChannelResponseProtoJsonTranslation(
const std::string& json_string) {
VaidateProtoJsonTranslation<grpc::channelz::v1::GetChannelResponse>( VaidateProtoJsonTranslation<grpc::channelz::v1::GetChannelResponse>(
json_c_str); json_string);
} }
void ValidateGetServerResponseProtoJsonTranslation(const char* json_c_str) { void ValidateGetServerResponseProtoJsonTranslation(
const std::string& json_string) {
VaidateProtoJsonTranslation<grpc::channelz::v1::GetServerResponse>( VaidateProtoJsonTranslation<grpc::channelz::v1::GetServerResponse>(
json_c_str); json_string);
} }
void ValidateSubchannelProtoJsonTranslation(const char* json_c_str) { void ValidateSubchannelProtoJsonTranslation(const std::string& json_string) {
VaidateProtoJsonTranslation<grpc::channelz::v1::Subchannel>(json_c_str); VaidateProtoJsonTranslation<grpc::channelz::v1::Subchannel>(json_string);
} }
void ValidateServerProtoJsonTranslation(const char* json_c_str) { void ValidateServerProtoJsonTranslation(const std::string& json_string) {
VaidateProtoJsonTranslation<grpc::channelz::v1::Server>(json_c_str); VaidateProtoJsonTranslation<grpc::channelz::v1::Server>(json_string);
} }
void ValidateGetServersResponseProtoJsonTranslation(const char* json_c_str) { void ValidateGetServersResponseProtoJsonTranslation(
const std::string& json_string) {
VaidateProtoJsonTranslation<grpc::channelz::v1::GetServersResponse>( VaidateProtoJsonTranslation<grpc::channelz::v1::GetServersResponse>(
json_c_str); json_string);
} }
} // namespace testing } // namespace testing

@ -19,17 +19,23 @@
#ifndef GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H #ifndef GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H
#define GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H #define GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H
#include <string>
namespace grpc { namespace grpc {
namespace testing { namespace testing {
void ValidateChannelTraceProtoJsonTranslation(const char* json_c_str); void ValidateChannelTraceProtoJsonTranslation(const std::string& json_string);
void ValidateChannelProtoJsonTranslation(const char* json_c_str); void ValidateChannelProtoJsonTranslation(const std::string& json_string);
void ValidateGetTopChannelsResponseProtoJsonTranslation(const char* json_c_str); void ValidateGetTopChannelsResponseProtoJsonTranslation(
void ValidateGetChannelResponseProtoJsonTranslation(const char* json_c_str); const std::string& json_string);
void ValidateGetServerResponseProtoJsonTranslation(const char* json_c_str); void ValidateGetChannelResponseProtoJsonTranslation(
void ValidateSubchannelProtoJsonTranslation(const char* json_c_str); const std::string& json_string);
void ValidateServerProtoJsonTranslation(const char* json_c_str); void ValidateGetServerResponseProtoJsonTranslation(
void ValidateGetServersResponseProtoJsonTranslation(const char* json_c_str); const std::string& json_string);
void ValidateSubchannelProtoJsonTranslation(const std::string& json_string);
void ValidateServerProtoJsonTranslation(const std::string& json_string);
void ValidateGetServersResponseProtoJsonTranslation(
const std::string& json_string);
} // namespace testing } // namespace testing
} // namespace grpc } // namespace grpc

Loading…
Cancel
Save