Merge pull request #18946 from yashykt/svccfgerrortransient

Service Config Changes to set channel in transient failure on invalid service config
pull/18839/head
Yash Tibrewal 6 years ago committed by GitHub
commit aa89a97531
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 41
      CMakeLists.txt
  2. 48
      Makefile
  3. 12
      build.yaml
  4. 198
      src/core/ext/filters/client_channel/client_channel.cc
  5. 8
      src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
  6. 83
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  7. 83
      src/core/ext/filters/client_channel/resolver_result_parsing.cc
  8. 58
      src/core/ext/filters/client_channel/resolver_result_parsing.h
  9. 33
      src/core/ext/filters/client_channel/resolving_lb_policy.cc
  10. 6
      src/core/ext/filters/client_channel/resolving_lb_policy.h
  11. 2
      test/core/end2end/tests/retry_throttled.cc
  12. 20
      test/cpp/end2end/BUILD
  13. 33
      test/cpp/end2end/grpclb_end2end_test.cc
  14. 561
      test/cpp/end2end/service_config_end2end_test.cc
  15. 1
      test/cpp/naming/gen_build_yaml.py
  16. 15
      test/cpp/naming/resolver_component_test.cc
  17. 100
      test/cpp/naming/resolver_component_tests_runner.py
  18. 118
      test/cpp/naming/resolver_test_record_groups.yaml
  19. 18
      tools/run_tests/generated/sources_and_headers.json
  20. 24
      tools/run_tests/generated/tests.json

