Merge pull request #22232 from markdroth/service_config_parsing_update

update service config parsing as per recent spec change
reviewable/pr22117/r3^2
Mark D. Roth 5 years ago committed by GitHub
commit 3590c04d14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/core/ext/filters/client_channel/client_channel.cc
  2. 15
      src/core/ext/filters/client_channel/resolver_result_parsing.cc
  3. 8
      src/core/ext/filters/client_channel/resolver_result_parsing.h
  4. 148
      src/core/ext/filters/client_channel/service_config.cc
  5. 26
      src/core/ext/filters/client_channel/service_config.h
  6. 14
      src/core/lib/slice/slice_internal.h
  7. 636
      test/core/client_channel/service_config_test.cc
  8. 2
      test/cpp/naming/resolver_component_tests_runner.py
  9. 4
      test/cpp/naming/resolver_test_record_groups.yaml

@ -1630,8 +1630,8 @@ void ChannelData::ProcessLbPolicy(
// If not, try the setting from channel args. // If not, try the setting from channel args.
const char* policy_name = nullptr; const char* policy_name = nullptr;
if (parsed_service_config != nullptr && if (parsed_service_config != nullptr &&
parsed_service_config->parsed_deprecated_lb_policy() != nullptr) { !parsed_service_config->parsed_deprecated_lb_policy().empty()) {
policy_name = parsed_service_config->parsed_deprecated_lb_policy(); policy_name = parsed_service_config->parsed_deprecated_lb_policy().c_str();
} else { } else {
const grpc_arg* channel_arg = const grpc_arg* channel_arg =
grpc_channel_args_find(resolver_result.args, GRPC_ARG_LB_POLICY_NAME); grpc_channel_args_find(resolver_result.args, GRPC_ARG_LB_POLICY_NAME);

@ -317,7 +317,7 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const Json& json,
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
std::vector<grpc_error*> error_list; std::vector<grpc_error*> error_list;
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config; RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
grpc_core::UniquePtr<char> lb_policy_name; std::string lb_policy_name;
Optional<ClientChannelGlobalParsedConfig::RetryThrottling> retry_throttling; Optional<ClientChannelGlobalParsedConfig::RetryThrottling> retry_throttling;
const char* health_check_service_name = nullptr; const char* health_check_service_name = nullptr;
// Parse LB config. // Parse LB config.
@ -340,16 +340,13 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const Json& json,
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:loadBalancingPolicy error:type should be string")); "field:loadBalancingPolicy error:type should be string"));
} else { } else {
lb_policy_name.reset(gpr_strdup(it->second.string_value().c_str())); lb_policy_name = it->second.string_value();
char* lb_policy = lb_policy_name.get(); for (size_t i = 0; i < lb_policy_name.size(); ++i) {
if (lb_policy != nullptr) { lb_policy_name[i] = tolower(lb_policy_name[i]);
for (size_t i = 0; i < strlen(lb_policy); ++i) {
lb_policy[i] = tolower(lb_policy[i]);
}
} }
bool requires_config = false; bool requires_config = false;
if (!LoadBalancingPolicyRegistry::LoadBalancingPolicyExists( if (!LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
lb_policy, &requires_config)) { lb_policy_name.c_str(), &requires_config)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:loadBalancingPolicy error:Unknown lb policy")); "field:loadBalancingPolicy error:Unknown lb policy"));
} else if (requires_config) { } else if (requires_config) {
@ -357,7 +354,7 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const Json& json,
gpr_asprintf(&error_msg, gpr_asprintf(&error_msg,
"field:loadBalancingPolicy error:%s requires a config. " "field:loadBalancingPolicy error:%s requires a config. "
"Please use loadBalancingConfig instead.", "Please use loadBalancingConfig instead.",
lb_policy); lb_policy_name.c_str());
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg)); error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg));
gpr_free(error_msg); gpr_free(error_msg);
} }

