xref: /aosp_15_r20/external/grpc-grpc/test/cpp/end2end/xds/xds_wrr_end2end_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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 <string>
17 #include <vector>
18 
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 
22 #include "absl/strings/str_cat.h"
23 #include "absl/strings/str_format.h"
24 
25 #include <grpc/event_engine/endpoint_config.h>
26 #include <grpcpp/ext/server_metric_recorder.h>
27 
28 #include "src/core/client_channel/backup_poller.h"
29 #include "src/core/lib/config/config_vars.h"
30 #include "src/proto/grpc/testing/xds/v3/client_side_weighted_round_robin.grpc.pb.h"
31 #include "src/proto/grpc/testing/xds/v3/wrr_locality.grpc.pb.h"
32 #include "test/core/util/fake_stats_plugin.h"
33 #include "test/core/util/scoped_env_var.h"
34 #include "test/cpp/end2end/xds/xds_end2end_test_lib.h"
35 
36 namespace grpc {
37 namespace testing {
38 namespace {
39 
40 using ::envoy::extensions::load_balancing_policies::
41     client_side_weighted_round_robin::v3::ClientSideWeightedRoundRobin;
42 using ::envoy::extensions::load_balancing_policies::wrr_locality::v3::
43     WrrLocality;
44 
45 class WrrTest : public XdsEnd2endTest {
46  protected:
SetUp()47   void SetUp() override {
48     // No-op -- tests must explicitly call InitClient().
49   }
50 };
51 
52 INSTANTIATE_TEST_SUITE_P(XdsTest, WrrTest, ::testing::Values(XdsTestType()),
53                          &XdsTestType::Name);
54 
TEST_P(WrrTest,Basic)55 TEST_P(WrrTest, Basic) {
56   InitClient();
57   CreateAndStartBackends(3);
58   // Expected weights = qps / (util + (eps/qps)) =
59   //   1/(0.2+0.2) : 1/(0.3+0.3) : 2/(1.5+0.1) = 6:4:3
60   backends_[0]->server_metric_recorder()->SetQps(100);
61   backends_[0]->server_metric_recorder()->SetEps(20);
62   backends_[0]->server_metric_recorder()->SetApplicationUtilization(0.2);
63   backends_[1]->server_metric_recorder()->SetQps(100);
64   backends_[1]->server_metric_recorder()->SetEps(30);
65   backends_[1]->server_metric_recorder()->SetApplicationUtilization(0.3);
66   backends_[2]->server_metric_recorder()->SetQps(200);
67   backends_[2]->server_metric_recorder()->SetEps(20);
68   backends_[2]->server_metric_recorder()->SetApplicationUtilization(1.5);
69   auto cluster = default_cluster_;
70   WrrLocality wrr_locality;
71   wrr_locality.mutable_endpoint_picking_policy()
72       ->add_policies()
73       ->mutable_typed_extension_config()
74       ->mutable_typed_config()
75       ->PackFrom(ClientSideWeightedRoundRobin());
76   cluster.mutable_load_balancing_policy()
77       ->add_policies()
78       ->mutable_typed_extension_config()
79       ->mutable_typed_config()
80       ->PackFrom(wrr_locality);
81   balancer_->ads_service()->SetCdsResource(cluster);
82   EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
83   balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
84   size_t num_picks = 0;
85   SendRpcsUntil(DEBUG_LOCATION, [&](const RpcResult&) {
86     if (++num_picks == 13) {
87       gpr_log(GPR_INFO, "request counts: %" PRIuPTR " %" PRIuPTR " %" PRIuPTR,
88               backends_[0]->backend_service()->request_count(),
89               backends_[1]->backend_service()->request_count(),
90               backends_[2]->backend_service()->request_count());
91       if (backends_[0]->backend_service()->request_count() == 6 &&
92           backends_[1]->backend_service()->request_count() == 4 &&
93           backends_[2]->backend_service()->request_count() == 3) {
94         return false;
95       }
96       num_picks = 0;
97       ResetBackendCounters();
98     }
99     return true;
100   });
101 }
102 
TEST_P(WrrTest,MetricsHaveLocalityLabel)103 TEST_P(WrrTest, MetricsHaveLocalityLabel) {
104   const auto kEndpointWeights =
105       grpc_core::GlobalInstrumentsRegistryTestPeer::
106           FindDoubleHistogramHandleByName("grpc.lb.wrr.endpoint_weights")
107               .value();
108   const std::string target = absl::StrCat("xds:", kServerName);
109   const absl::string_view kLabelValues[] = {/*target=*/target};
110   // Register stats plugin before initializing client.
111   auto stats_plugin = grpc_core::FakeStatsPluginBuilder()
112                           .UseDisabledByDefaultMetrics(true)
113                           .BuildAndRegister();
114   InitClient();
115   CreateAndStartBackends(2);
116   auto cluster = default_cluster_;
117   WrrLocality wrr_locality;
118   wrr_locality.mutable_endpoint_picking_policy()
119       ->add_policies()
120       ->mutable_typed_extension_config()
121       ->mutable_typed_config()
122       ->PackFrom(ClientSideWeightedRoundRobin());
123   cluster.mutable_load_balancing_policy()
124       ->add_policies()
125       ->mutable_typed_extension_config()
126       ->mutable_typed_config()
127       ->PackFrom(wrr_locality);
128   balancer_->ads_service()->SetCdsResource(cluster);
129   EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)},
130                         {"locality1", CreateEndpointsForBackends(1, 2)}});
131   balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
132   WaitForAllBackends(DEBUG_LOCATION);
133   // Make sure we have a metric value for each of the two localities.
134   EXPECT_THAT(
135       stats_plugin->GetHistogramValue(kEndpointWeights, kLabelValues,
136                                       {LocalityNameString("locality0")}),
137       ::testing::Optional(::testing::Not(::testing::IsEmpty())));
138   EXPECT_THAT(
139       stats_plugin->GetHistogramValue(kEndpointWeights, kLabelValues,
140                                       {LocalityNameString("locality1")}),
141       ::testing::Optional(::testing::Not(::testing::IsEmpty())));
142 }
143 
144 }  // namespace
145 }  // namespace testing
146 }  // namespace grpc
147 
main(int argc,char ** argv)148 int main(int argc, char** argv) {
149   grpc::testing::TestEnvironment env(&argc, argv);
150   ::testing::InitGoogleTest(&argc, argv);
151   // Make the backup poller poll very frequently in order to pick up
152   // updates from all the subchannels's FDs.
153   grpc_core::ConfigVars::Overrides overrides;
154   overrides.client_channel_backup_poll_interval_ms = 1;
155   grpc_core::ConfigVars::SetOverrides(overrides);
156 #if TARGET_OS_IPHONE
157   // Workaround Apple CFStream bug
158   grpc_core::SetEnv("grpc_cfstream", "0");
159 #endif
160   grpc_init();
161   const auto result = RUN_ALL_TESTS();
162   grpc_shutdown();
163   return result;
164 }
165