@ -703,6 +703,7 @@ add_dependencies(buildtests_cxx server_crash_test_client)
add_dependencies(buildtests_cxx server_early_return_test)
add_dependencies(buildtests_cxx server_interceptors_end2end_test)
add_dependencies(buildtests_cxx server_request_call_test)
add_dependencies(buildtests_cxx service_config_end2end_test)
add_dependencies(buildtests_cxx service_config_test)
add_dependencies(buildtests_cxx shutdown_test)
add_dependencies(buildtests_cxx slice_hash_table_test)
@ -15995,6 +15996,46 @@ target_link_libraries(server_request_call_test
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(service_config_end2end_test
test/cpp/end2end/service_config_end2end_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(service_config_end2end_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(service_config_end2end_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc++_test_util
grpc_test_util
grpc++
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)

@ -1265,6 +1265,7 @@ server_crash_test_client: $(BINDIR)/$(CONFIG)/server_crash_test_client
server_early_return_test: $(BINDIR)/$(CONFIG)/server_early_return_test
server_interceptors_end2end_test: $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test
server_request_call_test: $(BINDIR)/$(CONFIG)/server_request_call_test
service_config_end2end_test: $(BINDIR)/$(CONFIG)/service_config_end2end_test
service_config_test: $(BINDIR)/$(CONFIG)/service_config_test
shutdown_test: $(BINDIR)/$(CONFIG)/shutdown_test
slice_hash_table_test: $(BINDIR)/$(CONFIG)/slice_hash_table_test
@ -1736,6 +1737,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/server_early_return_test \
$(BINDIR)/$(CONFIG)/server_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/server_request_call_test \
$(BINDIR)/$(CONFIG)/service_config_end2end_test \
$(BINDIR)/$(CONFIG)/service_config_test \
$(BINDIR)/$(CONFIG)/shutdown_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
@ -1882,6 +1884,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/server_early_return_test \
$(BINDIR)/$(CONFIG)/server_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/server_request_call_test \
$(BINDIR)/$(CONFIG)/service_config_end2end_test \
$(BINDIR)/$(CONFIG)/service_config_test \
$(BINDIR)/$(CONFIG)/shutdown_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
@ -2402,6 +2405,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test || ( echo test server_interceptors_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing server_request_call_test"
$(Q) $(BINDIR)/$(CONFIG)/server_request_call_test || ( echo test server_request_call_test failed ; exit 1 )
$(E) "[RUN] Testing service_config_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/service_config_end2end_test || ( echo test service_config_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing service_config_test"
$(Q) $(BINDIR)/$(CONFIG)/service_config_test || ( echo test service_config_test failed ; exit 1 )
$(E) "[RUN] Testing shutdown_test"
@ -18960,6 +18965,49 @@ endif
$(OBJDIR)/$(CONFIG)/test/cpp/server/server_request_call_test.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc
SERVICE_CONFIG_END2END_TEST_SRC = \
test/cpp/end2end/service_config_end2end_test.cc \
SERVICE_CONFIG_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SERVICE_CONFIG_END2END_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/service_config_end2end_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
$(BINDIR)/$(CONFIG)/service_config_end2end_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/service_config_end2end_test: $(PROTOBUF_DEP) $(SERVICE_CONFIG_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(SERVICE_CONFIG_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/service_config_end2end_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/end2end/service_config_end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_service_config_end2end_test: $(SERVICE_CONFIG_END2END_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(SERVICE_CONFIG_END2END_TEST_OBJS:.o=.dep)
endif
endif
SERVICE_CONFIG_TEST_SRC = \
test/core/client_channel/service_config_test.cc \

@ -5542,6 +5542,18 @@ targets:
- grpc++_unsecure
- grpc_unsecure
- gpr
- name: service_config_end2end_test
gtest: true
build: test
language: c++
src:
- test/cpp/end2end/service_config_end2end_test.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- gpr
- name: service_config_test
gtest: true
build: test

@ -67,7 +67,6 @@
#include "src/core/lib/transport/status_metadata.h"
using grpc_core::internal::ClientChannelMethodParsedObject;
using grpc_core::internal::ProcessedResolverResult;
using grpc_core::internal::ServerRetryThrottleData;
//
@ -224,7 +223,8 @@ class ChannelData {
static bool ProcessResolverResultLocked(
void* arg, const Resolver::Result& result, const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config);
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
grpc_error** service_config_error);
grpc_error* DoPingLocked(grpc_transport_op* op);
@ -232,6 +232,12 @@ class ChannelData {
static void TryToConnectLocked(void* arg, grpc_error* error_ignored);
void ProcessLbPolicy(
const Resolver::Result& resolver_result,
const internal::ClientChannelGlobalParsedObject* parsed_service_config,
UniquePtr<char>* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config);
//
// Fields set at construction and never modified.
//
@ -241,6 +247,7 @@ class ChannelData {
grpc_channel_stack* owning_stack_;
ClientChannelFactory* client_channel_factory_;
UniquePtr<char> server_name_;
RefCountedPtr<ServiceConfig> default_service_config_;
// Initialized shortly after construction.
channelz::ClientChannelNode* channelz_node_ = nullptr;
@ -265,6 +272,8 @@ class ChannelData {
grpc_connectivity_state_tracker state_tracker_;
ExternalConnectivityWatcher::WatcherList external_connectivity_watcher_list_;
UniquePtr<char> health_check_service_name_;
RefCountedPtr<ServiceConfig> saved_service_config_;
bool received_first_resolver_result_ = false;
//
// Fields accessed from both data plane and control plane combiners.
@ -1066,6 +1075,19 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
"filter");
return;
}
// Get default service config
const char* service_config_json = grpc_channel_arg_get_string(
grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG));
// TODO(yashkt): Make sure we set the channel in TRANSIENT_FAILURE on an
// invalid default service config
if (service_config_json != nullptr) {
*error = GRPC_ERROR_NONE;
default_service_config_ = ServiceConfig::Create(service_config_json, error);
if (*error != GRPC_ERROR_NONE) {
default_service_config_.reset();
return;
}
}
grpc_uri* uri = grpc_uri_parse(server_uri, true);
if (uri != nullptr && uri->path[0] != '\0') {
server_name_.reset(
@ -1128,40 +1150,164 @@ ChannelData::~ChannelData() {
gpr_mu_destroy(&info_mu_);
}
void ChannelData::ProcessLbPolicy(
const Resolver::Result& resolver_result,
const internal::ClientChannelGlobalParsedObject* parsed_service_config,
UniquePtr<char>* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config) {
// Prefer the LB policy name found in the service config.
if (parsed_service_config != nullptr &&
parsed_service_config->parsed_lb_config() != nullptr) {
lb_policy_name->reset(
gpr_strdup(parsed_service_config->parsed_lb_config()->name()));
*lb_policy_config = parsed_service_config->parsed_lb_config();
return;
}
const char* local_policy_name = nullptr;
if (parsed_service_config != nullptr &&
parsed_service_config->parsed_deprecated_lb_policy() != nullptr) {
local_policy_name = parsed_service_config->parsed_deprecated_lb_policy();
} else {
const grpc_arg* channel_arg =
grpc_channel_args_find(resolver_result.args, GRPC_ARG_LB_POLICY_NAME);
local_policy_name = grpc_channel_arg_get_string(channel_arg);
}
// Special case: If at least one balancer address is present, we use
// the grpclb policy, regardless of what the resolver has returned.
bool found_balancer_address = false;
for (size_t i = 0; i < resolver_result.addresses.size(); ++i) {
const ServerAddress& address = resolver_result.addresses[i];
if (address.IsBalancer()) {
found_balancer_address = true;
break;
}
}
if (found_balancer_address) {
if (local_policy_name != nullptr &&
strcmp(local_policy_name, "grpclb") != 0) {
gpr_log(GPR_INFO,
"resolver requested LB policy %s but provided at least one "
"balancer address -- forcing use of grpclb LB policy",
local_policy_name);
}
local_policy_name = "grpclb";
}
// Use pick_first if nothing was specified and we didn't select grpclb
// above.
lb_policy_name->reset(gpr_strdup(
local_policy_name == nullptr ? "pick_first" : local_policy_name));
}
// Synchronous callback from ResolvingLoadBalancingPolicy to process a
// resolver result update.
bool ChannelData::ProcessResolverResultLocked(
void* arg, const Resolver::Result& result, const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config) {
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
grpc_error** service_config_error) {
ChannelData* chand = static_cast<ChannelData*>(arg);
ProcessedResolverResult resolver_result(result);
char* service_config_json = gpr_strdup(resolver_result.service_config_json());
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO, "chand=%p: resolver returned service config: \"%s\"",
chand, service_config_json);
}
chand->health_check_service_name_.reset(
gpr_strdup(resolver_result.health_check_service_name()));
// Create service config setter to update channel state in the data
// plane combiner. Destroys itself when done.
New<ServiceConfigSetter>(chand, resolver_result.retry_throttle_data(),
resolver_result.service_config());
RefCountedPtr<ServiceConfig> service_config;
// If resolver did not return a service config or returned an invalid service
// config, we need a fallback service config.
if (result.service_config_error != GRPC_ERROR_NONE) {
// If the service config was invalid, then fallback to the saved service
// config. If there is no saved config either, use the default service
// config.
if (chand->saved_service_config_ != nullptr) {
service_config = chand->saved_service_config_;
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p: resolver returned invalid service config. "
"Continuing to use previous service config.",
chand);
}
} else if (chand->default_service_config_ != nullptr) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p: resolver returned invalid service config. Using "
"default service config provided by client API.",
chand);
}
service_config = chand->default_service_config_;
}
} else if (result.service_config == nullptr) {
if (chand->default_service_config_ != nullptr) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p: resolver returned no service config. Using default "
"service config provided by client API.",
chand);
}
service_config = chand->default_service_config_;
}
} else {
service_config = result.service_config;
}
*service_config_error = GRPC_ERROR_REF(result.service_config_error);
if (service_config == nullptr &&
result.service_config_error != GRPC_ERROR_NONE) {
return false;
}
UniquePtr<char> service_config_json;
// Process service config.
const internal::ClientChannelGlobalParsedObject* parsed_service_config =
nullptr;
if (service_config != nullptr) {
parsed_service_config =
static_cast<const internal::ClientChannelGlobalParsedObject*>(
service_config->GetParsedGlobalServiceConfigObject(
internal::ClientChannelServiceConfigParser::ParserIndex()));
}
const bool service_config_changed =
((service_config == nullptr) !=
(chand->saved_service_config_ == nullptr)) ||
(service_config != nullptr &&
strcmp(service_config->service_config_json(),
chand->saved_service_config_->service_config_json()) != 0);
if (service_config_changed) {
service_config_json.reset(gpr_strdup(
service_config != nullptr ? service_config->service_config_json()
: ""));
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p: resolver returned updated service config: \"%s\"",
chand, service_config_json.get());
}
chand->saved_service_config_ = std::move(service_config);
if (parsed_service_config != nullptr) {
chand->health_check_service_name_.reset(
gpr_strdup(parsed_service_config->health_check_service_name()));
} else {
chand->health_check_service_name_.reset();
}
}
// We want to set the service config at least once. This should not really be
// needed, but we are doing it as a defensive approach. This can be removed,
// if we feel it is unnecessary.
if (service_config_changed || !chand->received_first_resolver_result_) {
chand->received_first_resolver_result_ = true;
Optional<internal::ClientChannelGlobalParsedObject::RetryThrottling>
retry_throttle_data;
if (parsed_service_config != nullptr) {
retry_throttle_data = parsed_service_config->retry_throttling();
}
// Create service config setter to update channel state in the data
// plane combiner. Destroys itself when done.
New<ServiceConfigSetter>(chand, retry_throttle_data,
chand->saved_service_config_);
}
UniquePtr<char> processed_lb_policy_name;
chand->ProcessLbPolicy(result, parsed_service_config,
&processed_lb_policy_name, lb_policy_config);
// Swap out the data used by GetChannelInfo().
bool service_config_changed;
{
MutexLock lock(&chand->info_mu_);
chand->info_lb_policy_name_ = resolver_result.lb_policy_name();
service_config_changed =
((service_config_json == nullptr) !=
(chand->info_service_config_json_ == nullptr)) ||
(service_config_json != nullptr &&
strcmp(service_config_json, chand->info_service_config_json_.get()) !=
0);
chand->info_service_config_json_.reset(service_config_json);
chand->info_lb_policy_name_ = std::move(processed_lb_policy_name);
if (service_config_json != nullptr) {
chand->info_service_config_json_ = std::move(service_config_json);
}
}
// Return results.
*lb_policy_name = chand->info_lb_policy_name_.get();
*lb_policy_config = resolver_result.lb_policy_config();
return service_config_changed;
}
@ -2883,6 +3029,8 @@ void CallData::AddSubchannelBatchesForPendingBatches(
// If we're not retrying, just send the batch as-is.
if (method_params_ == nullptr ||
method_params_->retry_policy() == nullptr || retry_committed_) {
// TODO(roth) : We should probably call
// MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy here.
AddClosureForSubchannelBatch(elem, batch, closures);
PendingBatchClear(pending);
continue;

@ -506,7 +506,13 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
GRPC_ARG_INHIBIT_HEALTH_CHECKING};
// Create a subchannel for each address.
for (size_t i = 0; i < addresses.size(); i++) {
GPR_ASSERT(!addresses[i].IsBalancer());
// TODO(roth): we should ideally hide this from the LB policy code. In
// principle, if we're dealing with this special case in the client_channel
// code for selecting grpclb, then we should also strip out these addresses
// there if we're not using grpclb.
if (addresses[i].IsBalancer()) {
continue;
}
InlinedVector<grpc_arg, 3> args_to_add;
const size_t subchannel_address_arg_index = args_to_add.size();
args_to_add.emplace_back(

@ -227,65 +227,94 @@ bool ValueInJsonArray(grpc_json* array, const char* value) {
return false;
}
char* ChooseServiceConfig(char* service_config_choice_json) {
char* ChooseServiceConfig(char* service_config_choice_json,
grpc_error** error) {
grpc_json* choices_json = grpc_json_parse_string(service_config_choice_json);
if (choices_json == nullptr || choices_json->type != GRPC_JSON_ARRAY) {
gpr_log(GPR_ERROR, "cannot parse service config JSON string");
if (choices_json == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Service Config JSON Parsing, error: could not parse");
return nullptr;
}
if (choices_json->type != GRPC_JSON_ARRAY) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Service Config Choices, error: should be of type array");
return nullptr;
}
char* service_config = nullptr;
InlinedVector<grpc_error*, 4> error_list;
bool found_choice = false; // have we found a choice?
for (grpc_json* choice = choices_json->child; choice != nullptr;
choice = choice->next) {
if (choice->type != GRPC_JSON_OBJECT) {
gpr_log(GPR_ERROR, "cannot parse service config JSON string");
break;
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Service Config Choice, error: should be of type object"));
continue;
}
grpc_json* service_config_json = nullptr;
bool selected = true; // has this choice been rejected?
for (grpc_json* field = choice->child; field != nullptr;
field = field->next) {
// Check client language, if specified.
if (strcmp(field->key, "clientLanguage") == 0) {
if (field->type != GRPC_JSON_ARRAY || !ValueInJsonArray(field, "c++")) {
service_config_json = nullptr;
break;
if (field->type != GRPC_JSON_ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:clientLanguage error:should be of type array"));
} else if (!ValueInJsonArray(field, "c++")) {
selected = false;
}
}
// Check client hostname, if specified.
if (strcmp(field->key, "clientHostname") == 0) {
if (field->type != GRPC_JSON_ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:clientHostname error:should be of type array"));
continue;
}
char* hostname = grpc_gethostname();
if (hostname == nullptr || field->type != GRPC_JSON_ARRAY ||
!ValueInJsonArray(field, hostname)) {
service_config_json = nullptr;
break;
if (hostname == nullptr || !ValueInJsonArray(field, hostname)) {
selected = false;
}
}
// Check percentage, if specified.
if (strcmp(field->key, "percentage") == 0) {
if (field->type != GRPC_JSON_NUMBER) {
service_config_json = nullptr;
break;
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:percentage error:should be of type number"));
continue;
}
int random_pct = rand() % 100;
int percentage;
if (sscanf(field->value, "%d", &percentage) != 1 ||
random_pct > percentage || percentage == 0) {
service_config_json = nullptr;
break;
if (sscanf(field->value, "%d", &percentage) != 1) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:percentage error:should be of type integer"));
continue;
}
if (random_pct > percentage || percentage == 0) {
selected = false;
}
}
// Save service config.
if (strcmp(field->key, "serviceConfig") == 0) {
if (field->type == GRPC_JSON_OBJECT) {
service_config_json = field;
} else {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:serviceConfig error:should be of type object"));
}
}
}
if (service_config_json != nullptr) {
if (!found_choice && selected && service_config_json != nullptr) {
service_config = grpc_json_dump_to_string(service_config_json, 0);
break;
found_choice = true;
}
}
grpc_json_destroy(choices_json);
if (!error_list.empty()) {
gpr_free(service_config);
service_config = nullptr;
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Service Config Choices Parser",
&error_list);
}
return service_config;
}
@ -303,17 +332,15 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
Result result;
result.addresses = std::move(*r->addresses_);
if (r->service_config_json_ != nullptr) {
char* service_config_string =
ChooseServiceConfig(r->service_config_json_);
char* service_config_string = ChooseServiceConfig(
r->service_config_json_, &result.service_config_error);
gpr_free(r->service_config_json_);
if (service_config_string != nullptr) {
if (result.service_config_error == GRPC_ERROR_NONE &&
service_config_string != nullptr) {
GRPC_CARES_TRACE_LOG("resolver:%p selected service config choice: %s",
r, service_config_string);
grpc_error* service_config_error = GRPC_ERROR_NONE;
result.service_config =
ServiceConfig::Create(service_config_string, &service_config_error);
// Error is currently unused.
GRPC_ERROR_UNREF(service_config_error);
result.service_config = ServiceConfig::Create(
service_config_string, &result.service_config_error);
}
gpr_free(service_config_string);
}

@ -58,89 +58,6 @@ void ClientChannelServiceConfigParser::Register() {
New<ClientChannelServiceConfigParser>()));
}
ProcessedResolverResult::ProcessedResolverResult(
const Resolver::Result& resolver_result)
: service_config_(resolver_result.service_config) {
// If resolver did not return a service config, use the default
// specified via the client API.
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) {
grpc_error* error = GRPC_ERROR_NONE;
service_config_ = ServiceConfig::Create(service_config_json, &error);
// Error is currently unused.
GRPC_ERROR_UNREF(error);
}
}
// Process service config.
const ClientChannelGlobalParsedObject* parsed_object = nullptr;
if (service_config_ != nullptr) {
parsed_object = static_cast<const ClientChannelGlobalParsedObject*>(
service_config_->GetParsedGlobalServiceConfigObject(
ClientChannelServiceConfigParser::ParserIndex()));
ProcessServiceConfig(resolver_result, parsed_object);
}
ProcessLbPolicy(resolver_result, parsed_object);
}
void ProcessedResolverResult::ProcessServiceConfig(
const Resolver::Result& resolver_result,
const ClientChannelGlobalParsedObject* parsed_object) {
health_check_service_name_ = parsed_object->health_check_service_name();
service_config_json_ = service_config_->service_config_json();
if (parsed_object != nullptr) {
retry_throttle_data_ = parsed_object->retry_throttling();
}
}
void ProcessedResolverResult::ProcessLbPolicy(
const Resolver::Result& resolver_result,
const ClientChannelGlobalParsedObject* parsed_object) {
// Prefer the LB policy name found in the service config.
if (parsed_object != nullptr) {
if (parsed_object->parsed_lb_config() != nullptr) {
lb_policy_name_.reset(
gpr_strdup(parsed_object->parsed_lb_config()->name()));
lb_policy_config_ = parsed_object->parsed_lb_config();
} else {
lb_policy_name_.reset(
gpr_strdup(parsed_object->parsed_deprecated_lb_policy()));
}
}
// Otherwise, find the LB policy name set by the client API.
if (lb_policy_name_ == nullptr) {
const grpc_arg* channel_arg =
grpc_channel_args_find(resolver_result.args, GRPC_ARG_LB_POLICY_NAME);
lb_policy_name_.reset(gpr_strdup(grpc_channel_arg_get_string(channel_arg)));
}
// Special case: If at least one balancer address is present, we use
// the grpclb policy, regardless of what the resolver has returned.
bool found_balancer_address = false;
for (size_t i = 0; i < resolver_result.addresses.size(); ++i) {
const ServerAddress& address = resolver_result.addresses[i];
if (address.IsBalancer()) {
found_balancer_address = true;
break;
}
}
if (found_balancer_address) {
if (lb_policy_name_ != nullptr &&
strcmp(lb_policy_name_.get(), "grpclb") != 0) {
gpr_log(GPR_INFO,
"resolver requested LB policy %s but provided at least one "
"balancer address -- forcing use of grpclb LB policy",
lb_policy_name_.get());
}
lb_policy_name_.reset(gpr_strdup("grpclb"));
}
// Use pick_first if nothing was specified and we didn't select grpclb
// above.
if (lb_policy_name_ == nullptr) {
lb_policy_name_.reset(gpr_strdup("pick_first"));
}
}
namespace {
// Parses a JSON field of the form generated for a google.proto.Duration

@ -118,64 +118,6 @@ class ClientChannelServiceConfigParser : public ServiceConfig::Parser {
static void Register();
};
// TODO(yashykt): It would be cleaner to move this logic to the client_channel
// code. A container of processed fields from the resolver result. Simplifies
// the usage of resolver result.
class ProcessedResolverResult {
public:
// Processes the resolver result and populates the relative members
// for later consumption.
ProcessedResolverResult(const Resolver::Result& resolver_result);
// Getters. Any managed object's ownership is transferred.
const char* service_config_json() { return service_config_json_; }
RefCountedPtr<ServiceConfig> service_config() { return service_config_; }
UniquePtr<char> lb_policy_name() { return std::move(lb_policy_name_); }
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config() {
return lb_policy_config_;
}
Optional<ClientChannelGlobalParsedObject::RetryThrottling>
retry_throttle_data() {
return retry_throttle_data_;
}
const char* health_check_service_name() { return health_check_service_name_; }
private:
// Finds the service config; extracts LB config and (maybe) retry throttle
// params from it.
void ProcessServiceConfig(
const Resolver::Result& resolver_result,
const ClientChannelGlobalParsedObject* parsed_object);
// Extracts the LB policy.
void ProcessLbPolicy(const Resolver::Result& resolver_result,
const ClientChannelGlobalParsedObject* parsed_object);
// Parses the service config. Intended to be used by
// ServiceConfig::ParseGlobalParams.
static void ParseServiceConfig(const grpc_json* field,
ProcessedResolverResult* parsing_state);
// Parses the LB config from service config.
void ParseLbConfigFromServiceConfig(const grpc_json* field);
// Parses the retry throttle parameters from service config.
void ParseRetryThrottleParamsFromServiceConfig(const grpc_json* field);
// Service config.
const char* service_config_json_ = nullptr;
RefCountedPtr<ServiceConfig> service_config_;
// LB policy.
UniquePtr<char> lb_policy_name_;
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config_;
// Retry throttle data.
Optional<ClientChannelGlobalParsedObject::RetryThrottling>
retry_throttle_data_;
const char* health_check_service_name_ = nullptr;
};
} // namespace internal
} // namespace grpc_core

@ -532,18 +532,32 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
const char* lb_policy_name = nullptr;
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config;
bool service_config_changed = false;
char* service_config_error_string = nullptr;
if (process_resolver_result_ != nullptr) {
service_config_changed =
process_resolver_result_(process_resolver_result_user_data_, result,
&lb_policy_name, &lb_policy_config);
grpc_error* service_config_error = GRPC_ERROR_NONE;
service_config_changed = process_resolver_result_(
process_resolver_result_user_data_, result, &lb_policy_name,
&lb_policy_config, &service_config_error);
if (service_config_error != GRPC_ERROR_NONE) {
service_config_error_string =
gpr_strdup(grpc_error_string(service_config_error));
if (lb_policy_name == nullptr) {
// Use an empty lb_policy_name as an indicator that we received an
// invalid service config and we don't have a fallback service config.
OnResolverError(service_config_error);
} else {
GRPC_ERROR_UNREF(service_config_error);
}
}
} else {
lb_policy_name = child_policy_name_.get();
lb_policy_config = child_lb_config_;
}
GPR_ASSERT(lb_policy_name != nullptr);
// Create or update LB policy, as needed.
CreateOrUpdateLbPolicyLocked(lb_policy_name, lb_policy_config,
std::move(result), &trace_strings);
if (lb_policy_name != nullptr) {
// Create or update LB policy, as needed.
CreateOrUpdateLbPolicyLocked(lb_policy_name, lb_policy_config,
std::move(result), &trace_strings);
}
// Add channel trace event.
if (channelz_node() != nullptr) {
if (service_config_changed) {
@ -551,10 +565,15 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
// config in the trace, at the risk of bloating the trace logs.
trace_strings.push_back(gpr_strdup("Service config changed"));
}
if (service_config_error_string != nullptr) {
trace_strings.push_back(service_config_error_string);
service_config_error_string = nullptr;
}
MaybeAddTraceMessagesForAddressChangesLocked(resolution_contains_addresses,
&trace_strings);
ConcatenateAndAddChannelTraceLocked(&trace_strings);
}
gpr_free(service_config_error_string);
}
} // namespace grpc_core

