| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 | /* * * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */#include <grpc/impl/codegen/port_platform.h>#include <set>#include <vector>#include <gmock/gmock.h>#include <grpc/grpc.h>#include <gtest/gtest.h>#include "src/core/ext/filters/load_reporting/registered_opencensus_objects.h"#include "src/core/lib/iomgr/exec_ctx.h"#include "src/cpp/server/load_reporter/constants.h"#include "src/cpp/server/load_reporter/load_reporter.h"#include "test/core/util/port.h"#include "test/core/util/test_config.h"#include "opencensus/stats/testing/test_utils.h"namespace grpc {namespace testing {namespace {using ::grpc::lb::v1::LoadBalancingFeedback;using ::grpc::load_reporter::CensusViewProvider;using ::grpc::load_reporter::CpuStatsProvider;using ::grpc::load_reporter::LoadReporter;using ::opencensus::stats::View;using ::opencensus::stats::ViewData;using ::opencensus::stats::ViewDataImpl;using ::opencensus::stats::ViewDescriptor;using ::testing::DoubleNear;using ::testing::Return;constexpr uint64_t kFeedbackSampleWindowSeconds = 5;constexpr uint64_t kFetchAndSampleIntervalSeconds = 1;constexpr uint64_t kNumFeedbackSamplesInWindow =    kFeedbackSampleWindowSeconds / kFetchAndSampleIntervalSeconds;class MockCensusViewProvider : public CensusViewProvider { public:  MOCK_METHOD0(FetchViewData, CensusViewProvider::ViewDataMap());  const ::opencensus::stats::ViewDescriptor& FindViewDescriptor(      const std::string& view_name) {    auto it = view_descriptor_map().find(view_name);    GPR_ASSERT(it != view_descriptor_map().end());    return it->second;  }};class MockCpuStatsProvider : public CpuStatsProvider { public:  MOCK_METHOD0(GetCpuStats, CpuStatsProvider::CpuStatsSample());};class LoadReporterTest : public ::testing::Test { public:  LoadReporterTest() {}  MockCensusViewProvider* mock_census_view_provider() {    return static_cast<MockCensusViewProvider*>(        load_reporter_->census_view_provider());  }  void PrepareCpuExpectation(size_t call_num) {    auto mock_cpu_stats_provider = static_cast<MockCpuStatsProvider*>(        load_reporter_->cpu_stats_provider());    ::testing::InSequence s;    for (size_t i = 0; i < call_num; ++i) {      EXPECT_CALL(*mock_cpu_stats_provider, GetCpuStats())          .WillOnce(Return(kCpuStatsSamples[i]))          .RetiresOnSaturation();    }  }  CpuStatsProvider::CpuStatsSample initial_cpu_stats_{2, 20};  const std::vector<CpuStatsProvider::CpuStatsSample> kCpuStatsSamples = {      {13, 53},    {64, 96},     {245, 345},  {314, 785},      {874, 1230}, {1236, 2145}, {1864, 2974}};  std::unique_ptr<LoadReporter> load_reporter_;  const std::string kHostname1 = "kHostname1";  const std::string kHostname2 = "kHostname2";  const std::string kHostname3 = "kHostname3";  // Pad to the length of a valid LB ID.  const std::string kLbId1 = "kLbId111";  const std::string kLbId2 = "kLbId222";  const std::string kLbId3 = "kLbId333";  const std::string kLbId4 = "kLbId444";  const std::string kLoadKey1 = "kLoadKey1";  const std::string kLoadKey2 = "kLoadKey2";  const std::string kLoadKey3 = "kLoadKey3";  const std::string kLbTag1 = "kLbTag1";  const std::string kLbTag2 = "kLbTag2";  const std::string kLbToken1 = "kLbId111kLbTag1";  const std::string kLbToken2 = "kLbId222kLbTag2";  const std::string kUser1 = "kUser1";  const std::string kUser2 = "kUser2";  const std::string kUser3 = "kUser3";  const std::string kClientIp0 = "00";  const std::string kClientIp1 = "0800000001";  const std::string kClientIp2 = "3200000000000000000000000000000002";  const std::string kMetric1 = "kMetric1";  const std::string kMetric2 = "kMetric2"; private:  void SetUp() override {    // Access the measures to make them valid.    ::grpc::load_reporter::MeasureStartCount();    ::grpc::load_reporter::MeasureEndCount();    ::grpc::load_reporter::MeasureEndBytesSent();    ::grpc::load_reporter::MeasureEndBytesReceived();    ::grpc::load_reporter::MeasureEndLatencyMs();    ::grpc::load_reporter::MeasureOtherCallMetric();    // Set up the load reporter.    auto mock_cpu = new MockCpuStatsProvider();    auto mock_census = new MockCensusViewProvider();    // Prepare the initial CPU stats data. Note that the expectation should be    // set up before the load reporter is initialized, because CPU stats is    // sampled at that point.    EXPECT_CALL(*mock_cpu, GetCpuStats())        .WillOnce(Return(initial_cpu_stats_))        .RetiresOnSaturation();    load_reporter_ = std::unique_ptr<LoadReporter>(        new LoadReporter(kFeedbackSampleWindowSeconds,                         std::unique_ptr<CensusViewProvider>(mock_census),                         std::unique_ptr<CpuStatsProvider>(mock_cpu)));  }};class LbFeedbackTest : public LoadReporterTest { public:  // Note that [start, start + count) of the fake samples (maybe plus the  // initial record) are in the window now.  void VerifyLbFeedback(const LoadBalancingFeedback& lb_feedback, size_t start,                        size_t count) {    const CpuStatsProvider::CpuStatsSample* base =        start == 0 ? &initial_cpu_stats_ : &kCpuStatsSamples[start - 1];    double expected_cpu_util =        static_cast<double>(kCpuStatsSamples[start + count - 1].first -                            base->first) /        static_cast<double>(kCpuStatsSamples[start + count - 1].second -                            base->second);    ASSERT_THAT(static_cast<double>(lb_feedback.server_utilization()),                DoubleNear(expected_cpu_util, 0.00001));    double qps_sum = 0, eps_sum = 0;    for (size_t i = 0; i < count; ++i) {      qps_sum += kQpsEpsSamples[start + i].first;      eps_sum += kQpsEpsSamples[start + i].second;    }    double expected_qps = qps_sum / count;    double expected_eps = eps_sum / count;    // TODO(juanlishen): The error is big because we use sleep(). It should be    // much smaller when we use fake clock.    ASSERT_THAT(static_cast<double>(lb_feedback.calls_per_second()),                DoubleNear(expected_qps, expected_qps * 0.3));    ASSERT_THAT(static_cast<double>(lb_feedback.errors_per_second()),                DoubleNear(expected_eps, expected_eps * 0.3));    gpr_log(GPR_INFO,            "Verified LB feedback matches the samples of index [%lu, %lu).",            start, start + count);  }  const std::vector<std::pair<double, double>> kQpsEpsSamples = {      {546.1, 153.1},  {62.1, 54.1},   {578.1, 154.2}, {978.1, 645.1},      {1132.1, 846.4}, {531.5, 315.4}, {874.1, 324.9}};};TEST_F(LbFeedbackTest, ZeroDuration) {  PrepareCpuExpectation(kCpuStatsSamples.size());  EXPECT_CALL(*mock_census_view_provider(), FetchViewData())      .WillRepeatedly(          Return(::grpc::load_reporter::CensusViewProvider::ViewDataMap()));  // Verify that divide-by-zero exception doesn't happen.  for (size_t i = 0; i < kCpuStatsSamples.size(); ++i) {    load_reporter_->FetchAndSample();  }  load_reporter_->GenerateLoadBalancingFeedback();}TEST_F(LbFeedbackTest, Normal) {  // Prepare view data list using the <QPS, EPS> samples.  std::vector<CensusViewProvider::ViewDataMap> view_data_map_list;  for (const auto& p : LbFeedbackTest::kQpsEpsSamples) {    double qps = p.first;    double eps = p.second;    double ok_count = (qps - eps) * kFetchAndSampleIntervalSeconds;    double error_count = eps * kFetchAndSampleIntervalSeconds;    double ok_count_1 = ok_count / 3.0;    double ok_count_2 = ok_count - ok_count_1;    auto end_count_vd = ::opencensus::stats::testing::TestUtils::MakeViewData(        mock_census_view_provider()->FindViewDescriptor(            ::grpc::load_reporter::kViewEndCount),        {{{kClientIp0 + kLbToken1, kHostname1, kUser1,           ::grpc::load_reporter::kCallStatusOk},          ok_count_1},         {{kClientIp0 + kLbToken1, kHostname1, kUser2,           ::grpc::load_reporter::kCallStatusOk},          ok_count_2},         {{kClientIp0 + kLbToken1, kHostname1, kUser1,           ::grpc::load_reporter::kCallStatusClientError},          error_count}});    // Values for other view data don't matter.    auto end_bytes_sent_vd =        ::opencensus::stats::testing::TestUtils::MakeViewData(            mock_census_view_provider()->FindViewDescriptor(                ::grpc::load_reporter::kViewEndBytesSent),            {{{kClientIp0 + kLbToken1, kHostname1, kUser1,               ::grpc::load_reporter::kCallStatusOk},              0},             {{kClientIp0 + kLbToken1, kHostname1, kUser2,               ::grpc::load_reporter::kCallStatusOk},              0},             {{kClientIp0 + kLbToken1, kHostname1, kUser1,               ::grpc::load_reporter::kCallStatusClientError},              0}});    auto end_bytes_received_vd =        ::opencensus::stats::testing::TestUtils::MakeViewData(            mock_census_view_provider()->FindViewDescriptor(                ::grpc::load_reporter::kViewEndBytesReceived),            {{{kClientIp0 + kLbToken1, kHostname1, kUser1,               ::grpc::load_reporter::kCallStatusOk},              0},             {{kClientIp0 + kLbToken1, kHostname1, kUser2,               ::grpc::load_reporter::kCallStatusOk},              0},             {{kClientIp0 + kLbToken1, kHostname1, kUser1,               ::grpc::load_reporter::kCallStatusClientError},              0}});    auto end_latency_vd = ::opencensus::stats::testing::TestUtils::MakeViewData(        mock_census_view_provider()->FindViewDescriptor(            ::grpc::load_reporter::kViewEndLatencyMs),        {{{kClientIp0 + kLbToken1, kHostname1, kUser1,           ::grpc::load_reporter::kCallStatusOk},          0},         {{kClientIp0 + kLbToken1, kHostname1, kUser2,           ::grpc::load_reporter::kCallStatusOk},          0},         {{kClientIp0 + kLbToken1, kHostname1, kUser1,           ::grpc::load_reporter::kCallStatusClientError},          0}});    view_data_map_list.push_back(        {{::grpc::load_reporter::kViewEndCount, end_count_vd},         {::grpc::load_reporter::kViewEndBytesSent, end_bytes_sent_vd},         {::grpc::load_reporter::kViewEndBytesReceived, end_bytes_received_vd},         {::grpc::load_reporter::kViewEndLatencyMs, end_latency_vd}});  }  {    ::testing::InSequence s;    for (size_t i = 0; i < view_data_map_list.size(); ++i) {      EXPECT_CALL(*mock_census_view_provider(), FetchViewData())          .WillOnce(Return(view_data_map_list[i]))          .RetiresOnSaturation();    }  }  PrepareCpuExpectation(kNumFeedbackSamplesInWindow + 2);  // When the load reporter is created, a trivial LB feedback record is added.  // But that's not enough for generating an LB feedback.  // Fetch some view data so that non-trivial LB feedback can be generated.  for (size_t i = 0; i < kNumFeedbackSamplesInWindow / 2; ++i) {    // TODO(juanlishen): Find some fake clock to speed up testing.    sleep(1);    load_reporter_->FetchAndSample();  }  VerifyLbFeedback(load_reporter_->GenerateLoadBalancingFeedback(), 0,                   kNumFeedbackSamplesInWindow / 2);  // Fetch more view data so that the feedback record window is just full (the  // initial record just falls out of the window).  for (size_t i = 0; i < (kNumFeedbackSamplesInWindow + 1) / 2; ++i) {    sleep(1);    load_reporter_->FetchAndSample();  }  VerifyLbFeedback(load_reporter_->GenerateLoadBalancingFeedback(), 0,                   kNumFeedbackSamplesInWindow);  // Further fetching will cause the old records to fall out of the window.  for (size_t i = 0; i < 2; ++i) {    sleep(1);    load_reporter_->FetchAndSample();  }  VerifyLbFeedback(load_reporter_->GenerateLoadBalancingFeedback(), 2,                   kNumFeedbackSamplesInWindow);}using LoadReportTest = LoadReporterTest;TEST_F(LoadReportTest, BasicReport) {  // Make up the first view data map.  CensusViewProvider::ViewDataMap vdm1;  vdm1.emplace(      ::grpc::load_reporter::kViewStartCount,      ::opencensus::stats::testing::TestUtils::MakeViewData(          mock_census_view_provider()->FindViewDescriptor(              ::grpc::load_reporter::kViewStartCount),          {{{kClientIp1 + kLbToken1, kHostname1, kUser1}, 1234},           {{kClientIp2 + kLbToken1, kHostname1, kUser1}, 1225},           {{kClientIp0 + kLbToken1, kHostname1, kUser1}, 10},           {{kClientIp2 + kLbToken1, kHostname1, kUser2}, 464},           {{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3}, 101},           {{kClientIp1 + kLbToken2, kHostname2, kUser3}, 17},           {{kClientIp2 + kLbId3 + kLbTag2, kHostname2, kUser3}, 23}}));  vdm1.emplace(::grpc::load_reporter::kViewEndCount,               ::opencensus::stats::testing::TestUtils::MakeViewData(                   mock_census_view_provider()->FindViewDescriptor(                       ::grpc::load_reporter::kViewEndCount),                   {{{kClientIp1 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusOk},                     641},                    {{kClientIp2 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusClientError},                     272},                    {{kClientIp2 + kLbToken1, kHostname1, kUser2,                      ::grpc::load_reporter::kCallStatusOk},                     996},                    {{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3,                      ::grpc::load_reporter::kCallStatusClientError},                     34},                    {{kClientIp1 + kLbToken2, kHostname2, kUser2,                      ::grpc::load_reporter::kCallStatusOk},                     18}}));  vdm1.emplace(::grpc::load_reporter::kViewEndBytesSent,               ::opencensus::stats::testing::TestUtils::MakeViewData(                   mock_census_view_provider()->FindViewDescriptor(                       ::grpc::load_reporter::kViewEndBytesSent),                   {{{kClientIp1 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusOk},                     8977},                    {{kClientIp2 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusClientError},                     266},                    {{kClientIp2 + kLbToken1, kHostname1, kUser2,                      ::grpc::load_reporter::kCallStatusOk},                     1276},                    {{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3,                      ::grpc::load_reporter::kCallStatusClientError},                     77823},                    {{kClientIp1 + kLbToken2, kHostname2, kUser2,                      ::grpc::load_reporter::kCallStatusOk},                     48}}));  vdm1.emplace(::grpc::load_reporter::kViewEndBytesReceived,               ::opencensus::stats::testing::TestUtils::MakeViewData(                   mock_census_view_provider()->FindViewDescriptor(                       ::grpc::load_reporter::kViewEndBytesReceived),                   {{{kClientIp1 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusOk},                     2341},                    {{kClientIp2 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusClientError},                     466},                    {{kClientIp2 + kLbToken1, kHostname1, kUser2,                      ::grpc::load_reporter::kCallStatusOk},                     518},                    {{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3,                      ::grpc::load_reporter::kCallStatusClientError},                     81},                    {{kClientIp1 + kLbToken2, kHostname2, kUser2,                      ::grpc::load_reporter::kCallStatusOk},                     27}}));  vdm1.emplace(::grpc::load_reporter::kViewEndLatencyMs,               ::opencensus::stats::testing::TestUtils::MakeViewData(                   mock_census_view_provider()->FindViewDescriptor(                       ::grpc::load_reporter::kViewEndLatencyMs),                   {{{kClientIp1 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusOk},                     3.14},                    {{kClientIp2 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusClientError},                     5.26},                    {{kClientIp2 + kLbToken1, kHostname1, kUser2,                      ::grpc::load_reporter::kCallStatusOk},                     45.4},                    {{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3,                      ::grpc::load_reporter::kCallStatusClientError},                     4.4},                    {{kClientIp1 + kLbToken2, kHostname2, kUser2,                      ::grpc::load_reporter::kCallStatusOk},                     2348.0}}));  vdm1.emplace(      ::grpc::load_reporter::kViewOtherCallMetricCount,      ::opencensus::stats::testing::TestUtils::MakeViewData(          mock_census_view_provider()->FindViewDescriptor(              ::grpc::load_reporter::kViewOtherCallMetricCount),          {{{kClientIp1 + kLbToken1, kHostname1, kUser2, kMetric1}, 1},           {{kClientIp1 + kLbToken1, kHostname1, kUser2, kMetric1}, 1},           {{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3, kMetric2},            1}}));  vdm1.emplace(      ::grpc::load_reporter::kViewOtherCallMetricValue,      ::opencensus::stats::testing::TestUtils::MakeViewData(          mock_census_view_provider()->FindViewDescriptor(              ::grpc::load_reporter::kViewOtherCallMetricValue),          {{{kClientIp1 + kLbToken1, kHostname1, kUser2, kMetric1}, 1.2},           {{kClientIp1 + kLbToken1, kHostname1, kUser2, kMetric1}, 1.2},           {{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3, kMetric2},            3.2}}));  // Make up the second view data map.  CensusViewProvider::ViewDataMap vdm2;  vdm2.emplace(      ::grpc::load_reporter::kViewStartCount,      ::opencensus::stats::testing::TestUtils::MakeViewData(          mock_census_view_provider()->FindViewDescriptor(              ::grpc::load_reporter::kViewStartCount),          {{{kClientIp2 + kLbToken1, kHostname1, kUser1}, 3},           {{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3}, 778}}));  vdm2.emplace(::grpc::load_reporter::kViewEndCount,               ::opencensus::stats::testing::TestUtils::MakeViewData(                   mock_census_view_provider()->FindViewDescriptor(                       ::grpc::load_reporter::kViewEndCount),                   {{{kClientIp1 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusOk},                     24},                    {{kClientIp1 + kLbToken2, kHostname2, kUser3,                      ::grpc::load_reporter::kCallStatusClientError},                     546}}));  vdm2.emplace(::grpc::load_reporter::kViewEndBytesSent,               ::opencensus::stats::testing::TestUtils::MakeViewData(                   mock_census_view_provider()->FindViewDescriptor(                       ::grpc::load_reporter::kViewEndBytesSent),                   {{{kClientIp1 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusOk},                     747},                    {{kClientIp1 + kLbToken2, kHostname2, kUser3,                      ::grpc::load_reporter::kCallStatusClientError},                     229}}));  vdm2.emplace(::grpc::load_reporter::kViewEndBytesReceived,               ::opencensus::stats::testing::TestUtils::MakeViewData(                   mock_census_view_provider()->FindViewDescriptor(                       ::grpc::load_reporter::kViewEndBytesReceived),                   {{{kClientIp1 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusOk},                     173},                    {{kClientIp1 + kLbToken2, kHostname2, kUser3,                      ::grpc::load_reporter::kCallStatusClientError},                     438}}));  vdm2.emplace(::grpc::load_reporter::kViewEndLatencyMs,               ::opencensus::stats::testing::TestUtils::MakeViewData(                   mock_census_view_provider()->FindViewDescriptor(                       ::grpc::load_reporter::kViewEndLatencyMs),                   {{{kClientIp1 + kLbToken1, kHostname1, kUser1,                      ::grpc::load_reporter::kCallStatusOk},                     187},                    {{kClientIp1 + kLbToken2, kHostname2, kUser3,                      ::grpc::load_reporter::kCallStatusClientError},                     34}}));  vdm2.emplace(      ::grpc::load_reporter::kViewOtherCallMetricCount,      ::opencensus::stats::testing::TestUtils::MakeViewData(          mock_census_view_provider()->FindViewDescriptor(              ::grpc::load_reporter::kViewOtherCallMetricCount),          {{{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3, kMetric1}, 1},           {{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3, kMetric2},            1}}));  vdm2.emplace(      ::grpc::load_reporter::kViewOtherCallMetricValue,      ::opencensus::stats::testing::TestUtils::MakeViewData(          mock_census_view_provider()->FindViewDescriptor(              ::grpc::load_reporter::kViewOtherCallMetricValue),          {{{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3, kMetric1}, 9.6},           {{kClientIp1 + kLbId2 + kLbTag1, kHostname2, kUser3, kMetric2},            5.7}}));  // Set up mock expectation.  EXPECT_CALL(*mock_census_view_provider(), FetchViewData())      .WillOnce(Return(vdm1))      .WillOnce(Return(vdm2));  PrepareCpuExpectation(2);  // Start testing.  load_reporter_->ReportStreamCreated(kHostname1, kLbId1, kLoadKey1);  load_reporter_->ReportStreamCreated(kHostname2, kLbId2, kLoadKey2);  load_reporter_->ReportStreamCreated(kHostname2, kLbId3, kLoadKey3);  // First fetch.  load_reporter_->FetchAndSample();  load_reporter_->GenerateLoads(kHostname1, kLbId1);  gpr_log(GPR_INFO, "First load generated.");  // Second fetch.  load_reporter_->FetchAndSample();  load_reporter_->GenerateLoads(kHostname2, kLbId2);  gpr_log(GPR_INFO, "Second load generated.");  // TODO(juanlishen): Verify the data.}}  // namespace}  // namespace testing}  // namespace grpcint main(int argc, char** argv) {  grpc::testing::TestEnvironment env(argc, argv);  ::testing::InitGoogleTest(&argc, argv);  return RUN_ALL_TESTS();}
 |