• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <grpc/grpc.h>
18 
19 #include <array>
20 #include <memory>
21 
22 #include "absl/status/status.h"
23 #include "absl/strings/string_view.h"
24 #include "absl/types/span.h"
25 #include "gtest/gtest.h"
26 #include "src/core/resolver/endpoint_addresses.h"
27 #include "src/core/util/orphanable.h"
28 #include "src/core/util/ref_counted_ptr.h"
29 #include "test/core/load_balancing/lb_policy_test_lib.h"
30 #include "test/core/test_util/test_config.h"
31 
32 namespace grpc_core {
33 namespace testing {
34 namespace {
35 
36 class RoundRobinTest : public LoadBalancingPolicyTest {
37  protected:
RoundRobinTest()38   RoundRobinTest() : LoadBalancingPolicyTest("round_robin") {}
39 };
40 
TEST_F(RoundRobinTest,Basic)41 TEST_F(RoundRobinTest, Basic) {
42   const std::array<absl::string_view, 3> kAddresses = {
43       "ipv4:127.0.0.1:441", "ipv4:127.0.0.1:442", "ipv4:127.0.0.1:443"};
44   EXPECT_EQ(ApplyUpdate(BuildUpdate(kAddresses, nullptr), lb_policy()),
45             absl::OkStatus());
46   ExpectRoundRobinStartup(kAddresses);
47 }
48 
TEST_F(RoundRobinTest,AddressUpdates)49 TEST_F(RoundRobinTest, AddressUpdates) {
50   const std::array<absl::string_view, 3> kAddresses = {
51       "ipv4:127.0.0.1:441", "ipv4:127.0.0.1:442", "ipv4:127.0.0.1:443"};
52   EXPECT_EQ(ApplyUpdate(BuildUpdate(kAddresses, nullptr), lb_policy()),
53             absl::OkStatus());
54   ExpectRoundRobinStartup(kAddresses);
55   // Send update to remove address 2.
56   EXPECT_EQ(
57       ApplyUpdate(BuildUpdate(absl::MakeSpan(kAddresses).first(2), nullptr),
58                   lb_policy()),
59       absl::OkStatus());
60   WaitForRoundRobinListChange(kAddresses, absl::MakeSpan(kAddresses).first(2));
61   // Send update to remove address 0 and re-add address 2.
62   EXPECT_EQ(
63       ApplyUpdate(BuildUpdate(absl::MakeSpan(kAddresses).last(2), nullptr),
64                   lb_policy()),
65       absl::OkStatus());
66   WaitForRoundRobinListChange(absl::MakeSpan(kAddresses).first(2),
67                               absl::MakeSpan(kAddresses).last(2));
68 }
69 
TEST_F(RoundRobinTest,MultipleAddressesPerEndpoint)70 TEST_F(RoundRobinTest, MultipleAddressesPerEndpoint) {
71   constexpr std::array<absl::string_view, 2> kEndpoint1Addresses = {
72       "ipv4:127.0.0.1:443", "ipv4:127.0.0.1:444"};
73   constexpr std::array<absl::string_view, 2> kEndpoint2Addresses = {
74       "ipv4:127.0.0.1:445", "ipv4:127.0.0.1:446"};
75   const std::array<EndpointAddresses, 2> kEndpoints = {
76       MakeEndpointAddresses(kEndpoint1Addresses),
77       MakeEndpointAddresses(kEndpoint2Addresses)};
78   EXPECT_EQ(ApplyUpdate(BuildUpdate(kEndpoints, nullptr), lb_policy_.get()),
79             absl::OkStatus());
80   // RR should have created a subchannel for each address.
81   auto* subchannel1_0 = FindSubchannel(kEndpoint1Addresses[0]);
82   ASSERT_NE(subchannel1_0, nullptr) << "Address: " << kEndpoint1Addresses[0];
83   auto* subchannel1_1 = FindSubchannel(kEndpoint1Addresses[1]);
84   ASSERT_NE(subchannel1_1, nullptr) << "Address: " << kEndpoint1Addresses[1];
85   auto* subchannel2_0 = FindSubchannel(kEndpoint2Addresses[0]);
86   ASSERT_NE(subchannel2_0, nullptr) << "Address: " << kEndpoint2Addresses[0];
87   auto* subchannel2_1 = FindSubchannel(kEndpoint2Addresses[1]);
88   ASSERT_NE(subchannel2_1, nullptr) << "Address: " << kEndpoint2Addresses[1];
89   // PF for each endpoint should try to connect to the first subchannel.
90   EXPECT_TRUE(subchannel1_0->ConnectionRequested());
91   EXPECT_FALSE(subchannel1_1->ConnectionRequested());
92   EXPECT_TRUE(subchannel2_0->ConnectionRequested());
93   EXPECT_FALSE(subchannel2_1->ConnectionRequested());
94   // In the first endpoint, the first subchannel reports CONNECTING.
95   // This causes RR to report CONNECTING.
96   subchannel1_0->SetConnectivityState(GRPC_CHANNEL_CONNECTING);
97   ExpectConnectingUpdate();
98   // In the second endpoint, the first subchannel reports CONNECTING.
99   subchannel2_0->SetConnectivityState(GRPC_CHANNEL_CONNECTING);
100   // In the first endpoint, the first subchannel fails to connect.
101   // This causes PF to start a connection attempt on the second subchannel.
102   subchannel1_0->SetConnectivityState(GRPC_CHANNEL_TRANSIENT_FAILURE,
103                                       absl::UnavailableError("ugh"));
104   EXPECT_TRUE(subchannel1_1->ConnectionRequested());
105   subchannel1_1->SetConnectivityState(GRPC_CHANNEL_CONNECTING);
106   // In the second endpoint, the first subchannel becomes connected.
107   // This causes RR to report READY with all RPCs going to a single address.
108   subchannel2_0->SetConnectivityState(GRPC_CHANNEL_READY);
109   auto picker = WaitForConnected();
110   ExpectRoundRobinPicks(picker.get(), {kEndpoint2Addresses[0]});
111   // In the first endpoint, the second subchannel becomes connected.
112   // This causes RR to add it to the rotation.
113   subchannel1_1->SetConnectivityState(GRPC_CHANNEL_READY);
114   WaitForRoundRobinListChange({kEndpoint2Addresses[0]},
115                               {kEndpoint1Addresses[1], kEndpoint2Addresses[0]});
116   // No more connection attempts triggered.
117   EXPECT_FALSE(subchannel1_0->ConnectionRequested());
118   EXPECT_FALSE(subchannel1_1->ConnectionRequested());
119   EXPECT_FALSE(subchannel2_0->ConnectionRequested());
120   EXPECT_FALSE(subchannel2_1->ConnectionRequested());
121   // First endpoint first subchannel finishes backoff, but this doesn't
122   // affect anything -- in fact, PF isn't even watching this subchannel
123   // anymore, since it's connected to the other one.  However, this
124   // ensures that the subchannel is in the right state when we try to
125   // reconnect below.
126   subchannel1_0->SetConnectivityState(GRPC_CHANNEL_IDLE);
127   EXPECT_FALSE(subchannel1_0->ConnectionRequested());
128   // Endpoint 1 switches to a different address.
129   ExpectEndpointAddressChange(kEndpoint1Addresses, 1, 0, [&]() {
130     // RR will remove the endpoint from the rotation when it becomes
131     // disconnected.
132     WaitForRoundRobinListChange(
133         {kEndpoint1Addresses[1], kEndpoint2Addresses[0]},
134         {kEndpoint2Addresses[0]});
135   });
136   // Then RR will re-add the endpoint with the new address.
137   WaitForRoundRobinListChange({kEndpoint2Addresses[0]},
138                               {kEndpoint1Addresses[0], kEndpoint2Addresses[0]});
139   // No more connection attempts triggered.
140   EXPECT_FALSE(subchannel1_0->ConnectionRequested());
141   EXPECT_FALSE(subchannel1_1->ConnectionRequested());
142   EXPECT_FALSE(subchannel2_0->ConnectionRequested());
143   EXPECT_FALSE(subchannel2_1->ConnectionRequested());
144 }
145 
146 // TODO(roth): Add test cases:
147 // - empty address list
148 // - subchannels failing connection attempts
149 
150 }  // namespace
151 }  // namespace testing
152 }  // namespace grpc_core
153 
main(int argc,char ** argv)154 int main(int argc, char** argv) {
155   ::testing::InitGoogleTest(&argc, argv);
156   grpc::testing::TestEnvironment env(&argc, argv);
157   return RUN_ALL_TESTS();
158 }
159