@ -65,10 +65,14 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
// Synchronous callback that takes the resolver result and sets
// lb_policy_name and lb_policy_config to point to the right data.
// Returns true if the service config has changed since the last result.
// If the returned service_config_error is not none and lb_policy_name is
// empty, it means that we don't have a valid service config to use, and we
// should set the channel to be in TRANSIENT_FAILURE.
typedef bool (*ProcessResolverResultCallback)(
void* user_data, const Resolver::Result& result,
const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config);
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
grpc_error** service_config_error);
// If error is set when this returns, then construction failed, and
// the caller may not use the new object.
ResolvingLoadBalancingPolicy(

@ -141,7 +141,7 @@ static void test_retry_throttled(grpc_end2end_test_config config) {
// purposes of this test.)
" \"retryThrottling\": {\n"
" \"maxTokens\": 2,\n"
" \"tokenRatio\": 1.0,\n"
" \"tokenRatio\": 1.0\n"
" }\n"
"}");
grpc_channel_args client_args = {1, &arg};

@ -423,6 +423,26 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "service_config_end2end_test",
srcs = ["service_config_end2end_test.cc"],
external_deps = [
"gmock",
"gtest",
],
deps = [
":test_service_impl",
"//:gpr",
"//:grpc",
"//:grpc++",
"//src/proto/grpc/testing:echo_messages_proto",
"//src/proto/grpc/testing:echo_proto",
"//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
"//test/core/util:grpc_test_util",
"//test/cpp/util:test_util",
],
)
grpc_cc_test(
name = "grpclb_end2end_test",
srcs = ["grpclb_end2end_test.cc"],

@ -737,6 +737,39 @@ TEST_F(SingleBalancerTest, SelectGrpclbWithMigrationServiceConfig) {
EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName());
}
TEST_F(SingleBalancerTest,
DoNotSpecialCaseUseGrpclbWithLoadBalancingConfigTest) {
const int kFallbackTimeoutMs = 200 * grpc_test_slowdown_factor();
ResetStub(kFallbackTimeoutMs);
SetNextResolution({AddressData{backends_[0]->port_, false, ""},
AddressData{balancers_[0]->port_, true, ""}},
"{\n"
" \"loadBalancingConfig\":[\n"
" {\"pick_first\":{} }\n"
" ]\n"
"}");
CheckRpcSendOk();
// Check LB policy name for the channel.
EXPECT_EQ("pick_first", channel_->GetLoadBalancingPolicyName());
}
TEST_F(
SingleBalancerTest,
DoNotSpecialCaseUseGrpclbWithLoadBalancingConfigTestAndNoBackendAddress) {
const int kFallbackTimeoutMs = 200 * grpc_test_slowdown_factor();
ResetStub(kFallbackTimeoutMs);
SetNextResolution({AddressData{balancers_[0]->port_, true, ""}},
"{\n"
" \"loadBalancingConfig\":[\n"
" {\"pick_first\":{} }\n"
" ]\n"
"}");
// This should fail since we do not have a non-balancer backend
CheckRpcSendFailure();
// Check LB policy name for the channel.
EXPECT_EQ("pick_first", channel_->GetLoadBalancingPolicyName());
}
TEST_F(SingleBalancerTest,
SelectGrpclbWithMigrationServiceConfigAndNoAddresses) {
const int kFallbackTimeoutMs = 200 * grpc_test_slowdown_factor();

@ -0,0 +1,561 @@
/*
*
* Copyright 2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <algorithm>
#include <memory>
#include <mutex>
#include <random>
#include <set>
#include <thread>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/health_check_service_interface.h>
#include <grpcpp/impl/codegen/sync.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include "src/core/ext/filters/client_channel/backup_poller.h"
#include "src/core/ext/filters/client_channel/global_subchannel_pool.h"
#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/lib/backoff/backoff.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
#include "src/cpp/client/secure_credentials.h"
#include "src/cpp/server/secure_server_credentials.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include "test/cpp/end2end/test_service_impl.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse;
using std::chrono::system_clock;
namespace grpc {
namespace testing {
namespace {
// Subclass of TestServiceImpl that increments a request counter for
// every call to the Echo RPC.
class MyTestServiceImpl : public TestServiceImpl {
public:
MyTestServiceImpl() : request_count_(0) {}
Status Echo(ServerContext* context, const EchoRequest* request,
EchoResponse* response) override {
{
grpc::internal::MutexLock lock(&mu_);
++request_count_;
}
AddClient(context->peer());
return TestServiceImpl::Echo(context, request, response);
}
int request_count() {
grpc::internal::MutexLock lock(&mu_);
return request_count_;
}
void ResetCounters() {
grpc::internal::MutexLock lock(&mu_);
request_count_ = 0;
}
std::set<grpc::string> clients() {
grpc::internal::MutexLock lock(&clients_mu_);
return clients_;
}
private:
void AddClient(const grpc::string& client) {
grpc::internal::MutexLock lock(&clients_mu_);
clients_.insert(client);
}
grpc::internal::Mutex mu_;
int request_count_;
grpc::internal::Mutex clients_mu_;
std::set<grpc::string> clients_;
};
class ServiceConfigEnd2endTest : public ::testing::Test {
protected:
ServiceConfigEnd2endTest()
: server_host_("localhost"),
kRequestMessage_("Live long and prosper."),
creds_(new SecureChannelCredentials(
grpc_fake_transport_security_credentials_create())) {
// Make the backup poller poll very frequently in order to pick up
// updates from all the subchannels's FDs.
GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
}
void SetUp() override {
grpc_init();
response_generator_ =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
}
void TearDown() override {
for (size_t i = 0; i < servers_.size(); ++i) {
servers_[i]->Shutdown();
}
// Explicitly destroy all the members so that we can make sure grpc_shutdown
// has finished by the end of this function, and thus all the registered
// LB policy factories are removed.
stub_.reset();
servers_.clear();
creds_.reset();
grpc_shutdown_blocking();
}
void CreateServers(size_t num_servers,
std::vector<int> ports = std::vector<int>()) {
servers_.clear();
for (size_t i = 0; i < num_servers; ++i) {
int port = 0;
if (ports.size() == num_servers) port = ports[i];
servers_.emplace_back(new ServerData(port));
}
}
void StartServer(size_t index) { servers_[index]->Start(server_host_); }
void StartServers(size_t num_servers,
std::vector<int> ports = std::vector<int>()) {
CreateServers(num_servers, std::move(ports));
for (size_t i = 0; i < num_servers; ++i) {
StartServer(i);
}
}
grpc_core::Resolver::Result BuildFakeResults(const std::vector<int>& ports) {
grpc_core::Resolver::Result result;
for (const int& port : ports) {
char* lb_uri_str;
gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", port);
grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true);
GPR_ASSERT(lb_uri != nullptr);
grpc_resolved_address address;
GPR_ASSERT(grpc_parse_uri(lb_uri, &address));
result.addresses.emplace_back(address.addr, address.len,
nullptr /* args */);
grpc_uri_destroy(lb_uri);
gpr_free(lb_uri_str);
}
return result;
}
void SetNextResolutionNoServiceConfig(const std::vector<int>& ports) {
grpc_core::ExecCtx exec_ctx;
grpc_core::Resolver::Result result = BuildFakeResults(ports);
response_generator_->SetResponse(result);
}
void SetNextResolutionValidServiceConfig(const std::vector<int>& ports) {
grpc_core::ExecCtx exec_ctx;
grpc_core::Resolver::Result result = BuildFakeResults(ports);
result.service_config =
grpc_core::ServiceConfig::Create("{}", &result.service_config_error);
response_generator_->SetResponse(result);
}
void SetNextResolutionInvalidServiceConfig(const std::vector<int>& ports) {
grpc_core::ExecCtx exec_ctx;
grpc_core::Resolver::Result result = BuildFakeResults(ports);
result.service_config =
grpc_core::ServiceConfig::Create("{", &result.service_config_error);
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) {
ports.push_back(servers_[i]->port_);
}
return ports;
}
std::unique_ptr<grpc::testing::EchoTestService::Stub> BuildStub(
const std::shared_ptr<Channel>& channel) {
return grpc::testing::EchoTestService::NewStub(channel);
}
std::shared_ptr<Channel> BuildChannel() {
ChannelArguments args;
args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
response_generator_.get());
return ::grpc::CreateCustomChannel("fake:///", creds_, args);
}
std::shared_ptr<Channel> BuildChannelWithDefaultServiceConfig() {
ChannelArguments args;
args.SetServiceConfigJSON(ValidDefaultServiceConfig());
args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
response_generator_.get());
return ::grpc::CreateCustomChannel("fake:///", creds_, args);
}
bool SendRpc(
const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
EchoResponse* response = nullptr, int timeout_ms = 1000,
Status* result = nullptr, bool wait_for_ready = false) {
const bool local_response = (response == nullptr);
if (local_response) response = new EchoResponse;
EchoRequest request;
request.set_message(kRequestMessage_);
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms));
if (wait_for_ready) context.set_wait_for_ready(true);
Status status = stub->Echo(&context, request, response);
if (result != nullptr) *result = status;
if (local_response) delete response;
return status.ok();
}
void CheckRpcSendOk(
const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
const grpc_core::DebugLocation& location, bool wait_for_ready = false) {
EchoResponse response;
Status status;
const bool success =
SendRpc(stub, &response, 2000, &status, wait_for_ready);
ASSERT_TRUE(success) << "From " << location.file() << ":" << location.line()
<< "\n"
<< "Error: " << status.error_message() << " "
<< status.error_details();
ASSERT_EQ(response.message(), kRequestMessage_)
<< "From " << location.file() << ":" << location.line();
if (!success) abort();
}
void CheckRpcSendFailure(
const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub) {
const bool success = SendRpc(stub);
EXPECT_FALSE(success);
}
struct ServerData {
int port_;
std::unique_ptr<Server> server_;
MyTestServiceImpl service_;
std::unique_ptr<std::thread> thread_;
bool server_ready_ = false;
bool started_ = false;
explicit ServerData(int port = 0) {
port_ = port > 0 ? port : grpc_pick_unused_port_or_die();
}
void Start(const grpc::string& server_host) {
gpr_log(GPR_INFO, "starting server on port %d", port_);
started_ = true;
grpc::internal::Mutex mu;
grpc::internal::MutexLock lock(&mu);
grpc::internal::CondVar cond;
thread_.reset(new std::thread(
std::bind(&ServerData::Serve, this, server_host, &mu, &cond)));
cond.WaitUntil(&mu, [this] { return server_ready_; });
server_ready_ = false;
gpr_log(GPR_INFO, "server startup complete");
}
void Serve(const grpc::string& server_host, grpc::internal::Mutex* mu,
grpc::internal::CondVar* cond) {
std::ostringstream server_address;
server_address << server_host << ":" << port_;
ServerBuilder builder;
std::shared_ptr<ServerCredentials> creds(new SecureServerCredentials(
grpc_fake_transport_security_server_credentials_create()));
builder.AddListeningPort(server_address.str(), std::move(creds));
builder.RegisterService(&service_);
server_ = builder.BuildAndStart();
grpc::internal::MutexLock lock(mu);
server_ready_ = true;
cond->Signal();
}
void Shutdown() {
if (!started_) return;
server_->Shutdown(grpc_timeout_milliseconds_to_deadline(0));
thread_->join();
started_ = false;
}
void SetServingStatus(const grpc::string& service, bool serving) {
server_->GetHealthCheckService()->SetServingStatus(service, serving);
}
};
void ResetCounters() {
for (const auto& server : servers_) server->service_.ResetCounters();
}
void WaitForServer(
const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
size_t server_idx, const grpc_core::DebugLocation& location,
bool ignore_failure = false) {
do {
if (ignore_failure) {
SendRpc(stub);
} else {
CheckRpcSendOk(stub, location, true);
}
} while (servers_[server_idx]->service_.request_count() == 0);
ResetCounters();
}
bool WaitForChannelNotReady(Channel* channel, int timeout_seconds = 5) {
const gpr_timespec deadline =
grpc_timeout_seconds_to_deadline(timeout_seconds);
grpc_connectivity_state state;
while ((state = channel->GetState(false /* try_to_connect */)) ==
GRPC_CHANNEL_READY) {
if (!channel->WaitForStateChange(state, deadline)) return false;
}
return true;
}
bool WaitForChannelReady(Channel* channel, int timeout_seconds = 5) {
const gpr_timespec deadline =
grpc_timeout_seconds_to_deadline(timeout_seconds);
grpc_connectivity_state state;
while ((state = channel->GetState(true /* try_to_connect */)) !=
GRPC_CHANNEL_READY) {
if (!channel->WaitForStateChange(state, deadline)) return false;
}
return true;
}
bool SeenAllServers() {
for (const auto& server : servers_) {
if (server->service_.request_count() == 0) return false;
}
return true;
}
// Updates \a connection_order by appending to it the index of the newly
// connected server. Must be called after every single RPC.
void UpdateConnectionOrder(
const std::vector<std::unique_ptr<ServerData>>& servers,
std::vector<int>* connection_order) {
for (size_t i = 0; i < servers.size(); ++i) {
if (servers[i]->service_.request_count() == 1) {
// Was the server index known? If not, update connection_order.
const auto it =
std::find(connection_order->begin(), connection_order->end(), i);
if (it == connection_order->end()) {
connection_order->push_back(i);
return;
}
}
}
}
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_;
grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
response_generator_;
const grpc::string kRequestMessage_;
std::shared_ptr<ChannelCredentials> creds_;
};
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);
auto channel = BuildChannelWithDefaultServiceConfig();
auto stub = BuildStub(channel);
SetNextResolutionNoServiceConfig(GetServersPorts());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidDefaultServiceConfig(),
channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest, InvalidServiceConfigTest) {
StartServers(1);
auto channel = BuildChannel();
auto stub = BuildStub(channel);
SetNextResolutionInvalidServiceConfig(GetServersPorts());
CheckRpcSendFailure(stub);
}
TEST_F(ServiceConfigEnd2endTest, InvalidServiceConfigWithDefaultConfigTest) {
StartServers(1);
auto channel = BuildChannelWithDefaultServiceConfig();
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);
auto channel = BuildChannelWithDefaultServiceConfig();
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());
CheckRpcSendOk(stub, DEBUG_LOCATION);
EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str());
}
TEST_F(ServiceConfigEnd2endTest,
InvalidServiceConfigUpdateAfterValidServiceConfigWithDefaultConfigTest) {
StartServers(1);
auto channel = BuildChannelWithDefaultServiceConfig();
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
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(argc, argv);
const auto result = RUN_ALL_TESTS();
return result;
}

