xref: /aosp_15_r20/external/grpc-grpc/test/cpp/end2end/xds/xds_pick_first_end2end_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 // Copyright 2017 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 <unistd.h>
17 
18 #include <cstddef>
19 #include <optional>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include <gmock/gmock.h>
25 #include <gtest/gtest.h>
26 
27 #include "absl/strings/str_cat.h"
28 
29 #include <grpc/event_engine/endpoint_config.h>
30 #include <grpcpp/support/status.h>
31 
32 #include "src/core/client_channel/backup_poller.h"
33 #include "src/core/lib/address_utils/sockaddr_utils.h"
34 #include "src/core/lib/config/config_vars.h"
35 #include "src/core/lib/gprpp/env.h"
36 #include "src/core/load_balancing/xds/xds_channel_args.h"
37 #include "src/core/resolver/fake/fake_resolver.h"
38 #include "src/proto/grpc/testing/xds/v3/cluster.grpc.pb.h"
39 #include "src/proto/grpc/testing/xds/v3/pick_first.pb.h"
40 #include "test/core/util/test_config.h"
41 #include "test/cpp/end2end/connection_attempt_injector.h"
42 #include "test/cpp/end2end/xds/xds_end2end_test_lib.h"
43 
44 namespace grpc {
45 namespace testing {
46 namespace {
47 
48 using ::envoy::extensions::load_balancing_policies::pick_first::v3::PickFirst;
49 
50 class PickFirstTest : public XdsEnd2endTest {
51  protected:
52   // Sends RPCs until one of them lands on a backend in the specified range, in
53   // which case it returns the index of that backend. Returns an error status if
54   // any of the RPCs fails.
WaitForAnyBackendHit(size_t start,size_t end)55   absl::StatusOr<size_t> WaitForAnyBackendHit(size_t start, size_t end) {
56     absl::StatusOr<size_t> output;
57     SendRpcsUntil(DEBUG_LOCATION, [&](const RpcResult& result) -> bool {
58       if (!result.status.ok()) {
59         output = absl::Status(
60             static_cast<absl::StatusCode>(result.status.error_code()),
61             result.status.error_message());
62         return false;
63       }
64       for (size_t i = start; i < end; ++i) {
65         if (backends_[i]->backend_service()->request_count() > 0) {
66           backends_[i]->backend_service()->ResetCounters();
67           output = i;
68           return false;
69         }
70       }
71       return true;
72     });
73     return output;
74   }
75 };
76 
77 // Run both with and without load reporting, just for test coverage.
78 INSTANTIATE_TEST_SUITE_P(XdsTest, PickFirstTest,
79                          ::testing::Values(XdsTestType()), &XdsTestType::Name);
80 
TEST_P(PickFirstTest,PickFirstConfigurationIsPropagated)81 TEST_P(PickFirstTest, PickFirstConfigurationIsPropagated) {
82   CreateAndStartBackends(6);
83   // Change cluster to use pick_first with shuffle option.
84   auto cluster = default_cluster_;
85   PickFirst pick_first;
86   pick_first.set_shuffle_address_list(true);
87   cluster.mutable_load_balancing_policy()
88       ->add_policies()
89       ->mutable_typed_extension_config()
90       ->mutable_typed_config()
91       ->PackFrom(pick_first);
92   balancer_->ads_service()->SetCdsResource(cluster);
93   size_t start_index = 0;
94   for (size_t i = 0; i < 100; ++i) {
95     // Update EDS resource.  This will send a new address list update to the LB
96     // policy.
97     balancer_->ads_service()->SetEdsResource(BuildEdsResource(
98         EdsResourceArgs({{"locality0", CreateEndpointsForBackends(
99                                            start_index, start_index + 3)}})));
100     auto result = WaitForAnyBackendHit(start_index, start_index + 3);
101     ASSERT_TRUE(result.ok()) << result.status();
102     if (*result != start_index) return;
103     // Toggle between backends 0-2 and 3-5
104     start_index = 3 - start_index;
105   }
106   FAIL() << "did not choose a different backend";
107 }
108 }  // namespace
109 }  // namespace testing
110 }  // namespace grpc
111 
main(int argc,char ** argv)112 int main(int argc, char** argv) {
113   grpc::testing::TestEnvironment env(&argc, argv);
114   ::testing::InitGoogleTest(&argc, argv);
115   // Make the backup poller poll very frequently in order to pick up
116   // updates from all the subchannels's FDs.
117   grpc_core::ConfigVars::Overrides overrides;
118   overrides.client_channel_backup_poll_interval_ms = 1;
119   grpc_core::ConfigVars::SetOverrides(overrides);
120 #if TARGET_OS_IPHONE
121   // Workaround Apple CFStream bug
122   grpc_core::SetEnv("grpc_cfstream", "0");
123 #endif
124   grpc_init();
125   grpc::testing::ConnectionAttemptInjector::Init();
126   const auto result = RUN_ALL_TESTS();
127   grpc_shutdown();
128   return result;
129 }
130