@ -46,7 +46,7 @@ class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig {
ClientChannelGlobalParsedConfig( ClientChannelGlobalParsedConfig(
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config, RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config,
grpc_core::UniquePtr<char> parsed_deprecated_lb_policy, std::string parsed_deprecated_lb_policy,
const Optional<RetryThrottling>& retry_throttling, const Optional<RetryThrottling>& retry_throttling,
const char* health_check_service_name) const char* health_check_service_name)
: parsed_lb_config_(std::move(parsed_lb_config)), : parsed_lb_config_(std::move(parsed_lb_config)),
@ -62,8 +62,8 @@ class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig {
return parsed_lb_config_; return parsed_lb_config_;
} }
const char* parsed_deprecated_lb_policy() const { const std::string& parsed_deprecated_lb_policy() const {
return parsed_deprecated_lb_policy_.get(); return parsed_deprecated_lb_policy_;
} }
const char* health_check_service_name() const { const char* health_check_service_name() const {
@ -72,7 +72,7 @@ class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig {
private: private:
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config_; RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config_;
grpc_core::UniquePtr<char> parsed_deprecated_lb_policy_; std::string parsed_deprecated_lb_policy_;
Optional<RetryThrottling> retry_throttling_; Optional<RetryThrottling> retry_throttling_;
const char* health_check_service_name_; const char* health_check_service_name_;
}; };

@ -20,6 +20,8 @@
#include <string.h> #include <string.h>
#include "absl/strings/str_cat.h"
#include <grpc/impl/codegen/grpc_types.h> #include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
@ -27,9 +29,7 @@
#include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/string.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/slice/slice_hash_table.h"
#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
namespace grpc_core { namespace grpc_core {
@ -77,6 +77,12 @@ ServiceConfig::ServiceConfig(std::string json_string, Json json,
} }
} }
ServiceConfig::~ServiceConfig() {
for (auto& p : parsed_method_configs_map_) {
grpc_slice_unref_internal(p.first);
}
}
grpc_error* ServiceConfig::ParseGlobalParams() { grpc_error* ServiceConfig::ParseGlobalParams() {
std::vector<grpc_error*> error_list; std::vector<grpc_error*> error_list;
for (size_t i = 0; i < g_registered_parsers->size(); i++) { for (size_t i = 0; i < g_registered_parsers->size(); i++) {
@ -91,10 +97,8 @@ grpc_error* ServiceConfig::ParseGlobalParams() {
return GRPC_ERROR_CREATE_FROM_VECTOR("Global Params", &error_list); return GRPC_ERROR_CREATE_FROM_VECTOR("Global Params", &error_list);
} }
grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigVectorTable( grpc_error* ServiceConfig::ParseJsonMethodConfig(const Json& json) {
const Json& json, // Parse method config with each registered parser.
InlinedVector<SliceHashTable<const ParsedConfigVector*>::Entry, 10>*
entries) {
auto objs_vector = absl::make_unique<ParsedConfigVector>(); auto objs_vector = absl::make_unique<ParsedConfigVector>();
InlinedVector<grpc_error*, 4> error_list; InlinedVector<grpc_error*, 4> error_list;
for (size_t i = 0; i < g_registered_parsers->size(); i++) { for (size_t i = 0; i < g_registered_parsers->size(); i++) {
@ -108,8 +112,8 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigVectorTable(
} }
parsed_method_config_vectors_storage_.push_back(std::move(objs_vector)); parsed_method_config_vectors_storage_.push_back(std::move(objs_vector));
const auto* vector_ptr = parsed_method_config_vectors_storage_.back().get(); const auto* vector_ptr = parsed_method_config_vectors_storage_.back().get();
// Construct list of paths. // Add an entry for each path.
InlinedVector<UniquePtr<char>, 10> paths; bool found_name = false;
auto it = json.object_value().find("name"); auto it = json.object_value().find("name");
if (it != json.object_value().end()) { if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) { if (it->second.type() != Json::Type::ARRAY) {
@ -120,29 +124,42 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigVectorTable(
const Json::Array& name_array = it->second.array_value(); const Json::Array& name_array = it->second.array_value();
for (const Json& name : name_array) { for (const Json& name : name_array) {
grpc_error* parse_error = GRPC_ERROR_NONE; grpc_error* parse_error = GRPC_ERROR_NONE;
UniquePtr<char> path = ParseJsonMethodName(name, &parse_error); std::string path = ParseJsonMethodName(name, &parse_error);
if (path == nullptr) { if (parse_error != GRPC_ERROR_NONE) {
error_list.push_back(parse_error); error_list.push_back(parse_error);
} else { } else {
GPR_DEBUG_ASSERT(parse_error == GRPC_ERROR_NONE); found_name = true;
paths.push_back(std::move(path)); if (path.empty()) {
if (default_method_config_vector_ != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error:multiple default method configs"));
}
default_method_config_vector_ = vector_ptr;
} else {
grpc_slice key = grpc_slice_from_copied_string(path.c_str());
// If the key is not already present in the map, this will
// store a ref to the key in the map.
auto& value = parsed_method_configs_map_[key];
if (value != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error:multiple method configs with same name"));
// The map entry already existed, so we need to unref the
// key we just created.
grpc_slice_unref_internal(key);
} else {
value = vector_ptr;
}
} }
} }
} }
if (paths.size() == 0) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("No names specified"));
} }
// Add entry for each path. if (!found_name) {
for (size_t i = 0; i < paths.size(); ++i) { parsed_method_config_vectors_storage_.pop_back();
entries->push_back(
{grpc_slice_from_copied_string(paths[i].get()), vector_ptr});
} }
return GRPC_ERROR_CREATE_FROM_VECTOR("methodConfig", &error_list); return GRPC_ERROR_CREATE_FROM_VECTOR("methodConfig", &error_list);
} }
grpc_error* ServiceConfig::ParsePerMethodParams() { grpc_error* ServiceConfig::ParsePerMethodParams() {
InlinedVector<SliceHashTable<const ParsedConfigVector*>::Entry, 10> entries;
std::vector<grpc_error*> error_list; std::vector<grpc_error*> error_list;
auto it = json_.object_value().find("methodConfig"); auto it = json_.object_value().find("methodConfig");
if (it != json_.object_value().end()) { if (it != json_.object_value().end()) {
@ -156,91 +173,80 @@ grpc_error* ServiceConfig::ParsePerMethodParams() {
"field:methodConfig error:not of type Object")); "field:methodConfig error:not of type Object"));
continue; continue;
} }
grpc_error* error = ParseJsonMethodConfigToServiceConfigVectorTable( grpc_error* error = ParseJsonMethodConfig(method_config);
method_config, &entries);
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
error_list.push_back(error); error_list.push_back(error);
} }
} }
} }
if (!entries.empty()) {
parsed_method_configs_table_ =
SliceHashTable<const ParsedConfigVector*>::Create(
entries.size(), entries.data(), nullptr);
}
return GRPC_ERROR_CREATE_FROM_VECTOR("Method Params", &error_list); return GRPC_ERROR_CREATE_FROM_VECTOR("Method Params", &error_list);
} }
UniquePtr<char> ServiceConfig::ParseJsonMethodName(const Json& json, std::string ServiceConfig::ParseJsonMethodName(const Json& json,
grpc_error** error) { grpc_error** error) {
if (json.type() != Json::Type::OBJECT) { if (json.type() != Json::Type::OBJECT) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error:type is not object"); "field:name error:type is not object");
return nullptr; return "";
} }
// Find service name. // Find service name.
const std::string* service_name = nullptr;
auto it = json.object_value().find("service"); auto it = json.object_value().find("service");
if (it == json.object_value().end()) { if (it != json.object_value().end() &&
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( it->second.type() != Json::Type::JSON_NULL) {
"field:name error: field:service error:not found");
return nullptr; // Required field.
}
if (it->second.type() != Json::Type::STRING) { if (it->second.type() != Json::Type::STRING) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:service error:not of type string"); "field:name error: field:service error:not of type string");
return nullptr; return "";
}
if (!it->second.string_value().empty()) {
service_name = &it->second.string_value();
} }
if (it->second.string_value().empty()) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:service error:empty value");
return nullptr;
} }
const char* service_name = it->second.string_value().c_str(); const std::string* method_name = nullptr;
const char* method_name = nullptr;
// Find method name. // Find method name.
it = json.object_value().find("method"); it = json.object_value().find("method");
if (it != json.object_value().end()) { if (it != json.object_value().end() &&
it->second.type() != Json::Type::JSON_NULL) {
if (it->second.type() != Json::Type::STRING) { if (it->second.type() != Json::Type::STRING) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:method error:not of type string"); "field:name error: field:method error:not of type string");
return nullptr; return "";
}
if (!it->second.string_value().empty()) {
method_name = &it->second.string_value();
} }
if (it->second.string_value().empty()) { }
// If neither service nor method are specified, it's the default.
// Method name may not be specified without service name.
if (service_name == nullptr) {
if (method_name != nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:method error:empty value"); "field:name error:method name populated without service name");
return nullptr;
} }
method_name = it->second.string_value().c_str(); return "";
} }
char* path; // Construct path.
gpr_asprintf(&path, "/%s/%s", service_name, return absl::StrCat("/", *service_name, "/",
method_name == nullptr ? "" : method_name); method_name == nullptr ? "" : *method_name);
return grpc_core::UniquePtr<char>(path);
} }
const ServiceConfig::ParsedConfigVector* const ServiceConfig::ParsedConfigVector*
ServiceConfig::GetMethodParsedConfigVector(const grpc_slice& path) { ServiceConfig::GetMethodParsedConfigVector(const grpc_slice& path) const {
if (parsed_method_configs_table_.get() == nullptr) { // Try looking up the full path in the map.
return nullptr; auto it = parsed_method_configs_map_.find(path);
} if (it != parsed_method_configs_map_.end()) return it->second;
const auto* value = parsed_method_configs_table_->Get(path);
// If we didn't find a match for the path, try looking for a wildcard // If we didn't find a match for the path, try looking for a wildcard
// entry (i.e., change "/service/method" to "/service/"). // entry (i.e., change "/service/method" to "/service/").
if (value == nullptr) { UniquePtr<char> path_str(grpc_slice_to_c_string(path));
char* path_str = grpc_slice_to_c_string(path); char* sep = strrchr(path_str.get(), '/') + 1;
const char* sep = strrchr(path_str, '/') + 1; if (sep == nullptr) return nullptr; // Shouldn't ever happen.
const size_t len = (size_t)(sep - path_str); *sep = '\0';
char* buf = (char*)gpr_malloc(len + 1); // trailing NUL grpc_slice wildcard_path = grpc_slice_from_static_string(path_str.get());
memcpy(buf, path_str, len); it = parsed_method_configs_map_.find(wildcard_path);
buf[len] = '\0'; if (it != parsed_method_configs_map_.end()) return it->second;
grpc_slice wildcard_path = grpc_slice_from_copied_string(buf); // Try default method config, if set.
gpr_free(buf); return default_method_config_vector_;
value = parsed_method_configs_table_->Get(wildcard_path);
grpc_slice_unref_internal(wildcard_path);
gpr_free(path_str);
if (value == nullptr) return nullptr;
}
return *value;
} }
size_t ServiceConfig::RegisterParser(std::unique_ptr<Parser> parser) { size_t ServiceConfig::RegisterParser(std::unique_ptr<Parser> parser) {

@ -19,6 +19,8 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include <unordered_map>
#include <grpc/impl/codegen/grpc_types.h> #include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
@ -27,7 +29,7 @@
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/slice/slice_hash_table.h" #include "src/core/lib/slice/slice_internal.h"
// The main purpose of the code here is to parse the service config in // The main purpose of the code here is to parse the service config in
// JSON form, which will look like this: // JSON form, which will look like this:
@ -129,6 +131,7 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
grpc_error** error); grpc_error** error);
ServiceConfig(std::string json_string, Json json, grpc_error** error); ServiceConfig(std::string json_string, Json json, grpc_error** error);
~ServiceConfig();
const std::string& json_string() const { return json_string_; } const std::string& json_string() const { return json_string_; }
@ -143,7 +146,8 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
/// Retrieves the vector of parsed configs for the method identified /// Retrieves the vector of parsed configs for the method identified
/// by \a path. The lifetime of the returned vector and contained objects /// by \a path. The lifetime of the returned vector and contained objects
/// is tied to the lifetime of the ServiceConfig object. /// is tied to the lifetime of the ServiceConfig object.
const ParsedConfigVector* GetMethodParsedConfigVector(const grpc_slice& path); const ParsedConfigVector* GetMethodParsedConfigVector(
const grpc_slice& path) const;
/// Globally register a service config parser. On successful registration, it /// Globally register a service config parser. On successful registration, it
/// returns the index at which the parser was registered. On failure, -1 is /// returns the index at which the parser was registered. On failure, -1 is
@ -162,15 +166,11 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
grpc_error* ParseGlobalParams(); grpc_error* ParseGlobalParams();
grpc_error* ParsePerMethodParams(); grpc_error* ParsePerMethodParams();
// Returns a path string for the JSON name object specified by \a json. // Returns a path string for the JSON name object specified by json.
// Returns null on error, and stores error in \a error. // Sets *error on error.
static UniquePtr<char> ParseJsonMethodName(const Json& json, static std::string ParseJsonMethodName(const Json& json, grpc_error** error);
grpc_error** error);
grpc_error* ParseJsonMethodConfigToServiceConfigVectorTable( grpc_error* ParseJsonMethodConfig(const Json& json);
const Json& json,
InlinedVector<SliceHashTable<const ParsedConfigVector*>::Entry, 10>*
entries);
std::string json_string_; std::string json_string_;
Json json_; Json json_;
@ -180,8 +180,10 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
// A map from the method name to the parsed config vector. Note that we are // A map from the method name to the parsed config vector. Note that we are
// using a raw pointer and not a unique pointer so that we can use the same // using a raw pointer and not a unique pointer so that we can use the same
// vector for multiple names. // vector for multiple names.
RefCountedPtr<SliceHashTable<const ParsedConfigVector*>> std::unordered_map<grpc_slice, const ParsedConfigVector*, SliceHash>
parsed_method_configs_table_; parsed_method_configs_map_;
// Default method config.
const ParsedConfigVector* default_method_config_vector_ = nullptr;
// Storage for all the vectors that are being used in // Storage for all the vectors that are being used in
// parsed_method_configs_table_. // parsed_method_configs_table_.
InlinedVector<std::unique_ptr<ParsedConfigVector>, 32> InlinedVector<std::unique_ptr<ParsedConfigVector>, 32>

