xds_rls_end2end_test.cc
Go to the documentation of this file.
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 <memory>
17 
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 
21 #include "absl/memory/memory.h"
22 #include "absl/strings/str_cat.h"
23 
25 #include "src/core/lib/gpr/env.h"
26 #include "src/proto/grpc/lookup/v1/rls.grpc.pb.h"
27 #include "src/proto/grpc/lookup/v1/rls.pb.h"
28 #include "src/proto/grpc/lookup/v1/rls_config.pb.h"
31 
32 namespace grpc {
33 namespace testing {
34 namespace {
35 
36 using ::grpc::lookup::v1::RouteLookupClusterSpecifier;
37 using ::grpc::lookup::v1::RouteLookupConfig;
38 
39 constexpr char kRlsTestKey[] = "test_key";
40 constexpr char kRlsTestKey1[] = "key1";
41 constexpr char kRlsTestValue[] = "test_value";
42 constexpr char kRlsHostKey[] = "host_key";
43 constexpr char kRlsServiceKey[] = "service_key";
44 constexpr char kRlsServiceValue[] = "grpc.testing.EchoTestService";
45 constexpr char kRlsMethodKey[] = "method_key";
46 constexpr char kRlsMethodValue[] = "Echo";
47 constexpr char kRlsConstantKey[] = "constant_key";
48 constexpr char kRlsConstantValue[] = "constant_value";
49 constexpr char kRlsClusterSpecifierPluginInstanceName[] = "rls_plugin_instance";
50 
51 class RlsTest : public XdsEnd2endTest {
52  protected:
53  class RlsServerThread : public ServerThread {
54  public:
55  explicit RlsServerThread(XdsEnd2endTest* test_obj)
56  : ServerThread(test_obj, /*use_xds_enabled_server=*/false),
57  rls_service_(new RlsServiceImpl()) {}
58 
59  RlsServiceImpl* rls_service() { return rls_service_.get(); }
60 
61  private:
62  const char* Type() override { return "Rls"; }
63 
64  void RegisterAllServices(ServerBuilder* builder) override {
65  builder->RegisterService(rls_service_.get());
66  }
67 
68  void StartAllServices() override { rls_service_->Start(); }
69 
70  void ShutdownAllServices() override { rls_service_->Shutdown(); }
71 
72  std::shared_ptr<RlsServiceImpl> rls_service_;
73  };
74 
75  RlsTest() {
76  rls_server_ = absl::make_unique<RlsServerThread>(this);
77  rls_server_->Start();
78  }
79 
80  void TearDown() override {
81  rls_server_->Shutdown();
83  }
84 
85  std::unique_ptr<RlsServerThread> rls_server_;
86 };
87 
88 // Test both with and without RDS.
90  XdsTest, RlsTest,
91  ::testing::Values(XdsTestType(), XdsTestType().set_enable_rds_testing(),
92  // Also test with xDS v2.
93  XdsTestType().set_enable_rds_testing().set_use_v2()),
95 
96 TEST_P(RlsTest, XdsRoutingClusterSpecifierPlugin) {
97  ScopedExperimentalEnvVar env_var("GRPC_EXPERIMENTAL_XDS_RLS_LB");
98  CreateAndStartBackends(2);
99  const char* kNewClusterName = "new_cluster";
100  const char* kNewEdsServiceName = "new_eds_service_name";
101  const size_t kNumEchoRpcs = 5;
102  // Populate new EDS resources.
103  EdsResourceArgs args({
104  {"locality0", CreateEndpointsForBackends(0, 1)},
105  });
106  EdsResourceArgs args1({
107  {"locality0", CreateEndpointsForBackends(1, 2)},
108  });
109  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
110  balancer_->ads_service()->SetEdsResource(
111  BuildEdsResource(args1, kNewEdsServiceName));
112  // Populate new CDS resources.
113  Cluster new_cluster = default_cluster_;
114  new_cluster.set_name(kNewClusterName);
115  new_cluster.mutable_eds_cluster_config()->set_service_name(
116  kNewEdsServiceName);
117  balancer_->ads_service()->SetCdsResource(new_cluster);
118  // Prepare the RLSLookupConfig and configure all the keys; change route
119  // configurations to use cluster specifier plugin.
120  rls_server_->rls_service()->SetResponse(
121  BuildRlsRequest({{kRlsTestKey, kRlsTestValue},
122  {kRlsHostKey, kServerName},
123  {kRlsServiceKey, kRlsServiceValue},
124  {kRlsMethodKey, kRlsMethodValue},
125  {kRlsConstantKey, kRlsConstantValue}}),
126  BuildRlsResponse({kNewClusterName}));
127  RouteLookupConfig route_lookup_config;
128  auto* key_builder = route_lookup_config.add_grpc_keybuilders();
129  auto* name = key_builder->add_names();
130  name->set_service(kRlsServiceValue);
131  name->set_method(kRlsMethodValue);
132  auto* header = key_builder->add_headers();
133  header->set_key(kRlsTestKey);
134  header->add_names(kRlsTestKey1);
135  header->add_names("key2");
136  auto* extra_keys = key_builder->mutable_extra_keys();
137  extra_keys->set_host(kRlsHostKey);
138  extra_keys->set_service(kRlsServiceKey);
139  extra_keys->set_method(kRlsMethodKey);
140  (*key_builder->mutable_constant_keys())[kRlsConstantKey] = kRlsConstantValue;
141  route_lookup_config.set_lookup_service(
142  absl::StrCat("localhost:", rls_server_->port()));
143  route_lookup_config.set_cache_size_bytes(5000);
144  RouteLookupClusterSpecifier rls;
145  *rls.mutable_route_lookup_config() = std::move(route_lookup_config);
146  RouteConfiguration new_route_config = default_route_config_;
147  auto* plugin = new_route_config.add_cluster_specifier_plugins();
148  plugin->mutable_extension()->set_name(kRlsClusterSpecifierPluginInstanceName);
149  plugin->mutable_extension()->mutable_typed_config()->PackFrom(rls);
150  auto* default_route =
151  new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
152  default_route->mutable_route()->set_cluster_specifier_plugin(
153  kRlsClusterSpecifierPluginInstanceName);
154  SetRouteConfiguration(balancer_.get(), new_route_config);
155  auto rpc_options = RpcOptions().set_metadata({{kRlsTestKey1, kRlsTestValue}});
156  WaitForAllBackends(DEBUG_LOCATION, 1, 2, /*check_status=*/nullptr,
157  WaitForBackendOptions(), rpc_options);
158  CheckRpcSendOk(DEBUG_LOCATION, kNumEchoRpcs, rpc_options);
159  // Make sure RPCs all go to the correct backend.
160  EXPECT_EQ(kNumEchoRpcs, backends_[1]->backend_service()->request_count());
161 }
162 
163 TEST_P(RlsTest, XdsRoutingClusterSpecifierPluginNacksUndefinedSpecifier) {
164  ScopedExperimentalEnvVar env_var("GRPC_EXPERIMENTAL_XDS_RLS_LB");
165  RouteConfiguration new_route_config = default_route_config_;
166  auto* default_route =
167  new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
168  // Set Cluster Specifier Plugin to something that does not exist.
169  default_route->mutable_route()->set_cluster_specifier_plugin(
170  kRlsClusterSpecifierPluginInstanceName);
171  SetRouteConfiguration(balancer_.get(), new_route_config);
172  const auto response_state = WaitForRdsNack(DEBUG_LOCATION);
173  ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
174  EXPECT_THAT(response_state->error_message,
176  "RouteAction cluster contains cluster specifier plugin "
177  "name not configured: ",
178  kRlsClusterSpecifierPluginInstanceName)));
179 }
180 
181 TEST_P(RlsTest, XdsRoutingClusterSpecifierPluginNacksDuplicateSpecifier) {
182  ScopedExperimentalEnvVar env_var("GRPC_EXPERIMENTAL_XDS_RLS_LB");
183  // Prepare the RLSLookupConfig: change route configurations to use cluster
184  // specifier plugin.
185  RouteLookupConfig route_lookup_config;
186  auto* key_builder = route_lookup_config.add_grpc_keybuilders();
187  auto* name = key_builder->add_names();
188  name->set_service(kRlsServiceValue);
189  name->set_method(kRlsMethodValue);
190  auto* header = key_builder->add_headers();
191  header->set_key(kRlsTestKey);
192  header->add_names(kRlsTestKey1);
193  route_lookup_config.set_lookup_service(
194  absl::StrCat("localhost:", rls_server_->port()));
195  route_lookup_config.set_cache_size_bytes(5000);
196  RouteLookupClusterSpecifier rls;
197  *rls.mutable_route_lookup_config() = std::move(route_lookup_config);
198  RouteConfiguration new_route_config = default_route_config_;
199  auto* plugin = new_route_config.add_cluster_specifier_plugins();
200  plugin->mutable_extension()->set_name(kRlsClusterSpecifierPluginInstanceName);
201  plugin->mutable_extension()->mutable_typed_config()->PackFrom(rls);
202  auto* duplicate_plugin = new_route_config.add_cluster_specifier_plugins();
203  duplicate_plugin->mutable_extension()->set_name(
204  kRlsClusterSpecifierPluginInstanceName);
205  duplicate_plugin->mutable_extension()->mutable_typed_config()->PackFrom(rls);
206  auto* default_route =
207  new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
208  default_route->mutable_route()->set_cluster_specifier_plugin(
209  kRlsClusterSpecifierPluginInstanceName);
210  SetRouteConfiguration(balancer_.get(), new_route_config);
211  const auto response_state = WaitForRdsNack(DEBUG_LOCATION);
212  ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
213  EXPECT_THAT(response_state->error_message,
215  "Duplicated definition of cluster_specifier_plugin ",
216  kRlsClusterSpecifierPluginInstanceName)));
217 }
218 
219 TEST_P(RlsTest,
220  XdsRoutingClusterSpecifierPluginNacksUnknownSpecifierProtoNotOptional) {
221  ScopedExperimentalEnvVar env_var("GRPC_EXPERIMENTAL_XDS_RLS_LB");
222  // Prepare the RLSLookupConfig: change route configurations to use cluster
223  // specifier plugin.
224  RouteLookupConfig route_lookup_config;
225  RouteConfiguration new_route_config = default_route_config_;
226  auto* plugin = new_route_config.add_cluster_specifier_plugins();
227  plugin->mutable_extension()->set_name(kRlsClusterSpecifierPluginInstanceName);
228  // Instead of grpc.lookup.v1.RouteLookupClusterSpecifier, let's say we
229  // mistakenly packed the inner RouteLookupConfig instead.
230  plugin->mutable_extension()->mutable_typed_config()->PackFrom(
231  route_lookup_config);
232  auto* default_route =
233  new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
234  default_route->mutable_route()->set_cluster_specifier_plugin(
235  kRlsClusterSpecifierPluginInstanceName);
236  SetRouteConfiguration(balancer_.get(), new_route_config);
237  const auto response_state = WaitForRdsNack(DEBUG_LOCATION);
238  ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
239  EXPECT_THAT(response_state->error_message,
240  ::testing::HasSubstr("Unknown ClusterSpecifierPlugin type "
241  "grpc.lookup.v1.RouteLookupConfig"));
242 }
243 
244 TEST_P(RlsTest,
245  XdsRoutingClusterSpecifierPluginIgnoreUnknownSpecifierProtoOptional) {
246  ScopedExperimentalEnvVar env_var("GRPC_EXPERIMENTAL_XDS_RLS_LB");
247  CreateAndStartBackends(1);
248  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
249  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
250  // Prepare the RLSLookupConfig: change route configurations to use cluster
251  // specifier plugin.
252  RouteLookupConfig route_lookup_config;
253  RouteConfiguration new_route_config = default_route_config_;
254  auto* plugin = new_route_config.add_cluster_specifier_plugins();
255  plugin->mutable_extension()->set_name(kRlsClusterSpecifierPluginInstanceName);
256  // Instead of grpc.lookup.v1.RouteLookupClusterSpecifier, let's say we
257  // mistakenly packed the inner RouteLookupConfig instead.
258  plugin->mutable_extension()->mutable_typed_config()->PackFrom(
259  route_lookup_config);
260  plugin->set_is_optional(true);
261  auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
262  route->mutable_route()->set_cluster_specifier_plugin(
263  kRlsClusterSpecifierPluginInstanceName);
264  auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
265  default_route->mutable_match()->set_prefix("");
266  default_route->mutable_route()->set_cluster(kDefaultClusterName);
267  SetRouteConfiguration(balancer_.get(), new_route_config);
268  // Ensure we ignore the cluster specifier plugin and send traffic according to
269  // the default route.
270  WaitForAllBackends(DEBUG_LOCATION);
271 }
272 
273 TEST_P(RlsTest, XdsRoutingRlsClusterSpecifierPluginNacksRequiredMatch) {
274  ScopedExperimentalEnvVar env_var("GRPC_EXPERIMENTAL_XDS_RLS_LB");
275  // Prepare the RLSLookupConfig and configure all the keys; add required_match
276  // field which should not be there.
277  RouteLookupConfig route_lookup_config;
278  auto* key_builder = route_lookup_config.add_grpc_keybuilders();
279  auto* name = key_builder->add_names();
280  name->set_service(kRlsServiceValue);
281  name->set_method(kRlsMethodValue);
282  auto* header = key_builder->add_headers();
283  header->set_key(kRlsTestKey);
284  header->add_names(kRlsTestKey1);
285  header->set_required_match(true);
286  route_lookup_config.set_lookup_service(
287  absl::StrCat("localhost:", rls_server_->port()));
288  route_lookup_config.set_cache_size_bytes(5000);
289  RouteLookupClusterSpecifier rls;
290  *rls.mutable_route_lookup_config() = std::move(route_lookup_config);
291  RouteConfiguration new_route_config = default_route_config_;
292  auto* plugin = new_route_config.add_cluster_specifier_plugins();
293  plugin->mutable_extension()->set_name(kRlsClusterSpecifierPluginInstanceName);
294  plugin->mutable_extension()->mutable_typed_config()->PackFrom(rls);
295  auto* default_route =
296  new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
297  default_route->mutable_route()->set_cluster_specifier_plugin(
298  kRlsClusterSpecifierPluginInstanceName);
299  SetRouteConfiguration(balancer_.get(), new_route_config);
300  const auto response_state = WaitForRdsNack(DEBUG_LOCATION);
301  ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
302  EXPECT_THAT(
303  response_state->error_message,
304  ::testing::HasSubstr("field:requiredMatch error:must not be present"));
305 }
306 
307 TEST_P(RlsTest, XdsRoutingClusterSpecifierPluginDisabled) {
308  CreateAndStartBackends(1);
309  // Populate new EDS resources.
310  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
311  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
312  // Prepare the RLSLookupConfig and configure all the keys; change route
313  // configurations to use cluster specifier plugin.
314  RouteLookupConfig route_lookup_config;
315  auto* key_builder = route_lookup_config.add_grpc_keybuilders();
316  auto* name = key_builder->add_names();
317  name->set_service(kRlsServiceValue);
318  name->set_method(kRlsMethodValue);
319  auto* header = key_builder->add_headers();
320  header->set_key(kRlsTestKey);
321  header->add_names(kRlsTestKey1);
322  route_lookup_config.set_lookup_service(
323  absl::StrCat("localhost:", rls_server_->port()));
324  route_lookup_config.set_cache_size_bytes(5000);
325  RouteLookupClusterSpecifier rls;
326  *rls.mutable_route_lookup_config() = std::move(route_lookup_config);
327  RouteConfiguration new_route_config = default_route_config_;
328  auto* plugin = new_route_config.add_cluster_specifier_plugins();
329  plugin->mutable_extension()->set_name(kRlsClusterSpecifierPluginInstanceName);
330  plugin->mutable_extension()->mutable_typed_config()->PackFrom(rls);
331  auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
332  route->mutable_route()->set_cluster_specifier_plugin(
333  kRlsClusterSpecifierPluginInstanceName);
334  auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
335  default_route->mutable_match()->set_prefix("");
336  default_route->mutable_route()->set_cluster(kDefaultClusterName);
337  SetRouteConfiguration(balancer_.get(), new_route_config);
338  // Ensure we ignore the cluster specifier plugin and send traffic according to
339  // the default route.
340  auto rpc_options = RpcOptions().set_metadata({{kRlsTestKey1, kRlsTestValue}});
341  WaitForAllBackends(DEBUG_LOCATION, 0, 1, /*check_status=*/nullptr,
342  WaitForBackendOptions(), rpc_options);
343 }
344 
345 } // namespace
346 } // namespace testing
347 } // namespace grpc
348 
349 int main(int argc, char** argv) {
350  grpc::testing::TestEnvironment env(&argc, argv);
351  ::testing::InitGoogleTest(&argc, argv);
352  // Make the backup poller poll very frequently in order to pick up
353  // updates from all the subchannels's FDs.
354  GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
355 #if TARGET_OS_IPHONE
356  // Workaround Apple CFStream bug
357  gpr_setenv("grpc_cfstream", "0");
358 #endif
359  grpc_init();
360  const auto result = RUN_ALL_TESTS();
361  grpc_shutdown();
362  return result;
363 }
grpc::EXPECT_THAT
EXPECT_THAT(status.error_message(), ::testing::HasSubstr("subject_token_type"))
grpc::testing::XdsEnd2endTest::TearDown
void TearDown() override
Definition: xds_end2end_test_lib.cc:519
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
Type
struct Type Type
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:673
testing
Definition: aws_request_signer_test.cc:25
main
int main(int argc, char **argv)
Definition: xds_rls_end2end_test.cc:349
env_var
Definition: win/process.c:40
generate.env
env
Definition: generate.py:37
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
grpc
Definition: grpcpp/alarm.h:33
route
XdsRouteConfigResource::Route route
Definition: xds_resolver.cc:337
false
#define false
Definition: setup_once.h:323
backends_
std::vector< std::unique_ptr< BackendServiceImpl > > backends_
Definition: client_channel_stress_test.cc:333
rls_server_
std::unique_ptr< RlsServerThread > rls_server_
Definition: xds_rls_end2end_test.cc:85
setup.name
name
Definition: setup.py:542
env.h
env.new
def new
Definition: env.py:51
DEBUG_LOCATION
#define DEBUG_LOCATION
Definition: debug_location.h:41
profile_analyzer.builder
builder
Definition: profile_analyzer.py:159
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
header
struct absl::base_internal::@2940::AllocList::Header header
xds_end2end_test_lib.h
grpc::testing::INSTANTIATE_TEST_SUITE_P
INSTANTIATE_TEST_SUITE_P(HistogramTestCases, HistogramTest, ::testing::Range< int >(0, GRPC_STATS_HISTOGRAM_COUNT))
backup_poller.h
RUN_ALL_TESTS
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2471
rls_service_
std::shared_ptr< RlsServiceImpl > rls_service_
Definition: xds_rls_end2end_test.cc:72
GPR_GLOBAL_CONFIG_SET
#define GPR_GLOBAL_CONFIG_SET(name, value)
Definition: global_config_generic.h:26
grpc::testing::BuildRlsRequest
grpc::lookup::v1::RouteLookupRequest BuildRlsRequest(std::map< std::string, std::string > key, grpc::lookup::v1::RouteLookupRequest::Reason reason, const char *stale_header_data)
Definition: rls_server.cc:82
testing::InitGoogleTest
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: bloaty/third_party/googletest/googletest/src/gtest.cc:6106
testing::Values
internal::ValueArray< T... > Values(T... v)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:335
grpc::testing::TestEnvironment
Definition: test/core/util/test_config.h:54
ASSERT_TRUE
#define ASSERT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1973
grpc::testing::EXPECT_EQ
EXPECT_EQ(options.token_exchange_service_uri, "https://foo/exchange")
rls_server.h
grpc::testing::BuildRlsResponse
grpc::lookup::v1::RouteLookupResponse BuildRlsResponse(std::vector< std::string > targets, const char *header_data)
Definition: rls_server.cc:94
grpc::testing::TEST_P
TEST_P(HistogramTest, IncHistogram)
Definition: stats_test.cc:87
run_xds_tests.backend_service
def backend_service
Definition: run_xds_tests.py:3255
grpc_init
GRPCAPI void grpc_init(void)
Definition: init.cc:146
testing::HasSubstr
PolymorphicMatcher< internal::HasSubstrMatcher< internal::string > > HasSubstr(const internal::string &substring)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8803
grpc_shutdown
GRPCAPI void grpc_shutdown(void)
Definition: init.cc:209
grpc::testing::XdsTestType::Name
static std::string Name(const ::testing::TestParamInfo< XdsTestType > &info)
Definition: xds_end2end_test_lib.h:143
gpr_setenv
void gpr_setenv(const char *name, const char *value)


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:59