• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 
16 #include <gmock/gmock.h>
17 #include <grpc/event_engine/endpoint_config.h>
18 #include <grpcpp/ext/server_metric_recorder.h>
19 #include <gtest/gtest.h>
20 
21 #include <string>
22 #include <vector>
23 
24 #include "absl/log/log.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/str_format.h"
27 #include "envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.pb.h"
28 #include "envoy/extensions/load_balancing_policies/wrr_locality/v3/wrr_locality.pb.h"
29 #include "src/core/client_channel/backup_poller.h"
30 #include "src/core/config/config_vars.h"
31 #include "test/core/test_util/fake_stats_plugin.h"
32 #include "test/core/test_util/scoped_env_var.h"
33 #include "test/cpp/end2end/xds/xds_end2end_test_lib.h"
34 
35 namespace grpc {
36 namespace testing {
37 namespace {
38 
39 using ::envoy::extensions::load_balancing_policies::
40     client_side_weighted_round_robin::v3::ClientSideWeightedRoundRobin;
41 using ::envoy::extensions::load_balancing_policies::wrr_locality::v3::
42     WrrLocality;
43 
44 class WrrTest : public XdsEnd2endTest {
45  protected:
SetUp()46   void SetUp() override {
47     // No-op -- tests must explicitly call InitClient().
48   }
49 };
50 
51 INSTANTIATE_TEST_SUITE_P(XdsTest, WrrTest, ::testing::Values(XdsTestType()),
52                          &XdsTestType::Name);
53 
TEST_P(WrrTest,Basic)54 TEST_P(WrrTest, Basic) {
55   InitClient();
56   CreateAndStartBackends(3);
57   // Expected weights = qps / (util + (eps/qps)) =
58   //   1/(0.2+0.2) : 1/(0.3+0.3) : 2/(1.5+0.1) = 6:4:3
59   backends_[0]->server_metric_recorder()->SetQps(100);
60   backends_[0]->server_metric_recorder()->SetEps(20);
61   backends_[0]->server_metric_recorder()->SetApplicationUtilization(0.2);
62   backends_[1]->server_metric_recorder()->SetQps(100);
63   backends_[1]->server_metric_recorder()->SetEps(30);
64   backends_[1]->server_metric_recorder()->SetApplicationUtilization(0.3);
65   backends_[2]->server_metric_recorder()->SetQps(200);
66   backends_[2]->server_metric_recorder()->SetEps(20);
67   backends_[2]->server_metric_recorder()->SetApplicationUtilization(1.5);
68   auto cluster = default_cluster_;
69   WrrLocality wrr_locality;
70   wrr_locality.mutable_endpoint_picking_policy()
71       ->add_policies()
72       ->mutable_typed_extension_config()
73       ->mutable_typed_config()
74       ->PackFrom(ClientSideWeightedRoundRobin());
75   cluster.mutable_load_balancing_policy()
76       ->add_policies()
77       ->mutable_typed_extension_config()
78       ->mutable_typed_config()
79       ->PackFrom(wrr_locality);
80   balancer_->ads_service()->SetCdsResource(cluster);
81   EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
82   balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
83   size_t num_picks = 0;
84   SendRpcsUntil(DEBUG_LOCATION, [&](const RpcResult&) {
85     if (++num_picks == 13) {
86       LOG(INFO) << "request counts: "
87                 << backends_[0]->backend_service()->request_count() << " "
88                 << backends_[1]->backend_service()->request_count() << " "
89                 << backends_[2]->backend_service()->request_count();
90       if (backends_[0]->backend_service()->request_count() == 6 &&
91           backends_[1]->backend_service()->request_count() == 4 &&
92           backends_[2]->backend_service()->request_count() == 3) {
93         return false;
94       }
95       num_picks = 0;
96       ResetBackendCounters();
97     }
98     return true;
99   });
100 }
101 
TEST_P(WrrTest,MetricsHaveLocalityLabel)102 TEST_P(WrrTest, MetricsHaveLocalityLabel) {
103   const auto kEndpointWeights =
104       grpc_core::GlobalInstrumentsRegistryTestPeer::
105           FindDoubleHistogramHandleByName("grpc.lb.wrr.endpoint_weights")
106               .value();
107   const std::string target = absl::StrCat("xds:", kServerName);
108   const absl::string_view kLabelValues[] = {/*target=*/target};
109   // Register stats plugin before initializing client.
110   auto stats_plugin = grpc_core::FakeStatsPluginBuilder()
111                           .UseDisabledByDefaultMetrics(true)
112                           .BuildAndRegister();
113   InitClient();
114   CreateAndStartBackends(2);
115   auto cluster = default_cluster_;
116   WrrLocality wrr_locality;
117   wrr_locality.mutable_endpoint_picking_policy()
118       ->add_policies()
119       ->mutable_typed_extension_config()
120       ->mutable_typed_config()
121       ->PackFrom(ClientSideWeightedRoundRobin());
122   cluster.mutable_load_balancing_policy()
123       ->add_policies()
124       ->mutable_typed_extension_config()
125       ->mutable_typed_config()
126       ->PackFrom(wrr_locality);
127   balancer_->ads_service()->SetCdsResource(cluster);
128   EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)},
129                         {"locality1", CreateEndpointsForBackends(1, 2)}});
130   balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
131   WaitForAllBackends(DEBUG_LOCATION);
132   // Make sure we have a metric value for each of the two localities.
133   EXPECT_THAT(
134       stats_plugin->GetDoubleHistogramValue(kEndpointWeights, kLabelValues,
135                                             {LocalityNameString("locality0")}),
136       ::testing::Optional(::testing::Not(::testing::IsEmpty())));
137   EXPECT_THAT(
138       stats_plugin->GetDoubleHistogramValue(kEndpointWeights, kLabelValues,
139                                             {LocalityNameString("locality1")}),
140       ::testing::Optional(::testing::Not(::testing::IsEmpty())));
141 }
142 
143 }  // namespace
144 }  // namespace testing
145 }  // namespace grpc
146 
main(int argc,char ** argv)147 int main(int argc, char** argv) {
148   grpc::testing::TestEnvironment env(&argc, argv);
149   ::testing::InitGoogleTest(&argc, argv);
150   // Make the backup poller poll very frequently in order to pick up
151   // updates from all the subchannels's FDs.
152   grpc_core::ConfigVars::Overrides overrides;
153   overrides.client_channel_backup_poll_interval_ms = 1;
154   grpc_core::ConfigVars::SetOverrides(overrides);
155 #if TARGET_OS_IPHONE
156   // Workaround Apple CFStream bug
157   grpc_core::SetEnv("grpc_cfstream", "0");
158 #endif
159   grpc_init();
160   const auto result = RUN_ALL_TESTS();
161   grpc_shutdown();
162   return result;
163 }
164