|
|
|
@ -1242,6 +1242,7 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> { |
|
|
|
|
int timeout_ms = 1000; |
|
|
|
|
bool wait_for_ready = false; |
|
|
|
|
bool server_fail = false; |
|
|
|
|
std::vector<std::pair<std::string, std::string>> metadata; |
|
|
|
|
|
|
|
|
|
RpcOptions() {} |
|
|
|
|
|
|
|
|
@ -1269,6 +1270,12 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> { |
|
|
|
|
server_fail = rpc_server_fail; |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RpcOptions& set_metadata( |
|
|
|
|
std::vector<std::pair<std::string, std::string>> rpc_metadata) { |
|
|
|
|
metadata = rpc_metadata; |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
template <typename Stub> |
|
|
|
@ -1463,6 +1470,9 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> { |
|
|
|
|
if (local_response) response = new EchoResponse; |
|
|
|
|
EchoRequest request; |
|
|
|
|
ClientContext context; |
|
|
|
|
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.wait_for_ready) context.set_wait_for_ready(true); |
|
|
|
@ -2417,11 +2427,7 @@ TEST_P(LdsRdsTest, RouteMatchHasCaseSensitiveFalse) { |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/"); |
|
|
|
|
route1->mutable_match()->mutable_case_sensitive()->set_value(false); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
|
SetNextResolutionForLbChannelAllBalancers(); |
|
|
|
@ -2433,48 +2439,46 @@ TEST_P(LdsRdsTest, RouteMatchHasCaseSensitiveFalse) { |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has a prefix
|
|
|
|
|
// string with no "/".
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixNonEmptyNoSlash) { |
|
|
|
|
// Tests that LDS client should ignore route which has query_parameters.
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasQueryParameters) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
route1->mutable_match()->set_prefix("grpc.testing.EchoTest1Service"); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/"); |
|
|
|
|
route1->mutable_match()->add_query_parameters(); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
|
SetNextResolutionForLbChannelAllBalancers(); |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "Prefix does not start with a /"); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "No valid routes specified."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has a prefix
|
|
|
|
|
// string does not end with "/".
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixNoEndingSlash) { |
|
|
|
|
// Tests that LDS client should send a ACK if route match has a prefix
|
|
|
|
|
// that is either empty or a single slash
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasValidPrefixEmptyOrSingleSlash) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service"); |
|
|
|
|
route1->mutable_match()->set_prefix(""); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix("/"); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
|
SetNextResolutionForLbChannelAllBalancers(); |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
(void)SendRpc(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, |
|
|
|
|
"Prefix not in the required format of /service/"); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has a prefix
|
|
|
|
|
// string does not start with "/".
|
|
|
|
|
// Tests that LDS client should ignore route which has a path
|
|
|
|
|
// prefix string does not start with "/".
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixNoLeadingSlash) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
@ -2487,31 +2491,31 @@ TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixNoLeadingSlash) { |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "Prefix does not start with a /"); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "No valid routes specified."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has a prefix
|
|
|
|
|
// string with extra content outside of "/service/".
|
|
|
|
|
// Tests that LDS client should ignore route which has a prefix
|
|
|
|
|
// string with more than 2 slashes.
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixExtraContent) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/Echo1"); |
|
|
|
|
route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/Echo1/"); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
|
SetNextResolutionForLbChannelAllBalancers(); |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "Prefix does not end with a /"); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "No valid routes specified."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has a prefix
|
|
|
|
|
// Tests that LDS client should ignore route which has a prefix
|
|
|
|
|
// string "//".
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixNoContent) { |
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixDoubleSlash) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
@ -2523,20 +2527,17 @@ TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixNoContent) { |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "Prefix contains empty service name"); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "No valid routes specified."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has path
|
|
|
|
|
// Tests that LDS client should ignore route which has path
|
|
|
|
|
// but it's empty.
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPathEmptyPath) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
route1->mutable_match()->set_path(""); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
@ -2544,20 +2545,17 @@ TEST_P(LdsRdsTest, RouteMatchHasInvalidPathEmptyPath) { |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "Path if set cannot be empty"); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "No valid routes specified."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has path
|
|
|
|
|
// Tests that LDS client should ignore route which has path
|
|
|
|
|
// string does not start with "/".
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPathNoLeadingSlash) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
route1->mutable_match()->set_path("grpc.testing.EchoTest1Service/Echo1"); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
@ -2565,20 +2563,17 @@ TEST_P(LdsRdsTest, RouteMatchHasInvalidPathNoLeadingSlash) { |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "Path does not start with a /"); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "No valid routes specified."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has path
|
|
|
|
|
// string that ends with "/".
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPathEndsWithSlash) { |
|
|
|
|
// Tests that LDS client should ignore route which has path
|
|
|
|
|
// string that has too many slashes; for example, ends with "/".
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPathTooManySlashes) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
route1->mutable_match()->set_path("/grpc.testing.EchoTest1Service/Echo1/"); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
@ -2586,21 +2581,17 @@ TEST_P(LdsRdsTest, RouteMatchHasInvalidPathEndsWithSlash) { |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, |
|
|
|
|
"Path not in the required format of /service/method"); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "No valid routes specified."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has path
|
|
|
|
|
// string that misses "/" between service and method.
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPathMissingMiddleSlash) { |
|
|
|
|
// Tests that LDS client should ignore route which has path
|
|
|
|
|
// string that has only 1 slash: missing "/" between service and method.
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPathOnlyOneSlash) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
route1->mutable_match()->set_path("/grpc.testing.EchoTest1Service.Echo1"); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
@ -2608,21 +2599,17 @@ TEST_P(LdsRdsTest, RouteMatchHasInvalidPathMissingMiddleSlash) { |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, |
|
|
|
|
"Path not in the required format of /service/method"); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "No valid routes specified."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has path
|
|
|
|
|
// Tests that LDS client should ignore route which has path
|
|
|
|
|
// string that is missing service.
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPathMissingService) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
route1->mutable_match()->set_path("//Echo1"); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
@ -2630,20 +2617,17 @@ TEST_P(LdsRdsTest, RouteMatchHasInvalidPathMissingService) { |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "Path contains empty service name"); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "No valid routes specified."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client should send a NACK if route match has path
|
|
|
|
|
// Tests that LDS client should ignore route which has path
|
|
|
|
|
// string that is missing method.
|
|
|
|
|
TEST_P(LdsRdsTest, RouteMatchHasInvalidPathMissingMethod) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
route1->mutable_match()->set_path("/grpc.testing.EchoTest1Service/"); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
@ -2651,7 +2635,7 @@ TEST_P(LdsRdsTest, RouteMatchHasInvalidPathMissingMethod) { |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "Path contains empty method name"); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "No valid routes specified."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2686,8 +2670,7 @@ TEST_P(LdsRdsTest, RouteActionUnsupportedClusterSpecifier) { |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, |
|
|
|
|
"No cluster or weighted_clusters found in RouteAction."); |
|
|
|
|
EXPECT_EQ(response_state.error_message, "Default route action is ignored."); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_P(LdsRdsTest, RouteActionClusterHasEmptyClusterName) { |
|
|
|
@ -2800,6 +2783,30 @@ TEST_P(LdsRdsTest, RouteActionWeightedTargetClusterHasNoWeight) { |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_P(LdsRdsTest, RouteHeaderMatchInvalidRange) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
const char* kNewCluster1Name = "new_cluster_1"; |
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/"); |
|
|
|
|
auto* header_matcher1 = route1->mutable_match()->add_headers(); |
|
|
|
|
header_matcher1->set_name("header1"); |
|
|
|
|
header_matcher1->mutable_range_match()->set_start(1001); |
|
|
|
|
header_matcher1->mutable_range_match()->set_end(1000); |
|
|
|
|
route1->mutable_route()->set_cluster(kNewCluster1Name); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
SetNextResolution({}); |
|
|
|
|
SetNextResolutionForLbChannelAllBalancers(); |
|
|
|
|
CheckRpcSendFailure(); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::NACKED); |
|
|
|
|
EXPECT_EQ(response_state.error_message, |
|
|
|
|
"Invalid range header matcher specifier specified: end " |
|
|
|
|
"cannot be smaller than start."); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that LDS client times out when no response received.
|
|
|
|
|
TEST_P(LdsRdsTest, Timeout) { |
|
|
|
|
ResetStub(0, "", 500); |
|
|
|
@ -3410,6 +3417,228 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateClusters) { |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_P(LdsRdsTest, XdsRoutingHeadersMatching) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
const char* kNewCluster1Name = "new_cluster_1"; |
|
|
|
|
const size_t kNumEcho1Rpcs = 100; |
|
|
|
|
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); |
|
|
|
|
// Populating Route Configurations for LDS.
|
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/"); |
|
|
|
|
auto* header_matcher1 = route1->mutable_match()->add_headers(); |
|
|
|
|
header_matcher1->set_name("header1"); |
|
|
|
|
header_matcher1->set_exact_match("POST"); |
|
|
|
|
auto* header_matcher3 = route1->mutable_match()->add_headers(); |
|
|
|
|
header_matcher3->set_name("header3"); |
|
|
|
|
header_matcher3->mutable_range_match()->set_start(1); |
|
|
|
|
header_matcher3->mutable_range_match()->set_end(1000); |
|
|
|
|
auto* header_matcher4 = route1->mutable_match()->add_headers(); |
|
|
|
|
header_matcher4->set_name("header4"); |
|
|
|
|
header_matcher4->set_present_match(false); |
|
|
|
|
auto* header_matcher5 = route1->mutable_match()->add_headers(); |
|
|
|
|
header_matcher5->set_name("header5"); |
|
|
|
|
header_matcher5->set_prefix_match("/grpc"); |
|
|
|
|
auto* header_matcher6 = route1->mutable_match()->add_headers(); |
|
|
|
|
header_matcher6->set_name("header6"); |
|
|
|
|
header_matcher6->set_suffix_match(".cc"); |
|
|
|
|
header_matcher6->set_invert_match(true); |
|
|
|
|
route1->mutable_route()->set_cluster(kNewCluster1Name); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
std::vector<std::pair<std::string, std::string>> metadata = { |
|
|
|
|
{"header1", "POST"}, {"header2", "blah"}, |
|
|
|
|
{"header3", "1"}, {"header5", "/grpc.testing.EchoTest1Service/"}, |
|
|
|
|
{"header6", "grpc.java"}, |
|
|
|
|
}; |
|
|
|
|
const auto header_match_rpc_options = RpcOptions() |
|
|
|
|
.set_rpc_service(SERVICE_ECHO1) |
|
|
|
|
.set_rpc_method(METHOD_ECHO1) |
|
|
|
|
.set_metadata(std::move(metadata)); |
|
|
|
|
// Make sure all backends are up.
|
|
|
|
|
WaitForAllBackends(0, 1); |
|
|
|
|
WaitForAllBackends(1, 2, true, header_match_rpc_options); |
|
|
|
|
// Send RPCs.
|
|
|
|
|
CheckRpcSendOk(kNumEchoRpcs); |
|
|
|
|
CheckRpcSendOk(kNumEcho1Rpcs, header_match_rpc_options); |
|
|
|
|
EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count()); |
|
|
|
|
EXPECT_EQ(0, backends_[0]->backend_service1()->request_count()); |
|
|
|
|
EXPECT_EQ(0, backends_[0]->backend_service2()->request_count()); |
|
|
|
|
EXPECT_EQ(0, backends_[1]->backend_service()->request_count()); |
|
|
|
|
EXPECT_EQ(kNumEcho1Rpcs, backends_[1]->backend_service1()->request_count()); |
|
|
|
|
EXPECT_EQ(0, backends_[1]->backend_service2()->request_count()); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_P(LdsRdsTest, XdsRoutingRuntimeFractionMatching) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
const char* kNewCluster1Name = "new_cluster_1"; |
|
|
|
|
const size_t kNumRpcs = 1000; |
|
|
|
|
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); |
|
|
|
|
// Populating Route Configurations for LDS.
|
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
route1->mutable_match() |
|
|
|
|
->mutable_runtime_fraction() |
|
|
|
|
->mutable_default_value() |
|
|
|
|
->set_numerator(25); |
|
|
|
|
route1->mutable_route()->set_cluster(kNewCluster1Name); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
WaitForAllBackends(0, 2); |
|
|
|
|
CheckRpcSendOk(kNumRpcs); |
|
|
|
|
const int default_backend_count = |
|
|
|
|
backends_[0]->backend_service()->request_count(); |
|
|
|
|
const int matched_backend_count = |
|
|
|
|
backends_[1]->backend_service()->request_count(); |
|
|
|
|
const double kErrorTolerance = 0.2; |
|
|
|
|
EXPECT_THAT(default_backend_count, |
|
|
|
|
::testing::AllOf( |
|
|
|
|
::testing::Ge(kNumRpcs * 75 / 100 * (1 - kErrorTolerance)), |
|
|
|
|
::testing::Le(kNumRpcs * 75 / 100 * (1 + kErrorTolerance)))); |
|
|
|
|
EXPECT_THAT(matched_backend_count, |
|
|
|
|
::testing::AllOf( |
|
|
|
|
::testing::Ge(kNumRpcs * 25 / 100 * (1 - kErrorTolerance)), |
|
|
|
|
::testing::Le(kNumRpcs * 25 / 100 * (1 + kErrorTolerance)))); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingUnmatchCases) { |
|
|
|
|
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true"); |
|
|
|
|
const char* kNewCluster1Name = "new_cluster_1"; |
|
|
|
|
const char* kNewCluster2Name = "new_cluster_2"; |
|
|
|
|
const char* kNewCluster3Name = "new_cluster_3"; |
|
|
|
|
const size_t kNumEcho1Rpcs = 100; |
|
|
|
|
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)}, |
|
|
|
|
}); |
|
|
|
|
AdsServiceImpl::EdsResourceArgs args2({ |
|
|
|
|
{"locality0", GetBackendPorts(2, 3)}, |
|
|
|
|
}); |
|
|
|
|
AdsServiceImpl::EdsResourceArgs args3({ |
|
|
|
|
{"locality0", GetBackendPorts(3, 4)}, |
|
|
|
|
}); |
|
|
|
|
balancers_[0]->ads_service()->SetEdsResource( |
|
|
|
|
AdsServiceImpl::BuildEdsResource(args)); |
|
|
|
|
balancers_[0]->ads_service()->SetEdsResource( |
|
|
|
|
AdsServiceImpl::BuildEdsResource(args1, kNewCluster1Name)); |
|
|
|
|
balancers_[0]->ads_service()->SetEdsResource( |
|
|
|
|
AdsServiceImpl::BuildEdsResource(args2, kNewCluster2Name)); |
|
|
|
|
balancers_[0]->ads_service()->SetEdsResource( |
|
|
|
|
AdsServiceImpl::BuildEdsResource(args3, kNewCluster3Name)); |
|
|
|
|
// 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); |
|
|
|
|
Cluster new_cluster2 = balancers_[0]->ads_service()->default_cluster(); |
|
|
|
|
new_cluster2.set_name(kNewCluster2Name); |
|
|
|
|
balancers_[0]->ads_service()->SetCdsResource(new_cluster2); |
|
|
|
|
Cluster new_cluster3 = balancers_[0]->ads_service()->default_cluster(); |
|
|
|
|
new_cluster1.set_name(kNewCluster3Name); |
|
|
|
|
balancers_[0]->ads_service()->SetCdsResource(new_cluster3); |
|
|
|
|
// Populating Route Configurations for LDS.
|
|
|
|
|
RouteConfiguration route_config = |
|
|
|
|
balancers_[0]->ads_service()->default_route_config(); |
|
|
|
|
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0); |
|
|
|
|
route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/"); |
|
|
|
|
auto* header_matcher1 = route1->mutable_match()->add_headers(); |
|
|
|
|
header_matcher1->set_name("header1"); |
|
|
|
|
header_matcher1->set_exact_match("POST"); |
|
|
|
|
route1->mutable_route()->set_cluster(kNewCluster1Name); |
|
|
|
|
auto route2 = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
route2->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/"); |
|
|
|
|
auto* header_matcher2 = route2->mutable_match()->add_headers(); |
|
|
|
|
header_matcher2->set_name("header2"); |
|
|
|
|
header_matcher2->mutable_range_match()->set_start(1); |
|
|
|
|
header_matcher2->mutable_range_match()->set_end(1000); |
|
|
|
|
route2->mutable_route()->set_cluster(kNewCluster2Name); |
|
|
|
|
auto route3 = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
route3->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/"); |
|
|
|
|
auto* header_matcher3 = route3->mutable_match()->add_headers(); |
|
|
|
|
header_matcher3->set_name("header3"); |
|
|
|
|
header_matcher3->set_suffix_match(".java"); |
|
|
|
|
route3->mutable_route()->set_cluster(kNewCluster3Name); |
|
|
|
|
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes(); |
|
|
|
|
default_route->mutable_match()->set_prefix(""); |
|
|
|
|
default_route->mutable_route()->set_cluster(kDefaultResourceName); |
|
|
|
|
SetRouteConfiguration(0, route_config); |
|
|
|
|
// Send headers which will mismatch each route
|
|
|
|
|
std::vector<std::pair<std::string, std::string>> metadata = { |
|
|
|
|
{"header1", "POST1"}, |
|
|
|
|
{"header2", "1000"}, |
|
|
|
|
{"header3", "grpc.cpp"}, |
|
|
|
|
}; |
|
|
|
|
WaitForAllBackends(0, 1); |
|
|
|
|
CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_metadata(metadata)); |
|
|
|
|
CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions() |
|
|
|
|
.set_rpc_service(SERVICE_ECHO1) |
|
|
|
|
.set_rpc_method(METHOD_ECHO1) |
|
|
|
|
.set_metadata(metadata)); |
|
|
|
|
// Verify that only the default backend got RPCs since all previous routes
|
|
|
|
|
// were mismatched.
|
|
|
|
|
for (size_t i = 1; i < 4; ++i) { |
|
|
|
|
EXPECT_EQ(0, backends_[i]->backend_service()->request_count()); |
|
|
|
|
EXPECT_EQ(0, backends_[i]->backend_service1()->request_count()); |
|
|
|
|
EXPECT_EQ(0, backends_[i]->backend_service2()->request_count()); |
|
|
|
|
} |
|
|
|
|
EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count()); |
|
|
|
|
EXPECT_EQ(kNumEcho1Rpcs, backends_[0]->backend_service1()->request_count()); |
|
|
|
|
EXPECT_EQ(0, backends_[0]->backend_service2()->request_count()); |
|
|
|
|
const auto& response_state = RouteConfigurationResponseState(0); |
|
|
|
|
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED); |
|
|
|
|
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
using CdsTest = BasicTest; |
|
|
|
|
|
|
|
|
|
// Tests that CDS client should send an ACK upon correct CDS response.
|
|
|
|
|