Add more tests for service config state transitions

reviewable/pr18946/r2
Yash Tibrewal 6 years ago
parent aa0a26cdbc
commit 8030e12624
  1. 8
      src/core/ext/filters/client_channel/client_channel.cc
  2. 31
      src/core/ext/filters/client_channel/resolver_result_parsing.cc
  3. 3
      src/core/ext/filters/client_channel/resolver_result_parsing.h
  4. 140
      test/cpp/end2end/service_config_end2end_test.cc

@ -266,6 +266,7 @@ class ChannelData {
grpc_connectivity_state_tracker state_tracker_;
ExternalConnectivityWatcher::WatcherList external_connectivity_watcher_list_;
UniquePtr<char> health_check_service_name_;
bool saved_service_config_ = false;
//
// Fields accessed from both data plane and control plane combiners.
@ -1136,13 +1137,14 @@ bool ChannelData::ProcessResolverResultLocked(
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
grpc_error** service_config_error) {
ChannelData* chand = static_cast<ChannelData*>(arg);
ProcessedResolverResult resolver_result(result);
ProcessedResolverResult resolver_result(result, chand->saved_service_config_);
*service_config_error = resolver_result.service_config_error();
if (*service_config_error != GRPC_ERROR_NONE) {
// We got an invalid service config.
// We got an invalid service config. If we had a service config previously,
// we will continue using it.
return false;
}
chand->saved_service_config_ = true;
char* service_config_json = gpr_strdup(resolver_result.service_config_json());
if (grpc_client_channel_routing_trace.enabled()) {
gpr_log(GPR_INFO, "chand=%p: resolver returned service config: \"%s\"",

@ -59,19 +59,34 @@ void ClientChannelServiceConfigParser::Register() {
}
ProcessedResolverResult::ProcessedResolverResult(
const Resolver::Result& resolver_result)
const Resolver::Result& resolver_result, bool saved_service_config)
: service_config_(resolver_result.service_config) {
// If resolver did not return a service config or returned an invalid service
// config, use the default specified via the client API.
// config, we need a fallback service config
if (service_config_ == nullptr) {
const char* service_config_json = grpc_channel_arg_get_string(
grpc_channel_args_find(resolver_result.args, GRPC_ARG_SERVICE_CONFIG));
if (service_config_json != nullptr) {
service_config_ =
ServiceConfig::Create(service_config_json, &service_config_error_);
} else {
// If the service config was invalid, then prefer using the saved service
// config, otherwise use the default service config provided by the client
// API
if (resolver_result.service_config_error != GRPC_ERROR_NONE &&
saved_service_config) {
// Return the service config error to client channel, so that it continues
// using the existing service config.
service_config_error_ =
GRPC_ERROR_REF(resolver_result.service_config_error);
} else {
// Either no service config or an invalid service config was received.
const char* service_config_json =
grpc_channel_arg_get_string(grpc_channel_args_find(
resolver_result.args, GRPC_ARG_SERVICE_CONFIG));
if (service_config_json != nullptr) {
service_config_ =
ServiceConfig::Create(service_config_json, &service_config_error_);
} else {
// We could not find a fallback service config, save the service config
// error.
service_config_error_ =
GRPC_ERROR_REF(resolver_result.service_config_error);
}
}
} else {
service_config_error_ =

@ -125,7 +125,8 @@ class ProcessedResolverResult {
public:
// Processes the resolver result and populates the relative members
// for later consumption.
ProcessedResolverResult(const Resolver::Result& resolver_result);
ProcessedResolverResult(const Resolver::Result& resolver_result,
bool saved_service_config);
~ProcessedResolverResult() { GRPC_ERROR_UNREF(service_config_error_); }

@ -201,6 +201,15 @@ class ServiceConfigEnd2endTest : public ::testing::Test {
response_generator_->SetResponse(result);
}
void SetNextResolutionWithServiceConfig(const std::vector<int>& ports,
const char* svc_cfg) {
grpc_core::ExecCtx exec_ctx;
grpc_core::Resolver::Result result = BuildFakeResults(ports);
result.service_config =
grpc_core::ServiceConfig::Create(svc_cfg, &result.service_config_error);
response_generator_->SetResponse(result);
}
std::vector<int> GetServersPorts(size_t start_index = 0) {
std::vector<int> ports;
for (size_t i = start_index; i < servers_.size(); ++i) {
@ -377,6 +386,18 @@ class ServiceConfigEnd2endTest : public ::testing::Test {
}
}
const char* ValidServiceConfigV1() { return "{\"version\": \"1\"}"; }
const char* ValidServiceConfigV2() { return "{\"version\": \"2\"}"; }
const char* ValidDefaultServiceConfig() {
return "{\"version\": \"valid_default\"}";
}
const char* InvalidDefaultServiceConfig() {
return "{\"version\": \"invalid_default\"}";
}
const grpc::string server_host_;
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
std::vector<std::unique_ptr<ServerData>> servers_;
@ -386,12 +407,25 @@ class ServiceConfigEnd2endTest : public ::testing::Test {
std::shared_ptr<ChannelCredentials> creds_;
};
TEST_F(ServiceConfigEnd2endTest, BasicTest) {
TEST_F(ServiceConfigEnd2endTest, NoServiceConfigTest) {
StartServers(1);
auto channel = BuildChannel();
auto stub = BuildStub(channel);
SetNextResolutionNoServiceConfig(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ("", channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest, NoServiceConfigWithDefaultConfigTest) {
StartServers(1);
ChannelArguments args;
args.SetServiceConfigJSON(ValidDefaultServiceConfig());
auto channel = BuildChannel(args);
auto stub = BuildStub(channel);
SetNextResolutionNoServiceConfig(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidDefaultServiceConfig(),
channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest, InvalidServiceConfigTest) {
@ -402,26 +436,120 @@ TEST_F(ServiceConfigEnd2endTest, InvalidServiceConfigTest) {
CheckRpcSendFailure(stub);
}
TEST_F(ServiceConfigEnd2endTest, ValidServiceConfigAfterInvalidTest) {
TEST_F(ServiceConfigEnd2endTest, InvalidServiceConfigWithDefaultConfigTest) {
StartServers(1);
ChannelArguments args;
args.SetServiceConfigJSON(ValidDefaultServiceConfig());
auto channel = BuildChannel(args);
auto stub = BuildStub(channel);
SetNextResolutionInvalidServiceConfig(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidDefaultServiceConfig(),
channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest, ValidServiceConfigUpdatesTest) {
StartServers(1);
auto channel = BuildChannel();
auto stub = BuildStub(channel);
SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV1());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str());
SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV2());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidServiceConfigV2(), channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest,
NoServiceConfigUpdateAfterValidServiceConfigTest) {
StartServers(1);
auto channel = BuildChannel();
auto stub = BuildStub(channel);
SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV1());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str());
SetNextResolutionNoServiceConfig(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ("", channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest,
NoServiceConfigUpdateAfterValidServiceConfigWithDefaultConfigTest) {
StartServers(1);
ChannelArguments args;
args.SetServiceConfigJSON(ValidDefaultServiceConfig());
auto channel = BuildChannel(args);
auto stub = BuildStub(channel);
SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV1());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str());
SetNextResolutionNoServiceConfig(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidDefaultServiceConfig(),
channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest,
InvalidServiceConfigUpdateAfterValidServiceConfigTest) {
StartServers(1);
auto channel = BuildChannel();
auto stub = BuildStub(channel);
SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV1());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str());
SetNextResolutionInvalidServiceConfig(GetServersPorts());
CheckRpcSendFailure(stub);
SetNextResolutionValidServiceConfig(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest, InvalidServiceConfigWithDefaultConfigTest) {
TEST_F(ServiceConfigEnd2endTest,
InvalidServiceConfigUpdateAfterValidServiceConfigWithDefaultConfigTest) {
StartServers(1);
ChannelArguments args;
args.SetServiceConfigJSON("{}");
args.SetServiceConfigJSON(ValidDefaultServiceConfig());
auto channel = BuildChannel(args);
auto stub = BuildStub(channel);
SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV1());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str());
SetNextResolutionInvalidServiceConfig(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest,
ValidServiceConfigAfterInvalidServiceConfigTest) {
StartServers(1);
auto channel = BuildChannel();
auto stub = BuildStub(channel);
SetNextResolutionInvalidServiceConfig(GetServersPorts());
CheckRpcSendFailure(stub);
SetNextResolutionValidServiceConfig(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
}
TEST_F(ServiceConfigEnd2endTest, NoServiceConfigAfterInvalidServiceConfigTest) {
StartServers(1);
auto channel = BuildChannel();
auto stub = BuildStub(channel);
SetNextResolutionInvalidServiceConfig(GetServersPorts());
CheckRpcSendFailure(stub);
SetNextResolutionNoServiceConfig(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ("", channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest,
AnotherInvalidServiceConfigAfterInvalidServiceConfigTest) {
StartServers(1);
auto channel = BuildChannel();
auto stub = BuildStub(channel);
SetNextResolutionInvalidServiceConfig(GetServersPorts());
CheckRpcSendFailure(stub);
SetNextResolutionInvalidServiceConfig(GetServersPorts());
CheckRpcSendFailure(stub);
}
} // namespace
} // namespace testing
} // namespace grpc

Loading…
Cancel
Save