xref: /aosp_15_r20/external/grpc-grpc/test/core/client_channel/lb_policy/round_robin_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 //
2 // Copyright 2022 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include <array>
18 #include <memory>
19 
20 #include "absl/status/status.h"
21 #include "absl/strings/string_view.h"
22 #include "absl/types/span.h"
23 #include "gtest/gtest.h"
24 
25 #include <grpc/grpc.h>
26 
27 #include "src/core/lib/gprpp/orphanable.h"
28 #include "src/core/lib/gprpp/ref_counted_ptr.h"
29 #include "src/core/resolver/endpoint_addresses.h"
30 #include "test/core/client_channel/lb_policy/lb_policy_test_lib.h"
31 #include "test/core/util/test_config.h"
32 
33 namespace grpc_core {
34 namespace testing {
35 namespace {
36 
37 class RoundRobinTest : public LoadBalancingPolicyTest {
38  protected:
RoundRobinTest()39   RoundRobinTest() : LoadBalancingPolicyTest("round_robin") {}
40 };
41 
TEST_F(RoundRobinTest,Basic)42 TEST_F(RoundRobinTest, Basic) {
43   const std::array<absl::string_view, 3> kAddresses = {
44       "ipv4:127.0.0.1:441", "ipv4:127.0.0.1:442", "ipv4:127.0.0.1:443"};
45   EXPECT_EQ(ApplyUpdate(BuildUpdate(kAddresses, nullptr), lb_policy()),
46             absl::OkStatus());
47   ExpectRoundRobinStartup(kAddresses);
48 }
49 
TEST_F(RoundRobinTest,AddressUpdates)50 TEST_F(RoundRobinTest, AddressUpdates) {
51   const std::array<absl::string_view, 3> kAddresses = {
52       "ipv4:127.0.0.1:441", "ipv4:127.0.0.1:442", "ipv4:127.0.0.1:443"};
53   EXPECT_EQ(ApplyUpdate(BuildUpdate(kAddresses, nullptr), lb_policy()),
54             absl::OkStatus());
55   ExpectRoundRobinStartup(kAddresses);
56   // Send update to remove address 2.
57   EXPECT_EQ(
58       ApplyUpdate(BuildUpdate(absl::MakeSpan(kAddresses).first(2), nullptr),
59                   lb_policy()),
60       absl::OkStatus());
61   WaitForRoundRobinListChange(kAddresses, absl::MakeSpan(kAddresses).first(2));
62   // Send update to remove address 0 and re-add address 2.
63   EXPECT_EQ(
64       ApplyUpdate(BuildUpdate(absl::MakeSpan(kAddresses).last(2), nullptr),
65                   lb_policy()),
66       absl::OkStatus());
67   WaitForRoundRobinListChange(absl::MakeSpan(kAddresses).first(2),
68                               absl::MakeSpan(kAddresses).last(2));
69 }
70 
TEST_F(RoundRobinTest,MultipleAddressesPerEndpoint)71 TEST_F(RoundRobinTest, MultipleAddressesPerEndpoint) {
72   constexpr std::array<absl::string_view, 2> kEndpoint1Addresses = {
73       "ipv4:127.0.0.1:443", "ipv4:127.0.0.1:444"};
74   constexpr std::array<absl::string_view, 2> kEndpoint2Addresses = {
75       "ipv4:127.0.0.1:445", "ipv4:127.0.0.1:446"};
76   const std::array<EndpointAddresses, 2> kEndpoints = {
77       MakeEndpointAddresses(kEndpoint1Addresses),
78       MakeEndpointAddresses(kEndpoint2Addresses)};
79   EXPECT_EQ(ApplyUpdate(BuildUpdate(kEndpoints, nullptr), lb_policy_.get()),
80             absl::OkStatus());
81   // RR should have created a subchannel for each address.
82   auto* subchannel1_0 = FindSubchannel(kEndpoint1Addresses[0]);
83   ASSERT_NE(subchannel1_0, nullptr) << "Address: " << kEndpoint1Addresses[0];
84   auto* subchannel1_1 = FindSubchannel(kEndpoint1Addresses[1]);
85   ASSERT_NE(subchannel1_1, nullptr) << "Address: " << kEndpoint1Addresses[1];
86   auto* subchannel2_0 = FindSubchannel(kEndpoint2Addresses[0]);
87   ASSERT_NE(subchannel2_0, nullptr) << "Address: " << kEndpoint2Addresses[0];
88   auto* subchannel2_1 = FindSubchannel(kEndpoint2Addresses[1]);
89   ASSERT_NE(subchannel2_1, nullptr) << "Address: " << kEndpoint2Addresses[1];
90   // PF for each endpoint should try to connect to the first subchannel.
91   EXPECT_TRUE(subchannel1_0->ConnectionRequested());
92   EXPECT_FALSE(subchannel1_1->ConnectionRequested());
93   EXPECT_TRUE(subchannel2_0->ConnectionRequested());
94   EXPECT_FALSE(subchannel2_1->ConnectionRequested());
95   // In the first endpoint, the first subchannel reports CONNECTING.
96   // This causes RR to report CONNECTING.
97   subchannel1_0->SetConnectivityState(GRPC_CHANNEL_CONNECTING);
98   ExpectConnectingUpdate();
99   // In the second endpoint, the first subchannel reports CONNECTING.
100   subchannel2_0->SetConnectivityState(GRPC_CHANNEL_CONNECTING);
101   // In the first endpoint, the first subchannel fails to connect.
102   // This causes PF to start a connection attempt on the second subchannel.
103   subchannel1_0->SetConnectivityState(GRPC_CHANNEL_TRANSIENT_FAILURE,
104                                       absl::UnavailableError("ugh"));
105   EXPECT_TRUE(subchannel1_1->ConnectionRequested());
106   subchannel1_1->SetConnectivityState(GRPC_CHANNEL_CONNECTING);
107   // In the second endpoint, the first subchannel becomes connected.
108   // This causes RR to report READY with all RPCs going to a single address.
109   subchannel2_0->SetConnectivityState(GRPC_CHANNEL_READY);
110   auto picker = WaitForConnected();
111   ExpectRoundRobinPicks(picker.get(), {kEndpoint2Addresses[0]});
112   // In the first endpoint, the second subchannel becomes connected.
113   // This causes RR to add it to the rotation.
114   subchannel1_1->SetConnectivityState(GRPC_CHANNEL_READY);
115   WaitForRoundRobinListChange({kEndpoint2Addresses[0]},
116                               {kEndpoint1Addresses[1], kEndpoint2Addresses[0]});
117   // No more connection attempts triggered.
118   EXPECT_FALSE(subchannel1_0->ConnectionRequested());
119   EXPECT_FALSE(subchannel1_1->ConnectionRequested());
120   EXPECT_FALSE(subchannel2_0->ConnectionRequested());
121   EXPECT_FALSE(subchannel2_1->ConnectionRequested());
122   // First endpoint first subchannel finishes backoff, but this doesn't
123   // affect anything -- in fact, PF isn't even watching this subchannel
124   // anymore, since it's connected to the other one.  However, this
125   // ensures that the subchannel is in the right state when we try to
126   // reconnect below.
127   subchannel1_0->SetConnectivityState(GRPC_CHANNEL_IDLE);
128   EXPECT_FALSE(subchannel1_0->ConnectionRequested());
129   // Endpoint 1 switches to a different address.
130   ExpectEndpointAddressChange(kEndpoint1Addresses, 1, 0, [&]() {
131     // RR will remove the endpoint from the rotation when it becomes
132     // disconnected.
133     WaitForRoundRobinListChange(
134         {kEndpoint1Addresses[1], kEndpoint2Addresses[0]},
135         {kEndpoint2Addresses[0]});
136   });
137   // Then RR will re-add the endpoint with the new address.
138   WaitForRoundRobinListChange({kEndpoint2Addresses[0]},
139                               {kEndpoint1Addresses[0], kEndpoint2Addresses[0]});
140   // No more connection attempts triggered.
141   EXPECT_FALSE(subchannel1_0->ConnectionRequested());
142   EXPECT_FALSE(subchannel1_1->ConnectionRequested());
143   EXPECT_FALSE(subchannel2_0->ConnectionRequested());
144   EXPECT_FALSE(subchannel2_1->ConnectionRequested());
145 }
146 
147 // TODO(roth): Add test cases:
148 // - empty address list
149 // - subchannels failing connection attempts
150 
151 }  // namespace
152 }  // namespace testing
153 }  // namespace grpc_core
154 
main(int argc,char ** argv)155 int main(int argc, char** argv) {
156   ::testing::InitGoogleTest(&argc, argv);
157   grpc::testing::TestEnvironment env(&argc, argv);
158   return RUN_ALL_TESTS();
159 }
160