Home | History | Annotate | Download | only in channel
      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 #include "src/core/lib/surface/channel.h"
     34 #include "src/core/lib/surface/server.h"
     35 
     36 #include "test/core/util/test_config.h"
     37 #include "test/cpp/util/channel_trace_proto_helper.h"
     38 
     39 #include <grpc/support/string_util.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 
     43 namespace grpc_core {
     44 namespace channelz {
     45 namespace testing {
     46 
     47 // testing peer to access channel internals
     48 class CallCountingHelperPeer {
     49  public:
     50   explicit CallCountingHelperPeer(CallCountingHelper* node) : node_(node) {}
     51   grpc_millis last_call_started_millis() const {
     52     return (grpc_millis)gpr_atm_no_barrier_load(
     53         &node_->last_call_started_millis_);
     54   }
     55 
     56  private:
     57   CallCountingHelper* node_;
     58 };
     59 
     60 namespace {
     61 
     62 grpc_json* GetJsonChild(grpc_json* parent, const char* key) {
     63   EXPECT_NE(parent, nullptr);
     64   for (grpc_json* child = parent->child; child != nullptr;
     65        child = child->next) {
     66     if (child->key != nullptr && strcmp(child->key, key) == 0) return child;
     67   }
     68   return nullptr;
     69 }
     70 
     71 void ValidateJsonArraySize(grpc_json* json, const char* key,
     72                            size_t expected_size) {
     73   grpc_json* arr = GetJsonChild(json, key);
     74   if (expected_size == 0) {
     75     ASSERT_EQ(arr, nullptr);
     76     return;
     77   }
     78   ASSERT_NE(arr, nullptr);
     79   ASSERT_EQ(arr->type, GRPC_JSON_ARRAY);
     80   size_t count = 0;
     81   for (grpc_json* child = arr->child; child != nullptr; child = child->next) {
     82     ++count;
     83   }
     84   EXPECT_EQ(count, expected_size);
     85 }
     86 
     87 void ValidateGetTopChannels(size_t expected_channels) {
     88   char* json_str = ChannelzRegistry::GetTopChannels(0);
     89   grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str);
     90   grpc_json* parsed_json = grpc_json_parse_string(json_str);
     91   // This check will naturally have to change when we support pagination.
     92   // tracked: https://github.com/grpc/grpc/issues/16019.
     93   ValidateJsonArraySize(parsed_json, "channel", expected_channels);
     94   grpc_json* end = GetJsonChild(parsed_json, "end");
     95   ASSERT_NE(end, nullptr);
     96   EXPECT_EQ(end->type, GRPC_JSON_TRUE);
     97   grpc_json_destroy(parsed_json);
     98   gpr_free(json_str);
     99   // also check that the core API formats this correctly
    100   char* core_api_json_str = grpc_channelz_get_top_channels(0);
    101   grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(
    102       core_api_json_str);
    103   gpr_free(core_api_json_str);
    104 }
    105 
    106 void ValidateGetServers(size_t expected_servers) {
    107   char* json_str = ChannelzRegistry::GetServers(0);
    108   grpc::testing::ValidateGetServersResponseProtoJsonTranslation(json_str);
    109   grpc_json* parsed_json = grpc_json_parse_string(json_str);
    110   // This check will naturally have to change when we support pagination.
    111   // tracked: https://github.com/grpc/grpc/issues/16019.
    112   ValidateJsonArraySize(parsed_json, "server", expected_servers);
    113   grpc_json* end = GetJsonChild(parsed_json, "end");
    114   ASSERT_NE(end, nullptr);
    115   EXPECT_EQ(end->type, GRPC_JSON_TRUE);
    116   grpc_json_destroy(parsed_json);
    117   gpr_free(json_str);
    118   // also check that the core API formats this correctly
    119   char* core_api_json_str = grpc_channelz_get_servers(0);
    120   grpc::testing::ValidateGetServersResponseProtoJsonTranslation(
    121       core_api_json_str);
    122   gpr_free(core_api_json_str);
    123 }
    124 
    125 class ChannelFixture {
    126  public:
    127   ChannelFixture(int max_trace_nodes = 0) {
    128     grpc_arg client_a[2];
    129     client_a[0] = grpc_channel_arg_integer_create(
    130         const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE),
    131         max_trace_nodes);
    132     client_a[1] = grpc_channel_arg_integer_create(
    133         const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true);
    134     grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
    135     channel_ =
    136         grpc_insecure_channel_create("fake_target", &client_args, nullptr);
    137   }
    138 
    139   ~ChannelFixture() { grpc_channel_destroy(channel_); }
    140 
    141   grpc_channel* channel() { return channel_; }
    142 
    143  private:
    144   grpc_channel* channel_;
    145 };
    146 
    147 class ServerFixture {
    148  public:
    149   explicit ServerFixture(int max_trace_nodes = 0) {
    150     grpc_arg server_a[] = {
    151         grpc_channel_arg_integer_create(
    152             const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE),
    153             max_trace_nodes),
    154         grpc_channel_arg_integer_create(
    155             const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true),
    156     };
    157     grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a};
    158     server_ = grpc_server_create(&server_args, nullptr);
    159   }
    160 
    161   ~ServerFixture() { grpc_server_destroy(server_); }
    162 
    163   grpc_server* server() const { return server_; }
    164 
    165  private:
    166   grpc_server* server_;
    167 };
    168 
    169 struct validate_channel_data_args {
    170   int64_t calls_started;
    171   int64_t calls_failed;
    172   int64_t calls_succeeded;
    173 };
    174 
    175 void ValidateChildInteger(grpc_json* json, int64_t expect, const char* key) {
    176   grpc_json* gotten_json = GetJsonChild(json, key);
    177   if (expect == 0) {
    178     ASSERT_EQ(gotten_json, nullptr);
    179     return;
    180   }
    181   ASSERT_NE(gotten_json, nullptr);
    182   int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0);
    183   EXPECT_EQ(gotten_number, expect);
    184 }
    185 
    186 void ValidateCounters(char* json_str, validate_channel_data_args args) {
    187   grpc_json* json = grpc_json_parse_string(json_str);
    188   ASSERT_NE(json, nullptr);
    189   grpc_json* data = GetJsonChild(json, "data");
    190   ValidateChildInteger(data, args.calls_started, "callsStarted");
    191   ValidateChildInteger(data, args.calls_failed, "callsFailed");
    192   ValidateChildInteger(data, args.calls_succeeded, "callsSucceeded");
    193   grpc_json_destroy(json);
    194 }
    195 
    196 void ValidateChannel(ChannelNode* channel, validate_channel_data_args args) {
    197   char* json_str = channel->RenderJsonString();
    198   grpc::testing::ValidateChannelProtoJsonTranslation(json_str);
    199   ValidateCounters(json_str, args);
    200   gpr_free(json_str);
    201   // also check that the core API formats this the correct way
    202   char* core_api_json_str = grpc_channelz_get_channel(channel->uuid());
    203   grpc::testing::ValidateGetChannelResponseProtoJsonTranslation(
    204       core_api_json_str);
    205   gpr_free(core_api_json_str);
    206 }
    207 
    208 void ValidateServer(ServerNode* server, validate_channel_data_args args) {
    209   char* json_str = server->RenderJsonString();
    210   grpc::testing::ValidateServerProtoJsonTranslation(json_str);
    211   ValidateCounters(json_str, args);
    212   gpr_free(json_str);
    213 }
    214 
    215 grpc_millis GetLastCallStartedMillis(CallCountingHelper* channel) {
    216   CallCountingHelperPeer peer(channel);
    217   return peer.last_call_started_millis();
    218 }
    219 
    220 void ChannelzSleep(int64_t sleep_us) {
    221   gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
    222                                gpr_time_from_micros(sleep_us, GPR_TIMESPAN)));
    223   grpc_core::ExecCtx::Get()->InvalidateNow();
    224 }
    225 
    226 }  // anonymous namespace
    227 
    228 class ChannelzChannelTest : public ::testing::TestWithParam<size_t> {};
    229 
    230 TEST_P(ChannelzChannelTest, BasicChannel) {
    231   grpc_core::ExecCtx exec_ctx;
    232   ChannelFixture channel(GetParam());
    233   ChannelNode* channelz_channel =
    234       grpc_channel_get_channelz_node(channel.channel());
    235   ValidateChannel(channelz_channel, {0, 0, 0});
    236 }
    237 
    238 TEST(ChannelzChannelTest, ChannelzDisabled) {
    239   grpc_core::ExecCtx exec_ctx;
    240   grpc_channel* channel =
    241       grpc_insecure_channel_create("fake_target", nullptr, nullptr);
    242   ChannelNode* channelz_channel = grpc_channel_get_channelz_node(channel);
    243   ASSERT_EQ(channelz_channel, nullptr);
    244   grpc_channel_destroy(channel);
    245 }
    246 
    247 TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) {
    248   grpc_core::ExecCtx exec_ctx;
    249   ChannelFixture channel(GetParam());
    250   ChannelNode* channelz_channel =
    251       grpc_channel_get_channelz_node(channel.channel());
    252   channelz_channel->RecordCallStarted();
    253   channelz_channel->RecordCallFailed();
    254   channelz_channel->RecordCallSucceeded();
    255   ValidateChannel(channelz_channel, {1, 1, 1});
    256   channelz_channel->RecordCallStarted();
    257   channelz_channel->RecordCallFailed();
    258   channelz_channel->RecordCallSucceeded();
    259   channelz_channel->RecordCallStarted();
    260   channelz_channel->RecordCallFailed();
    261   channelz_channel->RecordCallSucceeded();
    262   ValidateChannel(channelz_channel, {3, 3, 3});
    263 }
    264 
    265 TEST_P(ChannelzChannelTest, LastCallStartedMillis) {
    266   grpc_core::ExecCtx exec_ctx;
    267   CallCountingHelper counter;
    268   // start a call to set the last call started timestamp
    269   counter.RecordCallStarted();
    270   grpc_millis millis1 = GetLastCallStartedMillis(&counter);
    271   // time gone by should not affect the timestamp
    272   ChannelzSleep(100);
    273   grpc_millis millis2 = GetLastCallStartedMillis(&counter);
    274   EXPECT_EQ(millis1, millis2);
    275   // calls succeeded or failed should not affect the timestamp
    276   ChannelzSleep(100);
    277   counter.RecordCallFailed();
    278   counter.RecordCallSucceeded();
    279   grpc_millis millis3 = GetLastCallStartedMillis(&counter);
    280   EXPECT_EQ(millis1, millis3);
    281   // another call started should affect the timestamp
    282   // sleep for extra long to avoid flakes (since we cache Now())
    283   ChannelzSleep(5000);
    284   counter.RecordCallStarted();
    285   grpc_millis millis4 = GetLastCallStartedMillis(&counter);
    286   EXPECT_NE(millis1, millis4);
    287 }
    288 
    289 TEST(ChannelzGetTopChannelsTest, BasicGetTopChannelsTest) {
    290   grpc_core::ExecCtx exec_ctx;
    291   ChannelFixture channel;
    292   ValidateGetTopChannels(1);
    293 }
    294 
    295 TEST(ChannelzGetTopChannelsTest, NoChannelsTest) {
    296   grpc_core::ExecCtx exec_ctx;
    297   ValidateGetTopChannels(0);
    298 }
    299 
    300 TEST(ChannelzGetTopChannelsTest, ManyChannelsTest) {
    301   grpc_core::ExecCtx exec_ctx;
    302   ChannelFixture channels[10];
    303   (void)channels;  // suppress unused variable error
    304   ValidateGetTopChannels(10);
    305 }
    306 
    307 TEST(ChannelzGetTopChannelsTest, InternalChannelTest) {
    308   grpc_core::ExecCtx exec_ctx;
    309   ChannelFixture channels[10];
    310   (void)channels;  // suppress unused variable error
    311   // create an internal channel
    312   grpc_arg client_a[2];
    313   client_a[0] = grpc_channel_arg_integer_create(
    314       const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), true);
    315   client_a[1] = grpc_channel_arg_integer_create(
    316       const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true);
    317   grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
    318   grpc_channel* internal_channel =
    319       grpc_insecure_channel_create("fake_target", &client_args, nullptr);
    320   // The internal channel should not be returned from the request
    321   ValidateGetTopChannels(10);
    322   grpc_channel_destroy(internal_channel);
    323 }
    324 
    325 class ChannelzServerTest : public ::testing::TestWithParam<size_t> {};
    326 
    327 TEST_P(ChannelzServerTest, BasicServerAPIFunctionality) {
    328   grpc_core::ExecCtx exec_ctx;
    329   ServerFixture server(10);
    330   ServerNode* channelz_server = grpc_server_get_channelz_node(server.server());
    331   channelz_server->RecordCallStarted();
    332   channelz_server->RecordCallFailed();
    333   channelz_server->RecordCallSucceeded();
    334   ValidateServer(channelz_server, {1, 1, 1});
    335   channelz_server->RecordCallStarted();
    336   channelz_server->RecordCallFailed();
    337   channelz_server->RecordCallSucceeded();
    338   channelz_server->RecordCallStarted();
    339   channelz_server->RecordCallFailed();
    340   channelz_server->RecordCallSucceeded();
    341   ValidateServer(channelz_server, {3, 3, 3});
    342 }
    343 
    344 TEST(ChannelzGetServersTest, BasicGetServersTest) {
    345   grpc_core::ExecCtx exec_ctx;
    346   ServerFixture server;
    347   ValidateGetServers(1);
    348 }
    349 
    350 TEST(ChannelzGetServersTest, NoServersTest) {
    351   grpc_core::ExecCtx exec_ctx;
    352   ValidateGetServers(0);
    353 }
    354 
    355 TEST(ChannelzGetServersTest, ManyServersTest) {
    356   grpc_core::ExecCtx exec_ctx;
    357   ServerFixture servers[10];
    358   (void)servers;  // suppress unused variable error
    359   ValidateGetServers(10);
    360 }
    361 
    362 INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest,
    363                         ::testing::Values(0, 1, 2, 6, 10, 15));
    364 
    365 INSTANTIATE_TEST_CASE_P(ChannelzServerTestSweep, ChannelzServerTest,
    366                         ::testing::Values(0, 1, 2, 6, 10, 15));
    367 
    368 }  // namespace testing
    369 }  // namespace channelz
    370 }  // namespace grpc_core
    371 
    372 int main(int argc, char** argv) {
    373   grpc_test_init(argc, argv);
    374   grpc_init();
    375   ::testing::InitGoogleTest(&argc, argv);
    376   int ret = RUN_ALL_TESTS();
    377   grpc_shutdown();
    378   return ret;
    379 }
    380