Build out the channelz unit test

reviewable/pr15343/r3
ncteisen 7 years ago
parent 23c50fda51
commit 9a1bb05181
  1. 3
      include/grpc/grpc.h
  2. 16
      src/core/lib/channel/channel_trace.cc
  3. 13
      src/core/lib/channel/channel_trace.h
  4. 76
      src/core/lib/channel/channelz.cc
  5. 6
      src/core/lib/channel/channelz.h
  6. 5
      src/core/lib/surface/channel.cc
  7. 24
      test/core/channel/BUILD
  8. 182
      test/core/channel/channel_trace_test.cc
  9. 150
      test/core/channel/channelz_test.cc
  10. 11
      test/cpp/util/channel_trace_proto_helper.cc

@ -294,9 +294,6 @@ GRPCAPI char* grpc_channel_get_trace(grpc_channel* channel);
later time. */
GRPCAPI intptr_t grpc_channel_get_uuid(grpc_channel* channel);
/** channelz support */
GRPCAPI char* grpc_channelz_get_channel(intptr_t channel_id);
/** Error handling for grpc_call
Most grpc_call functions return a grpc_error. If the error is not GRPC_OK
then the operation failed due to some unsatisfied precondition.

@ -28,7 +28,6 @@
#include <stdlib.h>
#include <string.h>
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
@ -63,15 +62,13 @@ ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); }
ChannelTrace::ChannelTrace(size_t max_events)
: channel_uuid_(-1),
num_events_logged_(0),
: num_events_logged_(0),
list_size_(0),
max_list_size_(max_events),
head_trace_(nullptr),
tail_trace_(nullptr) {
if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
gpr_mu_init(&tracer_mu_);
channel_uuid_ = ChannelzRegistry::Register(this);
time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
GPR_CLOCK_REALTIME);
}
@ -84,12 +81,9 @@ ChannelTrace::~ChannelTrace() {
it = it->next();
Delete<TraceEvent>(to_free);
}
ChannelzRegistry::Unregister(channel_uuid_);
gpr_mu_destroy(&tracer_mu_);
}
intptr_t ChannelTrace::GetUuid() const { return channel_uuid_; }
void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
++num_events_logged_;
// first event case
@ -212,7 +206,7 @@ void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const {
}
}
char* ChannelTrace::RenderTrace() const {
grpc_json* ChannelTrace::RenderJSON() const {
if (!max_list_size_)
return nullptr; // tracing is disabled if max_events == 0
grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
@ -235,6 +229,12 @@ char* ChannelTrace::RenderTrace() const {
it->RenderTraceEvent(json_iterator);
it = it->next();
}
return json;
}
char* ChannelTrace::RenderTrace() const {
grpc_json* json = RenderJSON();
if (json == nullptr) return nullptr;
char* json_str = grpc_json_dump_to_string(json, 0);
grpc_json_destroy(json);
return json_str;

@ -40,9 +40,6 @@ class ChannelTrace {
ChannelTrace(size_t max_events);
~ChannelTrace();
// returns the tracer's uuid
intptr_t GetUuid() const;
enum Severity {
Unset = 0, // never to be used
Info, // we start at 1 to avoid using proto default values
@ -72,8 +69,13 @@ class ChannelTrace {
Severity severity, grpc_slice data,
RefCountedPtr<Channel> referenced_tracer);
// Returns the tracing data rendered as a grpc json string.
// The string is owned by the caller and must be freed.
// Creates and returns the raw grpc_json object, so a parent channelz
// object may incorporate the json before rendering.
grpc_json* RenderJSON() const;
// Returns the tracing data rendered as a grpc json string. The string
// is owned by the caller and must be freed. This is used for testing only
// so that we may unit test ChannelTrace in isolation.
char* RenderTrace() const;
private:
@ -117,7 +119,6 @@ class ChannelTrace {
void AddTraceEventHelper(TraceEvent* new_trace_event);
gpr_mu tracer_mu_;
intptr_t channel_uuid_;
uint64_t num_events_logged_;
size_t list_size_;
size_t max_list_size_;

@ -39,9 +39,6 @@
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/error_utils.h"
// TODO(ncteisen): actually implement this
char* grpc_channelz_get_channel(intptr_t channel_id) { return nullptr; }
namespace grpc_core {
namespace channelz {
@ -82,9 +79,9 @@ char* fmt_time(gpr_timespec tm) {
// TODO(ncteisen); move this to json library
grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name,
uint64_t num) {
int64_t num) {
char* num_str;
gpr_asprintf(&num_str, "%" PRIu64, num);
gpr_asprintf(&num_str, "%" PRId64, num);
return grpc_json_create_child(it, parent, name, num_str, GRPC_JSON_STRING,
true);
}
@ -96,10 +93,13 @@ Channel::Channel(grpc_channel* channel, size_t channel_tracer_max_nodes)
trace_.Init(channel_tracer_max_nodes);
target_ = grpc_channel_get_target(channel_);
channel_uuid_ = ChannelzRegistry::Register(this);
last_call_started_timestamp_ =
grpc_millis_to_timespec(ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME);
}
Channel::~Channel() {
gpr_free(const_cast<char*>(target_));
trace_.Destroy();
ChannelzRegistry::Unregister(channel_uuid_);
}
@ -125,7 +125,7 @@ char* Channel::RenderJSON() {
// create and fill the ref child
json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
GRPC_JSON_OBJECT, true);
GRPC_JSON_OBJECT, false);
json = json_iterator;
json_iterator = nullptr;
json_iterator = add_num_str(json, json_iterator, "channelId", channel_uuid_);
@ -134,33 +134,55 @@ char* Channel::RenderJSON() {
json = top_level_json;
json_iterator = nullptr;
// create and fill the data child
json_iterator = grpc_json_create_child(json_iterator, json, "data", nullptr,
GRPC_JSON_OBJECT, true);
json = json_iterator;
// create and fill the data child.
grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
GRPC_JSON_OBJECT, false);
json = data;
json_iterator = nullptr;
json_iterator =
add_num_str(json, json_iterator, "callsStarted", calls_started_);
json_iterator =
add_num_str(json, json_iterator, "callsSucceeded", calls_succeeded_);
json_iterator =
add_num_str(json, json_iterator, "callsFailed", calls_failed_);
json_iterator = grpc_json_create_child(
json_iterator, json, "lastCallStartedTimestamp",
fmt_time(last_call_started_timestamp_), GRPC_JSON_STRING, true);
// create and fill the connectivity state child.
grpc_connectivity_state connectivity_state = GetConnectivityState();
json_iterator = grpc_json_create_child(json_iterator, json, "state", nullptr,
GRPC_JSON_OBJECT, false);
json = json_iterator;
grpc_json_create_child(nullptr, json, "state",
grpc_connectivity_state_name(connectivity_state),
GRPC_JSON_STRING, false);
// reset the parent to be the data object.
json = data;
json_iterator = grpc_json_create_child(json_iterator, json, "target", target_,
GRPC_JSON_STRING, false);
grpc_connectivity_state connectivity_state = GetConnectivityState();
json_iterator =
grpc_json_create_child(json_iterator, json, "state",
grpc_connectivity_state_name(connectivity_state),
GRPC_JSON_STRING, false);
char* trace = trace_->RenderTrace();
// fill in the channel trace if applicable
grpc_json* trace = trace_->RenderJSON();
if (trace != nullptr) {
json_iterator = grpc_json_create_child(json_iterator, json, "trace", trace,
GRPC_JSON_STRING, true);
// we manuall link up and fill the child since it was created for us in
// ChannelTrace::RenderJSON
json_iterator = grpc_json_link_child(json, trace, json_iterator);
trace->parent = json;
trace->value = nullptr;
trace->key = "trace";
trace->owns_value = false;
}
// reset the parent to be the data object.
json = data;
json_iterator = nullptr;
// We use -1 as sentinel values since proto default value for integers is
// zero, and the confuses the parser into thinking the value weren't present
json_iterator = add_num_str(json, json_iterator, "callsStarted",
calls_started_ ? calls_started_ : -1);
json_iterator = add_num_str(json, json_iterator, "callsSucceeded",
calls_succeeded_ ? calls_succeeded_ : -1);
json_iterator = add_num_str(json, json_iterator, "callsFailed",
calls_failed_ ? calls_failed_ : -1);
json_iterator = grpc_json_create_child(
json_iterator, json, "lastCallStartedTimestamp",
fmt_time(last_call_started_timestamp_), GRPC_JSON_STRING, true);
// render and return the over json object
char* json_str = grpc_json_dump_to_string(top_level_json, 0);
grpc_json_destroy(top_level_json);

@ -59,9 +59,9 @@ class Channel : public RefCounted<Channel> {
bool channel_destroyed_ = false;
grpc_channel* channel_;
const char* target_;
uint64_t calls_started_ = 0;
uint64_t calls_succeeded_ = 0;
uint64_t calls_failed_ = 0;
int64_t calls_started_ = 0;
int64_t calls_succeeded_ = 0;
int64_t calls_failed_ = 0;
gpr_timespec last_call_started_timestamp_;
intptr_t channel_uuid_;
ManualConstructor<ChannelTrace> trace_;

@ -146,7 +146,6 @@ grpc_channel* grpc_channel_create_with_builder(
}
grpc_channel_args_destroy(args);
channel_tracer_max_nodes = 10;
channel->channelz_channel =
grpc_core::MakeRefCounted<grpc_core::channelz::Channel>(
channel, channel_tracer_max_nodes);
@ -201,7 +200,7 @@ grpc_core::channelz::Channel* grpc_channel_get_channelz_channel(
}
intptr_t grpc_channel_get_uuid(grpc_channel* channel) {
return channel->channelz_channel->Trace()->GetUuid();
return channel->channelz_channel->channel_uuid();
}
grpc_channel* grpc_channel_create(const char* target,
@ -430,6 +429,8 @@ void grpc_channel_destroy(grpc_channel* channel) {
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Destroyed");
elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
elem->filter->start_transport_op(elem, op);
channel->channelz_channel->set_channel_destroyed();
channel->channelz_channel.reset();
GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel");
}

@ -84,13 +84,8 @@ grpc_cc_test(
)
grpc_cc_test(
<<<<<<< HEAD
name = "channelz_registry_test",
srcs = ["channelz_registry_test.cc"],
=======
name = "channelz_test",
srcs = ["channelz_test.cc"],
>>>>>>> Add channelz test
language = "C++",
deps = [
"//:gpr",
@ -98,10 +93,23 @@ grpc_cc_test(
"//:grpc++",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
<<<<<<< HEAD
=======
"//test/cpp/util:channel_trace_proto_helper",
>>>>>>> Add channelz test
],
external_deps = [
"gtest",
],
)
grpc_cc_test(
name = "channelz_registry_test",
srcs = ["channelz_registry_test.cc"],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//:grpc++",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
],
external_deps = [
"gtest",

@ -25,6 +25,7 @@
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
@ -39,6 +40,7 @@
#include <string.h>
namespace grpc_core {
namespace channelz {
namespace testing {
namespace {
@ -77,13 +79,13 @@ void ValidateChannelTraceData(grpc_json* json,
ValidateJsonArraySize(json, "events", actual_num_events_expected);
}
void AddSimpleTrace(RefCountedPtr<ChannelTrace> tracer) {
void AddSimpleTrace(ChannelTrace* tracer) {
tracer->AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("simple trace"));
}
// checks for the existence of all the required members of the tracer.
void ValidateChannelTrace(RefCountedPtr<ChannelTrace> tracer,
void ValidateChannelTrace(ChannelTrace* tracer,
size_t expected_num_event_logged, size_t max_nodes) {
if (!max_nodes) return;
char* json_str = tracer->RenderTrace();
@ -95,16 +97,26 @@ void ValidateChannelTrace(RefCountedPtr<ChannelTrace> tracer,
gpr_free(json_str);
}
void ValidateTraceDataMatchedUuidLookup(RefCountedPtr<ChannelTrace> tracer) {
intptr_t uuid = tracer->GetUuid();
if (uuid == -1) return; // Doesn't make sense to lookup if tracing disabled
char* tracer_json_str = tracer->RenderTrace();
ChannelTrace* uuid_lookup = ChannelzRegistry::Get<ChannelTrace>(uuid);
char* uuid_lookup_json_str = uuid_lookup->RenderTrace();
EXPECT_EQ(strcmp(tracer_json_str, uuid_lookup_json_str), 0);
gpr_free(tracer_json_str);
gpr_free(uuid_lookup_json_str);
}
class ChannelFixture {
public:
ChannelFixture(int max_trace_nodes) {
grpc_arg client_a;
client_a.type = GRPC_ARG_INTEGER;
client_a.key =
const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
client_a.value.integer = max_trace_nodes;
grpc_channel_args client_args = {1, &client_a};
channel_ =
grpc_insecure_channel_create("fake_target", &client_args, nullptr);
}
~ChannelFixture() { grpc_channel_destroy(channel_); }
grpc_channel* channel() { return channel_; }
private:
grpc_channel* channel_;
};
} // anonymous namespace
@ -114,25 +126,22 @@ class ChannelTracerTest : public ::testing::TestWithParam<size_t> {};
// lookups by uuid.
TEST_P(ChannelTracerTest, BasicTest) {
grpc_core::ExecCtx exec_ctx;
RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam());
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
ValidateTraceDataMatchedUuidLookup(tracer);
tracer->AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("trace three"));
tracer->AddTraceEvent(ChannelTrace::Severity::Error,
grpc_slice_from_static_string("trace four error"));
ValidateChannelTrace(tracer, 4, GetParam());
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
ValidateChannelTrace(tracer, 6, GetParam());
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
ValidateChannelTrace(tracer, 10, GetParam());
ValidateTraceDataMatchedUuidLookup(tracer);
tracer.reset(nullptr);
ChannelTrace tracer(GetParam());
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
tracer.AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("trace three"));
tracer.AddTraceEvent(ChannelTrace::Severity::Error,
grpc_slice_from_static_string("trace four error"));
ValidateChannelTrace(&tracer, 4, GetParam());
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
ValidateChannelTrace(&tracer, 6, GetParam());
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
ValidateChannelTrace(&tracer, 10, GetParam());
}
// Tests more complex functionality, like a parent channel tracking
@ -140,42 +149,43 @@ TEST_P(ChannelTracerTest, BasicTest) {
// and this function will both hold refs to the subchannel.
TEST_P(ChannelTracerTest, ComplexTest) {
grpc_core::ExecCtx exec_ctx;
RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam());
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(GetParam());
tracer->AddTraceEventReferencingSubchannel(
ChannelTrace tracer(GetParam());
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
ChannelFixture channel1(GetParam());
RefCountedPtr<Channel> sc1 =
MakeRefCounted<Channel>(channel1.channel(), GetParam());
tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1);
ValidateChannelTrace(tracer, 3, GetParam());
AddSimpleTrace(sc1);
AddSimpleTrace(sc1);
AddSimpleTrace(sc1);
ValidateChannelTrace(sc1, 3, GetParam());
AddSimpleTrace(sc1);
AddSimpleTrace(sc1);
AddSimpleTrace(sc1);
ValidateChannelTrace(sc1, 6, GetParam());
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
ValidateChannelTrace(tracer, 5, GetParam());
ValidateTraceDataMatchedUuidLookup(tracer);
RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(GetParam());
tracer->AddTraceEventReferencingChannel(
ValidateChannelTrace(&tracer, 3, GetParam());
AddSimpleTrace(sc1->Trace());
AddSimpleTrace(sc1->Trace());
AddSimpleTrace(sc1->Trace());
ValidateChannelTrace(sc1->Trace(), 3, GetParam());
AddSimpleTrace(sc1->Trace());
AddSimpleTrace(sc1->Trace());
AddSimpleTrace(sc1->Trace());
ValidateChannelTrace(sc1->Trace(), 6, GetParam());
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
ValidateChannelTrace(&tracer, 5, GetParam());
ChannelFixture channel2(GetParam());
RefCountedPtr<Channel> sc2 =
MakeRefCounted<Channel>(channel2.channel(), GetParam());
tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("LB channel two created"), sc2);
tracer->AddTraceEventReferencingSubchannel(
tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("subchannel one inactive"), sc1);
ValidateChannelTrace(tracer, 7, GetParam());
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
ValidateTraceDataMatchedUuidLookup(tracer);
tracer.reset(nullptr);
ValidateChannelTrace(&tracer, 7, GetParam());
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
sc1.reset(nullptr);
sc2.reset(nullptr);
}
@ -185,39 +195,44 @@ TEST_P(ChannelTracerTest, ComplexTest) {
// gets deleted.
TEST_P(ChannelTracerTest, TestNesting) {
grpc_core::ExecCtx exec_ctx;
RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam());
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
ValidateChannelTrace(tracer, 2, GetParam());
RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(GetParam());
tracer->AddTraceEventReferencingChannel(
ChannelTrace tracer(GetParam());
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
ValidateChannelTrace(&tracer, 2, GetParam());
ChannelFixture channel1(GetParam());
RefCountedPtr<Channel> sc1 =
MakeRefCounted<Channel>(channel1.channel(), GetParam());
tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1);
ValidateChannelTrace(tracer, 3, GetParam());
AddSimpleTrace(sc1);
RefCountedPtr<ChannelTrace> conn1 = MakeRefCounted<ChannelTrace>(GetParam());
ValidateChannelTrace(&tracer, 3, GetParam());
AddSimpleTrace(sc1->Trace());
ChannelFixture channel2(GetParam());
RefCountedPtr<Channel> conn1 =
MakeRefCounted<Channel>(channel2.channel(), GetParam());
// nesting one level deeper.
sc1->AddTraceEventReferencingSubchannel(
sc1->Trace()->AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("connection one created"), conn1);
ValidateChannelTrace(tracer, 3, GetParam());
AddSimpleTrace(conn1);
AddSimpleTrace(tracer);
AddSimpleTrace(tracer);
ValidateChannelTrace(tracer, 5, GetParam());
ValidateChannelTrace(conn1, 1, GetParam());
RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(GetParam());
tracer->AddTraceEventReferencingSubchannel(
ValidateChannelTrace(&tracer, 3, GetParam());
AddSimpleTrace(conn1->Trace());
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
ValidateChannelTrace(&tracer, 5, GetParam());
ValidateChannelTrace(conn1->Trace(), 1, GetParam());
ChannelFixture channel3(GetParam());
RefCountedPtr<Channel> sc2 =
MakeRefCounted<Channel>(channel3.channel(), GetParam());
tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel two created"), sc2);
// this trace should not get added to the parents children since it is already
// present in the tracer.
tracer->AddTraceEventReferencingChannel(
tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("subchannel one inactive"), sc1);
AddSimpleTrace(tracer);
ValidateChannelTrace(tracer, 8, GetParam());
tracer.reset(nullptr);
AddSimpleTrace(&tracer);
ValidateChannelTrace(&tracer, 8, GetParam());
sc1.reset(nullptr);
sc2.reset(nullptr);
conn1.reset(nullptr);
@ -227,6 +242,7 @@ INSTANTIATE_TEST_CASE_P(ChannelTracerTestSweep, ChannelTracerTest,
::testing::Values(0, 1, 2, 6, 10, 15));
} // namespace testing
} // namespace channelz
} // namespace grpc_core
int main(int argc, char** argv) {

@ -25,26 +25,170 @@
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/surface/channel.h"
#include "test/core/util/test_config.h"
#include "test/cpp/util/channel_trace_proto_helper.h"
// remove me
#include <grpc/support/string_util.h>
#include <stdlib.h>
#include <string.h>
namespace grpc_core {
namespace channelz {
namespace testing {
namespace {} // anonymous namespace
namespace {
TEST(ChannelzTest, Channel) {}
grpc_json* GetJsonChild(grpc_json* parent, const char* key) {
EXPECT_NE(parent, nullptr);
for (grpc_json* child = parent->child; child != nullptr;
child = child->next) {
if (child->key != nullptr && strcmp(child->key, key) == 0) return child;
}
return nullptr;
}
class ChannelFixture {
public:
ChannelFixture(int max_trace_nodes) {
grpc_arg client_a;
client_a.type = GRPC_ARG_INTEGER;
client_a.key =
const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
client_a.value.integer = max_trace_nodes;
grpc_channel_args client_args = {1, &client_a};
channel_ =
grpc_insecure_channel_create("fake_target", &client_args, nullptr);
}
~ChannelFixture() { grpc_channel_destroy(channel_); }
grpc_channel* channel() { return channel_; }
private:
grpc_channel* channel_;
};
struct validate_channel_data_args {
int64_t calls_started;
int64_t calls_failed;
int64_t calls_succeeded;
};
void ValidateChildInteger(grpc_json* json, int64_t expect, const char* key) {
grpc_json* gotten_json = GetJsonChild(json, key);
EXPECT_NE(gotten_json, nullptr);
int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0);
EXPECT_EQ(gotten_number, expect);
}
void ValidateChannel(Channel* channel, validate_channel_data_args args) {
char* json_str = channel->RenderJSON();
grpc::testing::ValidateChannelProtoJsonTranslation(json_str);
grpc_json* json = grpc_json_parse_string(json_str);
EXPECT_NE(json, nullptr);
grpc_json* data = GetJsonChild(json, "data");
ValidateChildInteger(data, args.calls_started, "callsStarted");
ValidateChildInteger(data, args.calls_failed, "callsFailed");
ValidateChildInteger(data, args.calls_succeeded, "callsSucceeded");
grpc_json_destroy(json);
gpr_free(json_str);
}
char* GetLastCallStartedTimestamp(Channel* channel) {
char* json_str = channel->RenderJSON();
grpc_json* json = grpc_json_parse_string(json_str);
grpc_json* data = GetJsonChild(json, "data");
grpc_json* timestamp = GetJsonChild(data, "lastCallStartedTimestamp");
char* ts_str = grpc_json_dump_to_string(timestamp, 0);
grpc_json_destroy(json);
gpr_free(json_str);
return ts_str;
}
void ChannelzSleep(int64_t sleep_us) {
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_micros(sleep_us, GPR_TIMESPAN)));
grpc_core::ExecCtx::Get()->InvalidateNow();
}
} // anonymous namespace
class ChannelzChannelTest : public ::testing::TestWithParam<size_t> {};
TEST_P(ChannelzChannelTest, BasicChannel) {
grpc_core::ExecCtx exec_ctx;
ChannelFixture channel(GetParam());
intptr_t uuid = grpc_channel_get_uuid(channel.channel());
Channel* channelz_channel = ChannelzRegistry::Get<Channel>(uuid);
ValidateChannel(channelz_channel, {-1, -1, -1});
}
TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) {
grpc_core::ExecCtx exec_ctx;
ChannelFixture channel(GetParam());
intptr_t uuid = grpc_channel_get_uuid(channel.channel());
Channel* channelz_channel = ChannelzRegistry::Get<Channel>(uuid);
channelz_channel->CallStarted();
channelz_channel->CallFailed();
channelz_channel->CallSucceeded();
ValidateChannel(channelz_channel, {1, 1, 1});
channelz_channel->CallStarted();
channelz_channel->CallFailed();
channelz_channel->CallSucceeded();
channelz_channel->CallStarted();
channelz_channel->CallFailed();
channelz_channel->CallSucceeded();
ValidateChannel(channelz_channel, {3, 3, 3});
}
TEST_P(ChannelzChannelTest, LastCallStartedTimestamp) {
grpc_core::ExecCtx exec_ctx;
ChannelFixture channel(GetParam());
intptr_t uuid = grpc_channel_get_uuid(channel.channel());
Channel* channelz_channel = ChannelzRegistry::Get<Channel>(uuid);
// start a call to set the last call started timestamp
channelz_channel->CallStarted();
char* ts1 = GetLastCallStartedTimestamp(channelz_channel);
// time gone by should not affect the timestamp
ChannelzSleep(100);
char* ts2 = GetLastCallStartedTimestamp(channelz_channel);
EXPECT_STREQ(ts1, ts2);
// calls succeeded or failed should not affect the timestamp
ChannelzSleep(100);
channelz_channel->CallFailed();
channelz_channel->CallSucceeded();
char* ts3 = GetLastCallStartedTimestamp(channelz_channel);
EXPECT_STREQ(ts1, ts3);
// another call started should affect the timestamp
// sleep for extra long to avoid flakes (since we cache Now())
ChannelzSleep(5000);
grpc_core::ExecCtx::Get()->InvalidateNow();
channelz_channel->CallStarted();
char* ts4 = GetLastCallStartedTimestamp(channelz_channel);
EXPECT_STRNE(ts1, ts4);
// clean up
gpr_free(ts1);
gpr_free(ts2);
gpr_free(ts3);
gpr_free(ts4);
}
INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest,
::testing::Values(0, 1, 2, 6, 10, 15));
} // namespace testing
} // namespace channelz
} // namespace grpc_core
int main(int argc, char** argv) {

@ -45,16 +45,21 @@ void VaidateProtoJsonTranslation(char* json_c_str) {
// then compare the output, and determine what fields are missing.
//
// parse_options.ignore_unknown_fields = true;
ASSERT_EQ(google::protobuf::util::JsonStringToMessage(json_str, &msg,
EXPECT_EQ(google::protobuf::util::JsonStringToMessage(json_str, &msg,
parse_options),
google::protobuf::util::Status::OK);
std::string proto_json_str;
ASSERT_EQ(google::protobuf::util::MessageToJsonString(msg, &proto_json_str),
google::protobuf::util::JsonPrintOptions print_options;
// We usually do not want this to be true, however it can be helpful to
// uncomment and see the output produced then all fields are printed.
// print_options.always_print_primitive_fields = true;
EXPECT_EQ(google::protobuf::util::MessageToJsonString(msg, &proto_json_str,
print_options),
google::protobuf::util::Status::OK);
// uncomment these to compare the the json strings.
// gpr_log(GPR_ERROR, "tracer json: %s", json_str.c_str());
// gpr_log(GPR_ERROR, "proto json: %s", proto_json_str.c_str());
ASSERT_EQ(json_str, proto_json_str);
EXPECT_EQ(json_str, proto_json_str);
}
} // namespace

Loading…
Cancel
Save