@ -347,4 +347,18 @@ size_t grpc_slice_memory_usage(grpc_slice s);
grpc_core::UnmanagedMemorySlice grpc_slice_sub_no_ref( grpc_core::UnmanagedMemorySlice grpc_slice_sub_no_ref(
const grpc_core::UnmanagedMemorySlice& source, size_t begin, size_t end); const grpc_core::UnmanagedMemorySlice& source, size_t begin, size_t end);
namespace grpc_core {
struct SliceHash {
std::size_t operator()(const grpc_slice& slice) const {
return grpc_slice_hash_internal(slice);
}
};
} // namespace grpc_core
inline bool operator==(const grpc_slice& s1, const grpc_slice& s2) {
return grpc_slice_eq(s1, s2);
}
#endif /* GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H */ #endif /* GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H */

@ -18,6 +18,8 @@
#include <regex> #include <regex>
#include "absl/strings/str_cat.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <grpc/grpc.h> #include <grpc/grpc.h>
@ -127,10 +129,10 @@ class ErrorParser : public ServiceConfig::Parser {
static const char* GlobalError() { return "ErrorParser : globalError"; } static const char* GlobalError() { return "ErrorParser : globalError"; }
}; };
void VerifyRegexMatch(grpc_error* error, const std::regex& e) { void VerifyRegexMatch(grpc_error* error, const std::regex& regex) {
std::smatch match; std::smatch match;
std::string s(grpc_error_string(error)); std::string error_str = grpc_error_string(error);
EXPECT_TRUE(std::regex_search(s, match, e)); EXPECT_TRUE(std::regex_search(error_str, match, regex)) << error_str;
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
} }
@ -139,10 +141,10 @@ class ServiceConfigTest : public ::testing::Test {
void SetUp() override { void SetUp() override {
ServiceConfig::Shutdown(); ServiceConfig::Shutdown();
ServiceConfig::Init(); ServiceConfig::Init();
EXPECT_TRUE( EXPECT_EQ(ServiceConfig::RegisterParser(absl::make_unique<TestParser1>()),
ServiceConfig::RegisterParser(absl::make_unique<TestParser1>()) == 0); 0);
EXPECT_TRUE( EXPECT_EQ(ServiceConfig::RegisterParser(absl::make_unique<TestParser2>()),
ServiceConfig::RegisterParser(absl::make_unique<TestParser2>()) == 1); 1);
} }
}; };
@ -150,46 +152,128 @@ TEST_F(ServiceConfigTest, ErrorCheck1) {
const char* test_json = ""; const char* test_json = "";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(std::string("JSON parse error"));
ASSERT_TRUE(error != GRPC_ERROR_NONE); VerifyRegexMatch(error, regex);
std::regex e(std::string("JSON parse error"));
VerifyRegexMatch(error, e);
} }
TEST_F(ServiceConfigTest, BasicTest1) { TEST_F(ServiceConfigTest, BasicTest1) {
const char* test_json = "{}"; const char* test_json = "{}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
EXPECT_TRUE(error == GRPC_ERROR_NONE); EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
}
TEST_F(ServiceConfigTest, SkipMethodConfigWithNoNameOrEmptyName) {
const char* test_json =
"{\"methodConfig\": ["
" {\"method_param\":1},"
" {\"name\":[], \"method_param\":1},"
" {\"name\":[{\"service\":\"TestServ\"}], \"method_param\":2}"
"]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod"));
ASSERT_NE(vector_ptr, nullptr);
auto parsed_config = ((*vector_ptr)[1]).get();
EXPECT_EQ(static_cast<TestParsedConfig1*>(parsed_config)->value(), 2);
}
TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNames) {
const char* test_json =
"{\"methodConfig\": ["
" {\"name\":[{\"service\":\"TestServ\"}]},"
" {\"name\":[{\"service\":\"TestServ\"}]}"
"]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
std::regex regex(
std::string("Service config parsing error.*referenced_errors"
".*Method Params.*referenced_errors"
".*methodConfig.*referenced_errors"
".*multiple method configs with same name"));
VerifyRegexMatch(error, regex);
} }
TEST_F(ServiceConfigTest, ErrorNoNames) { TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNamesWithNullMethod) {
const char* test_json = "{\"methodConfig\": [{\"blah\":1}]}"; const char* test_json =
"{\"methodConfig\": ["
" {\"name\":[{\"service\":\"TestServ\",\"method\":null}]},"
" {\"name\":[{\"service\":\"TestServ\"}]}"
"]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); std::string("Service config parsing error.*referenced_errors"
std::regex e( ".*Method Params.*referenced_errors"
std::string("(Service config parsing error)(.*)(referenced_errors)" ".*methodConfig.*referenced_errors"
"(.*)(Method Params)(.*)(referenced_errors)" ".*multiple method configs with same name"));
"(.*)(methodConfig)(.*)(referenced_errors)" VerifyRegexMatch(error, regex);
"(.*)(No names specified)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ServiceConfigTest, ErrorNoNamesWithMultipleMethodConfigs) { TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNamesWithEmptyMethod) {
const char* test_json = const char* test_json =
"{\"methodConfig\": [{}, {\"name\":[{\"service\":\"TestServ\"}]}]}"; "{\"methodConfig\": ["
" {\"name\":[{\"service\":\"TestServ\",\"method\":\"\"}]},"
" {\"name\":[{\"service\":\"TestServ\"}]}"
"]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); std::string("Service config parsing error.*referenced_errors"
std::regex e( ".*Method Params.*referenced_errors"
std::string("(Service config parsing error)(.*)(referenced_errors)" ".*methodConfig.*referenced_errors"
"(.*)(Method Params)(.*)(referenced_errors)" ".*multiple method configs with same name"));
"(.*)(methodConfig)(.*)(referenced_errors)" VerifyRegexMatch(error, regex);
"(.*)(No names specified)")); }
VerifyRegexMatch(error, e);
TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigs) {
const char* test_json =
"{\"methodConfig\": ["
" {\"name\":[{}]},"
" {\"name\":[{}]}"
"]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
std::regex regex(
std::string("Service config parsing error.*referenced_errors"
".*Method Params.*referenced_errors"
".*methodConfig.*referenced_errors"
".*multiple default method configs"));
VerifyRegexMatch(error, regex);
}
TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithNullService) {
const char* test_json =
"{\"methodConfig\": ["
" {\"name\":[{\"service\":null}]},"
" {\"name\":[{}]}"
"]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
std::regex regex(
std::string("Service config parsing error.*referenced_errors"
".*Method Params.*referenced_errors"
".*methodConfig.*referenced_errors"
".*multiple default method configs"));
VerifyRegexMatch(error, regex);
}
TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithEmptyService) {
const char* test_json =
"{\"methodConfig\": ["
" {\"name\":[{\"service\":\"\"}]},"
" {\"name\":[{}]}"
"]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
std::regex regex(
std::string("Service config parsing error.*referenced_errors"
".*Method Params.*referenced_errors"
".*methodConfig.*referenced_errors"
".*multiple default method configs"));
VerifyRegexMatch(error, regex);
} }
TEST_F(ServiceConfigTest, ValidMethodConfig) { TEST_F(ServiceConfigTest, ValidMethodConfig) {
@ -197,19 +281,19 @@ TEST_F(ServiceConfigTest, ValidMethodConfig) {
"{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}]}]}"; "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}]}]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
EXPECT_TRUE(error == GRPC_ERROR_NONE); EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
} }
TEST_F(ServiceConfigTest, Parser1BasicTest1) { TEST_F(ServiceConfigTest, Parser1BasicTest1) {
const char* test_json = "{\"global_param\":5}"; const char* test_json = "{\"global_param\":5}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
EXPECT_TRUE( EXPECT_EQ((static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0)))
(static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0))) ->value(),
->value() == 5); 5);
EXPECT_TRUE(svc_cfg->GetMethodParsedConfigVector( EXPECT_EQ(svc_cfg->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod")) == grpc_slice_from_static_string("/TestServ/TestMethod")),
nullptr); nullptr);
} }
@ -217,36 +301,32 @@ TEST_F(ServiceConfigTest, Parser1BasicTest2) {
const char* test_json = "{\"global_param\":1000}"; const char* test_json = "{\"global_param\":1000}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
EXPECT_TRUE( EXPECT_EQ((static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0)))
(static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0))) ->value(),
->value() == 1000); 1000);
} }
TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) { TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) {
const char* test_json = "{\"global_param\":\"5\"}"; const char* test_json = "{\"global_param\":\"5\"}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); absl::StrCat("Service config parsing error.*referenced_errors.*"
std::regex e(std::string("(Service config parsing " "Global Params.*referenced_errors.*",
"error)(.*)(referenced_errors)(.*)(Global " TestParser1::InvalidTypeErrorMessage()));
"Params)(.*)(referenced_errors)(.*)") + VerifyRegexMatch(error, regex);
TestParser1::InvalidTypeErrorMessage());
VerifyRegexMatch(error, e);
} }
TEST_F(ServiceConfigTest, Parser1ErrorInvalidValue) { TEST_F(ServiceConfigTest, Parser1ErrorInvalidValue) {
const char* test_json = "{\"global_param\":-5}"; const char* test_json = "{\"global_param\":-5}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); absl::StrCat("Service config parsing error.*referenced_errors.*"
std::regex e(std::string("(Service config parsing " "Global Params.*referenced_errors.*",
"error)(.*)(referenced_errors)(.*)(Global " TestParser1::InvalidValueErrorMessage()));
"Params)(.*)(referenced_errors)(.*)") + VerifyRegexMatch(error, regex);
TestParser1::InvalidValueErrorMessage());
VerifyRegexMatch(error, e);
} }
TEST_F(ServiceConfigTest, Parser2BasicTest) { TEST_F(ServiceConfigTest, Parser2BasicTest) {
@ -255,12 +335,12 @@ TEST_F(ServiceConfigTest, Parser2BasicTest) {
"\"method_param\":5}]}"; "\"method_param\":5}]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod")); grpc_slice_from_static_string("/TestServ/TestMethod"));
EXPECT_TRUE(vector_ptr != nullptr); ASSERT_NE(vector_ptr, nullptr);
auto parsed_config = ((*vector_ptr)[1]).get(); auto parsed_config = ((*vector_ptr)[1]).get();
EXPECT_TRUE(static_cast<TestParsedConfig1*>(parsed_config)->value() == 5); EXPECT_EQ(static_cast<TestParsedConfig1*>(parsed_config)->value(), 5);
} }
TEST_F(ServiceConfigTest, Parser2ErrorInvalidType) { TEST_F(ServiceConfigTest, Parser2ErrorInvalidType) {
@ -269,14 +349,12 @@ TEST_F(ServiceConfigTest, Parser2ErrorInvalidType) {
"\"method_param\":\"5\"}]}"; "\"method_param\":\"5\"}]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error != GRPC_ERROR_NONE); std::regex regex(
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); absl::StrCat("Service config parsing error.*referenced_errors\":\\[.*"
std::regex e(std::string("(Service config parsing " "Method Params.*referenced_errors.*methodConfig.*"
"error)(.*)(referenced_errors\":\\[)(.*)(Method " "referenced_errors.*",
"Params)(.*)(referenced_errors)(.*)(methodConfig)(" TestParser2::InvalidTypeErrorMessage()));
".*)(referenced_errors)(.*)") + VerifyRegexMatch(error, regex);
TestParser2::InvalidTypeErrorMessage());
VerifyRegexMatch(error, e);
} }
TEST_F(ServiceConfigTest, Parser2ErrorInvalidValue) { TEST_F(ServiceConfigTest, Parser2ErrorInvalidValue) {
@ -285,14 +363,12 @@ TEST_F(ServiceConfigTest, Parser2ErrorInvalidValue) {
"\"method_param\":-5}]}"; "\"method_param\":-5}]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error != GRPC_ERROR_NONE); std::regex regex(
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); absl::StrCat("Service config parsing error.*referenced_errors\":\\[.*"
std::regex e(std::string("(Service config parsing " "Method Params.*referenced_errors.*methodConfig.*"
"error)(.*)(referenced_errors\":\\[)(.*)(Method " "referenced_errors.*",
"Params)(.*)(referenced_errors)()(.*)(methodConfig)(" TestParser2::InvalidValueErrorMessage()));
".*)(referenced_errors)(.*)") + VerifyRegexMatch(error, regex);
TestParser2::InvalidValueErrorMessage());
VerifyRegexMatch(error, e);
} }
// Test parsing with ErrorParsers which always add errors // Test parsing with ErrorParsers which always add errors
@ -301,10 +377,10 @@ class ErroredParsersScopingTest : public ::testing::Test {
void SetUp() override { void SetUp() override {
ServiceConfig::Shutdown(); ServiceConfig::Shutdown();
ServiceConfig::Init(); ServiceConfig::Init();
EXPECT_TRUE( EXPECT_EQ(ServiceConfig::RegisterParser(absl::make_unique<ErrorParser>()),
ServiceConfig::RegisterParser(absl::make_unique<ErrorParser>()) == 0); 0);
EXPECT_TRUE( EXPECT_EQ(ServiceConfig::RegisterParser(absl::make_unique<ErrorParser>()),
ServiceConfig::RegisterParser(absl::make_unique<ErrorParser>()) == 1); 1);
} }
}; };
@ -312,33 +388,24 @@ TEST_F(ErroredParsersScopingTest, GlobalParams) {
const char* test_json = "{}"; const char* test_json = "{}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error != GRPC_ERROR_NONE); std::regex regex(absl::StrCat(
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); "Service config parsing error.*referenced_errors\":\\[.*"
std::regex e(std::string("(Service config parsing " "Global Params.*referenced_errors.*",
"error)(.*)(referenced_errors\":\\[)(.*)(Global " ErrorParser::GlobalError(), ".*", ErrorParser::GlobalError()));
"Params)(.*)(referenced_errors)()(.*)") + VerifyRegexMatch(error, regex);
ErrorParser::GlobalError() + std::string("(.*)") +
ErrorParser::GlobalError());
VerifyRegexMatch(error, e);
} }
TEST_F(ErroredParsersScopingTest, MethodParams) { TEST_F(ErroredParsersScopingTest, MethodParams) {
const char* test_json = "{\"methodConfig\": [{}]}"; const char* test_json = "{\"methodConfig\": [{}]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error != GRPC_ERROR_NONE); std::regex regex(absl::StrCat(
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); "Service config parsing error.*referenced_errors\":\\[.*"
std::regex e(std::string("(Service config parsing " "Global Params.*referenced_errors.*",
"error)(.*)(referenced_errors\":\\[)(.*)(Global " ErrorParser::GlobalError(), ".*", ErrorParser::GlobalError(),
"Params)(.*)(referenced_errors)()(.*)") + ".*Method Params.*referenced_errors.*methodConfig.*referenced_errors.*",
ErrorParser::GlobalError() + std::string("(.*)") + ErrorParser::MethodError(), ".*", ErrorParser::MethodError()));
ErrorParser::GlobalError() + VerifyRegexMatch(error, regex);
std::string("(.*)(Method Params)(.*)(referenced_errors)"
"(.*)(methodConfig)(.*)(referenced_errors)(.*)") +
ErrorParser::MethodError() + std::string("(.*)") +
ErrorParser::MethodError() +
std::string("(.*)(No names specified)"));
VerifyRegexMatch(error, e);
} }
class ClientChannelParserTest : public ::testing::Test { class ClientChannelParserTest : public ::testing::Test {
@ -346,9 +413,9 @@ class ClientChannelParserTest : public ::testing::Test {
void SetUp() override { void SetUp() override {
ServiceConfig::Shutdown(); ServiceConfig::Shutdown();
ServiceConfig::Init(); ServiceConfig::Init();
EXPECT_TRUE( EXPECT_EQ(
ServiceConfig::RegisterParser( ServiceConfig::RegisterParser(
absl::make_unique<internal::ClientChannelServiceConfigParser>()) == absl::make_unique<internal::ClientChannelServiceConfigParser>()),
0); 0);
} }
}; };
@ -357,12 +424,12 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigPickFirst) {
const char* test_json = "{\"loadBalancingConfig\": [{\"pick_first\":{}}]}"; const char* test_json = "{\"loadBalancingConfig\": [{\"pick_first\":{}}]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
const auto* parsed_config = const auto* parsed_config =
static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>( static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
auto lb_config = parsed_config->parsed_lb_config(); auto lb_config = parsed_config->parsed_lb_config();
EXPECT_TRUE(strcmp(lb_config->name(), "pick_first") == 0); EXPECT_STREQ(lb_config->name(), "pick_first");
} }
TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) { TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) {
@ -370,12 +437,12 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) {
"{\"loadBalancingConfig\": [{\"round_robin\":{}}, {}]}"; "{\"loadBalancingConfig\": [{\"round_robin\":{}}, {}]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
auto parsed_config = auto parsed_config =
static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>( static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
auto lb_config = parsed_config->parsed_lb_config(); auto lb_config = parsed_config->parsed_lb_config();
EXPECT_TRUE(strcmp(lb_config->name(), "round_robin") == 0); EXPECT_STREQ(lb_config->name(), "round_robin");
} }
TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) { TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
@ -384,12 +451,12 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
"[{\"grpclb\":{\"childPolicy\":[{\"pick_first\":{}}]}}]}"; "[{\"grpclb\":{\"childPolicy\":[{\"pick_first\":{}}]}}]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
const auto* parsed_config = const auto* parsed_config =
static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>( static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
auto lb_config = parsed_config->parsed_lb_config(); auto lb_config = parsed_config->parsed_lb_config();
EXPECT_TRUE(strcmp(lb_config->name(), "grpclb") == 0); EXPECT_STREQ(lb_config->name(), "grpclb");
} }
TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) { TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) {
@ -402,105 +469,91 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
ASSERT_TRUE(error == GRPC_ERROR_NONE);
const auto* parsed_config = const auto* parsed_config =
static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>( static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
auto lb_config = parsed_config->parsed_lb_config(); auto lb_config = parsed_config->parsed_lb_config();
EXPECT_TRUE(strcmp(lb_config->name(), "xds_experimental") == 0); EXPECT_STREQ(lb_config->name(), "xds_experimental");
} }
TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) { TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) {
const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}"; const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Global Params.*referenced_errors.*"
std::string("(Service config parsing error)(.*)(referenced_errors)" "Client channel global parser.*referenced_errors.*"
"(.*)(Global Params)(.*)(referenced_errors)" "field:loadBalancingConfig.*referenced_errors.*"
"(.*)(Client channel global parser)(.*)(referenced_errors)" "No known policy");
"(.*)(field:loadBalancingConfig)(.*)(referenced_errors)" VerifyRegexMatch(error, regex);
"(.*)(No known policy)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) { TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) {
const char* test_json = const char* test_json =
"{\"loadBalancingConfig\": " "{\"loadBalancingConfig\": ["
"[{\"grpclb\":{\"childPolicy\":[{\"unknown\":{}}]}}]}"; " {\"grpclb\":{\"childPolicy\":1}},"
" {\"round_robin\":{}}"
"]}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Global Params.*referenced_errors.*"
std::string("(Service config parsing error)(.*)(referenced_errors)" "Client channel global parser.*referenced_errors.*"
"(.*)(Global Params)(.*)(referenced_errors)" "field:loadBalancingConfig.*referenced_errors.*"
"(.*)(Client channel global parser)(.*)(referenced_errors)" "GrpcLb Parser.*referenced_errors.*"
"(.*)(field:loadBalancingConfig)(.*)(referenced_errors)" "field:childPolicy.*referenced_errors.*"
"(.*)(GrpcLb Parser)(.*)(referenced_errors)" "type should be array");
"(.*)(field:childPolicy)(.*)(referenced_errors)" VerifyRegexMatch(error, regex);
"(.*)(No known policy)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicy) { TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicy) {
const char* test_json = "{\"loadBalancingPolicy\":\"pick_first\"}"; const char* test_json = "{\"loadBalancingPolicy\":\"pick_first\"}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
const auto* parsed_config = const auto* parsed_config =
static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>( static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
const auto* lb_policy = parsed_config->parsed_deprecated_lb_policy(); EXPECT_EQ(parsed_config->parsed_deprecated_lb_policy(), "pick_first");
ASSERT_TRUE(lb_policy != nullptr);
EXPECT_TRUE(strcmp(lb_policy, "pick_first") == 0);
} }
TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicyAllCaps) { TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicyAllCaps) {
const char* test_json = "{\"loadBalancingPolicy\":\"PICK_FIRST\"}"; const char* test_json = "{\"loadBalancingPolicy\":\"PICK_FIRST\"}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
ASSERT_TRUE(error == GRPC_ERROR_NONE);
const auto* parsed_config = const auto* parsed_config =
static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>( static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
const auto* lb_policy = parsed_config->parsed_deprecated_lb_policy(); EXPECT_EQ(parsed_config->parsed_deprecated_lb_policy(), "pick_first");
ASSERT_TRUE(lb_policy != nullptr);
EXPECT_TRUE(strcmp(lb_policy, "pick_first") == 0);
} }
TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) { TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) {
const char* test_json = "{\"loadBalancingPolicy\":\"unknown\"}"; const char* test_json = "{\"loadBalancingPolicy\":\"unknown\"}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Global Params.*referenced_errors.*"
std::string("(Service config parsing " "Client channel global parser.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Global " "field:loadBalancingPolicy error:Unknown lb policy");
"Params)(.*)(referenced_errors)(.*)(Client channel global " VerifyRegexMatch(error, regex);
"parser)(.*)(referenced_errors)(.*)(field:"
"loadBalancingPolicy error:Unknown lb policy)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, LoadBalancingPolicyXdsNotAllowed) { TEST_F(ClientChannelParserTest, LoadBalancingPolicyXdsNotAllowed) {
const char* test_json = "{\"loadBalancingPolicy\":\"xds_experimental\"}"; const char* test_json = "{\"loadBalancingPolicy\":\"xds_experimental\"}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Global Params.*referenced_errors.*"
std::string("(Service config parsing " "Client channel global parser.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Global " "field:loadBalancingPolicy error:xds_experimental requires "
"Params)(.*)(referenced_errors)(.*)(Client channel global " "a config. Please use loadBalancingConfig instead.");
"parser)(.*)(referenced_errors)(.*)(field:" VerifyRegexMatch(error, regex);
"loadBalancingPolicy error:xds_experimental requires a "
"config. Please use loadBalancingConfig instead.)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, ValidRetryThrottling) { TEST_F(ClientChannelParserTest, ValidRetryThrottling) {
@ -513,8 +566,7 @@ TEST_F(ClientChannelParserTest, ValidRetryThrottling) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
ASSERT_TRUE(error == GRPC_ERROR_NONE);
const auto* parsed_config = const auto* parsed_config =
static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>( static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
@ -532,16 +584,13 @@ TEST_F(ClientChannelParserTest, RetryThrottlingMissingFields) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Global Params.*referenced_errors.*"
std::string("(Service config parsing " "Client channel global parser.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Global " "field:retryThrottling field:maxTokens error:Not found.*"
"Params)(.*)(referenced_errors)(.*)(Client channel global " "field:retryThrottling field:tokenRatio error:Not found");
"parser)(.*)(referenced_errors)(.*)(field:retryThrottling " VerifyRegexMatch(error, regex);
"field:maxTokens error:Not found)(.*)(field:retryThrottling "
"field:tokenRatio error:Not found)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, InvalidRetryThrottlingNegativeMaxTokens) { TEST_F(ClientChannelParserTest, InvalidRetryThrottlingNegativeMaxTokens) {
@ -554,15 +603,13 @@ TEST_F(ClientChannelParserTest, InvalidRetryThrottlingNegativeMaxTokens) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Global Params.*referenced_errors.*"
std::string("(Service config parsing " "Client channel global parser.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Global " "field:retryThrottling field:maxTokens error:should "
"Params)(.*)(referenced_errors)(.*)(Client channel global " "be greater than zero");
"parser)(.*)(referenced_errors)(.*)(field:retryThrottling " VerifyRegexMatch(error, regex);
"field:maxTokens error:should be greater than zero)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, InvalidRetryThrottlingInvalidTokenRatio) { TEST_F(ClientChannelParserTest, InvalidRetryThrottlingInvalidTokenRatio) {
@ -575,15 +622,13 @@ TEST_F(ClientChannelParserTest, InvalidRetryThrottlingInvalidTokenRatio) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Global Params.*referenced_errors.*"
std::string("(Service config parsing " "Client channel global parser.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Global " "field:retryThrottling field:tokenRatio "
"Params)(.*)(referenced_errors)(.*)(Client channel global " "error:Failed parsing");
"parser)(.*)(referenced_errors)(.*)(field:retryThrottling " VerifyRegexMatch(error, regex);
"field:tokenRatio error:Failed parsing)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, ValidTimeout) { TEST_F(ClientChannelParserTest, ValidTimeout) {
@ -598,10 +643,10 @@ TEST_F(ClientChannelParserTest, ValidTimeout) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod")); grpc_slice_from_static_string("/TestServ/TestMethod"));
EXPECT_TRUE(vector_ptr != nullptr); ASSERT_NE(vector_ptr, nullptr);
auto parsed_config = ((*vector_ptr)[0]).get(); auto parsed_config = ((*vector_ptr)[0]).get();
EXPECT_EQ((static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>( EXPECT_EQ((static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>(
parsed_config)) parsed_config))
@ -621,16 +666,13 @@ TEST_F(ClientChannelParserTest, InvalidTimeout) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Method Params.*referenced_errors.*"
std::string("(Service config parsing " "methodConfig.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Method " "Client channel parser.*referenced_errors.*"
"Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(" "field:timeout error:Failed parsing");
"referenced_errors)(.*)(Client channel " VerifyRegexMatch(error, regex);
"parser)(.*)(referenced_errors)(.*)(field:timeout "
"error:Failed parsing)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, ValidWaitForReady) { TEST_F(ClientChannelParserTest, ValidWaitForReady) {
@ -645,12 +687,12 @@ TEST_F(ClientChannelParserTest, ValidWaitForReady) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod")); grpc_slice_from_static_string("/TestServ/TestMethod"));
EXPECT_TRUE(vector_ptr != nullptr); ASSERT_NE(vector_ptr, nullptr);
auto parsed_config = ((*vector_ptr)[0]).get(); auto parsed_config = ((*vector_ptr)[0]).get();
EXPECT_TRUE( ASSERT_TRUE(
(static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>( (static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>(
parsed_config)) parsed_config))
->wait_for_ready() ->wait_for_ready()
@ -674,16 +716,13 @@ TEST_F(ClientChannelParserTest, InvalidWaitForReady) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Method Params.*referenced_errors.*"
std::string("(Service config parsing " "methodConfig.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Method " "Client channel parser.*referenced_errors.*"
"Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(" "field:waitForReady error:Type should be true/false");
"referenced_errors)(.*)(Client channel " VerifyRegexMatch(error, regex);
"parser)(.*)(referenced_errors)(.*)(field:waitForReady "
"error:Type should be true/false)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, ValidRetryPolicy) { TEST_F(ClientChannelParserTest, ValidRetryPolicy) {
@ -704,15 +743,14 @@ TEST_F(ClientChannelParserTest, ValidRetryPolicy) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
ASSERT_TRUE(error == GRPC_ERROR_NONE);
const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod")); grpc_slice_from_static_string("/TestServ/TestMethod"));
EXPECT_TRUE(vector_ptr != nullptr); ASSERT_NE(vector_ptr, nullptr);
const auto* parsed_config = const auto* parsed_config =
static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>( static_cast<grpc_core::internal::ClientChannelMethodParsedConfig*>(
((*vector_ptr)[0]).get()); ((*vector_ptr)[0]).get());
EXPECT_TRUE(parsed_config->retry_policy() != nullptr); ASSERT_NE(parsed_config->retry_policy(), nullptr);
EXPECT_EQ(parsed_config->retry_policy()->max_attempts, 3); EXPECT_EQ(parsed_config->retry_policy()->max_attempts, 3);
EXPECT_EQ(parsed_config->retry_policy()->initial_backoff, 1000); EXPECT_EQ(parsed_config->retry_policy()->initial_backoff, 1000);
EXPECT_EQ(parsed_config->retry_policy()->max_backoff, 120000); EXPECT_EQ(parsed_config->retry_policy()->max_backoff, 120000);
@ -739,16 +777,14 @@ TEST_F(ClientChannelParserTest, InvalidRetryPolicyMaxAttempts) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e(std::string( "Method Params.*referenced_errors.*"
"(Service config parsing " "methodConfig.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Method " "Client channel parser.*referenced_errors.*"
"Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(referenced_errors)(" "retryPolicy.*referenced_errors.*"
".*)(Client channel " "field:maxAttempts error:should be at least 2");
"parser)(.*)(referenced_errors)(.*)(retryPolicy)(.*)(referenced_errors)(." VerifyRegexMatch(error, regex);
"*)(field:maxAttempts error:should be at least 2)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, InvalidRetryPolicyInitialBackoff) { TEST_F(ClientChannelParserTest, InvalidRetryPolicyInitialBackoff) {
@ -769,16 +805,14 @@ TEST_F(ClientChannelParserTest, InvalidRetryPolicyInitialBackoff) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e(std::string( "Method Params.*referenced_errors.*"
"(Service config parsing " "methodConfig.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Method " "Client channel parser.*referenced_errors.*"
"Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(referenced_errors)(" "retryPolicy.*referenced_errors.*"
".*)(Client channel " "field:initialBackoff error:Failed to parse");
"parser)(.*)(referenced_errors)(.*)(retryPolicy)(.*)(referenced_errors)(." VerifyRegexMatch(error, regex);
"*)(field:initialBackoff error:Failed to parse)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, InvalidRetryPolicyMaxBackoff) { TEST_F(ClientChannelParserTest, InvalidRetryPolicyMaxBackoff) {
@ -799,16 +833,14 @@ TEST_F(ClientChannelParserTest, InvalidRetryPolicyMaxBackoff) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e(std::string( "Method Params.*referenced_errors.*"
"(Service config parsing " "methodConfig.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Method " "Client channel parser.*referenced_errors.*"
"Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(referenced_errors)(" "retryPolicy.*referenced_errors.*"
".*)(Client channel " "field:maxBackoff error:failed to parse");
"parser)(.*)(referenced_errors)(.*)(retryPolicy)(.*)(referenced_errors)(." VerifyRegexMatch(error, regex);
"*)(field:maxBackoff error:failed to parse)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, InvalidRetryPolicyBackoffMultiplier) { TEST_F(ClientChannelParserTest, InvalidRetryPolicyBackoffMultiplier) {
@ -829,16 +861,14 @@ TEST_F(ClientChannelParserTest, InvalidRetryPolicyBackoffMultiplier) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e(std::string( "Method Params.*referenced_errors.*"
"(Service config parsing " "methodConfig.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Method " "Client channel parser.*referenced_errors.*"
"Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(referenced_errors)(" "retryPolicy.*referenced_errors.*"
".*)(Client channel " "field:backoffMultiplier error:should be of type number");
"parser)(.*)(referenced_errors)(.*)(retryPolicy)(.*)(referenced_errors)(." VerifyRegexMatch(error, regex);
"*)(field:backoffMultiplier error:should be of type number)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, InvalidRetryPolicyRetryableStatusCodes) { TEST_F(ClientChannelParserTest, InvalidRetryPolicyRetryableStatusCodes) {
@ -859,16 +889,14 @@ TEST_F(ClientChannelParserTest, InvalidRetryPolicyRetryableStatusCodes) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e(std::string( "Method Params.*referenced_errors.*"
"(Service config parsing " "methodConfig.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Method " "Client channel parser.*referenced_errors.*"
"Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(referenced_errors)(" "retryPolicy.*referenced_errors.*"
".*)(Client channel " "field:retryableStatusCodes error:should be non-empty");
"parser)(.*)(referenced_errors)(.*)(retryPolicy)(.*)(referenced_errors)(." VerifyRegexMatch(error, regex);
"*)(field:retryableStatusCodes error:should be non-empty)"));
VerifyRegexMatch(error, e);
} }
TEST_F(ClientChannelParserTest, ValidHealthCheck) { TEST_F(ClientChannelParserTest, ValidHealthCheck) {
@ -880,14 +908,13 @@ TEST_F(ClientChannelParserTest, ValidHealthCheck) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
const auto* parsed_config = const auto* parsed_config =
static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>( static_cast<grpc_core::internal::ClientChannelGlobalParsedConfig*>(
svc_cfg->GetGlobalParsedConfig(0)); svc_cfg->GetGlobalParsedConfig(0));
ASSERT_TRUE(parsed_config != nullptr); ASSERT_NE(parsed_config, nullptr);
EXPECT_EQ(strcmp(parsed_config->health_check_service_name(), EXPECT_STREQ(parsed_config->health_check_service_name(),
"health_check_service_name"), "health_check_service_name");
0);
} }
TEST_F(ClientChannelParserTest, InvalidHealthCheckMultipleEntries) { TEST_F(ClientChannelParserTest, InvalidHealthCheckMultipleEntries) {
@ -902,12 +929,10 @@ TEST_F(ClientChannelParserTest, InvalidHealthCheckMultipleEntries) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "JSON parsing failed.*referenced_errors.*"
std::regex e( "duplicate key \"healthCheckConfig\" at index 104");
std::string("(JSON parsing failed)(.*)(referenced_errors)" VerifyRegexMatch(error, regex);
"(.*)(duplicate key \"healthCheckConfig\" at index 104)"));
VerifyRegexMatch(error, e);
} }
class MessageSizeParserTest : public ::testing::Test { class MessageSizeParserTest : public ::testing::Test {
@ -915,8 +940,9 @@ class MessageSizeParserTest : public ::testing::Test {
void SetUp() override { void SetUp() override {
ServiceConfig::Shutdown(); ServiceConfig::Shutdown();
ServiceConfig::Init(); ServiceConfig::Init();
EXPECT_TRUE(ServiceConfig::RegisterParser( EXPECT_EQ(
absl::make_unique<MessageSizeParser>()) == 0); ServiceConfig::RegisterParser(absl::make_unique<MessageSizeParser>()),
0);
} }
}; };
@ -933,14 +959,13 @@ TEST_F(MessageSizeParserTest, Valid) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
ASSERT_TRUE(error == GRPC_ERROR_NONE);
const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod")); grpc_slice_from_static_string("/TestServ/TestMethod"));
EXPECT_TRUE(vector_ptr != nullptr); ASSERT_NE(vector_ptr, nullptr);
auto parsed_config = auto parsed_config =
static_cast<MessageSizeParsedConfig*>(((*vector_ptr)[0]).get()); static_cast<MessageSizeParsedConfig*>(((*vector_ptr)[0]).get());
ASSERT_TRUE(parsed_config != nullptr); ASSERT_NE(parsed_config, nullptr);
EXPECT_EQ(parsed_config->limits().max_send_size, 1024); EXPECT_EQ(parsed_config->limits().max_send_size, 1024);
EXPECT_EQ(parsed_config->limits().max_recv_size, 1024); EXPECT_EQ(parsed_config->limits().max_recv_size, 1024);
} }
@ -957,16 +982,13 @@ TEST_F(MessageSizeParserTest, InvalidMaxRequestMessageBytes) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Method Params.*referenced_errors.*"
std::string("(Service config parsing " "methodConfig.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Method " "Message size parser.*referenced_errors.*"
"Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(" "field:maxRequestMessageBytes error:should be non-negative");
"referenced_errors)(.*)(Message size " VerifyRegexMatch(error, regex);
"parser)(.*)(referenced_errors)(.*)(field:"
"maxRequestMessageBytes error:should be non-negative)"));
VerifyRegexMatch(error, e);
} }
TEST_F(MessageSizeParserTest, InvalidMaxResponseMessageBytes) { TEST_F(MessageSizeParserTest, InvalidMaxResponseMessageBytes) {
@ -981,16 +1003,14 @@ TEST_F(MessageSizeParserTest, InvalidMaxResponseMessageBytes) {
"}"; "}";
grpc_error* error = GRPC_ERROR_NONE; grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error); auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex regex(
ASSERT_TRUE(error != GRPC_ERROR_NONE); "Service config parsing error.*referenced_errors.*"
std::regex e( "Method Params.*referenced_errors.*"
std::string("(Service config parsing " "methodConfig.*referenced_errors.*"
"error)(.*)(referenced_errors)(.*)(Method " "Message size parser.*referenced_errors.*"
"Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(" "field:maxResponseMessageBytes error:should be of type "
"referenced_errors)(.*)(Message size " "number");
"parser)(.*)(referenced_errors)(.*)(field:" VerifyRegexMatch(error, regex);
"maxResponseMessageBytes error:should be of type number)"));
VerifyRegexMatch(error, e);
} }
} // namespace testing } // namespace testing