@ -47,6 +47,7 @@ def _resolver_test_cases(resolver_component_data):
_build_expected_addrs_cmd_arg(test_case['expected_addrs'])),
('expected_chosen_service_config',
(test_case['expected_chosen_service_config'] or '')),
('expected_service_config_error', (test_case['expected_service_config_error'] or '')),
('expected_lb_policy', (test_case['expected_lb_policy'] or '')),
('enable_srv_queries', test_case['enable_srv_queries']),
('enable_txt_queries', test_case['enable_txt_queries']),

@ -93,6 +93,8 @@ DEFINE_string(expected_addrs, "",
DEFINE_string(expected_chosen_service_config, "",
"Expected service config json string that gets chosen (no "
"whitespace). Empty for none.");
DEFINE_string(expected_service_config_error, "",
"Expected service config error. Empty for none.");
DEFINE_string(
local_dns_server_address, "",
"Optional. This address is placed as the uri authority if present.");
@ -194,6 +196,7 @@ struct ArgsStruct {
grpc_channel_args* channel_args;
vector<GrpcLBAddress> expected_addrs;
std::string expected_service_config_string;
std::string expected_service_config_error;
std::string expected_lb_policy;
};
@ -259,13 +262,19 @@ void PollPollsetUntilRequestDone(ArgsStruct* args) {
}
void CheckServiceConfigResultLocked(const char* service_config_json,
grpc_error* service_config_error,
ArgsStruct* args) {
if (args->expected_service_config_string != "") {
GPR_ASSERT(service_config_json != nullptr);
EXPECT_EQ(service_config_json, args->expected_service_config_string);
}
if (args->expected_service_config_error == "") {
EXPECT_EQ(service_config_error, GRPC_ERROR_NONE);
} else {
GPR_ASSERT(service_config_json == nullptr);
EXPECT_THAT(grpc_error_string(service_config_error),
testing::HasSubstr(args->expected_service_config_error));
}
GRPC_ERROR_UNREF(service_config_error);
}
void CheckLBPolicyResultLocked(const grpc_channel_args* channel_args,
@ -480,7 +489,8 @@ class CheckingResultHandler : public ResultHandler {
result.service_config == nullptr
? nullptr
: result.service_config->service_config_json();
CheckServiceConfigResultLocked(service_config_json, args);
CheckServiceConfigResultLocked(
service_config_json, GRPC_ERROR_REF(result.service_config_error), args);
if (args->expected_service_config_string == "") {
CheckLBPolicyResultLocked(result.args, args);
}
@ -539,6 +549,7 @@ void RunResolvesRelevantRecordsTest(
ArgsInit(&args);
args.expected_addrs = ParseExpectedAddrs(FLAGS_expected_addrs);
args.expected_service_config_string = FLAGS_expected_chosen_service_config;
args.expected_service_config_error = FLAGS_expected_service_config_error;
args.expected_lb_policy = FLAGS_expected_lb_policy;
// maybe build the address with an authority
char* whole_uri = nullptr;

@ -124,6 +124,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'no-srv-ipv4-single-target.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '5.5.5.5:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -139,6 +140,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv4-single-target.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:1234,True',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -154,6 +156,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv4-multi-target.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.5:1234,True;1.2.3.6:1234,True;1.2.3.7:1234,True',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -169,6 +172,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv6-single-target.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '[2607:f8b0:400a:801::1001]:1234,True',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -184,6 +188,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv6-multi-target.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1003]:1234,True;[2607:f8b0:400a:801::1004]:1234,True',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -198,7 +203,8 @@ current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'srv-ipv4-simple-service-config.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:1234,True',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}',
'--expected_service_config_error', '',
'--expected_lb_policy', 'round_robin',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -213,7 +219,8 @@ current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'ipv4-no-srv-simple-service-config.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService"}],"waitForReady":true}]}',
'--expected_service_config_error', '',
'--expected_lb_policy', 'round_robin',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -229,6 +236,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'ipv4-no-config-for-cpp.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -244,6 +252,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'ipv4-cpp-config-has-zero-percentage.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -258,7 +267,8 @@ current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'ipv4-second-language-is-cpp.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}',
'--expected_service_config_error', '',
'--expected_lb_policy', 'round_robin',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -273,7 +283,8 @@ current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'ipv4-config-with-percentages.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService"}],"waitForReady":true}]}',
'--expected_service_config_error', '',
'--expected_lb_policy', 'round_robin',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -289,6 +300,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:1234,True;1.2.3.4:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -304,6 +316,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1002]:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -318,7 +331,8 @@ current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'ipv4-config-causing-fallback-to-tcp.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooThree","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFour","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFive","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSix","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSeven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEight","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooNine","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEleven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true}]}',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -334,6 +348,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv4-single-target-srv-disabled.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '2.3.4.5:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'False',
'--enable_txt_queries', 'True',
@ -349,6 +364,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv4-multi-target-srv-disabled.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '9.2.3.5:443,False;9.2.3.6:443,False;9.2.3.7:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'False',
'--enable_txt_queries', 'True',
@ -364,6 +380,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv6-single-target-srv-disabled.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '[2600::1001]:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'False',
'--enable_txt_queries', 'True',
@ -379,6 +396,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv6-multi-target-srv-disabled.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '[2600::1002]:443,False;[2600::1003]:443,False;[2600::1004]:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'False',
'--enable_txt_queries', 'True',
@ -393,7 +411,8 @@ current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'srv-ipv4-simple-service-config-srv-disabled.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '5.5.3.4:443,False',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}',
'--expected_service_config_error', '',
'--expected_lb_policy', 'round_robin',
'--enable_srv_queries', 'False',
'--enable_txt_queries', 'True',
@ -409,6 +428,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'srv-ipv4-simple-service-config-txt-disabled.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:1234,True',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'False',
@ -424,6 +444,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'ipv4-cpp-config-has-zero-percentage-txt-disabled.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'False',
@ -439,6 +460,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'ipv4-second-language-is-cpp-txt-disabled.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'False',
@ -448,12 +470,77 @@ current_test_subprocess.communicate()
if current_test_subprocess.returncode != 0:
num_test_failures += 1
test_runner_log('Run test with target: %s' % 'ipv4-svc_cfg_bad_json.resolver-tests-version-4.grpctestingexp.')
current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'ipv4-svc_cfg_bad_json.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', 'could not parse',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
'--inject_broken_nameserver_list', 'False',
'--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port])
current_test_subprocess.communicate()
if current_test_subprocess.returncode != 0:
num_test_failures += 1
test_runner_log('Run test with target: %s' % 'ipv4-svc_cfg_bad_client_language.resolver-tests-version-4.grpctestingexp.')
current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'ipv4-svc_cfg_bad_client_language.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', 'field:clientLanguage error:should be of type array',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
'--inject_broken_nameserver_list', 'False',
'--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port])
current_test_subprocess.communicate()
if current_test_subprocess.returncode != 0:
num_test_failures += 1
test_runner_log('Run test with target: %s' % 'ipv4-svc_cfg_bad_percentage.resolver-tests-version-4.grpctestingexp.')
current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'ipv4-svc_cfg_bad_percentage.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', 'field:percentage error:should be of type number',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
'--inject_broken_nameserver_list', 'False',
'--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port])
current_test_subprocess.communicate()
if current_test_subprocess.returncode != 0:
num_test_failures += 1
test_runner_log('Run test with target: %s' % 'ipv4-svc_cfg_bad_wait_for_ready.resolver-tests-version-4.grpctestingexp.')
current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'ipv4-svc_cfg_bad_wait_for_ready.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', 'field:waitForReady error:Type should be true/false',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
'--inject_broken_nameserver_list', 'False',
'--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port])
current_test_subprocess.communicate()
if current_test_subprocess.returncode != 0:
num_test_failures += 1
test_runner_log('Run test with target: %s' % 'no-srv-ipv4-single-target-inject-broken-nameservers.resolver-tests-version-4.grpctestingexp.')
current_test_subprocess = subprocess.Popen([
args.test_bin_path,
'--target_name', 'no-srv-ipv4-single-target-inject-broken-nameservers.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '5.5.5.5:443,False',
'--expected_chosen_service_config', '',
'--expected_service_config_error', '',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',
@ -469,6 +556,7 @@ current_test_subprocess = subprocess.Popen([
'--target_name', 'ipv4-config-causing-fallback-to-tcp-inject-broken-nameservers.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}',
'--expected_service_config_error', 'Service config parsing error',
'--expected_lb_policy', '',
'--enable_srv_queries', 'True',
'--enable_txt_queries', 'True',

@ -4,6 +4,7 @@ resolver_component_tests:
- expected_addrs:
- {address: '5.5.5.5:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -15,6 +16,7 @@ resolver_component_tests:
- expected_addrs:
- {address: '1.2.3.4:1234', is_balancer: true}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -30,6 +32,7 @@ resolver_component_tests:
- {address: '1.2.3.6:1234', is_balancer: true}
- {address: '1.2.3.7:1234', is_balancer: true}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -45,6 +48,7 @@ resolver_component_tests:
- expected_addrs:
- {address: '[2607:f8b0:400a:801::1001]:1234', is_balancer: true}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -60,6 +64,7 @@ resolver_component_tests:
- {address: '[2607:f8b0:400a:801::1003]:1234', is_balancer: true}
- {address: '[2607:f8b0:400a:801::1004]:1234', is_balancer: true}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -74,7 +79,8 @@ resolver_component_tests:
- {TTL: '2100', data: '2607:f8b0:400a:801::1004', type: AAAA}
- expected_addrs:
- {address: '1.2.3.4:1234', is_balancer: true}
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}'
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}'
expected_service_config_error: null
expected_lb_policy: round_robin
enable_srv_queries: true
enable_txt_queries: true
@ -86,11 +92,12 @@ resolver_component_tests:
ipv4-simple-service-config:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.srv-ipv4-simple-service-config:
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}'
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService"}],"waitForReady":true}]}'
expected_service_config_error: null
expected_lb_policy: round_robin
enable_srv_queries: true
enable_txt_queries: true
@ -100,11 +107,12 @@ resolver_component_tests:
ipv4-no-srv-simple-service-config:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-no-srv-simple-service-config:
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -114,11 +122,12 @@ resolver_component_tests:
ipv4-no-config-for-cpp:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-no-config-for-cpp:
- {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["python"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"PythonService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["python"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"PythonService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -128,11 +137,12 @@ resolver_component_tests:
ipv4-cpp-config-has-zero-percentage:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-cpp-config-has-zero-percentage:
- {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}'
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}'
expected_service_config_error: null
expected_lb_policy: round_robin
enable_srv_queries: true
enable_txt_queries: true
@ -142,11 +152,12 @@ resolver_component_tests:
ipv4-second-language-is-cpp:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-second-language-is-cpp:
- {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["go"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService","waitForReady":true}]}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["go"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService"}],"waitForReady":true}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}'
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService"}],"waitForReady":true}]}'
expected_service_config_error: null
expected_lb_policy: round_robin
enable_srv_queries: true
enable_txt_queries: true
@ -156,12 +167,13 @@ resolver_component_tests:
ipv4-config-with-percentages:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-config-with-percentages:
- {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NeverPickedService","waitForReady":true}]}]}},{"percentage":100,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NeverPickedService"}],"waitForReady":true}]}},{"percentage":100,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:1234', is_balancer: true}
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -178,6 +190,7 @@ resolver_component_tests:
- {address: '[2607:f8b0:400a:801::1002]:1234', is_balancer: true}
- {address: '[2607:f8b0:400a:801::1002]:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -192,7 +205,8 @@ resolver_component_tests:
- {TTL: '2100', data: '2607:f8b0:400a:801::1002', type: AAAA}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}'
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooThree","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFour","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFive","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSix","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSeven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEight","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooNine","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEleven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true}]}'
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -202,12 +216,13 @@ resolver_component_tests:
ipv4-config-causing-fallback-to-tcp:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-config-causing-fallback-to-tcp:
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooThree","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFour","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFive","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSix","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSeven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEight","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooNine","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEleven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true}]}}]',
type: TXT}
# Tests for which we don't enable SRV queries
- expected_addrs:
- {address: '2.3.4.5:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: false
enable_txt_queries: true
@ -225,6 +240,7 @@ resolver_component_tests:
- {address: '9.2.3.6:443', is_balancer: false}
- {address: '9.2.3.7:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: false
enable_txt_queries: true
@ -244,6 +260,7 @@ resolver_component_tests:
- expected_addrs:
- {address: '[2600::1001]:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: false
enable_txt_queries: true
@ -261,6 +278,7 @@ resolver_component_tests:
- {address: '[2600::1003]:443', is_balancer: false}
- {address: '[2600::1004]:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: false
enable_txt_queries: true
@ -279,7 +297,8 @@ resolver_component_tests:
- {TTL: '2100', data: '2600::1004', type: AAAA}
- expected_addrs:
- {address: '5.5.3.4:443', is_balancer: false}
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}'
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}'
expected_service_config_error: null
expected_lb_policy: round_robin
enable_srv_queries: false
enable_txt_queries: true
@ -293,11 +312,12 @@ resolver_component_tests:
srv-ipv4-simple-service-config-srv-disabled:
- {TTL: '2100', data: 5.5.3.4, type: A}
_grpc_config.srv-ipv4-simple-service-config-srv-disabled:
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:1234', is_balancer: true}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: false
@ -309,11 +329,12 @@ resolver_component_tests:
ipv4-simple-service-config-txt-disabled:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.srv-ipv4-simple-service-config-txt-disabled:
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: false
@ -323,11 +344,12 @@ resolver_component_tests:
ipv4-cpp-config-has-zero-percentage-txt-disabled:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-cpp-config-has-zero-percentage-txt-disabled:
- {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: false
@ -337,12 +359,73 @@ resolver_component_tests:
ipv4-second-language-is-cpp-txt-disabled:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-second-language-is-cpp-txt-disabled:
- {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["go"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService","waitForReady":true}]}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}}]',
- {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["go"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService"}],"waitForReady":true}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: 'could not parse'
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
inject_broken_nameserver_list: false
record_to_resolve: ipv4-svc_cfg_bad_json
records:
ipv4-svc_cfg_bad_json:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-svc_cfg_bad_json:
- {TTL: '2100', data: 'grpc_config=[{]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: 'field:clientLanguage error:should be of type array'
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
inject_broken_nameserver_list: false
record_to_resolve: ipv4-svc_cfg_bad_client_language
records:
ipv4-svc_cfg_bad_client_language:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-svc_cfg_bad_client_language:
- {TTL: '2100', data: 'grpc_config=[{"clientLanguage":"go","serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService"}],"waitForReady":true}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: 'field:percentage error:should be of type number'
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
inject_broken_nameserver_list: false
record_to_resolve: ipv4-svc_cfg_bad_percentage
records:
ipv4-svc_cfg_bad_percentage:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-svc_cfg_bad_percentage:
- {TTL: '2100', data: 'grpc_config=[{"percentage":"0","serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService"}],"waitForReady":true}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]',
type: TXT}
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: 'field:waitForReady error:Type should be true/false'
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
inject_broken_nameserver_list: false
record_to_resolve: ipv4-svc_cfg_bad_wait_for_ready
records:
ipv4-svc_cfg_bad_wait_for_ready:
- {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-svc_cfg_bad_wait_for_ready:
- {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":"true"}]}}]',
type: TXT}
# Tests for which we also exercise the resolver's ability to skip past a broken DNS server in its nameserver list
- expected_addrs:
- {address: '5.5.5.5:443', is_balancer: false}
expected_chosen_service_config: null
expected_service_config_error: null
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true
@ -354,6 +437,7 @@ resolver_component_tests:
- expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false}
expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}'
expected_service_config_error: 'Service config parsing error'
expected_lb_policy: null
enable_srv_queries: true
enable_txt_queries: true

@ -4795,6 +4795,24 @@
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
"grpc",
"grpc++",
"grpc++_test_util",
"grpc_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c++",
"name": "service_config_end2end_test",
"src": [
"test/cpp/end2end/service_config_end2end_test.cc"
],
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",

@ -5445,6 +5445,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "service_config_end2end_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save