xds_csds_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 #include <string>
18 #include <vector>
19 
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 
23 #include "absl/memory/memory.h"
24 #include "absl/strings/str_cat.h"
25 
26 #include <grpcpp/create_channel.h>
28 
31 #include "src/proto/grpc/testing/xds/v3/cluster.grpc.pb.h"
32 #include "src/proto/grpc/testing/xds/v3/endpoint.grpc.pb.h"
33 #include "src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.h"
34 #include "src/proto/grpc/testing/xds/v3/listener.grpc.pb.h"
35 #include "src/proto/grpc/testing/xds/v3/route.grpc.pb.h"
38 
39 #ifndef DISABLED_XDS_PROTO_IN_CC
40 
42 #include "src/proto/grpc/testing/xds/v3/csds.grpc.pb.h"
43 
44 namespace grpc {
45 namespace testing {
46 namespace {
47 
48 using ::envoy::admin::v3::ClientResourceStatus;
49 using ::envoy::config::cluster::v3::Cluster;
50 using ::envoy::config::endpoint::v3::ClusterLoadAssignment;
52 using ::envoy::config::route::v3::RouteConfiguration;
53 using ::envoy::extensions::filters::network::http_connection_manager::v3::
54  HttpConnectionManager;
55 
56 MATCHER_P4(EqNode, id, user_agent_name, user_agent_version, client_features,
57  "equals Node") {
58  bool ok = true;
59  ok &= ::testing::ExplainMatchResult(id, arg.id(), result_listener);
60  ok &= ::testing::ExplainMatchResult(user_agent_name, arg.user_agent_name(),
61  result_listener);
63  user_agent_version, arg.user_agent_version(), result_listener);
64  ok &= ::testing::ExplainMatchResult(client_features, arg.client_features(),
65  result_listener);
66  return ok;
67 }
68 
69 MATCHER_P6(EqGenericXdsConfig, type_url, name, version_info, xds_config,
70  client_status, error_state, "equals GenericXdsConfig") {
71  bool ok = true;
72  ok &=
73  ::testing::ExplainMatchResult(type_url, arg.type_url(), result_listener);
74  ok &= ::testing::ExplainMatchResult(name, arg.name(), result_listener);
75  ok &= ::testing::ExplainMatchResult(version_info, arg.version_info(),
76  result_listener);
77  ok &= ::testing::ExplainMatchResult(xds_config, arg.xds_config(),
78  result_listener);
79  ok &= ::testing::ExplainMatchResult(client_status, arg.client_status(),
80  result_listener);
81  ok &= ::testing::ExplainMatchResult(error_state, arg.error_state(),
82  result_listener);
83  return ok;
84 }
85 
86 MATCHER_P2(EqListener, name, api_listener, "equals Listener") {
87  bool ok = true;
88  ok &= ::testing::ExplainMatchResult(name, arg.name(), result_listener);
90  api_listener, arg.api_listener().api_listener(), result_listener);
91  return ok;
92 }
93 
94 MATCHER_P(EqHttpConnectionManagerNotRds, route_config,
95  "equals HttpConnectionManager") {
96  bool ok = true;
97  ok &= ::testing::ExplainMatchResult(route_config, arg.route_config(),
98  result_listener);
99  return ok;
100 }
101 
102 MATCHER_P(EqRouteConfigurationName, name, "equals RouteConfiguration") {
103  bool ok = true;
104  ok &= ::testing::ExplainMatchResult(name, arg.name(), result_listener);
105  return ok;
106 }
107 
108 MATCHER_P2(EqRouteConfiguration, name, cluster_name,
109  "equals RouteConfiguration") {
110  bool ok = true;
111  ok &= ::testing::ExplainMatchResult(name, arg.name(), result_listener);
119  cluster_name))))),
120  arg.virtual_hosts(), result_listener);
121  return ok;
122 }
123 
124 MATCHER_P(EqCluster, name, "equals Cluster") {
125  bool ok = true;
126  ok &= ::testing::ExplainMatchResult(name, arg.name(), result_listener);
127  return ok;
128 }
129 
130 MATCHER_P(EqEndpoint, port, "equals Endpoint") {
131  bool ok = true;
133  port, arg.address().socket_address().port_value(), result_listener);
134  return ok;
135 }
136 
137 MATCHER_P2(EqLocalityLbEndpoints, port, weight, "equals LocalityLbEndpoints") {
138  bool ok = true;
141  &envoy::config::endpoint::v3::LbEndpoint::endpoint,
142  EqEndpoint(port))),
143  arg.lb_endpoints(), result_listener);
145  weight, arg.load_balancing_weight().value(), result_listener);
146  return ok;
147 }
148 
149 MATCHER_P(EqClusterLoadAssignmentName, cluster_name,
150  "equals ClusterLoadAssignment") {
151  bool ok = true;
153  result_listener);
154  return ok;
155 }
156 
157 MATCHER_P3(EqClusterLoadAssignment, cluster_name, port, weight,
158  "equals ClusterLoadAssignment") {
159  bool ok = true;
161  result_listener);
163  ::testing::ElementsAre(EqLocalityLbEndpoints(port, weight)),
164  arg.endpoints(), result_listener);
165  return ok;
166 }
167 
168 MATCHER_P2(EqUpdateFailureState, details, version_info,
169  "equals UpdateFailureState") {
170  bool ok = true;
171  ok &= ::testing::ExplainMatchResult(details, arg.details(), result_listener);
172  ok &= ::testing::ExplainMatchResult(version_info, arg.version_info(),
173  result_listener);
174  return ok;
175 }
176 
177 MATCHER_P(UnpackListener, matcher, "is a Listener") {
179  if (!::testing::ExplainMatchResult(true, arg.UnpackTo(&config),
180  result_listener)) {
181  return false;
182  }
183  return ::testing::ExplainMatchResult(matcher, config, result_listener);
184 }
185 
186 MATCHER_P(UnpackRouteConfiguration, matcher, "is a RouteConfiguration") {
187  RouteConfiguration config;
188  if (!::testing::ExplainMatchResult(true, arg.UnpackTo(&config),
189  result_listener)) {
190  return false;
191  }
192  return ::testing::ExplainMatchResult(matcher, config, result_listener);
193 }
194 
195 MATCHER_P(UnpackHttpConnectionManager, matcher, "is a HttpConnectionManager") {
196  HttpConnectionManager config;
197  if (!::testing::ExplainMatchResult(true, arg.UnpackTo(&config),
198  result_listener)) {
199  return false;
200  }
201  return ::testing::ExplainMatchResult(matcher, config, result_listener);
202 }
203 
204 MATCHER_P(UnpackCluster, matcher, "is a Cluster") {
205  Cluster config;
206  if (!::testing::ExplainMatchResult(true, arg.UnpackTo(&config),
207  result_listener)) {
208  return false;
209  }
210  return ::testing::ExplainMatchResult(matcher, config, result_listener);
211 }
212 
213 MATCHER_P(UnpackClusterLoadAssignment, matcher, "is a ClusterLoadAssignment") {
214  ClusterLoadAssignment config;
215  if (!::testing::ExplainMatchResult(true, arg.UnpackTo(&config),
216  result_listener)) {
217  return false;
218  }
219  return ::testing::ExplainMatchResult(matcher, config, result_listener);
220 }
221 
222 MATCHER(IsRdsEnabledHCM, "is a RDS enabled HttpConnectionManager") {
224  UnpackHttpConnectionManager(
225  ::testing::Property(&HttpConnectionManager::has_rds, true)),
226  arg, result_listener);
227 }
228 
229 MATCHER_P2(EqNoRdsHCM, route_configuration_name, cluster_name,
230  "equals RDS disabled HttpConnectionManager") {
232  UnpackHttpConnectionManager(EqHttpConnectionManagerNotRds(
233  EqRouteConfiguration(route_configuration_name, cluster_name))),
234  arg, result_listener);
235 }
236 
237 class ClientStatusDiscoveryServiceTest : public XdsEnd2endTest {
238  public:
239  ClientStatusDiscoveryServiceTest() {
240  admin_server_thread_ = absl::make_unique<AdminServerThread>(this);
241  admin_server_thread_->Start();
242  std::string admin_server_address = absl::StrCat(
243  ipv6_only_ ? "[::1]:" : "127.0.0.1:", admin_server_thread_->port());
245  admin_server_address,
246  std::make_shared<SecureChannelCredentials>(
248  csds_stub_ =
249  envoy::service::status::v3::ClientStatusDiscoveryService::NewStub(
251  if (GetParam().use_csds_streaming()) {
252  stream_ = csds_stub_->StreamClientStatus(&stream_context_);
253  }
254  }
255 
256  ~ClientStatusDiscoveryServiceTest() override {
257  if (stream_ != nullptr) {
258  EXPECT_TRUE(stream_->WritesDone());
259  Status status = stream_->Finish();
260  EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
261  << " message=" << status.error_message();
262  }
263  admin_server_thread_->Shutdown();
264  }
265 
266  envoy::service::status::v3::ClientStatusResponse FetchCsdsResponse() {
267  envoy::service::status::v3::ClientStatusResponse response;
268  if (!GetParam().use_csds_streaming()) {
269  // Fetch through unary pulls
270  ClientContext context;
271  Status status = csds_stub_->FetchClientStatus(
272  &context, envoy::service::status::v3::ClientStatusRequest(),
273  &response);
274  EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
275  << " message=" << status.error_message();
276  } else {
277  // Fetch through streaming pulls
278  EXPECT_TRUE(
279  stream_->Write(envoy::service::status::v3::ClientStatusRequest()));
280  EXPECT_TRUE(stream_->Read(&response));
281  }
282  return response;
283  }
284 
285  private:
286  // Server thread for CSDS server.
287  class AdminServerThread : public ServerThread {
288  public:
289  explicit AdminServerThread(XdsEnd2endTest* test_obj)
290  : ServerThread(test_obj) {}
291 
292  private:
293  const char* Type() override { return "Admin"; }
294 
295  void RegisterAllServices(ServerBuilder* builder) override {
296  builder->RegisterService(&csds_service_);
297  }
298  void StartAllServices() override {}
299  void ShutdownAllServices() override {}
300 
302  };
303 
304  std::unique_ptr<AdminServerThread> admin_server_thread_;
305  std::shared_ptr<Channel> admin_channel_;
306  std::unique_ptr<
307  envoy::service::status::v3::ClientStatusDiscoveryService::Stub>
309  ClientContext stream_context_;
310  std::unique_ptr<
311  ClientReaderWriter<envoy::service::status::v3::ClientStatusRequest,
312  envoy::service::status::v3::ClientStatusResponse>>
314 };
315 
316 // Run CSDS tests with RDS enabled and disabled.
317 // These need to run with the bootstrap from an env var instead of from
318 // a channel arg, since there needs to be a global XdsClient instance.
320  XdsTest, ClientStatusDiscoveryServiceTest,
321  ::testing::Values(
322  XdsTestType().set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar),
323  XdsTestType()
324  .set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar)
325  .set_enable_rds_testing(),
326  XdsTestType()
327  .set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar)
328  .set_use_csds_streaming(),
329  XdsTestType()
330  .set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar)
331  .set_enable_rds_testing()
332  .set_use_csds_streaming()),
334 
335 TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpVanilla) {
336  CreateAndStartBackends(1);
337  const size_t kNumRpcs = 5;
338  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
339  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
340  // Send several RPCs to ensure the xDS setup works
341  CheckRpcSendOk(DEBUG_LOCATION, kNumRpcs);
342  // Fetches the client config
343  auto csds_response = FetchCsdsResponse();
344  gpr_log(GPR_INFO, "xDS config dump: %s", csds_response.DebugString().c_str());
345  EXPECT_EQ(1, csds_response.config_size());
346  const auto& client_config = csds_response.config(0);
347  // Validate the Node information
348  EXPECT_THAT(client_config.node(),
349  EqNode("xds_end2end_test", ::testing::HasSubstr("C-core"),
352  "envoy.lb.does_not_support_overprovisioning")));
353  // Listener matcher depends on whether RDS is enabled.
354  ::testing::Matcher<google::protobuf::Any> api_listener_matcher;
355  if (GetParam().enable_rds_testing()) {
356  api_listener_matcher = IsRdsEnabledHCM();
357  } else {
358  api_listener_matcher =
359  EqNoRdsHCM(kDefaultRouteConfigurationName, kDefaultClusterName);
360  }
361  // Construct list of all matchers.
362  std::vector<::testing::Matcher<
363  envoy::service::status::v3::ClientConfig_GenericXdsConfig>>
364  matchers = {
365  // Listener
366  EqGenericXdsConfig(
367  kLdsTypeUrl, kServerName, "1",
368  UnpackListener(EqListener(kServerName, api_listener_matcher)),
369  ClientResourceStatus::ACKED, ::testing::_),
370  // Cluster
371  EqGenericXdsConfig(kCdsTypeUrl, kDefaultClusterName, "1",
372  UnpackCluster(EqCluster(kDefaultClusterName)),
373  ClientResourceStatus::ACKED, ::testing::_),
374  // ClusterLoadAssignment
375  EqGenericXdsConfig(
376  kEdsTypeUrl, kDefaultEdsServiceName, "1",
377  UnpackClusterLoadAssignment(EqClusterLoadAssignment(
378  kDefaultEdsServiceName, backends_[0]->port(),
379  kDefaultLocalityWeight)),
380  ClientResourceStatus::ACKED, ::testing::_),
381  };
382  // If RDS is enabled, add matcher for RDS resource.
383  if (GetParam().enable_rds_testing()) {
384  matchers.push_back(EqGenericXdsConfig(
385  kRdsTypeUrl, kDefaultRouteConfigurationName, "1",
386  UnpackRouteConfiguration(EqRouteConfiguration(
387  kDefaultRouteConfigurationName, kDefaultClusterName)),
388  ClientResourceStatus::ACKED, ::testing::_));
389  }
390  // Validate the dumped xDS configs
391  EXPECT_THAT(client_config.generic_xds_configs(),
393  << "Actual: " << client_config.DebugString();
394 }
395 
396 TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpEmpty) {
397  // The CSDS service should not fail if XdsClient is not initialized or there
398  // is no working xDS configs.
399  FetchCsdsResponse();
400 }
401 
402 TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpListenerError) {
403  CreateAndStartBackends(1);
404  int kFetchConfigRetries = 3;
405  int kFetchIntervalMilliseconds = 200;
406  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
407  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
408  // Ensure the xDS resolver has working configs.
409  CheckRpcSendOk(DEBUG_LOCATION);
410  // Bad Listener should be rejected.
411  Listener listener;
412  listener.set_name(kServerName);
413  balancer_->ads_service()->SetLdsResource(listener);
414  // The old xDS configs should still be effective.
415  CheckRpcSendOk(DEBUG_LOCATION);
416  ::testing::Matcher<google::protobuf::Any> api_listener_matcher;
417  if (GetParam().enable_rds_testing()) {
418  api_listener_matcher = IsRdsEnabledHCM();
419  } else {
420  api_listener_matcher =
421  EqNoRdsHCM(kDefaultRouteConfigurationName, kDefaultClusterName);
422  }
423  for (int i = 0; i < kFetchConfigRetries; ++i) {
424  auto csds_response = FetchCsdsResponse();
425  // Check if error state is propagated
426  bool ok = ::testing::Value(
427  csds_response.config(0).generic_xds_configs(),
428  ::testing::Contains(EqGenericXdsConfig(
429  kLdsTypeUrl, kServerName, "1",
430  UnpackListener(EqListener(kServerName, api_listener_matcher)),
431  ClientResourceStatus::NACKED,
432  EqUpdateFailureState(
434  "Listener has neither address nor ApiListener"),
435  "2"))));
436  if (ok) return; // TEST PASSED!
438  grpc_timeout_milliseconds_to_deadline(kFetchIntervalMilliseconds));
439  }
440  FAIL() << "error_state not seen in CSDS responses";
441 }
442 
443 TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpRouteError) {
444  CreateAndStartBackends(1);
445  int kFetchConfigRetries = 3;
446  int kFetchIntervalMilliseconds = 200;
447  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
448  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
449  // Ensure the xDS resolver has working configs.
450  CheckRpcSendOk(DEBUG_LOCATION);
451  // Bad route config will be rejected.
452  RouteConfiguration route_config;
453  route_config.set_name(kDefaultRouteConfigurationName);
454  route_config.add_virtual_hosts();
455  SetRouteConfiguration(balancer_.get(), route_config);
456  // The old xDS configs should still be effective.
457  CheckRpcSendOk(DEBUG_LOCATION);
458  for (int i = 0; i < kFetchConfigRetries; ++i) {
459  auto csds_response = FetchCsdsResponse();
460  bool ok = false;
461  if (GetParam().enable_rds_testing()) {
463  csds_response.config(0).generic_xds_configs(),
464  ::testing::Contains(EqGenericXdsConfig(
465  kRdsTypeUrl, kDefaultRouteConfigurationName, "1",
466  UnpackRouteConfiguration(EqRouteConfiguration(
467  kDefaultRouteConfigurationName, kDefaultClusterName)),
468  ClientResourceStatus::NACKED,
469  EqUpdateFailureState(
470  ::testing::HasSubstr("VirtualHost has no domains"), "2"))));
471  } else {
473  csds_response.config(0).generic_xds_configs(),
474  ::testing::Contains(EqGenericXdsConfig(
475  kLdsTypeUrl, kServerName, "1",
476  UnpackListener(EqListener(
477  kServerName, EqNoRdsHCM(kDefaultRouteConfigurationName,
478  kDefaultClusterName))),
479  ClientResourceStatus::NACKED,
480  EqUpdateFailureState(
481  ::testing::HasSubstr("VirtualHost has no domains"), "2"))));
482  }
483  if (ok) return; // TEST PASSED!
485  grpc_timeout_milliseconds_to_deadline(kFetchIntervalMilliseconds));
486  }
487  FAIL() << "error_state not seen in CSDS responses";
488 }
489 
490 TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpClusterError) {
491  CreateAndStartBackends(1);
492  int kFetchConfigRetries = 3;
493  int kFetchIntervalMilliseconds = 200;
494  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
495  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
496  // Ensure the xDS resolver has working configs.
497  CheckRpcSendOk(DEBUG_LOCATION);
498  // Listener without any route, will be rejected.
499  Cluster cluster;
500  cluster.set_name(kDefaultClusterName);
501  balancer_->ads_service()->SetCdsResource(cluster);
502  // The old xDS configs should still be effective.
503  CheckRpcSendOk(DEBUG_LOCATION);
504  for (int i = 0; i < kFetchConfigRetries; ++i) {
505  auto csds_response = FetchCsdsResponse();
506  // Check if error state is propagated
507  bool ok = ::testing::Value(
508  csds_response.config(0).generic_xds_configs(),
509  ::testing::Contains(EqGenericXdsConfig(
510  kCdsTypeUrl, kDefaultClusterName, "1",
511  UnpackCluster(EqCluster(kDefaultClusterName)),
512  ClientResourceStatus::NACKED,
513  EqUpdateFailureState(
514  ::testing::HasSubstr("DiscoveryType not found"), "2"))));
515  if (ok) return; // TEST PASSED!
517  grpc_timeout_milliseconds_to_deadline(kFetchIntervalMilliseconds));
518  }
519  FAIL() << "error_state not seen in CSDS responses";
520 }
521 
522 TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpEndpointError) {
523  CreateAndStartBackends(1);
524  int kFetchConfigRetries = 3;
525  int kFetchIntervalMilliseconds = 200;
526  EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
527  balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
528  // Ensure the xDS resolver has working configs.
529  CheckRpcSendOk(DEBUG_LOCATION);
530  // Bad endpoint config will be rejected.
531  ClusterLoadAssignment cluster_load_assignment;
532  cluster_load_assignment.set_cluster_name(kDefaultEdsServiceName);
533  auto* endpoints = cluster_load_assignment.add_endpoints();
534  endpoints->mutable_load_balancing_weight()->set_value(1);
535  auto* endpoint = endpoints->add_lb_endpoints()->mutable_endpoint();
536  endpoint->mutable_address()->mutable_socket_address()->set_port_value(1 << 1);
537  balancer_->ads_service()->SetEdsResource(cluster_load_assignment);
538  // The old xDS configs should still be effective.
539  CheckRpcSendOk(DEBUG_LOCATION);
540  for (int i = 0; i < kFetchConfigRetries; ++i) {
541  auto csds_response = FetchCsdsResponse();
542  // Check if error state is propagated
543  bool ok = ::testing::Value(
544  csds_response.config(0).generic_xds_configs(),
545  ::testing::Contains(EqGenericXdsConfig(
546  kEdsTypeUrl, kDefaultEdsServiceName, "1",
547  UnpackClusterLoadAssignment(EqClusterLoadAssignment(
548  kDefaultEdsServiceName, backends_[0]->port(),
549  kDefaultLocalityWeight)),
550  ClientResourceStatus::NACKED,
551  EqUpdateFailureState(::testing::HasSubstr("Empty locality"),
552  "2"))));
553  if (ok) return; // TEST PASSED!
555  grpc_timeout_milliseconds_to_deadline(kFetchIntervalMilliseconds));
556  }
557  FAIL() << "error_state not seen in CSDS responses";
558 }
559 
560 TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpListenerRequested) {
561  int kTimeoutMillisecond = 1000;
562  balancer_->ads_service()->UnsetResource(kLdsTypeUrl, kServerName);
563  CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::DEADLINE_EXCEEDED,
564  "Deadline Exceeded",
565  RpcOptions().set_timeout_ms(kTimeoutMillisecond));
566  auto csds_response = FetchCsdsResponse();
567  EXPECT_THAT(csds_response.config(0).generic_xds_configs(),
568  ::testing::Contains(EqGenericXdsConfig(
569  kLdsTypeUrl, kServerName, ::testing::_, ::testing::_,
570  ClientResourceStatus::REQUESTED, ::testing::_)));
571 }
572 
573 TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpClusterRequested) {
574  int kTimeoutMillisecond = 1000;
575  std::string kClusterName1 = "cluster-1";
576  std::string kClusterName2 = "cluster-2";
577  // Create a route config requesting two non-existing clusters
578  RouteConfiguration route_config;
579  route_config.set_name(kDefaultRouteConfigurationName);
580  auto* vh = route_config.add_virtual_hosts();
581  // The VirtualHost must match the domain name, otherwise will cause resolver
582  // transient failure.
583  vh->add_domains("*");
584  auto* routes1 = vh->add_routes();
585  routes1->mutable_match()->set_prefix("");
586  routes1->mutable_route()->set_cluster(kClusterName1);
587  auto* routes2 = vh->add_routes();
588  routes2->mutable_match()->set_prefix("");
589  routes2->mutable_route()->set_cluster(kClusterName2);
590  SetRouteConfiguration(balancer_.get(), route_config);
591  // Try to get the configs plumb through
592  CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::DEADLINE_EXCEEDED,
593  "Deadline Exceeded",
594  RpcOptions().set_timeout_ms(kTimeoutMillisecond));
595  auto csds_response = FetchCsdsResponse();
596  EXPECT_THAT(csds_response.config(0).generic_xds_configs(),
597  ::testing::AllOf(
598  ::testing::Contains(EqGenericXdsConfig(
599  kCdsTypeUrl, kClusterName1, ::testing::_, ::testing::_,
600  ClientResourceStatus::REQUESTED, ::testing::_)),
601  ::testing::Contains(EqGenericXdsConfig(
602  kCdsTypeUrl, kClusterName2, ::testing::_, ::testing::_,
603  ClientResourceStatus::REQUESTED, ::testing::_))));
604 }
605 
606 class CsdsShortAdsTimeoutTest : public ClientStatusDiscoveryServiceTest {
607  protected:
608  void SetUp() override {
609  // Shorten the ADS subscription timeout to speed up the test run.
610  InitClient(BootstrapBuilder(), /*lb_expected_authority=*/"",
611  /*xds_resource_does_not_exist_timeout_ms=*/2000);
612  }
613 };
614 
615 // Run CSDS tests with RDS enabled and disabled.
616 // These need to run with the bootstrap from an env var instead of from
617 // a channel arg, since there needs to be a global XdsClient instance.
619  XdsTest, CsdsShortAdsTimeoutTest,
620  ::testing::Values(
621  XdsTestType().set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar),
622  XdsTestType()
623  .set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar)
624  .set_enable_rds_testing(),
625  XdsTestType()
626  .set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar)
627  .set_use_csds_streaming(),
628  XdsTestType()
629  .set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar)
630  .set_enable_rds_testing()
631  .set_use_csds_streaming()),
633 
634 TEST_P(CsdsShortAdsTimeoutTest, XdsConfigDumpListenerDoesNotExist) {
635  int kTimeoutMillisecond = 1000000; // 1000s wait for the transient failure.
636  balancer_->ads_service()->UnsetResource(kLdsTypeUrl, kServerName);
637  CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::UNAVAILABLE,
638  absl::StrCat("empty address list: ", kServerName,
639  ": xDS listener resource does not exist"),
640  RpcOptions().set_timeout_ms(kTimeoutMillisecond));
641  auto csds_response = FetchCsdsResponse();
642  EXPECT_THAT(csds_response.config(0).generic_xds_configs(),
643  ::testing::Contains(EqGenericXdsConfig(
644  kLdsTypeUrl, kServerName, ::testing::_, ::testing::_,
645  ClientResourceStatus::DOES_NOT_EXIST, ::testing::_)));
646 }
647 
648 TEST_P(CsdsShortAdsTimeoutTest, XdsConfigDumpRouteConfigDoesNotExist) {
649  if (!GetParam().enable_rds_testing()) return;
650  int kTimeoutMillisecond = 1000000; // 1000s wait for the transient failure.
651  balancer_->ads_service()->UnsetResource(kRdsTypeUrl,
652  kDefaultRouteConfigurationName);
653  CheckRpcSendFailure(
655  absl::StrCat("empty address list: ", kDefaultRouteConfigurationName,
656  ": xDS route configuration resource does not exist"),
657  RpcOptions().set_timeout_ms(kTimeoutMillisecond));
658  auto csds_response = FetchCsdsResponse();
659  EXPECT_THAT(
660  csds_response.config(0).generic_xds_configs(),
661  ::testing::Contains(EqGenericXdsConfig(
662  kRdsTypeUrl, kDefaultRouteConfigurationName, ::testing::_,
663  ::testing::_, ClientResourceStatus::DOES_NOT_EXIST, ::testing::_)));
664 }
665 
666 TEST_P(CsdsShortAdsTimeoutTest, XdsConfigDumpClusterDoesNotExist) {
667  int kTimeoutMillisecond = 1000000; // 1000s wait for the transient failure.
668  balancer_->ads_service()->UnsetResource(kCdsTypeUrl, kDefaultClusterName);
669  CheckRpcSendFailure(
671  absl::StrCat("CDS resource \"", kDefaultClusterName, "\" does not exist"),
672  RpcOptions().set_timeout_ms(kTimeoutMillisecond));
673  auto csds_response = FetchCsdsResponse();
674  EXPECT_THAT(csds_response.config(0).generic_xds_configs(),
675  ::testing::Contains(EqGenericXdsConfig(
676  kCdsTypeUrl, kDefaultClusterName, ::testing::_, ::testing::_,
677  ClientResourceStatus::DOES_NOT_EXIST, ::testing::_)));
678 }
679 
680 TEST_P(CsdsShortAdsTimeoutTest, XdsConfigDumpEndpointDoesNotExist) {
681  int kTimeoutMillisecond = 1000000; // 1000s wait for the transient failure.
682  balancer_->ads_service()->UnsetResource(kEdsTypeUrl, kDefaultEdsServiceName);
683  CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::UNAVAILABLE,
684  // TODO(roth): Improve this error message as part of
685  // https://github.com/grpc/grpc/issues/22883.
686  "no children in weighted_target policy: ",
687  RpcOptions().set_timeout_ms(kTimeoutMillisecond));
688  auto csds_response = FetchCsdsResponse();
689  EXPECT_THAT(
690  csds_response.config(0).generic_xds_configs(),
691  ::testing::Contains(EqGenericXdsConfig(
692  kEdsTypeUrl, kDefaultEdsServiceName, ::testing::_, ::testing::_,
693  ClientResourceStatus::DOES_NOT_EXIST, ::testing::_)));
694 }
695 
696 } // namespace
697 } // namespace testing
698 } // namespace grpc
699 
700 #endif // DISABLED_XDS_PROTO_IN_CC
701 
702 int main(int argc, char** argv) {
703  grpc::testing::TestEnvironment env(&argc, argv);
704  ::testing::InitGoogleTest(&argc, argv);
705  // Make the backup poller poll very frequently in order to pick up
706  // updates from all the subchannels's FDs.
707  GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
708 #if TARGET_OS_IPHONE
709  // Workaround Apple CFStream bug
710  gpr_setenv("grpc_cfstream", "0");
711 #endif
712  grpc_init();
713  const auto result = RUN_ALL_TESTS();
714  grpc_shutdown();
715  return result;
716 }
main
int main(int argc, char **argv)
Definition: xds_csds_end2end_test.cc:702
grpc::EXPECT_THAT
EXPECT_THAT(status.error_message(), ::testing::HasSubstr("subject_token_type"))
_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
GPR_INFO
#define GPR_INFO
Definition: include/grpc/impl/codegen/log.h:56
testing
Definition: aws_request_signer_test.cc:25
grpc::status
auto status
Definition: cpp/client/credentials_test.cc:200
grpc::testing::XdsTestType::kBootstrapFromEnvVar
@ kBootstrapFromEnvVar
Definition: xds_end2end_test_lib.h:64
ipv6_only_
bool ipv6_only_
Definition: client_lb_end2end_test.cc:217
generate.env
env
Definition: generate.py:37
MATCHER_P4
#define MATCHER_P4(name, p0, p1, p2, p3, description)
Definition: bloaty/third_party/googletest/googlemock/include/gmock/gmock-generated-matchers.h:485
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
grpc::testing::kCdsTypeUrl
constexpr char kCdsTypeUrl[]
Definition: xds_server.h:55
grpc
Definition: grpcpp/alarm.h:33
route
XdsRouteConfigResource::Route route
Definition: xds_resolver.cc:337
grpc::testing::kRdsTypeUrl
constexpr char kRdsTypeUrl[]
Definition: xds_server.h:53
backends_
std::vector< std::unique_ptr< BackendServiceImpl > > backends_
Definition: client_channel_stress_test.cc:333
admin_channel_
std::shared_ptr< Channel > admin_channel_
Definition: xds_csds_end2end_test.cc:305
Listener
::grpc_event_engine::experimental::EventEngine::Listener Listener
Definition: event_engine_test_utils.cc:42
cluster_name
std::string cluster_name
Definition: xds_cluster_resolver.cc:91
Listener
Definition: transport_common.h:31
matchers
XdsRouteConfigResource::Route::Matchers matchers
Definition: xds_server_config_fetcher.cc:317
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
secure_credentials.h
arg::value
void * value
Definition: cmdline.cc:44
setup.name
name
Definition: setup.py:542
testing::ElementsAre
internal::ElementsAreMatcher< ::testing::tuple<> > ElementsAre()
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:13040
grpc::testing::kEdsTypeUrl
constexpr char kEdsTypeUrl[]
Definition: xds_server.h:57
testing::Property
PolymorphicMatcher< internal::PropertyMatcher< Class, PropertyType > > Property(PropertyType(Class::*property)() const, const PropertyMatcher &matcher)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8732
DEBUG_LOCATION
#define DEBUG_LOCATION
Definition: debug_location.h:41
grpc_version_string
const GRPCAPI char * grpc_version_string(void)
Definition: version.cc:26
MATCHER
#define MATCHER(name, description)
<< DiffStrings(str, arg);
Definition: bloaty/third_party/googletest/googlemock/include/gmock/gmock-generated-matchers.h:263
profile_analyzer.builder
builder
Definition: profile_analyzer.py:159
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
cluster
absl::string_view cluster
Definition: xds_resolver.cc:331
arg::name
const char * name
Definition: cmdline.cc:41
config
struct config_s config
csds_stub_
std::unique_ptr< envoy::service::status::v3::ClientStatusDiscoveryService::Stub > csds_stub_
Definition: xds_csds_end2end_test.cc:308
grpc_timeout_milliseconds_to_deadline
gpr_timespec grpc_timeout_milliseconds_to_deadline(int64_t time_ms)
Definition: test/core/util/test_config.cc:89
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
gpr_sleep_until
GPRAPI void gpr_sleep_until(gpr_timespec until)
grpc_fake_transport_security_credentials_create
grpc_channel_credentials * grpc_fake_transport_security_credentials_create()
Definition: fake_credentials.cc:79
arg
Definition: cmdline.cc:40
xds_end2end_test_lib.h
grpc::testing::kLdsTypeUrl
constexpr char kLdsTypeUrl[]
Definition: xds_server.h:51
grpc::testing::INSTANTIATE_TEST_SUITE_P
INSTANTIATE_TEST_SUITE_P(HistogramTestCases, HistogramTest, ::testing::Range< int >(0, GRPC_STATS_HISTOGRAM_COUNT))
backup_poller.h
stream_
std::unique_ptr< ClientReaderWriter< envoy::service::status::v3::ClientStatusRequest, envoy::service::status::v3::ClientStatusResponse > > stream_
Definition: xds_csds_end2end_test.cc:313
grpc::testing::FAIL
@ FAIL
Definition: h2_ssl_cert_test.cc:201
kNumRpcs
const int kNumRpcs
Definition: thread_stress_test.cc:50
grpc::CreateChannel
std::shared_ptr< Channel > CreateChannel(const grpc::string &target, const std::shared_ptr< ChannelCredentials > &creds)
csds.h
RUN_ALL_TESTS
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2471
weight
uint32_t weight
Definition: weighted_target.cc:84
testing::Matcher
Definition: bloaty/third_party/googletest/googlemock/include/gmock/internal/gmock-internal-utils.h:52
GPR_GLOBAL_CONFIG_SET
#define GPR_GLOBAL_CONFIG_SET(name, value)
Definition: global_config_generic.h:26
MATCHER_P6
#define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)
Definition: bloaty/third_party/googletest/googlemock/include/gmock/gmock-generated-matchers.h:633
tests.unit._exit_scenarios.port
port
Definition: _exit_scenarios.py:179
details
static grpc_slice details
Definition: test/core/fling/client.cc:46
test_config.h
routes
std::vector< Route > routes
Definition: xds_server_config_fetcher.cc:338
testing::_
const internal::AnythingMatcher _
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8548
testing::InitGoogleTest
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: bloaty/third_party/googletest/googletest/src/gtest.cc:6106
credentials.h
stream_context_
ClientContext stream_context_
Definition: xds_csds_end2end_test.cc:309
testing::Values
internal::ValueArray< T... > Values(T... v)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:335
MATCHER_P2
#define MATCHER_P2(name, p0, p1, description)
Definition: bloaty/third_party/googletest/googlemock/include/gmock/gmock-generated-matchers.h:364
MATCHER_P3
#define MATCHER_P3(name, p0, p1, p2, description)
Definition: bloaty/third_party/googletest/googlemock/include/gmock/gmock-generated-matchers.h:423
csds_service_
grpc::xds::experimental::ClientStatusDiscoveryService csds_service_
Definition: xds_csds_end2end_test.cc:301
asyncio_get_stats.response
response
Definition: asyncio_get_stats.py:28
testing::ExplainMatchResult
bool ExplainMatchResult(M matcher, const T &value, MatchResultListener *listener)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:9173
grpc::testing::TestEnvironment
Definition: test/core/util/test_config.h:54
MATCHER_P
#define MATCHER_P(name, p0, description)
Definition: bloaty/third_party/googletest/googlemock/include/gmock/gmock-generated-matchers.h:311
grpc::protobuf::util::Status
GRPC_CUSTOM_UTIL_STATUS Status
Definition: include/grpcpp/impl/codegen/config_protobuf.h:93
type_url
string * type_url
Definition: bloaty/third_party/protobuf/conformance/conformance_cpp.cc:72
ok
bool ok
Definition: async_end2end_test.cc:197
grpc::xds::experimental::ClientStatusDiscoveryService
Definition: csds.h:37
grpc::testing::EXPECT_EQ
EXPECT_EQ(options.token_exchange_service_uri, "https://foo/exchange")
config_s
Definition: bloaty/third_party/zlib/deflate.c:120
grpc.StatusCode.UNAVAILABLE
tuple UNAVAILABLE
Definition: src/python/grpcio/grpc/__init__.py:278
testing::AllOf
internal::AllOfResult2< M1, M2 >::type AllOf(M1 m1, M2 m2)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:13472
admin_server_thread_
std::unique_ptr< AdminServerThread > admin_server_thread_
Definition: xds_csds_end2end_test.cc:304
context
grpc::ClientContext context
Definition: istio_echo_server_lib.cc:61
testing::UnorderedElementsAreArray
internal::UnorderedElementsAreArrayMatcher< typename ::std::iterator_traits< Iter >::value_type > UnorderedElementsAreArray(Iter first, Iter last)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8507
grpc::testing::TEST_P
TEST_P(HistogramTest, IncHistogram)
Definition: stats_test.cc:87
grpc::testing::EXPECT_TRUE
EXPECT_TRUE(grpc::experimental::StsCredentialsOptionsFromJson(minimum_valid_json, &options) .ok())
Value
struct Value Value
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:676
grpc_init
GRPCAPI void grpc_init(void)
Definition: init.cc:146
grpc.StatusCode.DEADLINE_EXCEEDED
tuple DEADLINE_EXCEEDED
Definition: src/python/grpcio/grpc/__init__.py:264
testing::HasSubstr
PolymorphicMatcher< internal::HasSubstrMatcher< internal::string > > HasSubstr(const internal::string &substring)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8803
testing::Contains
internal::ContainsMatcher< M > Contains(M matcher)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:9101
grpc_shutdown
GRPCAPI void grpc_shutdown(void)
Definition: init.cc:209
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
create_channel.h
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:58