@ -331,7 +331,7 @@ current_test_subprocess = subprocess.Popen([
args.test_bin_path, args.test_bin_path,
'--target_name', 'ipv4-config-causing-fallback-to-tcp.resolver-tests-version-4.grpctestingexp.', '--target_name', 'ipv4-config-causing-fallback-to-tcp.resolver-tests-version-4.grpctestingexp.',
'--expected_addrs', '1.2.3.4:443,False', '--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":"FooThirteen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFourteen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFifteen","service":"SimpleService"}],"waitForReady":true}]}',
'--expected_service_config_error', '', '--expected_service_config_error', '',
'--expected_lb_policy', '', '--expected_lb_policy', '',
'--enable_srv_queries', 'True', '--enable_srv_queries', 'True',

@ -205,7 +205,7 @@ resolver_component_tests:
- {TTL: '2100', data: '2607:f8b0:400a:801::1002', type: AAAA} - {TTL: '2100', data: '2607:f8b0:400a:801::1002', type: AAAA}
- expected_addrs: - expected_addrs:
- {address: '1.2.3.4:443', is_balancer: false} - {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":"FooThirteen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFourteen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFifteen","service":"SimpleService"}],"waitForReady":true}]}'
expected_service_config_error: null expected_service_config_error: null
expected_lb_policy: null expected_lb_policy: null
enable_srv_queries: true enable_srv_queries: true
@ -216,7 +216,7 @@ resolver_component_tests:
ipv4-config-causing-fallback-to-tcp: ipv4-config-causing-fallback-to-tcp:
- {TTL: '2100', data: 1.2.3.4, type: A} - {TTL: '2100', data: 1.2.3.4, type: A}
_grpc_config.ipv4-config-causing-fallback-to-tcp: _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":"FooThirteen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFourteen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFifteen","service":"SimpleService"}],"waitForReady":true}]}}]',
type: TXT} type: TXT}
# Tests for which we don't enable SRV queries # Tests for which we don't enable SRV queries
- expected_addrs: - expected_addrs:

Loading…
Cancel
Save