| 
					
				 | 
			
			
				@@ -1531,7 +1531,8 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   std::tuple<int, int, int> WaitForAllBackends( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       size_t start_index = 0, size_t stop_index = 0, bool reset_counters = true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      const RpcOptions& rpc_options = RpcOptions()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const RpcOptions& rpc_options = RpcOptions(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      bool allow_failures = false) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     int num_ok = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     int num_failure = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     int num_drops = 0; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1545,7 +1546,7 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             "Performed %d warm up requests against the backends. " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             "%d succeeded, %d failed, %d dropped.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             num_total, num_ok, num_failure, num_drops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    EXPECT_EQ(num_failure, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!allow_failures) EXPECT_EQ(num_failure, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return std::make_tuple(num_ok, num_failure, num_drops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1662,8 +1663,10 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     for (const auto& metadata : rpc_options.metadata) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       context.AddMetadata(metadata.first, metadata.second); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    context.set_deadline( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        grpc_timeout_milliseconds_to_deadline(rpc_options.timeout_ms)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (rpc_options.timeout_ms != 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      context.set_deadline( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          grpc_timeout_milliseconds_to_deadline(rpc_options.timeout_ms)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (rpc_options.wait_for_ready) context.set_wait_for_ready(true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     request.set_message(kRequestMessage_); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (rpc_options.server_fail) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -3593,6 +3596,101 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateClusters) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                              (1 + kErrorToleranceSmallLoad)))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+TEST_P(LdsRdsTest, XdsRoutingClusterUpdateClusters) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const char* kNewCluster1Name = "new_cluster_1"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const size_t kNumEchoRpcs = 5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SetNextResolution({}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SetNextResolutionForLbChannelAllBalancers(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Populate new EDS resources. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  AdsServiceImpl::EdsResourceArgs args({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      {"locality0", GetBackendPorts(0, 1)}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  AdsServiceImpl::EdsResourceArgs args1({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      {"locality0", GetBackendPorts(1, 2)}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  balancers_[0]->ads_service()->SetEdsResource( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      AdsServiceImpl::BuildEdsResource(args)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  balancers_[0]->ads_service()->SetEdsResource( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      AdsServiceImpl::BuildEdsResource(args1, kNewCluster1Name)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Populate new CDS resources. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Cluster new_cluster1 = balancers_[0]->ads_service()->default_cluster(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  new_cluster1.set_name(kNewCluster1Name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  balancers_[0]->ads_service()->SetCdsResource(new_cluster1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Send Route Configuration. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  RouteConfiguration new_route_config = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      balancers_[0]->ads_service()->default_route_config(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SetRouteConfiguration(0, new_route_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  WaitForAllBackends(0, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  CheckRpcSendOk(kNumEchoRpcs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Make sure RPCs all go to the correct backend. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Change Route Configurations: new default cluster. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  auto* default_route = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      new_route_config.mutable_virtual_hosts(0)->mutable_routes(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  default_route->mutable_route()->set_cluster(kNewCluster1Name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SetRouteConfiguration(0, new_route_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  WaitForAllBackends(1, 2); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  CheckRpcSendOk(kNumEchoRpcs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Make sure RPCs all go to the correct backend. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  EXPECT_EQ(kNumEchoRpcs, backends_[1]->backend_service()->request_count()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+TEST_P(LdsRdsTest, XdsRoutingClusterUpdateClustersWithPickingDelays) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const char* kNewCluster1Name = "new_cluster_1"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SetNextResolution({}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SetNextResolutionForLbChannelAllBalancers(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Populate new EDS resources. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  AdsServiceImpl::EdsResourceArgs args({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      {"locality0", GetBackendPorts(0, 1)}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  AdsServiceImpl::EdsResourceArgs args1({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      {"locality0", GetBackendPorts(1, 2)}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  balancers_[0]->ads_service()->SetEdsResource( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      AdsServiceImpl::BuildEdsResource(args)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  balancers_[0]->ads_service()->SetEdsResource( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      AdsServiceImpl::BuildEdsResource(args1, kNewCluster1Name)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Populate new CDS resources. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Cluster new_cluster1 = balancers_[0]->ads_service()->default_cluster(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  new_cluster1.set_name(kNewCluster1Name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  balancers_[0]->ads_service()->SetCdsResource(new_cluster1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Bring down the current backend: 0, this will delay route picking time, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // resulting in un-committed RPCs. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ShutdownBackend(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Send a RouteConfiguration with a default route that points to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // backend 0. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  RouteConfiguration new_route_config = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      balancers_[0]->ads_service()->default_route_config(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SetRouteConfiguration(0, new_route_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Send exactly one RPC with no deadline and with wait_for_ready=true. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // This RPC will not complete until after backend 0 is started. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  std::thread sending_rpc([this]() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    SendRpc(RpcOptions().set_wait_for_ready(true).set_timeout_ms(0)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Send a non-wait_for_ready RPC which should fail, this will tell us 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // that the client has received the update and attempted to connect. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const Status status = SendRpc(RpcOptions().set_timeout_ms(0)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  EXPECT_FALSE(status.ok()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Send a update RouteConfiguration to use backend 1. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  auto* default_route = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      new_route_config.mutable_virtual_hosts(0)->mutable_routes(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  default_route->mutable_route()->set_cluster(kNewCluster1Name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SetRouteConfiguration(0, new_route_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Wait for RPCs to go to the new backend: 1, this ensures that the client has 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // processed the update. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  WaitForAllBackends(1, 2, false, RpcOptions(), true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Bring up the previous backend: 0, this will allow the delayed RPC to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // finally call on_call_committed upon completion. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  StartBackend(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  sending_rpc.join(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Make sure RPCs go to the correct backend: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Before moving routing to XdsConfigSelector, 2 to backend 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // TODO(donnadionne): After moving routing to XdsConfigSelector, 1 for each 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // backend. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  EXPECT_EQ(0, backends_[0]->backend_service()->request_count()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  EXPECT_EQ(2, backends_[1]->backend_service()->request_count()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 TEST_P(LdsRdsTest, XdsRoutingHeadersMatching) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const char* kNewCluster1Name = "new_cluster_1"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const size_t kNumEcho1Rpcs = 100; 
			 |